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 0c5528abf..6cb24a16a 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 @@ -747,7 +747,6 @@ public class HallServer extends AbstractServer { private int _tickCounter = 60; public void cleanup(boolean forceRefresh) throws SQLException, IOException { - _hallDataAccessLock.writeLock().lock(); try { // Remove finished games @@ -869,6 +868,7 @@ public class HallServer extends AbstractServer { public ManualGameSpawner GetManualGameSpawner(Tournament tournament, LotroFormat format, GameTimer timer, String description) { return new ManualGameSpawner(tournament, format, timer, description); } + public class ManualGameSpawner implements TournamentCallback { private final Tournament _tournament; private final GameSettings _settings; @@ -891,7 +891,6 @@ public class HallServer extends AbstractServer { _hallDataAccessLock.writeLock().lock(); try { if (!_shutdown) { - final GameTable gameTable = tableHolder.setupTournamentTable(_settings, participants); final LotroGameMediator mediator = createGameMediator(participants, _notifyHallListeners, _tournament.getTournamentName(), _settings); diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/DefaultTournament.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/DefaultTournament.java index 77ff56992..81a6231ef 100644 --- a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/DefaultTournament.java +++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/DefaultTournament.java @@ -17,12 +17,13 @@ import org.apache.commons.lang3.StringUtils; import java.time.ZonedDateTime; import java.util.*; +import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; public class DefaultTournament implements Tournament { // 10 minutes - public static int DeckBuildTime = 10 * 60 * 1000; + public static final int DeckBuildTime = 10 * 60 * 1000; public static long PairingDelayTime = 1000 * 60 * 1; private final PairingMechanism _pairingMechanism; @@ -46,7 +47,10 @@ public class DefaultTournament implements Tournament { private final TournamentService _tournamentService; - private final ReadWriteLock _lock = new ReentrantReadWriteLock(); + private final ReadWriteLock lock = new ReentrantReadWriteLock(); + private final Lock readLock = lock.readLock(); + private final Lock writeLock = lock.writeLock(); + private TournamentTask _nextTask; private long _deckBuildStartTime; @@ -54,14 +58,11 @@ public class DefaultTournament implements Tournament { private List _currentStandings; - private final boolean _manualKickoff; - private boolean _hasKickedOff; - private String _tournamentReport; public DefaultTournament(TournamentService tournamentService, String tournamentId, String tournamentName, String format, CollectionType collectionType, - int tournamentRound, Stage tournamentStage, boolean manualKickoff, + int tournamentRound, Stage tournamentStage, PairingMechanism pairingMechanism, TournamentPrizes tournamentPrizes, CollectionsManager collectionsManager, ProductLibrary productLibrary, DraftPack draftPack) { _tournamentService = tournamentService; @@ -71,7 +72,6 @@ public class DefaultTournament implements Tournament { _collectionType = collectionType; _tournamentRound = tournamentRound; _tournamentStage = tournamentStage; - _manualKickoff = manualKickoff; _pairingMechanism = pairingMechanism; _tournamentPrizes = tournamentPrizes; @@ -104,8 +104,6 @@ public class DefaultTournament implements Tournament { _players); } else if (_tournamentStage == Stage.DECK_BUILDING) { _deckBuildStartTime = System.currentTimeMillis(); - } else if (_tournamentStage == Stage.AWAITING_KICKOFF || _tournamentStage == Stage.PAUSED) { - } else if (_tournamentStage == Stage.FINISHED) { _finishedTournamentMatches.addAll(_tournamentService.getMatches(_tournamentId)); } @@ -114,14 +112,10 @@ public class DefaultTournament implements Tournament { public DefaultTournament(TournamentService tournamentService, CollectionsManager collectionsManager, ProductLibrary productLibrary, DraftPack draftPack, TournamentInfo info) { this(tournamentService, info.tournamentId(), info.name(), info.format(), info.collectionType(), - info.round(), info.tournamentStage(), info.manualKickoff(), info.pairingMechanism(), info.prizesScheme(), + info.round(), info.tournamentStage(), info.pairingMechanism(), info.prizesScheme(), collectionsManager, productLibrary, draftPack); } - public DefaultTournament( TournamentService tournamentService, TournamentInfo info) { - this(tournamentService, null, null, null, info); - } - protected void regeneratePlayerList() { _playerList = ""; @@ -144,7 +138,8 @@ public class DefaultTournament implements Tournament { } - public void setWaitForPairingsTime(long waitForPairingsTime) { + // Used for test only + protected void setWaitForPairingsTime(long waitForPairingsTime) { PairingDelayTime = waitForPairingsTime; } @@ -155,7 +150,12 @@ public class DefaultTournament implements Tournament { @Override public int getPlayersInCompetitionCount() { - return _players.size() - _droppedPlayers.size(); + readLock.lock(); + try { + return _players.size() - _droppedPlayers.size(); + } finally { + readLock.unlock(); + } } @Override @@ -195,17 +195,17 @@ public class DefaultTournament implements Tournament { @Override public boolean isPlayerInCompetition(String player) { - _lock.readLock().lock(); + readLock.lock(); try { return _tournamentStage != Stage.FINISHED && _players.contains(player) && !_droppedPlayers.contains(player); } finally { - _lock.readLock().unlock(); + readLock.unlock(); } } @Override public void reportGameFinished(String winner, String loser) { - _lock.writeLock().lock(); + writeLock.lock(); try { if (_tournamentStage == Stage.PLAYING_GAMES && _currentlyPlayingPlayers.contains(winner) && _currentlyPlayingPlayers.contains(loser)) { @@ -221,51 +221,53 @@ public class DefaultTournament implements Tournament { _currentStandings = null; } } finally { - _lock.writeLock().unlock(); + writeLock.unlock(); } } @Override public void playerSubmittedDeck(String player, LotroDeck deck) { - _lock.writeLock().lock(); + writeLock.lock(); try { if (_tournamentStage == Stage.DECK_BUILDING && _players.contains(player)) { _tournamentService.setPlayerDeck(_tournamentId, player, deck); _playerDecks.put(player, deck); } } finally { - _lock.writeLock().unlock(); + writeLock.unlock(); } } + @Override public LotroDeck getPlayerDeck(String player) { - _lock.readLock().lock(); + readLock.lock(); try { return _playerDecks.get(player); } finally { - _lock.readLock().unlock(); + readLock.unlock(); } } + @Override public Draft getDraft() { return _draft; } @Override public void playerChosenCard(String playerName, String cardId) { - _lock.writeLock().lock(); + writeLock.lock(); try { if (_tournamentStage == Stage.DRAFT) { _draft.playerChosenCard(playerName, cardId); } } finally { - _lock.writeLock().unlock(); + writeLock.unlock(); } } @Override public boolean dropPlayer(String player) { - _lock.writeLock().lock(); + writeLock.lock(); try { if (_currentlyPlayingPlayers.contains(player)) return false; @@ -281,13 +283,13 @@ public class DefaultTournament implements Tournament { regeneratePlayerList(); return true; } finally { - _lock.writeLock().unlock(); + writeLock.unlock(); } } @Override public boolean advanceTournament(TournamentCallback tournamentCallback, CollectionsManager collectionsManager) { - _lock.writeLock().lock(); + writeLock.lock(); try { boolean result = false; if (_nextTask == null) { @@ -310,14 +312,7 @@ public class DefaultTournament implements Tournament { result = true; } } - if (_tournamentStage == Stage.AWAITING_KICKOFF || _tournamentStage == Stage.PAUSED) { - - } - else if (_tournamentStage == Stage.PREPARING) { - _tournamentStage = Stage.PLAYING_GAMES; - _tournamentService.updateTournamentStage(_tournamentId, _tournamentStage); - } - else if (_tournamentStage == Stage.PLAYING_GAMES) { + if (_tournamentStage == Stage.PLAYING_GAMES) { if (_currentlyPlayingPlayers.isEmpty()) { if (_pairingMechanism.isFinished(_tournamentRound, _players, _droppedPlayers)) { finishTournament(tournamentCallback, collectionsManager); @@ -337,7 +332,7 @@ public class DefaultTournament implements Tournament { } return result; } finally { - _lock.writeLock().unlock(); + writeLock.unlock(); } } @@ -347,12 +342,12 @@ public class DefaultTournament implements Tournament { if (result != null) return result; - _lock.readLock().lock(); + readLock.lock(); try { _currentStandings = ModifiedMedianStandingsProducer.produceStandings(_players, _finishedTournamentMatches, 1, 0, _playerByes); return _currentStandings; } finally { - _lock.readLock().unlock(); + readLock.unlock(); } } @@ -467,97 +462,101 @@ public class DefaultTournament implements Tournament { @Override public String produceReport(DeckRenderer renderer) throws CardNotFoundException { - if(_tournamentReport != null) - return _tournamentReport; + readLock.lock(); + try { + if (_tournamentReport == null) { + ZonedDateTime tournamentStart = null; + ZonedDateTime tournamentEnd = null; - ZonedDateTime start = null; - ZonedDateTime end = null; + var games = _tournamentService.getGames(_tournamentName); - var games = _tournamentService.getGames(_tournamentName); + for (var match : _finishedTournamentMatches) { + var game = games.stream() + .filter((x) -> x.winner.equals(match.getWinner()) && x.loser.equals(match.getLoser())) + .findFirst() + .orElse(null); - for(var match : _finishedTournamentMatches) { - var game = games.stream() - .filter((x) -> x.winner.equals(match.getWinner()) && x.loser.equals(match.getLoser())) - .findFirst() - .orElse(null); + if (game == null) + continue; - if(game == null) - continue; + var gameStart = game.GetUTCStartDate(); + var gameEnd = game.GetUTCEndDate(); - var gameStart = game.GetUTCStartDate(); - var gameEnd = game.GetUTCEndDate(); + if (tournamentStart == null || gameStart.isBefore(tournamentStart)) { + tournamentStart = gameStart; + } - if(start == null || gameStart.isBefore(start)) { - start = gameStart; - } - - if(end == null || gameEnd.isAfter(end)) { - end = gameEnd; + if (tournamentEnd == null || gameEnd.isAfter(tournamentEnd)) { + tournamentEnd = gameEnd; + } + } + + StringBuilder summary = new StringBuilder(); + summary + .append("

").append(StringEscapeUtils.escapeHtml3(_tournamentName)).append("

") + .append("


"); + + var sections = new ArrayList(); + sections.add(summary.toString()); + + for (var standing : getCurrentStandings()) { + var playerName = standing.playerName; + + var rounds = new ArrayList>(); + + var playerRounds = _finishedTournamentMatches.stream() + .filter((x) -> x.getPlayerOne().equals(playerName) || x.getPlayerTwo().equals(playerName)) + .toList(); + for (int i = 1; i <= _tournamentRound; i++) { + if (_playerByes.containsKey(playerName) && _playerByes.get(playerName) == i) { + rounds.add(createEntry("[bye]", "")); + continue; + } + + int currentRound = i; + var match = playerRounds.stream().filter(x -> x.getRound() == currentRound) + .findFirst().orElse(null); + + if (match == null) { + rounds.add(createEntry("[dropped]", "")); + continue; + } + + var game = games.stream().filter((x) -> x.winner.equals(match.getWinner()) && x.loser.equals(match.getLoser())) + .findFirst() + .orElse(null); + if (game == null) + continue; + + String replayId = game.win_recording_id; + if (match.getLoser().equals(playerName)) { + replayId = game.lose_recording_id; + } + + String label = "Round " + i; + String url = "https://play.lotrtcgpc.net/gemp-lotr/game.html?replayId=" + + playerName.replace("_", "%5F") + "$" + replayId; + + rounds.add(createEntry(label, url)); + } + + LotroDeck deck = _tournamentService.getPlayerDeck(_tournamentId, playerName, _format); + + var fragment = renderer.convertDeckToForumFragment(deck, playerName, rounds); + sections.add(fragment); + } + + _tournamentReport = renderer.AddDeckReadoutHeaderAndFooter(sections); } + } finally { + readLock.unlock(); } - - StringBuilder summary = new StringBuilder(); - summary.append("") - .append("

").append(StringEscapeUtils.escapeHtml3(_tournamentName)).append("

") - .append("
    ") - .append("
  • Format: ").append(_format).append("
  • ") - .append("
  • Collection: ").append(_collectionType.getFullName()).append("
  • ") - .append("
  • Total Rounds: ").append(_tournamentRound).append("
  • ") - .append("
  • Start: ").append(DateUtils.FormatDateTime(start)).append("
  • ") - .append("
  • End: ").append(DateUtils.FormatDateTime(end)).append("
  • ") - .append("



"); - - var decks = new ArrayList(); - decks.add(summary.toString()); - - for(var standing : getCurrentStandings()) { - var playerName = standing.playerName; - - var rounds = new ArrayList>(); - - var playerRounds = _finishedTournamentMatches.stream() - .filter((x) -> x.getPlayerOne().equals(playerName) || x.getPlayerTwo().equals(playerName)) - .toList(); - for(int i = 1; i <= _tournamentRound; i++) { - if(_playerByes.containsKey(playerName) && _playerByes.get(playerName) == i) { - rounds.add(createEntry("[bye]", "")); - continue; - } - - int currentRound = i; - var match = playerRounds.stream().filter(x -> x.getRound() == currentRound) - .findFirst().orElse(null); - - if(match == null) { - rounds.add(createEntry("[dropped]", "")); - continue; - } - - var game = games.stream().filter((x) -> x.winner.equals(match.getWinner()) && x.loser.equals(match.getLoser())) - .findFirst() - .orElse(null); - if(game == null) - continue; - - String replayId = game.win_recording_id; - if(match.getLoser().equals(playerName)) { - replayId = game.lose_recording_id; - } - - String label = "Round " + i; - String url = "https://play.lotrtcgpc.net/gemp-lotr/game.html?replayId=" + - playerName.replace("_", "%5F") + "$" + replayId; - - rounds.add(createEntry(label, url)); - } - - LotroDeck deck = _tournamentService.getPlayerDeck(_tournamentId, playerName, _format); - - var fragment = renderer.convertDeckToForumFragment(deck, playerName, rounds); - decks.add(fragment); - - } - - return renderer.AddDeckReadoutHeaderAndFooter(decks); + return _tournamentReport; } } diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/ImmediateRecurringQueue.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/ImmediateRecurringQueue.java index 56e8daed5..1ca7e3553 100644 --- a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/ImmediateRecurringQueue.java +++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/ImmediateRecurringQueue.java @@ -46,7 +46,7 @@ public class ImmediateRecurringQueue extends AbstractTournamentQueue implements } var info = new TournamentInfo(tournamentId, null, tournamentName, _format, ZonedDateTime.now(), - _collectionType, Tournament.Stage.PLAYING_GAMES, 0, false, + _collectionType, Tournament.Stage.PLAYING_GAMES, 0, Tournament.getPairingMechanism("singleElimination"), _tournamentPrizes); var tournament = _tournamentService.addTournament(info); diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/RecurringScheduledQueue.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/RecurringScheduledQueue.java index 71c472ec1..6ecba832c 100644 --- a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/RecurringScheduledQueue.java +++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/RecurringScheduledQueue.java @@ -71,7 +71,7 @@ public class RecurringScheduledQueue extends AbstractTournamentQueue implements _tournamentService.addPlayer(tournamentId, player, _playerDecks.get(player)); var info = new TournamentInfo(tournamentId, null, tournamentName, _format, ZonedDateTime.now(), - _collectionType, Tournament.Stage.PLAYING_GAMES, 0, false, + _collectionType, Tournament.Stage.PLAYING_GAMES, 0, _pairingMechanism, _tournamentPrizes); var tournament = _tournamentService.addTournament(info); diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/ScheduledTournamentQueue.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/ScheduledTournamentQueue.java index d414f2496..4fe32ee57 100644 --- a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/ScheduledTournamentQueue.java +++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/ScheduledTournamentQueue.java @@ -35,12 +35,7 @@ public class ScheduledTournamentQueue extends AbstractTournamentQueue implements _startCondition = "at " + _startTime.format(DateUtils.DateTimeFormat); _minimumPlayers = info.minimum_players; - if(info.manual_kickoff) { - _stage = Tournament.Stage.AWAITING_KICKOFF; - } - else { - _stage = Tournament.Stage.PLAYING_GAMES; - } + _stage = Tournament.Stage.PLAYING_GAMES; } @Override @@ -63,12 +58,11 @@ public class ScheduledTournamentQueue extends AbstractTournamentQueue implements var now = ZonedDateTime.now(); if (now.isAfter(_startTime)) { if (_players.size() >= _minimumPlayers) { - for (String player : _players) _tournamentService.addPlayer(_scheduledTournamentId, player, _playerDecks.get(player)); var info = new TournamentInfo(_scheduledTournamentId, null, _tournamentName, _format, ZonedDateTime.now(), - _collectionType, _stage, 0, false, + _collectionType, _stage, 0, _pairingMechanism, _tournamentPrizes); var tournament = _tournamentService.addTournament(info); @@ -87,7 +81,7 @@ public class ScheduledTournamentQueue extends AbstractTournamentQueue implements @Override public boolean isJoinable() { var window = _signupTimeBeforeStart; - if(_scheduledTournamentId.toLowerCase().contains("wc")) { + if (_scheduledTournamentId.toLowerCase().contains("wc")) { window = _wcSignupTimeBeforeStart; } return ZonedDateTime.now().isAfter(_startTime.minus(window)); 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 2c8c00965..72077255d 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 @@ -18,9 +18,6 @@ public interface Tournament { public enum Stage { DRAFT("Drafting"), DECK_BUILDING("Deck building"), - AWAITING_KICKOFF("Awaiting kickoff"), - PAUSED("Paused"), - PREPARING("Preparing"), PLAYING_GAMES("Playing games"), FINISHED("Finished"); diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/TournamentInfo.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/TournamentInfo.java index eb7b8d927..633c02d44 100644 --- a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/TournamentInfo.java +++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/TournamentInfo.java @@ -10,21 +10,21 @@ import java.util.List; public record TournamentInfo(String tournamentId, String draftType, String name, String format, ZonedDateTime startDate, CollectionType collectionType, - Tournament.Stage tournamentStage, int round, boolean manualKickoff, + Tournament.Stage tournamentStage, int round, PairingMechanism pairingMechanism, TournamentPrizes prizesScheme - ) { +) { public TournamentInfo(ProductLibrary library, DBDefs.Tournament info) { this(info.tournament_id, info.draft_type, info.name, info.format, info.GetUTCStartDate(), CollectionType.parseCollectionCode(info.collection), Tournament.Stage.parseStage(info.stage), - info.round, info.manual_kickoff, Tournament.getPairingMechanism(info.pairing), + info.round, Tournament.getPairingMechanism(info.pairing), Tournament.getTournamentPrizes(library, info.prizes)); } - public TournamentInfo(ProductLibrary library, DBDefs.ScheduledTournament info) { + public TournamentInfo(ProductLibrary library, DBDefs.ScheduledTournament info) { this(info.tournament_id, null, info.name, info.format, info.GetUTCStartDate(), - CollectionType.ALL_CARDS, info.manual_kickoff ? Tournament.Stage.AWAITING_KICKOFF : Tournament.Stage.PLAYING_GAMES, - 0, info.manual_kickoff, Tournament.getPairingMechanism(info.playoff), + CollectionType.ALL_CARDS, Tournament.Stage.PLAYING_GAMES, + 0, Tournament.getPairingMechanism(info.playoff), Tournament.getTournamentPrizes(library, info.prizes)); } @@ -38,24 +38,23 @@ public record TournamentInfo(String tournamentId, String draftType, String name, tourney.collection = this.collectionType.getCode(); tourney.stage = this.tournamentStage.getHumanReadable(); tourney.round = this.round; - tourney.manual_kickoff = this.manualKickoff; tourney.pairing = this.pairingMechanism.getRegistryRepresentation(); tourney.prizes = this.prizesScheme.getRegistryRepresentation(); return tourney; } - public static List fromDB(ProductLibrary library, List dbinfos) { + public static List fromDB(ProductLibrary library, List dbinfos) { List infos = new ArrayList<>(); - for(var result : dbinfos) { + for (var result : dbinfos) { infos.add(new TournamentInfo(library, result)); } return infos; } - public static List fromSDB(ProductLibrary library, List dbinfos) { + public static List fromSDB(ProductLibrary library, List dbinfos) { List infos = new ArrayList<>(); - for(var result : dbinfos) { + for (var result : dbinfos) { infos.add(new TournamentInfo(library, result)); } return infos; diff --git a/gemp-lotr/gemp-lotr-server/src/test/java/com/gempukku/lotro/tournament/DefaultTournamentTest.java b/gemp-lotr/gemp-lotr-server/src/test/java/com/gempukku/lotro/tournament/DefaultTournamentTest.java index 9b459f90c..05e54a0ea 100644 --- a/gemp-lotr/gemp-lotr-server/src/test/java/com/gempukku/lotro/tournament/DefaultTournamentTest.java +++ b/gemp-lotr/gemp-lotr-server/src/test/java/com/gempukku/lotro/tournament/DefaultTournamentTest.java @@ -47,7 +47,7 @@ public class DefaultTournamentTest extends AbstractAtTest { CollectionsManager collectionsManager = Mockito.mock(CollectionsManager.class); var tournament = new DefaultTournament(tournamentService, tournamentId, "Name", "format", - CollectionType.ALL_CARDS, 0, Tournament.Stage.PLAYING_GAMES, false, pairingMechanism, + CollectionType.ALL_CARDS, 0, Tournament.Stage.PLAYING_GAMES, pairingMechanism, new SingleEliminationOnDemandPrizes(_cardLibrary, "onDemand"),null, null, null); tournament.setWaitForPairingsTime(_waitForPairingsTime);