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 bac6cbdd1..4c91bc3b2 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
@@ -813,9 +813,13 @@ var GempLotrHallUI = Class.extend({
}
rowhtml += "
" + tournament.getAttribute("name") + " | " +
- "" + tournament.getAttribute("system") + " | " +
- "" + tournament.getAttribute("stage") + " | " +
- "" + tournament.getAttribute("round") + " | " +
+ "" + tournament.getAttribute("system") + " | ";
+ if (tournament.hasAttribute("timeRemaining")) {
+ rowhtml += "" + tournament.getAttribute("stage") + " - " + tournament.getAttribute("timeRemaining") + " | ";
+ } else {
+ rowhtml += "" + tournament.getAttribute("stage") + " | ";
+ }
+ rowhtml += "" + tournament.getAttribute("round") + " | " +
"" + tournament.getAttribute("playerCount") + " | " +
"";
@@ -843,7 +847,11 @@ var GempLotrHallUI = Class.extend({
var tablesRow = $("
");
tablesRow.append("" + tournament.getAttribute("format") + " | ");
tablesRow.append(" Tournament - " + displayType + " - " + tournament.getAttribute("name") + " | ");
- tablesRow.append("" + tournament.getAttribute("stage") + " | ");
+ if (tournament.hasAttribute("timeRemaining")) {
+ tablesRow.append("" + tournament.getAttribute("stage") + " - " + tournament.getAttribute("timeRemaining") + " | ");
+ } else {
+ tablesRow.append("" + tournament.getAttribute("stage") + " | ");
+ }
tablesRow.append("" + tournament.getAttribute("playerList") + " | ");
var actionsFieldClone = actionsField.clone(true);
tablesRow.append(actionsFieldClone);
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 2a6d7898c..0ab1d1ba8 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
@@ -1,11 +1,13 @@
package com.gempukku.lotro.hall;
+import com.gempukku.lotro.common.DateUtils;
import com.gempukku.lotro.game.Player;
import com.gempukku.polling.LongPollableResource;
import com.gempukku.polling.WaitingRequest;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.mutable.MutableObject;
+import java.time.Duration;
import java.util.*;
public class HallCommunicationChannel implements LongPollableResource {
@@ -128,7 +130,8 @@ 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, boolean joinable) {
+ String tournamentStage, int round, int playerCount, String playerList, boolean playerInCompetition, boolean abandoned, boolean joinable,
+ long secsRemaining) {
Map props = new HashMap<>();
props.put("collection", collectionName);
props.put("format", formatName);
@@ -142,6 +145,9 @@ public class HallCommunicationChannel implements LongPollableResource {
props.put("signedUp", String.valueOf(playerInCompetition));
props.put("abandoned", String.valueOf(abandoned));
props.put("joinable", String.valueOf(joinable));
+ if (secsRemaining >= 0) {
+ props.put("timeRemaining", DateUtils.HumanDuration(Duration.ofSeconds(secsRemaining)));
+ }
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 6e49cbe33..a7abe541a 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,8 @@ 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, boolean joinable);
+ String pairingDescription, String tournamentStage, int round, int playerCount, String playerList, boolean playerInCompetition, boolean abandoned, boolean joinable,
+ long secsRemaining);
public void runningPlayerGame(String gameId);
}
diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/BaseTournament.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/BaseTournament.java
index 7bbf74025..2ceab395f 100644
--- a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/BaseTournament.java
+++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/BaseTournament.java
@@ -7,25 +7,21 @@ import com.gempukku.lotro.common.DateUtils;
import com.gempukku.lotro.competitive.ModifiedMedianStandingsProducer;
import com.gempukku.lotro.competitive.PlayerStanding;
import com.gempukku.lotro.db.vo.CollectionType;
-import com.gempukku.lotro.draft.Draft;
import com.gempukku.lotro.draft2.SoloDraftDefinitions;
import com.gempukku.lotro.draft3.TableDraftDefinitions;
import com.gempukku.lotro.game.CardCollection;
import com.gempukku.lotro.game.CardNotFoundException;
import com.gempukku.lotro.game.formats.LotroFormatLibrary;
import com.gempukku.lotro.hall.TableHolder;
-import com.gempukku.lotro.logic.actions.AbstractCostToEffectAction;
import com.gempukku.lotro.logic.vo.LotroDeck;
import com.gempukku.lotro.packs.ProductLibrary;
import com.gempukku.lotro.tournament.action.BroadcastAction;
import com.gempukku.lotro.tournament.action.CreateGameAction;
import com.gempukku.lotro.tournament.action.TournamentProcessAction;
import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.lang3.time.DurationFormatUtils;
import org.apache.commons.text.StringEscapeUtils;
import java.time.Duration;
-import java.time.ZonedDateTime;
import java.util.*;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
@@ -519,4 +515,9 @@ public abstract class BaseTournament implements Tournament {
}
return _tournamentReport;
}
+
+ @Override
+ public long getSecondsRemaining() throws IllegalStateException{
+ throw new IllegalStateException();
+ }
}
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 29f827c12..8f318ef20 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
@@ -16,11 +16,14 @@ import com.gempukku.lotro.tournament.action.BroadcastAction;
import com.gempukku.lotro.tournament.action.TournamentProcessAction;
import org.apache.commons.lang3.StringUtils;
+import java.time.Duration;
+import java.time.ZonedDateTime;
import java.util.*;
public class SealedTournament extends BaseTournament implements Tournament {
private SealedTournamentInfo _sealedInfo;
+ private ZonedDateTime nextRoundStart = null;
public SealedTournament(TournamentService tournamentService, CollectionsManager collectionsManager, ProductLibrary productLibrary,
LotroFormatLibrary formatLibrary, SoloDraftDefinitions soloDraftDefinitions, TableDraftDefinitions tableDraftDefinitions, TableHolder tables, String tournamentId) {
@@ -201,6 +204,7 @@ public class SealedTournament extends BaseTournament implements Tournament {
if (_tournamentInfo.PairingMechanism.isFinished(getCurrentRound(), _players, _droppedPlayers)) {
result.add(finishTournament(collectionsManager));
} else {
+ nextRoundStart = DateUtils.Now().plus(PairingDelayTime);
if(getCurrentRound() == 0) {
result.add(new BroadcastAction("Deck registration for tournament " + getTournamentName()
+ " has closed. Round "
@@ -247,4 +251,17 @@ public class SealedTournament extends BaseTournament implements Tournament {
getTournamentStage() == Tournament.Stage.PAUSED || getTournamentStage() == Tournament.Stage.AWAITING_KICKOFF)
&& (maximumPlayers > activePlayers.size() || maximumPlayers < 0);
}
+
+ @Override
+ public long getSecondsRemaining() throws IllegalStateException {
+ if (getTournamentStage() == Stage.DECK_BUILDING) {
+ return Duration.between(DateUtils.Now(), _sealedInfo.DeckbuildingDeadline).getSeconds();
+ } else if (getTournamentStage() == Stage.DECK_REGISTRATION) {
+ return Duration.between(DateUtils.Now(), _sealedInfo.RegistrationDeadline).getSeconds();
+ } else if (getTournamentStage() == Stage.PLAYING_GAMES && nextRoundStart != null && DateUtils.Now().isBefore(nextRoundStart)) {
+ return Duration.between(DateUtils.Now(), nextRoundStart).getSeconds();
+ } else {
+ throw new IllegalStateException();
+ }
+ }
}
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 438e70a77..f4b567aef 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
@@ -18,12 +18,15 @@ import com.gempukku.lotro.tournament.action.BroadcastAction;
import com.gempukku.lotro.tournament.action.TournamentProcessAction;
import org.apache.commons.lang3.StringUtils;
+import java.time.Duration;
+import java.time.ZonedDateTime;
import java.util.*;
public class SoloDraftTournament extends BaseTournament implements Tournament {
private static final int HIGH_ENOUGH_PRIME_NUMBER = 8963;
private SoloDraftTournamentInfo _soloDraftInfo;
+ private ZonedDateTime nextRoundStart = null;
public SoloDraftTournament(TournamentService tournamentService, CollectionsManager collectionsManager, ProductLibrary productLibrary,
LotroFormatLibrary formatLibrary, SoloDraftDefinitions soloDraftDefinitions, TableDraftDefinitions tableDraftDefinitions, TableHolder tables, String tournamentId) {
@@ -196,6 +199,7 @@ public class SoloDraftTournament extends BaseTournament implements Tournament {
if (_tournamentInfo.PairingMechanism.isFinished(getCurrentRound(), _players, _droppedPlayers)) {
result.add(finishTournament(collectionsManager));
} else {
+ nextRoundStart = DateUtils.Now().plus(PairingDelayTime);
if(getCurrentRound() == 0) {
result.add(new BroadcastAction("Deck registration for tournament " + getTournamentName()
+ " has closed. Round "
@@ -262,4 +266,17 @@ public class SoloDraftTournament extends BaseTournament implements Tournament {
getTournamentStage() == Tournament.Stage.PAUSED || getTournamentStage() == Tournament.Stage.AWAITING_KICKOFF)
&& (maximumPlayers > activePlayers.size() || maximumPlayers < 0);
}
+
+ @Override
+ public long getSecondsRemaining() throws IllegalStateException {
+ if (getTournamentStage() == Stage.DECK_BUILDING) {
+ return Duration.between(DateUtils.Now(), _soloDraftInfo.DeckbuildingDeadline).getSeconds();
+ } else if (getTournamentStage() == Stage.DECK_REGISTRATION) {
+ return Duration.between(DateUtils.Now(), _soloDraftInfo.RegistrationDeadline).getSeconds();
+ } else if (getTournamentStage() == Stage.PLAYING_GAMES && nextRoundStart != null && DateUtils.Now().isBefore(nextRoundStart)) {
+ return Duration.between(DateUtils.Now(), nextRoundStart).getSeconds();
+ } else {
+ throw new IllegalStateException();
+ }
+ }
}
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 01a77415e..bc1498fbd 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
@@ -16,12 +16,15 @@ import com.gempukku.lotro.tournament.action.BroadcastAction;
import com.gempukku.lotro.tournament.action.TournamentProcessAction;
import org.apache.commons.lang3.StringUtils;
+import java.time.Duration;
+import java.time.ZonedDateTime;
import java.util.*;
public class SoloTableDraftTournament extends BaseTournament implements Tournament {
private SoloTableDraftTournamentInfo soloTableDraftInfo;
private Map tables = null;
+ private ZonedDateTime nextRoundStart = null;
public SoloTableDraftTournament(TournamentService tournamentService, CollectionsManager collectionsManager, ProductLibrary productLibrary,
LotroFormatLibrary formatLibrary, SoloDraftDefinitions soloDraftDefinitions, TableDraftDefinitions tableDraftDefinitions,
@@ -176,6 +179,7 @@ public class SoloTableDraftTournament extends BaseTournament implements Tourname
if (_tournamentInfo.PairingMechanism.isFinished(getCurrentRound(), _players, _droppedPlayers)) {
result.add(finishTournament(collectionsManager));
} else {
+ nextRoundStart = DateUtils.Now().plus(PairingDelayTime);
if(getCurrentRound() == 0) {
result.add(new BroadcastAction("Deck registration for tournament " + getTournamentName()
+ " has closed. Round "
@@ -245,4 +249,17 @@ public class SoloTableDraftTournament extends BaseTournament implements Tourname
getTournamentStage() == Tournament.Stage.PAUSED || getTournamentStage() == Tournament.Stage.AWAITING_KICKOFF)
&& (maximumPlayers > activePlayers.size() || maximumPlayers < 0);
}
+
+ @Override
+ public long getSecondsRemaining() throws IllegalStateException {
+ if (getTournamentStage() == Stage.DECK_BUILDING) {
+ return Duration.between(DateUtils.Now(), soloTableDraftInfo.deckbuildingDeadline).getSeconds();
+ } else if (getTournamentStage() == Stage.DECK_REGISTRATION) {
+ return Duration.between(DateUtils.Now(), soloTableDraftInfo.registrationDeadline).getSeconds();
+ } else if (getTournamentStage() == Stage.PLAYING_GAMES && nextRoundStart != null && DateUtils.Now().isBefore(nextRoundStart)) {
+ return Duration.between(DateUtils.Now(), nextRoundStart).getSeconds();
+ } else {
+ throw new IllegalStateException();
+ }
+ }
}
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 281eea745..d90935837 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
@@ -18,6 +18,8 @@ import com.gempukku.lotro.tournament.action.BroadcastAction;
import com.gempukku.lotro.tournament.action.TournamentProcessAction;
import org.apache.commons.lang3.StringUtils;
+import java.time.Duration;
+import java.time.ZonedDateTime;
import java.util.*;
public class TableDraftTournament extends BaseTournament implements Tournament {
@@ -25,6 +27,7 @@ public class TableDraftTournament extends BaseTournament implements Tournament {
private TableDraftTournamentInfo tableDraftInfo;
private TableDraft table = null;
private final ChatServer chatServer;
+ private ZonedDateTime nextRoundStart = null;
public TableDraftTournament(TournamentService tournamentService, CollectionsManager collectionsManager, ProductLibrary productLibrary,
LotroFormatLibrary formatLibrary, SoloDraftDefinitions soloDraftDefinitions, TableDraftDefinitions tableDraftDefinitions,
@@ -201,6 +204,7 @@ public class TableDraftTournament extends BaseTournament implements Tournament {
if (_tournamentInfo.PairingMechanism.isFinished(getCurrentRound(), _players, _droppedPlayers)) {
result.add(finishTournament(collectionsManager));
} else {
+ nextRoundStart = DateUtils.Now().plus(PairingDelayTime);
if(getCurrentRound() == 0) {
result.add(new BroadcastAction("Deck registration for tournament " + getTournamentName()
+ " has closed. Round "
@@ -262,4 +266,17 @@ public class TableDraftTournament extends BaseTournament implements Tournament {
public boolean isJoinable() {
return false; // cannot join draft in progress
}
+
+ @Override
+ public long getSecondsRemaining() throws IllegalStateException {
+ if (getTournamentStage() == Stage.DECK_BUILDING) {
+ return Duration.between(DateUtils.Now(), tableDraftInfo.deckbuildingDeadline).getSeconds();
+ } else if (getTournamentStage() == Stage.DECK_REGISTRATION) {
+ return Duration.between(DateUtils.Now(), tableDraftInfo.registrationDeadline).getSeconds();
+ } else if (getTournamentStage() == Stage.PLAYING_GAMES && nextRoundStart != null && DateUtils.Now().isBefore(nextRoundStart)) {
+ return Duration.between(DateUtils.Now(), nextRoundStart).getSeconds();
+ } else {
+ throw new IllegalStateException();
+ }
+ }
}
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 3ed4b703f..a4a559a95 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
@@ -206,4 +206,5 @@ public interface Tournament {
TournamentInfo getInfo();
boolean isJoinable();
+ long getSecondsRemaining() throws IllegalStateException;
}
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 732f12b46..8cb288799 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
@@ -264,11 +264,17 @@ public class TournamentService {
for (var entry : _activeTournaments.entrySet()) {
var tourneyID = entry.getKey();
var tournament = entry.getValue();
+ long secsRemaining = -1;
+ try {
+ secsRemaining = tournament.getSecondsRemaining();
+ } catch (IllegalStateException ignore) {
+
+ }
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.isJoinable());
+ tournament.isJoinable(), secsRemaining);
}
}