From 3d6a8c6ff55a30e23c14a4a2e1452704dbc7b3bb Mon Sep 17 00:00:00 2001 From: "marcins78@gmail.com" Date: Sun, 18 Sep 2011 11:39:56 +0000 Subject: [PATCH] Fixing problems with concurrency and decision timeouts during preparation of the game. --- .../gempukku/lotro/game/state/GameState.java | 96 +++++++------------ .../gempukku/lotro/game/state/LotroGame.java | 2 + .../effects/CorruptRingBearerEffect.java | 2 +- .../lotro/logic/timing/DefaultLotroGame.java | 45 ++++++--- .../logic/timing/GameResultListener.java | 2 +- .../lotro/logic/timing/TurnProcedure.java | 2 +- .../lotro/game/LotroGameMediator.java | 10 +- .../com/gempukku/lotro/game/LotroServer.java | 4 +- 8 files changed, 78 insertions(+), 85 deletions(-) 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 83113c5a1..276898e66 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 @@ -39,17 +39,13 @@ public class GameState { private Map _gameStateListeners = new HashMap(); - private String _winnerPlayerId; - private String _winReason; - private Map _losers = new HashMap(); - private int _nextCardId = 0; private int nextCardId() { return _nextCardId++; } - public GameState(PlayerOrder playerOrder, String firstPlayer, Map> cards, LotroCardBlueprintLibrary library) { + public void init(PlayerOrder playerOrder, String firstPlayer, Map> cards, LotroCardBlueprintLibrary library) { _playerOrder = playerOrder; _currentPlayerId = firstPlayer; for (Map.Entry> stringListEntry : cards.entrySet()) { @@ -63,31 +59,9 @@ public class GameState { addPlayerCards(stringListEntry.getKey(), stringListEntry.getValue(), library); } - } - public void setWinnerPlayerId(String winnerPlayerId, String reason) { - _winnerPlayerId = winnerPlayerId; - _winReason = reason; - for (GameStateListener listener : getAllGameStateListeners()) - listener.sendMessage(winnerPlayerId + " is the winner due to: " + reason); - } - - public String setLoserPlayerId(String loserPlayerId, String reason) { - _losers.put(loserPlayerId, reason); - for (GameStateListener listener : getAllGameStateListeners()) - listener.sendMessage(loserPlayerId + " lost due to: " + reason); - - if (_losers.size() + 1 == _playerOrder.getAllPlayers().size()) { - List allPlayers = new LinkedList(_playerOrder.getAllPlayers()); - allPlayers.removeAll(_losers.keySet()); - setWinnerPlayerId(allPlayers.get(0), "Last remaining player in game"); - return allPlayers.get(0); - } - return null; - } - - public String getWinnerPlayerId() { - return _winnerPlayerId; + for (String playerId : _gameStateListeners.keySet()) + sendStateToPlayer(playerId); } private void addPlayerCards(String playerId, List cards, LotroCardBlueprintLibrary library) { @@ -143,43 +117,39 @@ public class GameState { } private void sendStateToPlayer(String playerId) { - GameStateListener listener = _gameStateListeners.get(playerId); - listener.setPlayerOrder(_playerOrder.getAllPlayers()); - if (_currentPlayerId != null) - listener.setCurrentPlayerId(_currentPlayerId); - if (_currentPhase != null) - listener.setCurrentPhase(_currentPhase); - listener.setTwilight(_twilightPool); - for (Map.Entry stringIntegerEntry : _playerPosition.entrySet()) - listener.setPlayerPosition(stringIntegerEntry.getKey(), stringIntegerEntry.getValue()); + if (_playerOrder != null) { + GameStateListener listener = _gameStateListeners.get(playerId); + listener.setPlayerOrder(_playerOrder.getAllPlayers()); + if (_currentPlayerId != null) + listener.setCurrentPlayerId(_currentPlayerId); + if (_currentPhase != null) + listener.setCurrentPhase(_currentPhase); + listener.setTwilight(_twilightPool); + for (Map.Entry stringIntegerEntry : _playerPosition.entrySet()) + listener.setPlayerPosition(stringIntegerEntry.getKey(), stringIntegerEntry.getValue()); - for (List physicalCards : _inPlay.values()) - for (PhysicalCardImpl physicalCard : physicalCards) - listener.cardCreated(physicalCard); + for (List physicalCards : _inPlay.values()) + for (PhysicalCardImpl physicalCard : physicalCards) + listener.cardCreated(physicalCard); - List hand = _hands.get(playerId); - if (hand != null) { - for (PhysicalCardImpl physicalCard : hand) - listener.cardCreated(physicalCard); + List hand = _hands.get(playerId); + if (hand != null) { + for (PhysicalCardImpl physicalCard : hand) + listener.cardCreated(physicalCard); + } + + for (Skirmish assignment : _assignments) + listener.addAssignment(assignment.getFellowshipCharacter(), assignment.getShadowCharacters()); + + if (_skirmish != null) + listener.startSkirmish(_skirmish.getFellowshipCharacter(), _skirmish.getShadowCharacters()); + + for (Map.Entry> physicalCardMapEntry : _cardTokens.entrySet()) { + PhysicalCard card = physicalCardMapEntry.getKey(); + for (Map.Entry tokenIntegerEntry : physicalCardMapEntry.getValue().entrySet()) + listener.addTokens(card, tokenIntegerEntry.getKey(), tokenIntegerEntry.getValue()); + } } - - for (Skirmish assignment : _assignments) - listener.addAssignment(assignment.getFellowshipCharacter(), assignment.getShadowCharacters()); - - if (_skirmish != null) - listener.startSkirmish(_skirmish.getFellowshipCharacter(), _skirmish.getShadowCharacters()); - - for (Map.Entry> physicalCardMapEntry : _cardTokens.entrySet()) { - PhysicalCard card = physicalCardMapEntry.getKey(); - for (Map.Entry tokenIntegerEntry : physicalCardMapEntry.getValue().entrySet()) - listener.addTokens(card, tokenIntegerEntry.getKey(), tokenIntegerEntry.getValue()); - } - - for (Map.Entry playerLoseReason : _losers.entrySet()) - listener.sendMessage(playerLoseReason.getKey() + " lost due to: " + playerLoseReason.getValue()); - - if (_winnerPlayerId != null) - listener.sendMessage(_winnerPlayerId + " is the winner due to: " + _winReason); } private boolean isZonePublic(Zone zone) { diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/game/state/LotroGame.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/game/state/LotroGame.java index 4ae76d398..f050a490e 100644 --- a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/game/state/LotroGame.java +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/game/state/LotroGame.java @@ -21,4 +21,6 @@ public interface LotroGame { public void playerWon(String currentPlayerId, String reason); public void playerLost(String currentPlayerId, String reason); + + public String getWinnerPlayerId(); } diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/effects/CorruptRingBearerEffect.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/effects/CorruptRingBearerEffect.java index 34ae46aa2..0f0d5a882 100644 --- a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/effects/CorruptRingBearerEffect.java +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/effects/CorruptRingBearerEffect.java @@ -6,6 +6,6 @@ import com.gempukku.lotro.logic.timing.UnrespondableEffect; public class CorruptRingBearerEffect extends UnrespondableEffect { @Override public void doPlayEffect(LotroGame game) { - game.getGameState().setLoserPlayerId(game.getGameState().getCurrentPlayerId(), "The Ring-Bearer is corrupted by a card effect"); + game.playerLost(game.getGameState().getCurrentPlayerId(), "The Ring-Bearer is corrupted by a card effect"); } } 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 00c8167c1..e23981e1e 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 @@ -30,10 +30,18 @@ public class DefaultLotroGame implements LotroGame { private Map _gameStateListeners = new HashMap(); private GameResultListener _gameResultListener; + private Set _allPlayers; + + private String _winnerPlayerId; + private String _winReason; + private Map _losers = new HashMap(); + public DefaultLotroGame(Map decks, UserFeedback userFeedback, GameResultListener gameResultListener, final LotroCardBlueprintLibrary library) { _gameResultListener = gameResultListener; _actionStack = new ActionStack(); + _allPlayers = decks.keySet(); + _actionsEnvironment = new DefaultActionsEnvironment(this, _actionStack); final Map> cards = new HashMap>(); @@ -49,11 +57,13 @@ public class DefaultLotroGame implements LotroGame { cards.put(playerId, deck); } + _gameState = new GameState(); + _turnProcedure = new TurnProcedure(this, decks.keySet(), userFeedback, _actionStack, new PlayerOrderFeedback() { @Override public void setPlayerOrder(PlayerOrder playerOrder, String firstPlayer) { - _gameState = new GameState(playerOrder, firstPlayer, cards, library); + _gameState.init(playerOrder, firstPlayer, cards, library); for (Map.Entry stringGameStateListenerEntry : _gameStateListeners.entrySet()) _gameState.addGameStateListener(stringGameStateListenerEntry.getKey(), stringGameStateListenerEntry.getValue()); _gameStateListeners = null; @@ -76,22 +86,33 @@ public class DefaultLotroGame implements LotroGame { } @Override - public void playerWon(String currentPlayerId, String reason) { - _gameState.setWinnerPlayerId(currentPlayerId, reason); + public String getWinnerPlayerId() { + return _winnerPlayerId; + } + + @Override + public void playerWon(String playerId, String reason) { + _winnerPlayerId = playerId; + _winReason = reason; + if (_gameState != null) + _gameState.sendMessage(_winnerPlayerId + " is the winner due to: " + reason); if (_gameResultListener != null) { - Set losers = new HashSet(_gameState.getPlayerOrder().getAllPlayers()); - losers.remove(currentPlayerId); - _gameResultListener.gameFinished(currentPlayerId, losers); + Set losers = new HashSet(_allPlayers); + losers.remove(_winnerPlayerId); + _gameResultListener.gameFinished(_winnerPlayerId, losers, reason); } } @Override - public void playerLost(String currentPlayerId, String reason) { - String winner = _gameState.setLoserPlayerId(currentPlayerId, reason); - if (winner != null && _gameResultListener != null) { - Set losers = new HashSet(_gameState.getPlayerOrder().getAllPlayers()); - losers.remove(winner); - _gameResultListener.gameFinished(winner, losers); + public void playerLost(String playerId, String reason) { + _losers.put(playerId, reason); + if (_gameState != null) + _gameState.sendMessage(playerId + " lst due to: " + reason); + + if (_losers.size() + 1 == _allPlayers.size()) { + List allPlayers = new LinkedList(_allPlayers); + allPlayers.removeAll(_losers.keySet()); + playerWon(allPlayers.get(0), "Last remaining player in game"); } } diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/timing/GameResultListener.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/timing/GameResultListener.java index a6154ee47..37c71869d 100644 --- a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/timing/GameResultListener.java +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/timing/GameResultListener.java @@ -3,5 +3,5 @@ package com.gempukku.lotro.logic.timing; import java.util.Set; public interface GameResultListener { - public void gameFinished(String winnerPlayerId, Set loserPlayerIds); + public void gameFinished(String winnerPlayerId, Set loserPlayerIds, String reason); } diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/timing/TurnProcedure.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/timing/TurnProcedure.java index 03cb3faa5..773cab870 100644 --- a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/timing/TurnProcedure.java +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/timing/TurnProcedure.java @@ -35,7 +35,7 @@ public class TurnProcedure { } public void carryOutPendingActionsUntilDecisionNeeded() { - while (!_userFeedback.hasPendingDecisions() && (_game.getGameState() == null || _game.getGameState().getWinnerPlayerId() == null)) { + while (!_userFeedback.hasPendingDecisions() && _game.getWinnerPlayerId() == null) { if (_actionStack.isEmpty()) { if (_playedGameProcess) { _gameProcess = _gameProcess.getNextProcess(); diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/game/LotroGameMediator.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/game/LotroGameMediator.java index 59a6c70af..1522e45ad 100644 --- a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/game/LotroGameMediator.java +++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/game/LotroGameMediator.java @@ -1,6 +1,7 @@ package com.gempukku.lotro.game; import com.gempukku.lotro.common.CardType; +import com.gempukku.lotro.common.Phase; import com.gempukku.lotro.game.formats.LotroFormat; import com.gempukku.lotro.game.state.GameState; import com.gempukku.lotro.game.state.Skirmish; @@ -46,17 +47,16 @@ public class LotroGameMediator { } public String getGameStatus() { - if (_lotroGame.getGameState() == null) - return "Preparation"; - if (_lotroGame.getGameState().getWinnerPlayerId() != null) + if (_lotroGame.getWinnerPlayerId() != null) return "Finished"; + if (_lotroGame.getGameState().getCurrentPhase() == Phase.GAME_SETUP) + return "Preparation"; return "Playing"; } public synchronized String produceCardInfo(String participantId, int cardId) { StringBuilder sb = new StringBuilder(); - PhysicalCard card = _lotroGame.getGameState().findCardById(cardId); if (card == null) return null; @@ -104,7 +104,7 @@ public class LotroGameMediator { } } - if (_lotroGame.getGameState() != null && _lotroGame.getGameState().getWinnerPlayerId() == null) { + if (_lotroGame.getGameState() != null && _lotroGame.getWinnerPlayerId() == null) { for (Map.Entry playerDecision : _decisionQuerySentTimes.entrySet()) { String playerId = playerDecision.getKey(); long decisionSent = playerDecision.getValue(); diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/game/LotroServer.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/game/LotroServer.java index d0584965c..9d19d0bf5 100644 --- a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/game/LotroServer.java +++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/game/LotroServer.java @@ -111,8 +111,8 @@ public class LotroServer extends AbstractServer { LotroGameMediator lotroGameMediator = new LotroGameMediator(lotroFormat, participants, _lotroCardBlueprintLibrary, new GameResultListener() { @Override - public void gameFinished(String winnerPlayerId, Set loserPlayerIds) { - log.debug("Game finished, winner is: " + winnerPlayerId); + public void gameFinished(String winnerPlayerId, Set loserPlayerIds, String reason) { + log.debug("Game finished, winner is - " + winnerPlayerId + " due to: " + reason); synchronized (_finishedGamesTime) { _finishedGamesTime.put(gameId, new Date()); }