diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/game/state/GameState.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/game/state/GameState.java index e552db1f0..2266a7a77 100644 --- a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/game/state/GameState.java +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/game/state/GameState.java @@ -118,6 +118,10 @@ public class GameState { sendStateToPlayer(playerId); } + public void removeGameStateListener(String playerId, GameStateListener gameStateListener) { + _gameStateListeners.remove(playerId); + } + private Collection getPrivateGameStateListeners(PhysicalCard physicalCard) { String owner = physicalCard.getOwner(); GameStateListener result = _gameStateListeners.get(owner); diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/timing/DefaultLotroGame.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/timing/DefaultLotroGame.java index 4a35f6407..114aa727e 100644 --- a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/timing/DefaultLotroGame.java +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/timing/DefaultLotroGame.java @@ -152,4 +152,11 @@ public class DefaultLotroGame implements LotroGame { else _gameStateListeners.put(playerId, gameStateListener); } + + public void removeGameStateListener(String playerId, GameStateListener gameStateListener) { + if (_gameState != null) + _gameState.removeGameStateListener(playerId, gameStateListener); + else + _gameStateListeners.remove(playerId); + } } diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/GatheringParticipantCommunicationChannel.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/GatheringParticipantCommunicationChannel.java index 53dae07ad..055ddfd05 100644 --- a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/GatheringParticipantCommunicationChannel.java +++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/GatheringParticipantCommunicationChannel.java @@ -5,6 +5,7 @@ import com.gempukku.lotro.common.Token; import com.gempukku.lotro.communication.GameStateListener; import com.gempukku.lotro.game.PhysicalCard; +import java.util.Date; import java.util.LinkedList; import java.util.List; @@ -13,6 +14,7 @@ import static com.gempukku.lotro.GameEvent.Type.*; public class GatheringParticipantCommunicationChannel implements GameStateListener { private List _events = new LinkedList(); private String _self; + private Date _lastConsumed; public GatheringParticipantCommunicationChannel(String self) { _self = self; @@ -105,6 +107,11 @@ public class GatheringParticipantCommunicationChannel implements GameStateListen public List consumeGameEvents() { List result = _events; _events = new LinkedList(); + _lastConsumed = new Date(); return result; } + + public Date getLastConsumed() { + return _lastConsumed; + } } diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/LotroGameMediator.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/LotroGameMediator.java index 89a7d3a68..9b1f3fd26 100644 --- a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/LotroGameMediator.java +++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/LotroGameMediator.java @@ -20,7 +20,11 @@ public class LotroGameMediator { private DefaultLotroGame _lotroGame; private Map _playerClocks = new HashMap(); private Map _decisionQuerySentTimes = new HashMap(); - private final int _maxSecondsPerPlayer = 60 * 30; // 30 minutes + + private final int _maxSecondsForGamePerPlayer = 60 * 30; // 30 minutes + private final int _channelInactivityTimeoutPeriod = 30; // 30 seconds + private final int _playerDecisionTimeoutPeriod = 60 * 5; // 5 minutes + public LotroGameMediator(LotroFormat lotroFormat, LotroGameParticipant[] participants, LotroCardBlueprintLibrary library, GameResultListener gameResultListener) { if (participants.length < 1) @@ -76,6 +80,27 @@ public class LotroGameMediator { startClocksForUsersPendingDecision(); } + public synchronized void cleanup() { + long currentTime = System.currentTimeMillis(); + Map channelsCopy = new HashMap(_communicationChannels); + for (Map.Entry playerChannels : channelsCopy.entrySet()) { + String playerId = playerChannels.getKey(); + // Channel is stale (user no longer connected to game, to save memory, we remove the channel + // User can always reconnect and establish a new channel + GatheringParticipantCommunicationChannel channel = playerChannels.getValue(); + _lotroGame.removeGameStateListener(playerId, channel); + if (currentTime > channel.getLastConsumed().getTime() + _channelInactivityTimeoutPeriod) + _communicationChannels.remove(playerId); + } + + for (Map.Entry playerDecision : _decisionQuerySentTimes.entrySet()) { + String playerId = playerDecision.getKey(); + long decisionSent = playerDecision.getValue(); + if (currentTime > decisionSent + _playerDecisionTimeoutPeriod) + _lotroGame.playerLost(playerId); + } + } + public synchronized void playerAnswered(String lotroGameParticipant, int decisionId, String answer) { AwaitingDecision awaitingDecision = _userFeedback.getAwaitingDecision(lotroGameParticipant); if (awaitingDecision != null) { @@ -99,28 +124,6 @@ public class LotroGameMediator { } } - private void startClocksForUsersPendingDecision() { - long currentTime = System.currentTimeMillis(); - Set users = _userFeedback.getUsersPendingDecision(); - for (String user : users) - _decisionQuerySentTimes.put(user, currentTime); - } - - private void addTimeSpentOnDecisionToUserClock(String participantId) { - long queryTime = _decisionQuerySentTimes.remove(participantId); - long currentTime = System.currentTimeMillis(); - long diffSec = (currentTime - queryTime) / 1000; - _playerClocks.put(participantId, _playerClocks.get(participantId) + (int) diffSec); - } - - private int getCurrentUserPendingTime(String participantId) { - if (!_decisionQuerySentTimes.containsKey(participantId)) - return 0; - long queryTime = _decisionQuerySentTimes.get(participantId); - long currentTime = System.currentTimeMillis(); - return (int) ((currentTime - queryTime) / 1000); - } - public synchronized void processCommunicationChannel(String participantId, ParticipantCommunicationVisitor visitor) { GatheringParticipantCommunicationChannel communicationChannel = _communicationChannels.get(participantId); if (communicationChannel != null) @@ -136,7 +139,7 @@ public class LotroGameMediator { Map secondsLeft = new HashMap(); for (Map.Entry playerClock : _playerClocks.entrySet()) { String player = playerClock.getKey(); - secondsLeft.put(player, _maxSecondsPerPlayer - playerClock.getValue() - getCurrentUserPendingTime(player)); + secondsLeft.put(player, _maxSecondsForGamePerPlayer - playerClock.getValue() - getCurrentUserPendingTime(player)); } visitor.visitClock(secondsLeft); } @@ -160,8 +163,30 @@ public class LotroGameMediator { Map secondsLeft = new HashMap(); for (Map.Entry playerClock : _playerClocks.entrySet()) { String player = playerClock.getKey(); - secondsLeft.put(player, _maxSecondsPerPlayer - playerClock.getValue() - getCurrentUserPendingTime(player)); + secondsLeft.put(player, _maxSecondsForGamePerPlayer - playerClock.getValue() - getCurrentUserPendingTime(player)); } visitor.visitClock(secondsLeft); } + + private void startClocksForUsersPendingDecision() { + long currentTime = System.currentTimeMillis(); + Set users = _userFeedback.getUsersPendingDecision(); + for (String user : users) + _decisionQuerySentTimes.put(user, currentTime); + } + + private void addTimeSpentOnDecisionToUserClock(String participantId) { + long queryTime = _decisionQuerySentTimes.remove(participantId); + long currentTime = System.currentTimeMillis(); + long diffSec = (currentTime - queryTime) / 1000; + _playerClocks.put(participantId, _playerClocks.get(participantId) + (int) diffSec); + } + + private int getCurrentUserPendingTime(String participantId) { + if (!_decisionQuerySentTimes.containsKey(participantId)) + return 0; + long queryTime = _decisionQuerySentTimes.get(participantId); + long currentTime = System.currentTimeMillis(); + return (int) ((currentTime - queryTime) / 1000); + } } diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/LotroServer.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/LotroServer.java index 9c362f1bb..309628803 100644 --- a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/LotroServer.java +++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/LotroServer.java @@ -103,6 +103,9 @@ public class LotroServer { } } } + + for (LotroGameMediator lotroGameMediator : _runningGames.values()) + lotroGameMediator.cleanup(); } private String getChatRoomName(String gameId) {