diff --git a/gemp-lotr/gemp-lotr-common/src/main/java/com/gempukku/lotro/common/Zone.java b/gemp-lotr/gemp-lotr-common/src/main/java/com/gempukku/lotro/common/Zone.java index 6659f830c..d8656ab8a 100644 --- a/gemp-lotr/gemp-lotr-common/src/main/java/com/gempukku/lotro/common/Zone.java +++ b/gemp-lotr/gemp-lotr-common/src/main/java/com/gempukku/lotro/common/Zone.java @@ -1,16 +1,28 @@ package com.gempukku.lotro.common; public enum Zone implements Filterable { - FREE_CHARACTERS("play", true), SUPPORT("play", true), SHADOW_CHARACTERS("play", true), - ADVENTURE_PATH("play", true), - HAND("hand", false), VOID("void", false), DECK("deck", false), ATTACHED("play", true), STACKED("stacked", false), - DISCARD("discard", false), DEAD("dead pile", false); + // Public knowledge and in play + FREE_CHARACTERS("play", true, true, true), SUPPORT("play", true, true, true), SHADOW_CHARACTERS("play", true, true, true), + ADVENTURE_PATH("play", true, true, true), ATTACHED("play", true, true, true), + + // Public knowledge but not in play + STACKED("stacked", true, true, false), DEAD("dead pile", true, true, false), + + // Private knowledge + HAND("hand", false, true, false), DISCARD("discard", false, true, false), + + // Nobody sees + VOID("void", false, false, false), DECK("deck", false, false, false); private String _humanReadable; + private boolean _public; + private boolean _visibleByOwner; private boolean _inPlay; - private Zone(String humanReadable, boolean inPlay) { + private Zone(String humanReadable, boolean isPublic, boolean visibleByOwner, boolean inPlay) { _humanReadable = humanReadable; + _public = isPublic; + _visibleByOwner = visibleByOwner; _inPlay = inPlay; } @@ -21,4 +33,12 @@ public enum Zone implements Filterable { public boolean isInPlay() { return _inPlay; } + + public boolean isPublic() { + return _public; + } + + public boolean isVisibleByOwner() { + return _visibleByOwner; + } } 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 6b4db7475..11e7eff99 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 @@ -5,18 +5,7 @@ import com.gempukku.lotro.communication.GameStateListener; import com.gempukku.lotro.game.*; import com.gempukku.lotro.logic.PlayerOrder; import com.gempukku.lotro.logic.timing.GameStats; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.transform.Result; -import javax.xml.transform.Source; -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.dom.DOMSource; -import javax.xml.transform.stream.StreamResult; -import java.io.File; import java.util.*; public class GameState { @@ -56,8 +45,7 @@ public class GameState { private List _assignments = new LinkedList(); private Skirmish _skirmish = null; - private Map _recordingListeners = new HashMap(); - private Map _gameStateListeners = new HashMap(); + private Set _gameStateListeners = new HashSet(); private int _nextCardId = 0; @@ -81,29 +69,8 @@ public class GameState { addPlayerCards(stringListEntry.getKey(), stringListEntry.getValue(), library); } - for (String playerId : playerOrder.getAllPlayers()) { - GatheringParticipantCommunicationChannel listener = new GatheringParticipantCommunicationChannel(playerId); - listener.setPlayerOrder(playerOrder.getAllPlayers()); - _recordingListeners.put(playerId, listener); - + for (String playerId : playerOrder.getAllPlayers()) _playerThreats.put(playerId, 0); - } - - for (String playerId : _gameStateListeners.keySet()) - sendStateToPlayer(playerId, gameStats); - } - - private String _possibleChars = "abcdefghijklmnopqrstuvwxyz0123456789"; - private int _charsCount = _possibleChars.length(); - - private String randomUid() { - int length = 16; - char[] chars = new char[length]; - Random rnd = new Random(); - for (int i = 0; i < length; i++) - chars[i] = _possibleChars.charAt(rnd.nextInt(_charsCount)); - - return new String(chars); } public void setInitiativeSide(Side initiativeSide) { @@ -114,47 +81,6 @@ public class GameState { return _initiativeSide; } - public void gameFinished() { - File gameReplayFolder = new File("i:\\gemp-lotr\\replay"); - gameReplayFolder.mkdirs(); - for (Map.Entry playerRecordings : _recordingListeners.entrySet()) { - String playerId = playerRecordings.getKey(); - File playerReplayFolder = new File(gameReplayFolder, playerId); - playerReplayFolder.mkdir(); - File replayFile; - do { - replayFile = new File(playerReplayFolder, randomUid() + ".xml"); - } while (replayFile.exists()); - - final List gameEvents = playerRecordings.getValue().consumeGameEvents(); - - try { - DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); - DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder(); - Document doc = documentBuilder.newDocument(); - Element gameReplay = doc.createElement("gameReplay"); - EventSerializer serializer = new EventSerializer(); - for (GameEvent gameEvent : gameEvents) { - gameReplay.appendChild(serializer.serializeEvent(doc, gameEvent)); - } - - doc.appendChild(gameReplay); - - // Prepare the DOM document for writing - Source source = new DOMSource(doc); - - // Prepare the output file - Result result = new StreamResult(replayFile); - - // Write the DOM document to the file - Transformer xformer = TransformerFactory.newInstance().newTransformer(); - xformer.transform(source, result); - } catch (Exception exp) { - - } - } - } - private void addPlayerCards(String playerId, List cards, LotroCardBlueprintLibrary library) { for (String blueprintId : cards) { LotroCardBlueprint card = library.getLotroCardBlueprint(blueprintId); @@ -192,34 +118,20 @@ public class GameState { } public void addGameStateListener(String playerId, GameStateListener gameStateListener, GameStats gameStats) { - _gameStateListeners.put(playerId, gameStateListener); - sendStateToPlayer(playerId, gameStats); + _gameStateListeners.add(gameStateListener); + sendStateToPlayer(playerId, gameStateListener, gameStats); } public void removeGameStateListener(String playerId, GameStateListener gameStateListener) { - _gameStateListeners.remove(playerId); - } - - private Collection getPrivateGameStateListeners(PhysicalCard physicalCard) { - String owner = physicalCard.getOwner(); - Set listeners = new HashSet(); - GameStateListener result = _gameStateListeners.get(owner); - if (result != null) - listeners.add(result); - - listeners.add(_recordingListeners.get(owner)); - return listeners; + _gameStateListeners.remove(gameStateListener); } private Collection getAllGameStateListeners() { - Set allListeners = new HashSet(_gameStateListeners.values()); - allListeners.addAll(_recordingListeners.values()); - return allListeners; + return Collections.unmodifiableSet(_gameStateListeners); } - private void sendStateToPlayer(String playerId, GameStats gameStats) { + private void sendStateToPlayer(String playerId, GameStateListener listener, GameStats gameStats) { if (_playerOrder != null) { - GameStateListener listener = _gameStateListeners.get(playerId); listener.setPlayerOrder(_playerOrder.getAllPlayers()); if (_currentPlayerId != null) listener.setCurrentPlayerId(_currentPlayerId); @@ -281,15 +193,6 @@ public class GameState { } } - private boolean isZonePublic(Zone zone) { - return zone == Zone.FREE_CHARACTERS || zone == Zone.SUPPORT || zone == Zone.SHADOW_CHARACTERS || zone == Zone.SUPPORT - || zone == Zone.ADVENTURE_PATH || zone == Zone.ATTACHED || zone == Zone.STACKED || zone == Zone.DEAD; - } - - private boolean isZonePrivate(Zone zone) { - return zone == Zone.DISCARD || zone == Zone.HAND; - } - public void sendMessage(String message) { for (GameStateListener listener : getAllGameStateListeners()) listener.sendMessage(message); @@ -383,7 +286,14 @@ public class GameState { } public void removeCardsFromZone(String playerPerforming, Collection cards) { - Map> listenerCards = new HashMap>(); + for (PhysicalCard card : cards) { + List zoneCards = getZoneCards(card.getOwner(), card.getBlueprint().getCardType(), card.getZone()); + if (!zoneCards.contains(card)) + throw new RuntimeException("Card was not found in the expected zone"); + } + + for (GameStateListener listener : getAllGameStateListeners()) + listener.cardsRemoved(playerPerforming, cards); for (PhysicalCard card : cards) { Zone zone = card.getZone(); @@ -395,9 +305,7 @@ public class GameState { stopAffectingStacked(card); List zoneCards = getZoneCards(card.getOwner(), card.getBlueprint().getCardType(), zone); - boolean b = zoneCards.remove(card); - if (!b) - throw new RuntimeException("Card was not found in the expected zone"); + zoneCards.remove(card); if (zone == Zone.ATTACHED) ((PhysicalCardImpl) card).attachTo(null); @@ -417,20 +325,8 @@ public class GameState { removeAllTokens(card); - if (isZonePublic(zone)) - for (GameStateListener listener : getAllGameStateListeners()) { - getValue(listenerCards, listener).add(card); - } - else if (isZonePrivate(zone)) - for (GameStateListener listener : getPrivateGameStateListeners(card)) { - getValue(listenerCards, listener).add(card); - } - ((PhysicalCardImpl) card).setZone(null); } - - for (Map.Entry> gameStateListenerSetEntry : listenerCards.entrySet()) - gameStateListenerSetEntry.getKey().cardsRemoved(playerPerforming, gameStateListenerSetEntry.getValue()); } private Set getValue(Map> map, GameStateListener listener) { @@ -462,12 +358,8 @@ public class GameState { for (GameStateListener listener : getAllGameStateListeners()) listener.setSite(card); } else { - if (isZonePublic(zone)) - for (GameStateListener listener : getAllGameStateListeners()) - listener.cardCreated(card); - else if (isZonePrivate(zone)) - for (GameStateListener listener : getPrivateGameStateListeners(card)) - listener.cardCreated(card); + for (GameStateListener listener : getAllGameStateListeners()) + listener.cardCreated(card); } if (zone.isInPlay()) { diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/game/state/GatheringParticipantCommunicationChannel.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/game/state/GatheringParticipantCommunicationChannel.java index 66bb71af3..b6d8583ef 100644 --- a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/game/state/GatheringParticipantCommunicationChannel.java +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/game/state/GatheringParticipantCommunicationChannel.java @@ -6,10 +6,7 @@ import com.gempukku.lotro.communication.GameStateListener; import com.gempukku.lotro.game.PhysicalCard; import com.gempukku.lotro.logic.timing.GameStats; -import java.util.Collection; -import java.util.Date; -import java.util.LinkedList; -import java.util.List; +import java.util.*; import static com.gempukku.lotro.game.state.GameEvent.Type.*; @@ -75,7 +72,8 @@ public class GatheringParticipantCommunicationChannel implements GameStateListen @Override public void cardCreated(PhysicalCard card) { - _events.add(new GameEvent(PCIP).card(card)); + if (card.getZone().isPublic() || (card.getZone().isVisibleByOwner() && card.getOwner().equals(_self))) + _events.add(new GameEvent(PCIP).card(card)); } @Override @@ -85,7 +83,13 @@ public class GatheringParticipantCommunicationChannel implements GameStateListen @Override public void cardsRemoved(String playerPerforming, Collection cards) { - _events.add(new GameEvent(RCFP).otherCardIds(getCardIds(cards)).participantId(playerPerforming)); + Set removedCardsVisibleByPlayer = new HashSet(); + for (PhysicalCard card : cards) { + if (card.getZone().isPublic() || (card.getZone().isVisibleByOwner() && card.getOwner().equals(_self))) + removedCardsVisibleByPlayer.add(card); + } + + _events.add(new GameEvent(RCFP).otherCardIds(getCardIds(removedCardsVisibleByPlayer)).participantId(playerPerforming)); } @Override 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 82aed8134..5f47a91d1 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 @@ -32,7 +32,6 @@ public class DefaultLotroGame implements LotroGame { private ActionStack _actionStack; private LotroFormat _format; - private GameResultListener _gameResultListener; private Set _allPlayers; @@ -40,9 +39,10 @@ public class DefaultLotroGame implements LotroGame { private String _winReason; private Map _losers = new HashMap(); - public DefaultLotroGame(LotroFormat format, Map decks, UserFeedback userFeedback, GameResultListener gameResultListener, final LotroCardBlueprintLibrary library) { + private Set _gameResultListeners = new HashSet(); + + public DefaultLotroGame(LotroFormat format, Map decks, UserFeedback userFeedback, final LotroCardBlueprintLibrary library) { _format = format; - _gameResultListener = gameResultListener; _actionStack = new ActionStack(); _allPlayers = decks.keySet(); @@ -79,6 +79,14 @@ public class DefaultLotroGame implements LotroGame { ruleSet.applyRuleSet(); } + public void addGameResultListener(GameResultListener listener) { + _gameResultListeners.add(listener); + } + + public void removeGameResultListener(GameResultListener listener) { + _gameResultListeners.remove(listener); + } + @Override public LotroFormat getFormat() { return _format; @@ -103,12 +111,10 @@ public class DefaultLotroGame implements LotroGame { _winReason = reason; if (_gameState != null) _gameState.sendMessage(_winnerPlayerId + " is the winner due to: " + reason); - if (_gameState != null) - _gameState.gameFinished(); - if (_gameResultListener != null) { + for (GameResultListener gameResultListener : _gameResultListeners) { Set losers = new HashSet(_allPlayers); losers.remove(_winnerPlayerId); - _gameResultListener.gameFinished(_winnerPlayerId, losers, reason); + gameResultListener.gameFinished(_winnerPlayerId, losers, reason); } } diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/game/GameRecording.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/game/GameRecording.java new file mode 100644 index 000000000..693e8fd77 --- /dev/null +++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/game/GameRecording.java @@ -0,0 +1,85 @@ +package com.gempukku.lotro.game; + +import com.gempukku.lotro.game.state.EventSerializer; +import com.gempukku.lotro.game.state.GameEvent; +import com.gempukku.lotro.game.state.GatheringParticipantCommunicationChannel; +import com.gempukku.lotro.logic.timing.GameResultListener; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.transform.Result; +import javax.xml.transform.Source; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; +import java.io.File; +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.Set; + +public class GameRecording implements GameResultListener { + private Map _gameProgress; + + private static String _possibleChars = "abcdefghijklmnopqrstuvwxyz0123456789"; + private static int _charsCount = _possibleChars.length(); + + public GameRecording(Map gameProgress) { + _gameProgress = gameProgress; + } + + private String randomUid() { + int length = 16; + char[] chars = new char[length]; + Random rnd = new Random(); + for (int i = 0; i < length; i++) + chars[i] = _possibleChars.charAt(rnd.nextInt(_charsCount)); + + return new String(chars); + } + + @Override + public void gameFinished(String winnerPlayerId, Set loserPlayerIds, String reason) { + File gameReplayFolder = new File("i:\\gemp-lotr\\replay"); + gameReplayFolder.mkdirs(); + for (Map.Entry playerRecordings : _gameProgress.entrySet()) { + String playerId = playerRecordings.getKey(); + File playerReplayFolder = new File(gameReplayFolder, playerId); + playerReplayFolder.mkdir(); + File replayFile; + do { + replayFile = new File(playerReplayFolder, randomUid() + ".xml"); + } while (replayFile.exists()); + + final List gameEvents = playerRecordings.getValue().consumeGameEvents(); + + try { + DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder(); + Document doc = documentBuilder.newDocument(); + Element gameReplay = doc.createElement("gameReplay"); + EventSerializer serializer = new EventSerializer(); + for (GameEvent gameEvent : gameEvents) { + gameReplay.appendChild(serializer.serializeEvent(doc, gameEvent)); + } + + doc.appendChild(gameReplay); + + // Prepare the DOM document for writing + Source source = new DOMSource(doc); + + // Prepare the output file + Result result = new StreamResult(replayFile); + + // Write the DOM document to the file + Transformer xformer = TransformerFactory.newInstance().newTransformer(); + xformer.transform(source, result); + } catch (Exception exp) { + + } + } + } +} 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 31103fe32..635c63a0f 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 @@ -32,12 +32,11 @@ public class LotroGameMediator { private ReentrantReadWriteLock.ReadLock _readLock = _lock.readLock(); private ReentrantReadWriteLock.WriteLock _writeLock = _lock.writeLock(); - public LotroGameMediator(LotroFormat lotroFormat, LotroGameParticipant[] participants, LotroCardBlueprintLibrary library, GameResultListener gameResultListener) { + public LotroGameMediator(LotroFormat lotroFormat, LotroGameParticipant[] participants, LotroCardBlueprintLibrary library) { if (participants.length < 1) throw new IllegalArgumentException("Game can't have less than one participant"); Map decks = new HashMap(); - _communicationChannels = new HashMap(); for (LotroGameParticipant participant : participants) { String participantId = participant.getPlayerId(); @@ -45,7 +44,26 @@ public class LotroGameMediator { _playerClocks.put(participantId, 0); _playersPlaying.add(participantId); } - _lotroGame = new DefaultLotroGame(lotroFormat, decks, _userFeedback, gameResultListener, library); + + _lotroGame = new DefaultLotroGame(lotroFormat, decks, _userFeedback, library); + + final HashMap recordingChannels = new HashMap(); + for (String playerId : _playersPlaying) { + final GatheringParticipantCommunicationChannel playerRecording = new GatheringParticipantCommunicationChannel(playerId); + _lotroGame.addGameStateListener(playerId, playerRecording); + recordingChannels.put(playerId, playerRecording); + } + + _lotroGame.addGameResultListener( + new GameRecording(recordingChannels)); + } + + public void addGameResultListener(GameResultListener listener) { + _lotroGame.addGameResultListener(listener); + } + + public void removeGameResultListener(GameResultListener listener) { + _lotroGame.removeGameResultListener(listener); } public String getWinner() { 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 dc4edbb1f..a5df4462d 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 @@ -108,7 +108,8 @@ public class LotroServer extends AbstractServer { ChatRoomMediator room = _chatServer.createChatRoom(chatRoomName); room.sendMessage("System", "You're starting a game of " + formatName); - LotroGameMediator lotroGameMediator = new LotroGameMediator(lotroFormat, participants, _lotroCardBlueprintLibrary, + LotroGameMediator lotroGameMediator = new LotroGameMediator(lotroFormat, participants, _lotroCardBlueprintLibrary); + lotroGameMediator.addGameResultListener( new GameResultListener() { @Override public void gameFinished(String winnerPlayerId, Set loserPlayerIds, String reason) {