From 62334bb638a5ffcfbf005dfb5ab23cc0c8ab9afc Mon Sep 17 00:00:00 2001 From: "jakub.salavec" Date: Mon, 14 Apr 2025 13:32:46 +0200 Subject: [PATCH] Fixed players being able to join 1v1 limited games after they start to force more rounds --- .../src/main/web/js/gemp-022/hallUi.js | 4 +-- .../lotro/hall/HallCommunicationChannel.java | 3 +- .../gempukku/lotro/hall/HallInfoVisitor.java | 2 +- .../com/gempukku/lotro/hall/HallServer.java | 35 ++++++++++--------- .../tournament/ConstructedTournament.java | 9 +++++ .../lotro/tournament/SealedTournament.java | 9 +++++ .../lotro/tournament/SoloDraftTournament.java | 10 ++++++ .../tournament/SoloTableDraftTournament.java | 10 ++++++ .../tournament/TableDraftTournament.java | 5 +++ .../gempukku/lotro/tournament/Tournament.java | 2 ++ .../lotro/tournament/TournamentService.java | 5 ++- 11 files changed, 73 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 bd34f4ae6..d7c9ceec5 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 @@ -666,6 +666,7 @@ var GempLotrHallUI = Class.extend({ var stage = tournament.getAttribute("stage"); if(stage !== null) stage = stage.toLowerCase(); + var joinable = tournament.getAttribute("joinable") === "true"; var abandoned = tournament.getAttribute("abandoned") === "true"; if (action == "add" || action == "update") { var actionsField = $(""); @@ -763,8 +764,7 @@ var GempLotrHallUI = Class.extend({ actionsField.append(but); } else if(!abandoned){ - if(!(type === "table_draft") && (stage === "deck-building" || stage === "drafting" || stage === "awaiting kickoff" - || stage === "preparing" || stage === "paused between rounds")) { + if(joinable) { var but = $(""); $(but).button().click(( function(tourneyInfo) { diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/hall/HallCommunicationChannel.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/hall/HallCommunicationChannel.java index 08534db31..2a6d7898c 100644 --- a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/hall/HallCommunicationChannel.java +++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/hall/HallCommunicationChannel.java @@ -128,7 +128,7 @@ public class HallCommunicationChannel implements LongPollableResource { @Override public void visitTournament(String tournamentKey, String collectionName, String formatName, String tournamentName, String type, String pairingDescription, - String tournamentStage, int round, int playerCount, String playerList, boolean playerInCompetition, boolean abandoned) { + String tournamentStage, int round, int playerCount, String playerList, boolean playerInCompetition, boolean abandoned, boolean joinable) { Map props = new HashMap<>(); props.put("collection", collectionName); props.put("format", formatName); @@ -141,6 +141,7 @@ public class HallCommunicationChannel implements LongPollableResource { props.put("playerList", playerList); props.put("signedUp", String.valueOf(playerInCompetition)); props.put("abandoned", String.valueOf(abandoned)); + props.put("joinable", String.valueOf(joinable)); tournamentsOnServer.put(tournamentKey, props); } diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/hall/HallInfoVisitor.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/hall/HallInfoVisitor.java index 65f845dbc..6e49cbe33 100644 --- a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/hall/HallInfoVisitor.java +++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/hall/HallInfoVisitor.java @@ -18,7 +18,7 @@ public interface HallInfoVisitor { int readyCheckSecsRemaining, boolean confirmedReadyCheck); public void visitTournament(String tournamentKey, String collectionName, String formatName, String tournamentName, String type, - String pairingDescription, String tournamentStage, int round, int playerCount, String playerList, boolean playerInCompetition, boolean abandoned); + String pairingDescription, String tournamentStage, int round, int playerCount, String playerList, boolean playerInCompetition, boolean abandoned, boolean joinable); public void runningPlayerGame(String gameId); } 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 2bedd4f32..fb26fb66f 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 @@ -1,6 +1,9 @@ package com.gempukku.lotro.hall; -import com.gempukku.lotro.*; +import com.gempukku.lotro.AbstractServer; +import com.gempukku.lotro.PrivateInformationException; +import com.gempukku.lotro.SubscriptionConflictException; +import com.gempukku.lotro.SubscriptionExpiredException; import com.gempukku.lotro.chat.ChatCommandCallback; import com.gempukku.lotro.chat.ChatCommandErrorException; import com.gempukku.lotro.chat.ChatRoomMediator; @@ -18,7 +21,10 @@ import com.gempukku.lotro.logic.GameUtils; import com.gempukku.lotro.logic.timing.GameResultListener; import com.gempukku.lotro.logic.vo.LotroDeck; import com.gempukku.lotro.service.AdminService; -import com.gempukku.lotro.tournament.*; +import com.gempukku.lotro.tournament.Tournament; +import com.gempukku.lotro.tournament.TournamentCallback; +import com.gempukku.lotro.tournament.TournamentQueue; +import com.gempukku.lotro.tournament.TournamentService; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -540,24 +546,21 @@ public class HallServer extends AbstractServer { try { 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 = null; - if (tournament.getInfo().Parameters().requiresDeck) { - lotroDeck = validateUserAndDeck(_formatLibrary.getFormat(tournament.getFormatCode()), player, deckName, tournament.getCollectionType()); - } - - _tournamentService.recordTournamentPlayer(tournamentId, player.getName(), lotroDeck); - tournament.issuePlayerMaterial(player.getName()); + if (tournament == null) { + result = "That tournament is already over."; + } else if (!tournament.isJoinable()) { + result = "That tournament does not allow late joining."; + } else { + LotroDeck lotroDeck = null; + if (tournament.getInfo().Parameters().requiresDeck) { + lotroDeck = validateUserAndDeck(_formatLibrary.getFormat(tournament.getFormatCode()), player, deckName, tournament.getCollectionType()); } + + _tournamentService.recordTournamentPlayer(tournamentId, player.getName(), lotroDeck); + tournament.issuePlayerMaterial(player.getName()); result = "Joined tournament " + tournament.getTournamentName() + " successfully."; hallChanged(); } - else { - result = "That tournament is already over."; - } 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 6c34f347f..cd3f1e69d 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 @@ -127,4 +127,13 @@ public class ConstructedTournament extends BaseTournament implements Tournament //This is for draft only } + @Override + public boolean isJoinable() { + Set activePlayers = new HashSet<>(_players); + activePlayers.removeAll(_droppedPlayers); + int maximumPlayers = _tournamentInfo._params.maximumPlayers; + return (getTournamentStage() == Tournament.Stage.STARTING || getTournamentStage() == Stage.PREPARING || + getTournamentStage() == Tournament.Stage.PAUSED || getTournamentStage() == Tournament.Stage.AWAITING_KICKOFF) + && (maximumPlayers > activePlayers.size() || maximumPlayers < 0); + } } 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 ee8ff9cd1..29f827c12 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 @@ -238,4 +238,13 @@ public class SealedTournament extends BaseTournament implements Tournament { //This is for draft only } + @Override + public boolean isJoinable() { + Set activePlayers = new HashSet<>(_players); + activePlayers.removeAll(_droppedPlayers); + int maximumPlayers = _tournamentInfo._params.maximumPlayers; + return (getTournamentStage() == Stage.STARTING || getTournamentStage() == Stage.DECK_BUILDING || getTournamentStage() == Stage.DECK_REGISTRATION || + getTournamentStage() == Tournament.Stage.PAUSED || getTournamentStage() == Tournament.Stage.AWAITING_KICKOFF) + && (maximumPlayers > activePlayers.size() || maximumPlayers < 0); + } } 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 0998cd7de..438e70a77 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 @@ -252,4 +252,14 @@ public class SoloDraftTournament extends BaseTournament implements Tournament { public CollectionType getCollectionType() { return _soloDraftInfo.generateCollectionInfo(); } + + @Override + public boolean isJoinable() { + Set activePlayers = new HashSet<>(_players); + activePlayers.removeAll(_droppedPlayers); + int maximumPlayers = _tournamentInfo._params.maximumPlayers; + return (getTournamentStage() == Stage.STARTING || getTournamentStage() == Stage.DECK_BUILDING || getTournamentStage() == Stage.DECK_REGISTRATION || + getTournamentStage() == Tournament.Stage.PAUSED || getTournamentStage() == Tournament.Stage.AWAITING_KICKOFF) + && (maximumPlayers > activePlayers.size() || maximumPlayers < 0); + } } diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/SoloTableDraftTournament.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/SoloTableDraftTournament.java index 51a5d13f1..01a77415e 100644 --- a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/SoloTableDraftTournament.java +++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/SoloTableDraftTournament.java @@ -235,4 +235,14 @@ public class SoloTableDraftTournament extends BaseTournament implements Tourname public CollectionType getCollectionType() { return soloTableDraftInfo.generateCollectionInfo(); } + + @Override + public boolean isJoinable() { + Set activePlayers = new HashSet<>(_players); + activePlayers.removeAll(_droppedPlayers); + int maximumPlayers = _tournamentInfo._params.maximumPlayers; + return (getTournamentStage() == Stage.STARTING || getTournamentStage() == Stage.DECK_BUILDING || getTournamentStage() == Stage.DECK_REGISTRATION || + getTournamentStage() == Tournament.Stage.PAUSED || getTournamentStage() == Tournament.Stage.AWAITING_KICKOFF) + && (maximumPlayers > activePlayers.size() || maximumPlayers < 0); + } } diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/TableDraftTournament.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/TableDraftTournament.java index 04f847c10..281eea745 100644 --- a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/TableDraftTournament.java +++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/TableDraftTournament.java @@ -257,4 +257,9 @@ public class TableDraftTournament extends BaseTournament implements Tournament { public CollectionType getCollectionType() { return tableDraftInfo.generateCollectionInfo(); } + + @Override + public boolean isJoinable() { + return false; // cannot join draft in progress + } } 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 ccf878962..3ed4b703f 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 @@ -204,4 +204,6 @@ public interface Tournament { String produceReport(DeckRenderer renderer) throws CardNotFoundException; TournamentInfo getInfo(); + + boolean isJoinable(); } diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/TournamentService.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/TournamentService.java index 07955a59b..732f12b46 100644 --- a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/TournamentService.java +++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/TournamentService.java @@ -101,6 +101,7 @@ public class TournamentService { sealedParams.name = queueName; sealedParams.cost = 0; sealedParams.minimumPlayers = 2; + sealedParams.maximumPlayers = 2; sealedParams.playoff = Tournament.PairingType.SINGLE_ELIMINATION; sealedParams.prizes = Tournament.PrizeType.NONE; @@ -128,6 +129,7 @@ public class TournamentService { soloDraftParams.name = queueName; soloDraftParams.cost = 0; soloDraftParams.minimumPlayers = 2; + soloDraftParams.maximumPlayers = 2; soloDraftParams.playoff = Tournament.PairingType.SINGLE_ELIMINATION; soloDraftParams.prizes = Tournament.PrizeType.NONE; @@ -265,7 +267,8 @@ public class TournamentService { visitor.visitTournament(tourneyID, tournament.getCollectionType().getFullName(), formatLibrary.getFormat(tournament.getFormatCode()).getName(), tournament.getTournamentName(), tournament.getInfo().Parameters().type.toString(), tournament.getPlayOffSystem(), tournament.getTournamentStage().getHumanReadable(), - tournament.getCurrentRound(), tournament.getPlayersInCompetitionCount(), tournament.getPlayerList(), tournament.isPlayerInCompetition(player.getName()), tournament.isPlayerAbandoned(player.getName())); + tournament.getCurrentRound(), tournament.getPlayersInCompetitionCount(), tournament.getPlayerList(), tournament.isPlayerInCompetition(player.getName()), tournament.isPlayerAbandoned(player.getName()), + tournament.isJoinable()); } }