Tournament admins can create solo table and table tournaments; max players attribute added to tournament parameters; queues enforce max players attribute

This commit is contained in:
jakub.salavec
2025-03-04 14:30:49 +01:00
parent 49205635cf
commit 2d8a047a12
13 changed files with 212 additions and 9 deletions

View File

@@ -11,6 +11,8 @@ import com.gempukku.lotro.db.PlayerDAO;
import com.gempukku.lotro.db.vo.CollectionType;
import com.gempukku.lotro.db.vo.League;
import com.gempukku.lotro.draft2.SoloDraftDefinitions;
import com.gempukku.lotro.draft3.DraftTimerProducer;
import com.gempukku.lotro.draft3.TableDraftDefinitions;
import com.gempukku.lotro.game.CardCollection;
import com.gempukku.lotro.game.LotroCardBlueprintLibrary;
import com.gempukku.lotro.game.Player;
@@ -58,6 +60,7 @@ public class AdminRequestHandler extends LotroServerRequestHandler implements Ur
private final PlayerDAO _playerDAO;
private final AdminService _adminService;
private final ChatServer _chatServer;
private final TableDraftDefinitions _tableDraftLibrary;
private static final Logger _log = LogManager.getLogger(AdminRequestHandler.class);
@@ -76,6 +79,7 @@ public class AdminRequestHandler extends LotroServerRequestHandler implements Ur
_cardLibrary = extractObject(context, LotroCardBlueprintLibrary.class);
_productLibrary = extractObject(context, ProductLibrary.class);
_chatServer = extractObject(context, ChatServer.class);
_tableDraftLibrary = extractObject(context, TableDraftDefinitions.class);
}
@Override
@@ -921,6 +925,15 @@ public class AdminRequestHandler extends LotroServerRequestHandler implements Ur
String soloDraftTurnInDurationStr = getFormParameterSafely(postDecoder, "soloDraftTurnInDuration");
String soloDraftFormatCodeStr = getFormParameterSafely(postDecoder, "soloDraftFormatCode");
String soloTableDraftDeckbuildingDurationStr = getFormParameterSafely(postDecoder, "soloTableDraftDeckbuildingDuration");
String soloTableDraftTurnInDurationStr = getFormParameterSafely(postDecoder, "soloTableDraftTurnInDuration");
String soloTableDraftFormatCodeStr = getFormParameterSafely(postDecoder, "soloTableDraftFormatCode");
String tableDraftDeckbuildingDurationStr = getFormParameterSafely(postDecoder, "tableDraftDeckbuildingDuration");
String tableDraftTurnInDurationStr = getFormParameterSafely(postDecoder, "tableDraftTurnInDuration");
String tableDraftFormatCodeStr = getFormParameterSafely(postDecoder, "tableDraftFormatCode");
String tableDraftTimer = getFormParameterSafely(postDecoder, "tableDraftTimer");
String wcStr = getFormParameterSafely(postDecoder, "wc");
String tournamentId = getFormParameterSafely(postDecoder, "tournamentId");
String formatStr = getFormParameterSafely(postDecoder, "formatCode");
@@ -1004,6 +1017,38 @@ public class AdminRequestHandler extends LotroServerRequestHandler implements Ur
soloDraftParams.requiresDeck = false;
params = soloDraftParams;
}
else if (type == Tournament.TournamentType.TABLE_SOLODRAFT) {
var soloTableDraftParams = new SoloTableDraftTournamentParams();
soloTableDraftParams.type = Tournament.TournamentType.TABLE_SOLODRAFT;
soloTableDraftParams.deckbuildingDuration = Throw400IfNullOrNonInteger("soloTableDraftDeckbuildingDuration", soloTableDraftDeckbuildingDurationStr);
soloTableDraftParams.turnInDuration = Throw400IfNullOrNonInteger("soloTableDraftTurnInDuration", soloTableDraftTurnInDurationStr);
Throw400IfStringNull("soloTableDraftFormatCode", soloTableDraftFormatCodeStr);
var tableDraftDefinition = _tableDraftLibrary.getTableDraftDefinition(soloTableDraftFormatCodeStr);
Throw400IfValidationFails("soloTableDraftFormatCode", soloTableDraftFormatCodeStr,tableDraftDefinition != null);
soloTableDraftParams.soloTableDraftFormatCode = soloTableDraftFormatCodeStr;
soloTableDraftParams.format = tableDraftDefinition.getFormat();
soloTableDraftParams.requiresDeck = false;
params = soloTableDraftParams;
}
else if (type == Tournament.TournamentType.TABLE_DRAFT) {
var tableDraftParams = new TableDraftTournamentParams();
tableDraftParams.type = Tournament.TournamentType.TABLE_DRAFT;
tableDraftParams.deckbuildingDuration = Throw400IfNullOrNonInteger("tableDraftDeckbuildingDuration", tableDraftDeckbuildingDurationStr);
tableDraftParams.turnInDuration = Throw400IfNullOrNonInteger("tableDraftTurnInDuration", tableDraftTurnInDurationStr);
Throw400IfStringNull("tableDraftFormatCode", tableDraftFormatCodeStr);
var tableDraftDefinition = _tableDraftLibrary.getTableDraftDefinition(tableDraftFormatCodeStr);
Throw400IfValidationFails("tableDraftFormatCode", tableDraftFormatCodeStr,tableDraftDefinition != null);
tableDraftParams.tableDraftFormatCode = tableDraftFormatCodeStr;
tableDraftParams.format = tableDraftDefinition.getFormat();
tableDraftParams.requiresDeck = false;
tableDraftParams.draftTimerProducerType = DraftTimerProducer.getDraftTimerProducer(tableDraftTimer);
tableDraftParams.maximumPlayers = tableDraftDefinition.getMaxPlayers();
params = tableDraftParams;
}
else {
params.type = Tournament.TournamentType.CONSTRUCTED;
var format = _formatLibrary.getFormat(formatStr);
@@ -1027,6 +1072,15 @@ public class AdminRequestHandler extends LotroServerRequestHandler implements Ur
if(type == Tournament.TournamentType.SEALED) {
info = new SealedTournamentInfo(_tournamentService, _productLibrary, _formatLibrary, start, (SealedTournamentParams)params);
}
else if (type == Tournament.TournamentType.SOLODRAFT) {
info = new SoloDraftTournamentInfo(_tournamentService, _productLibrary, _formatLibrary, start, ((SoloDraftTournamentParams) params), _soloDraftDefinitions);
}
else if (type == Tournament.TournamentType.TABLE_SOLODRAFT) {
info = new SoloTableDraftTournamentInfo(_tournamentService, _productLibrary, _formatLibrary, start, ((SoloTableDraftTournamentParams) params), _tableDraftLibrary);
}
else if (type == Tournament.TournamentType.TABLE_DRAFT) {
info = new TableDraftTournamentInfo(_tournamentService, _productLibrary, _formatLibrary, start, ((TableDraftTournamentParams) params), _tableDraftLibrary);
}
else {
info = new TournamentInfo(_tournamentService, _productLibrary, _formatLibrary, start, params);
}

View File

@@ -8,6 +8,8 @@ import com.gempukku.lotro.common.Side;
import com.gempukku.lotro.db.DeckDAO;
import com.gempukku.lotro.db.DeckSerialization;
import com.gempukku.lotro.draft2.SoloDraftDefinitions;
import com.gempukku.lotro.draft3.DraftTimerProducer;
import com.gempukku.lotro.draft3.TableDraftDefinitions;
import com.gempukku.lotro.game.*;
import com.gempukku.lotro.game.formats.LotroFormatLibrary;
import com.gempukku.lotro.league.SealedEventDefinition;
@@ -41,6 +43,7 @@ public class DeckRequestHandler extends LotroServerRequestHandler implements Uri
private final SoloDraftDefinitions _draftLibrary;
private final LotroServer _lotroServer;
private final MarkdownParser _markdownParser;
private final TableDraftDefinitions _tableDraftDefinitions;
private static final Logger _log = LogManager.getLogger(DeckRequestHandler.class);
@@ -53,6 +56,7 @@ public class DeckRequestHandler extends LotroServerRequestHandler implements Uri
_lotroServer = extractObject(context, LotroServer.class);
_draftLibrary = extractObject(context, SoloDraftDefinitions.class);
_markdownParser = extractObject(context, MarkdownParser.class);
_tableDraftDefinitions = extractObject(context, TableDraftDefinitions.class);
}
@Override
@@ -110,6 +114,10 @@ public class DeckRequestHandler extends LotroServerRequestHandler implements Uri
data.DraftTemplates = _draftLibrary.getAllSoloDrafts().values().stream()
.map(soloDraft -> new JSONDefs.ItemStub(soloDraft.getCode(), soloDraft.getFormat()))
.collect(Collectors.toMap(x-> x.code, x-> x));
data.TableDraftTemplates = _tableDraftDefinitions.getAllTableDrafts().values().stream()
.map(tableDraftDefinition -> new JSONDefs.ItemStub(tableDraftDefinition.getFormat(), tableDraftDefinition.getCode()))
.collect(Collectors.toMap(itemStub -> itemStub.name, itemStub -> itemStub));
data.TableDraftTimerTypes = DraftTimerProducer.getAllTypes();
json = JsonUtils.Serialize(data);
}

View File

@@ -156,22 +156,44 @@ $(document).ready(
$('.sealed-only').show();
$('.constructed-only').hide();
$('.solodraft-only').hide();
$('.solo-table-draft-only').hide();
$('.table-draft-only').hide();
}
else if(type === "SOLODRAFT") {
$('.sealed-only').hide();
$('.constructed-only').hide();
$('.solodraft-only').show();
$('.solo-table-draft-only').hide();
$('.table-draft-only').hide();
}
else if(type === "TABLE_SOLODRAFT") {
$('.sealed-only').hide();
$('.constructed-only').hide();
$('.solodraft-only').hide();
$('.solo-table-draft-only').show();
$('.table-draft-only').hide();
}
else if(type === "TABLE_DRAFT") {
$('.sealed-only').hide();
$('.constructed-only').hide();
$('.solodraft-only').hide();
$('.solo-table-draft-only').hide();
$('.table-draft-only').show();
}
else {
$('.sealed-only').hide();
$('.constructed-only').show();
$('.solodraft-only').hide();
$('.solo-table-draft-only').hide();
$('.table-draft-only').hide();
}
});
$('.sealed-only').hide();
$('.solodraft-only').hide();
$('.constructed-only').show();
$('.solo-table-draft-only').hide();
$('.table-draft-only').hide();
hall.comm.getFormats(true,
@@ -180,7 +202,9 @@ $(document).ready(
//console.log(json);
let drafts = json.DraftTemplates;
let formats = json.Formats;
let sealed = json.SealedTemplates
let sealed = json.SealedTemplates;
let tableDrafts = json.TableDraftTemplates;
let tableDraftTimers = json.TableDraftTimerTypes;
for (var prop in formats) {
if (Object.prototype.hasOwnProperty.call(formats, prop)) {
@@ -247,6 +271,34 @@ $(document).ready(
$("#sch-tourney-solodraft-format").append(item);
}
}
for (var prop in tableDrafts) {
if (Object.prototype.hasOwnProperty.call(tableDrafts, prop)) {
//console.log(prop);
let code = tableDrafts[prop].format;
let id = tableDrafts[prop].id;
var item = $("<option/>")
.attr("value", id)
.text(prop);
$("#sch-tourney-solo-table-draft-format").append(item);
var item2 = $("<option/>")
.attr("value", id)
.text(prop);
$("#sch-tourney-table-draft-format").append(item2);
}
}
for (var prop in tableDraftTimers) {
if (Object.prototype.hasOwnProperty.call(tableDraftTimers, prop)) {
//console.log(prop);
var item = $("<option/>")
.attr("value", tableDraftTimers[prop])
.text(tableDraftTimers[prop]);
$("#sch-tourney-table-draft-timer").append(item);
}
}
},
tourneyErrorMap());
});
@@ -275,6 +327,15 @@ function processScheduledTournament(preview, resultdiv, callback) {
$("#sch-tourney-solodraft-format").val(),
$("#sch-tourney-solodraft-deckbuild").val(),
$("#sch-tourney-solodraft-registration").val(),
$("#sch-tourney-solo-table-draft-format").val(),
$("#sch-tourney-solo-table-draft-deckbuild").val(),
$("#sch-tourney-solo-table-draft-registration").val(),
$("#sch-tourney-table-draft-format").val(),
$("#sch-tourney-table-draft-timer").val(),
$("#sch-tourney-table-draft-deckbuild").val(),
$("#sch-tourney-table-draft-registration").val(),
$("#sch-tourney-start").val(),
$("#sch-tourney-cost").val(),
@@ -414,7 +475,8 @@ function tourneyErrorMap(outputControl, callback=null) {
<option value="CONSTRUCTED">Constructed</option>
<option value="SEALED">Sealed</option>
<option value="SOLODRAFT">Solo Draft</option>
<option value="TABLE_SOLODRAFT">Table Solo Draft</option>
<option value="TABLE_DRAFT">Table Draft</option>
</select>
</div>
@@ -452,6 +514,41 @@ function tourneyErrorMap(outputControl, callback=null) {
<div class="label-column">Deck registration grace period (in minutes): </div>
<input type="number" min="1" id="sch-tourney-solodraft-registration" value="5" class="flex-fill">
</div>
<div class="flex-horiz solo-table-draft-only">
<div class="label-column">Solo Table Draft Format: </div>
<select id="sch-tourney-solo-table-draft-format" name="format" class="flex-fill"></select>
</div>
<div class="flex-horiz solo-table-draft-only">
<div class="label-column">Solo Table Drafting + Deckbuilding duration (in minutes): </div>
<input type="number" min="1" id="sch-tourney-solo-table-draft-deckbuild" value="25" class="flex-fill">
</div>
<div class="flex-horiz solo-table-draft-only">
<div class="label-column">Deck registration grace period (in minutes): </div>
<input type="number" min="1" id="sch-tourney-solo-table-draft-registration" value="5" class="flex-fill">
</div>
<div class="flex-horiz table-draft-only">
<div class="label-column">Table Draft Format: </div>
<select id="sch-tourney-table-draft-format" name="format" class="flex-fill"></select>
</div>
<div class="flex-horiz table-draft-only">
<div class="label-column">Table Draft Timer: </div>
<select id="sch-tourney-table-draft-timer" name="format" class="flex-fill"></select>
</div>
<div class="flex-horiz table-draft-only">
<div class="label-column">Deckbuilding duration after draft (in minutes): </div>
<input type="number" min="1" id="sch-tourney-table-draft-deckbuild" value="15" class="flex-fill">
</div>
<div class="flex-horiz table-draft-only">
<div class="label-column">Deck registration grace period (in minutes): </div>
<input type="number" min="1" id="sch-tourney-table-draft-registration" value="2" class="flex-fill">
</div>
<div class="flex-horiz">
<div class="label-column">World Championship: </div>

View File

@@ -1192,6 +1192,8 @@ var GempLotrCommunication = Class.extend({
processScheduledTournament:function (preview, name, type, wc, tournamentId,
formatCode, sealedFormatCode, deckbuildingDuration, turnInDuration,
soloDraftFormatCode, soloDraftDeckbuildingDuration, soloDraftTurnInDuration,
soloTableDraftFormatCode, soloTableDraftDeckbuildingDuration, soloTableDraftTurnInDuration,
tableDraftFormatCode, tableDraftTimer, tableDraftDeckbuildingDuration, tableDraftTurnInDuration,
start, cost, playoff, tiebreaker, prizeStructure, minPlayers, manualKickoff,
callback, errorMap) {
$.ajax({
@@ -1211,6 +1213,13 @@ var GempLotrCommunication = Class.extend({
soloDraftFormatCode:soloDraftFormatCode,
soloDraftDeckbuildingDuration:soloDraftDeckbuildingDuration,
soloDraftTurnInDuration:soloDraftTurnInDuration,
soloTableDraftFormatCode:soloTableDraftFormatCode,
soloTableDraftDeckbuildingDuration:soloTableDraftDeckbuildingDuration,
soloTableDraftTurnInDuration:soloTableDraftTurnInDuration,
tableDraftFormatCode:tableDraftFormatCode,
tableDraftTimer:tableDraftTimer,
tableDraftDeckbuildingDuration:tableDraftDeckbuildingDuration,
tableDraftTurnInDuration:tableDraftTurnInDuration,
start:start,
cost:cost,
playoff:playoff,

View File

@@ -84,6 +84,12 @@ public class JSONDefs {
public Map<String, Format> Formats;
public Map<String, SealedTemplate> SealedTemplates;
public Map<String, ItemStub> DraftTemplates;
public Map<String, ItemStub> TableDraftTemplates;
public List<String> TableDraftTimerTypes;
}
public static class TimerType {
public String type;
}
public static class ErrataInfo {

View File

@@ -1,10 +1,12 @@
package com.gempukku.lotro.draft3;
import java.util.List;
public interface DraftTimerProducer {
DraftTimer getDraftTimer();
enum Type {
CLASSIC
CLASSIC, NO_TIMER
}
static DraftTimerProducer getDraftTimerProducer(Type type) {
@@ -14,4 +16,16 @@ public interface DraftTimerProducer {
return null;
}
}
static Type getDraftTimerProducer(String type) {
if (type.equals("CLASSIC")) {
return Type.CLASSIC;
} else {
return Type.NO_TIMER;
}
}
static List<String> getAllTypes() {
return List.of("CLASSIC", "NO_TIMER");
}
}

View File

@@ -5,7 +5,8 @@ import com.gempukku.lotro.db.vo.CollectionType;
public interface TableDraftDefinition {
TableDraft getTableDraft(CollectionsManager collectionsManager, CollectionType collectionType, DraftTimerProducer draftTimerProducer);
int getMaxPlayers();
String getFormatCode();
String getCode();
String getFormat();
}

View File

@@ -15,7 +15,7 @@ public class TableDraftDefinitions {
public TableDraftDefinitions(CollectionsManager collectionsManager, LotroCardBlueprintLibrary cardLibrary,
LotroFormatLibrary formatLibrary) {
FotrTableDraftDefinition fotrTableDraftDefinition = new FotrTableDraftDefinition(collectionsManager, cardLibrary, formatLibrary);
draftTypes.put(fotrTableDraftDefinition.getFormatCode(), fotrTableDraftDefinition);
draftTypes.put(fotrTableDraftDefinition.getCode(), fotrTableDraftDefinition);
}
public TableDraftDefinition getTableDraftDefinition(String draftType) {

View File

@@ -26,7 +26,12 @@ public class FotrTableDraftDefinition implements TableDraftDefinition {
}
@Override
public String getFormatCode() {
public int getMaxPlayers() {
return PLAYER_COUNT;
}
@Override
public String getCode() {
return "fotr_table_draft";
}

View File

@@ -5,10 +5,12 @@ import com.gempukku.lotro.collection.CollectionsManager;
public class ImmediateRecurringQueue extends AbstractTournamentQueue implements TournamentQueue {
private final int _playerCap;
private final int maxPlayers;
public ImmediateRecurringQueue(TournamentService tournamentService, String queueId, String queueName, TournamentInfo info) {
super(tournamentService, queueId, queueName, info);
_playerCap = info.Parameters().minimumPlayers;
maxPlayers = info.Parameters().maximumPlayers;
}
@Override
@@ -42,7 +44,7 @@ public class ImmediateRecurringQueue extends AbstractTournamentQueue implements
@Override
public boolean isJoinable() {
return true;
return maxPlayers < 0 || _players.size() < maxPlayers;
}
private TournamentInfo getInfo(String tournamentId, String tournamentName) {
@@ -115,6 +117,7 @@ public class ImmediateRecurringQueue extends AbstractTournamentQueue implements
tbr.cost = getCost();
tbr.prizes = _tournamentInfo._params.prizes;
tbr.minimumPlayers = _playerCap;
tbr.maximumPlayers = maxPlayers;
tbr.requiresDeck = _tournamentInfo._params.requiresDeck;
return tbr;

View File

@@ -17,10 +17,12 @@ public class RecurringScheduledQueue extends AbstractTournamentQueue implements
private String _nextStartText;
private final int _minimumPlayers;
private final int _maximumPlayers;
public RecurringScheduledQueue(TournamentService tournamentService, String queueId, String queueName, TournamentInfo info, Duration repeatEvery) {
super(tournamentService, queueId, queueName, info);
_minimumPlayers = info._params.minimumPlayers;
_maximumPlayers = info._params.maximumPlayers;
_repeatEvery = repeatEvery;
var sinceOriginal = Duration.between(info.StartTime, ZonedDateTime.now());
@@ -49,7 +51,7 @@ public class RecurringScheduledQueue extends AbstractTournamentQueue implements
@Override
public boolean isJoinable() {
return ZonedDateTime.now().isAfter(_nextStart.minus(_signupTimeBeforeStart));
return ZonedDateTime.now().isAfter(_nextStart.minus(_signupTimeBeforeStart)) && (_maximumPlayers < 0 || _players.size() < _maximumPlayers);
}
@Override
@@ -149,6 +151,7 @@ public class RecurringScheduledQueue extends AbstractTournamentQueue implements
tbr.cost = getCost();
tbr.prizes = _tournamentInfo._params.prizes;
tbr.minimumPlayers = _minimumPlayers;
tbr.maximumPlayers = _maximumPlayers;
tbr.requiresDeck = _tournamentInfo._params.requiresDeck;
return tbr;

View File

@@ -12,10 +12,12 @@ public class ScheduledTournamentQueue extends AbstractTournamentQueue implements
private static final Duration _signupTimeBeforeStart = Duration.ofMinutes(60);
private static final Duration _wcSignupTimeBeforeStart = Duration.ofHours(30);
private final ZonedDateTime _startTime;
private final int maximumPlayers;
public ScheduledTournamentQueue(TournamentService tournamentService, String queueId, String queueName, TournamentInfo info) {
super(tournamentService, queueId, queueName, info);
_startTime = DateUtils.ParseDate(info.Parameters().startTime);
maximumPlayers = info.Parameters().maximumPlayers;
}
@Override
@@ -61,6 +63,6 @@ public class ScheduledTournamentQueue extends AbstractTournamentQueue implements
if (_tournamentInfo.Parameters().tournamentId.toLowerCase().contains("wc")) {
window = _wcSignupTimeBeforeStart;
}
return DateUtils.Now().isAfter(_startTime.minus(window));
return DateUtils.Now().isAfter(_startTime.minus(window)) && (maximumPlayers < 0 || _players.size() < maximumPlayers);
}
}

View File

@@ -18,6 +18,7 @@ public class TournamentParams {
public int cost;
public String tiebreaker;
public int minimumPlayers = 2;
public int maximumPlayers = -1; // Negative value = no maximum set
public Tournament.PrizeType prizes = Tournament.PrizeType.NONE;
public Tournament.Stage getInitialStage() {