From 1d39bf2811fb4fc01949480dc6cb9c0bd537323e Mon Sep 17 00:00:00 2001 From: Christian 'ketura' McCarty Date: Mon, 23 Sep 2024 19:25:18 -0500 Subject: [PATCH 1/3] Bug fixes - Fixed missing return value in deck stats causing a superfluous error in the log - Fixed deck validation causing an error in PC-Movie if a Map was added before a RB or Ring - Fixed leagues not permitting decks to be altered or tables to be created on the same day of a serie end --- .../lotro/async/handler/DeckRequestHandler.java | 1 + .../main/java/com/gempukku/lotro/common/DateUtils.java | 9 ++++++++- .../lotro/game/formats/DefaultLotroFormat.java | 10 ++++++++-- .../java/com/gempukku/lotro/league/LeagueService.java | 2 +- 4 files changed, 18 insertions(+), 4 deletions(-) diff --git a/gemp-lotr/gemp-lotr-async/src/main/java/com/gempukku/lotro/async/handler/DeckRequestHandler.java b/gemp-lotr/gemp-lotr-async/src/main/java/com/gempukku/lotro/async/handler/DeckRequestHandler.java index 508e9c172..5b38c29f8 100644 --- a/gemp-lotr/gemp-lotr-async/src/main/java/com/gempukku/lotro/async/handler/DeckRequestHandler.java +++ b/gemp-lotr/gemp-lotr-async/src/main/java/com/gempukku/lotro/async/handler/DeckRequestHandler.java @@ -157,6 +157,7 @@ public class DeckRequestHandler extends LotroServerRequestHandler implements Uri if(format == null || targetFormat == null) { responseWriter.writeHtmlResponse("Invalid format: " + targetFormat); + return; } List validation = format.validateDeck(deck); diff --git a/gemp-lotr/gemp-lotr-common/src/main/java/com/gempukku/lotro/common/DateUtils.java b/gemp-lotr/gemp-lotr-common/src/main/java/com/gempukku/lotro/common/DateUtils.java index fcf3cec15..2c3512238 100644 --- a/gemp-lotr/gemp-lotr-common/src/main/java/com/gempukku/lotro/common/DateUtils.java +++ b/gemp-lotr/gemp-lotr-common/src/main/java/com/gempukku/lotro/common/DateUtils.java @@ -38,7 +38,14 @@ public class DateUtils { public static boolean IsToday(ZonedDateTime date) { return DaysSince(date) == 0; } public static boolean IsAtLeastDayAfter(ZonedDateTime a, ZonedDateTime b) { return DaysBetween(b, a) >= 1; } public static boolean IsAfterStart(ZonedDateTime date, ZonedDateTime start) { return date.isEqual(start) || date.isAfter(start); } - public static boolean IsBeforeEnd(ZonedDateTime date, ZonedDateTime end) { return DaysBetween(end, date) < 0; } + public static boolean IsBeforeEnd(ZonedDateTime date, ZonedDateTime end) { + if(IsSameDay(date, end)) { + return date.isBefore(end.plusDays(1)); + } + else { + return date.isBefore(end); + } + } public static boolean IsSameDay(ZonedDateTime a, ZonedDateTime b) { return DaysBetween(a, b) == 0; } public static long DaysBetween(ZonedDateTime a, ZonedDateTime b) { return Duration.between(a, b).toDays(); } public static long DaysSince(ZonedDateTime date) { return DaysBetween(date, Now()); } diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/game/formats/DefaultLotroFormat.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/game/formats/DefaultLotroFormat.java index b84a2ba5b..bb134d5cc 100644 --- a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/game/formats/DefaultLotroFormat.java +++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/game/formats/DefaultLotroFormat.java @@ -4,6 +4,7 @@ import com.gempukku.lotro.common.*; import com.gempukku.lotro.game.*; import com.gempukku.lotro.logic.GameUtils; import com.gempukku.lotro.logic.vo.LotroDeck; +import org.apache.commons.lang3.StringUtils; import java.util.*; import java.util.stream.Collectors; @@ -712,8 +713,13 @@ public class DefaultLotroFormat implements LotroFormat { sites.add(new PhysicalCardImpl(0, bp, "", _library.getLotroCardBlueprint(bp))); } - var rb = new PhysicalCardImpl(0, deck.getRingBearer(), "", _library.getLotroCardBlueprint(deck.getRingBearer())); - var ring = new PhysicalCardImpl(0, deck.getRing(), "", _library.getLotroCardBlueprint(deck.getRing())); + PhysicalCardImpl rb = null, ring = null; + if(!StringUtils.isEmpty(deck.getRingBearer())) { + rb = new PhysicalCardImpl(0, deck.getRingBearer(), "", _library.getLotroCardBlueprint(deck.getRingBearer())); + } + if(!StringUtils.isEmpty(deck.getRing())) { + ring = new PhysicalCardImpl(0, deck.getRing(), "", _library.getLotroCardBlueprint(deck.getRing())); + } var result = map.validatePreGameDeckCheck(freeps, shadow, sites, rb, ring, new PhysicalCardImpl(0, mapBP, "", map)); if(!result.success()) diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/league/LeagueService.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/league/LeagueService.java index f686d7c71..b0dce0c6b 100644 --- a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/league/LeagueService.java +++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/league/LeagueService.java @@ -149,7 +149,7 @@ public class LeagueService { var currentDate = DateUtils.Now(); for (LeagueSerieInfo leagueSerieInfo : league.getLeagueData(_productLibrary, _formatLibrary, _soloDraftDefinitions).getSeries()) { - if (currentDate.isAfter( leagueSerieInfo.getStart()) && currentDate.isBefore(leagueSerieInfo.getEnd())) + if (currentDate.isAfter( leagueSerieInfo.getStart()) && DateUtils.IsBeforeEnd(currentDate, leagueSerieInfo.getEnd())) return leagueSerieInfo; } From 429b4d092aa437381a6d87c86a22e71543ff5b68 Mon Sep 17 00:00:00 2001 From: Christian 'ketura' McCarty Date: Mon, 23 Sep 2024 19:54:27 -0500 Subject: [PATCH 2/3] Adding currently active sealed leagues/tournaments to the deck target format dropdown so that validation can be used. --- .../gempukku/lotro/async/handler/CollectionRequestHandler.java | 2 ++ .../gemp-lotr-async/src/main/web/js/gemp-022/deckBuildingUi.js | 1 + 2 files changed, 3 insertions(+) diff --git a/gemp-lotr/gemp-lotr-async/src/main/java/com/gempukku/lotro/async/handler/CollectionRequestHandler.java b/gemp-lotr/gemp-lotr-async/src/main/java/com/gempukku/lotro/async/handler/CollectionRequestHandler.java index d24c31bc5..bfdd58ec2 100644 --- a/gemp-lotr/gemp-lotr-async/src/main/java/com/gempukku/lotro/async/handler/CollectionRequestHandler.java +++ b/gemp-lotr/gemp-lotr-async/src/main/java/com/gempukku/lotro/async/handler/CollectionRequestHandler.java @@ -254,6 +254,7 @@ public class CollectionRequestHandler extends LotroServerRequestHandler implemen Element collectionElem = doc.createElement("collection"); collectionElem.setAttribute("type", collectionType.getCode()); collectionElem.setAttribute("name", collectionType.getFullName()); + collectionElem.setAttribute("format", serie.getFormat().getCode()); collectionsElem.appendChild(collectionElem); } } @@ -266,6 +267,7 @@ public class CollectionRequestHandler extends LotroServerRequestHandler implemen Element collectionElem = doc.createElement("collection"); collectionElem.setAttribute("type", collectionType.getCode()); collectionElem.setAttribute("name", collectionType.getFullName()); + collectionElem.setAttribute("format", tourney.getFormatCode()); collectionsElem.appendChild(collectionElem); } diff --git a/gemp-lotr/gemp-lotr-async/src/main/web/js/gemp-022/deckBuildingUi.js b/gemp-lotr/gemp-lotr-async/src/main/web/js/gemp-022/deckBuildingUi.js index 1c58638eb..c32823209 100644 --- a/gemp-lotr/gemp-lotr-async/src/main/web/js/gemp-022/deckBuildingUi.js +++ b/gemp-lotr/gemp-lotr-async/src/main/web/js/gemp-022/deckBuildingUi.js @@ -393,6 +393,7 @@ var GempLotrDeckBuildingUI = Class.extend({ for (var i = 0; i < collections.length; i++) { var collection = collections[i]; $("#collectionSelect").append(""); + $("#formatSelect").append(""); } } }); From 6b2af8fa75f079e96f5cecb235d6b571454dbb7f Mon Sep 17 00:00:00 2001 From: Christian 'ketura' McCarty Date: Mon, 23 Sep 2024 21:42:46 -0500 Subject: [PATCH 3/3] Sealed tournament fixes - Fixed sealed tournaments swallowing deck registration during the deck registration phase - Removed the "all players have registered" short-circuit condition, so that players don't get rug-pulled if making last-minute adjustments --- .../src/main/web/js/gemp-022/hallUi.js | 2 +- .../com/gempukku/lotro/hall/HallServer.java | 21 ++++++++++++------- .../tournament/ConstructedTournament.java | 3 ++- .../lotro/tournament/SealedTournament.java | 19 +++++++++-------- .../lotro/tournament/SoloDraftTournament.java | 9 ++++++-- .../gempukku/lotro/tournament/Tournament.java | 2 +- 6 files changed, 35 insertions(+), 21 deletions(-) diff --git a/gemp-lotr/gemp-lotr-async/src/main/web/js/gemp-022/hallUi.js b/gemp-lotr/gemp-lotr-async/src/main/web/js/gemp-022/hallUi.js index 8a7f44af6..a6a8668e3 100644 --- a/gemp-lotr/gemp-lotr-async/src/main/web/js/gemp-022/hallUi.js +++ b/gemp-lotr/gemp-lotr-async/src/main/web/js/gemp-022/hallUi.js @@ -542,7 +542,7 @@ var GempLotrHallUI = Class.extend({ if (joined == "true") { that.inTournament = true; debugger; - if(type === "sealed" && (stage === "deck-building" || stage === "registering decks")) { + if(type === "sealed" && (stage === "deck-building" || stage === "registering decks" || stage === "awaiting kickoff" || stage === "paused between rounds")) { var but = $(""); $(but).button().click(( function(tourneyInfo) { diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/hall/HallServer.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/hall/HallServer.java index a8ac3d611..ff990f61a 100644 --- a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/hall/HallServer.java +++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/hall/HallServer.java @@ -528,19 +528,26 @@ public class HallServer extends AbstractServer { String result = ""; var tournament = _tournamentService.getTournamentById(tournamentId); if (tournament != null) { - var stage = tournament.getInfo().Stage; - if(stage == Tournament.Stage.STARTING || stage == Tournament.Stage.DECK_BUILDING || - stage == Tournament.Stage.PAUSED || stage == Tournament.Stage.AWAITING_KICKOFF) { - LotroDeck lotroDeck = validateUserAndDeck(_formatLibrary.getFormat(tournament.getFormatCode()), player, deckName, tournament.getCollectionType()); + LotroDeck lotroDeck = validateUserAndDeck(_formatLibrary.getFormat(tournament.getFormatCode()), player, deckName, tournament.getCollectionType()); + var submitted = tournament.playerSubmittedDeck(player.getName(), lotroDeck); - tournament.playerSubmittedDeck(player.getName(), lotroDeck); + if(submitted) { + result = "Registered deck '" + deckName + "' with tournament " + tournament.getTournamentName() + " successfully." + + "

If you make an update to your deck, you will need to register it here again for any changes to take effect."; + _log.trace("Player '" + player.getName() + "' registered deck '" + deckName + "' for tournament '" + tournament.getTournamentName() + "' successfully."); } - result = "Registered deck '" + deckName + "' with tournament " + tournament.getTournamentName() + " successfully." - + "

If you make an update to your deck, you will need to register it here again for any changes to take effect."; + else { + result = "Could not register deck with tournament " + tournament.getTournamentName() + "." + + "

Please contact an administrator if you think this was in error."; + + _log.trace("Player '" + player.getName() + "' failed to register deck '" + deckName + "' for tournament '" + tournament.getTournamentName() + "'."); + } + hallChanged(); } else { result = "Registration for that tournament has already closed."; + _log.trace("Player '" + player.getName() + "' attempted to register deck '" + deckName + "' for tournament '" + tournament.getTournamentName() + "' after registration closed."); } return result; diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/ConstructedTournament.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/ConstructedTournament.java index f60a5f3d2..58f519a4f 100644 --- a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/ConstructedTournament.java +++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/ConstructedTournament.java @@ -39,8 +39,9 @@ public class ConstructedTournament extends BaseTournament implements Tournament } @Override - public void playerSubmittedDeck(String player, LotroDeck deck) { + public boolean playerSubmittedDeck(String player, LotroDeck deck) { //Constructed has all decks submitted upon signup, so nothing to do here + return false; } diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/SealedTournament.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/SealedTournament.java index 79a2cadec..0459471ea 100644 --- a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/SealedTournament.java +++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/SealedTournament.java @@ -37,13 +37,18 @@ public class SealedTournament extends BaseTournament implements Tournament { @Override - public void playerSubmittedDeck(String player, LotroDeck deck) { + public boolean playerSubmittedDeck(String player, LotroDeck deck) { writeLock.lock(); try { - if (getTournamentStage() == Stage.DECK_BUILDING && _players.contains(player)) { + var stage = getTournamentStage(); + if ((stage == Stage.DECK_BUILDING || stage == Stage.DECK_REGISTRATION || + stage == Tournament.Stage.PAUSED || stage == Tournament.Stage.AWAITING_KICKOFF) + && _players.contains(player)) { _tournamentService.updateRecordedPlayerDeck(_tournamentId, player, deck); _playerDecks.put(player, deck); + return true; } + return false; } finally { writeLock.unlock(); } @@ -150,7 +155,7 @@ public class SealedTournament extends BaseTournament implements Tournament { + "

Remember to return to the game hall and register your deck before " + DateUtils.FormatTime(_sealedInfo.RegistrationDeadline) + ".")); } else if (getTournamentStage() == Stage.DECK_BUILDING) { - if (DateUtils.Now().isAfter(_sealedInfo.DeckbuildingDeadline) && _playerDecks.values().stream().anyMatch(x -> StringUtils.isEmpty(x.getDeckName()))) { + if (DateUtils.Now().isAfter(_sealedInfo.DeckbuildingDeadline)) { _tournamentInfo.Stage = Stage.DECK_REGISTRATION; _tournamentService.recordTournamentStage(_tournamentId, getTournamentStage()); @@ -158,16 +163,12 @@ public class SealedTournament extends BaseTournament implements Tournament { result.add(new BroadcastAction("Deck building in tournament " + getTournamentName() + " has finished. Players now have " + duration + " to finish registering their decks. Any player who has not turned in their deck by the deadline at " + DateUtils.FormatTime(_sealedInfo.RegistrationDeadline) + " will be auto-disqualified." - + "

Once all players have turned in decks or the deadline has passed, the tournament will begin.")); - } - else if (DateUtils.Now().isAfter(_sealedInfo.DeckbuildingDeadline) && _playerDecks.values().stream().noneMatch(x -> StringUtils.isEmpty(x.getDeckName()))) { - _tournamentInfo.Stage = _sealedInfo.PostRegistrationStage(); - _tournamentService.recordTournamentStage(_tournamentId, getTournamentStage()); + + "

Once the deadline has passed, the tournament will begin.")); } } if (getTournamentStage() == Stage.DECK_REGISTRATION) { - if (DateUtils.Now().isAfter(_sealedInfo.RegistrationDeadline) || _playerDecks.values().stream().noneMatch(x -> StringUtils.isEmpty(x.getDeckName()))) { + if (DateUtils.Now().isAfter(_sealedInfo.RegistrationDeadline)) { disqualifyUnregisteredPlayers(); _tournamentInfo.Stage = _sealedInfo.PostRegistrationStage(); diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/SoloDraftTournament.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/SoloDraftTournament.java index d6e5ac4c6..d3e41e3ba 100644 --- a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/SoloDraftTournament.java +++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/SoloDraftTournament.java @@ -35,13 +35,18 @@ public class SoloDraftTournament extends BaseTournament implements Tournament { @Override - public void playerSubmittedDeck(String player, LotroDeck deck) { + public boolean playerSubmittedDeck(String player, LotroDeck deck) { writeLock.lock(); try { - if (getTournamentStage() == Stage.DECK_BUILDING && _players.contains(player)) { + var stage = getTournamentStage(); + if ((stage == Tournament.Stage.DECK_BUILDING || stage == Tournament.Stage.DECK_REGISTRATION || + stage == Tournament.Stage.PAUSED || stage == Tournament.Stage.AWAITING_KICKOFF) + && _players.contains(player)) { _tournamentService.updateRecordedPlayerDeck(_tournamentId, player, deck); _playerDecks.put(player, deck); + return true; } + return false; } finally { writeLock.unlock(); } diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/Tournament.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/Tournament.java index a0571dfdf..3e0009063 100644 --- a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/Tournament.java +++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/Tournament.java @@ -180,7 +180,7 @@ public interface Tournament { void reportGameFinished(String winner, String loser); void playerChosenCard(String playerName, String cardId); - void playerSubmittedDeck(String player, LotroDeck deck); + boolean playerSubmittedDeck(String player, LotroDeck deck); void issuePlayerMaterial(String player); LotroDeck getPlayerDeck(String player); String dropPlayer(String player);