From b4b02d0f68cb4b6d85aed2ed227c3723158c8602 Mon Sep 17 00:00:00 2001 From: BetaSteward Date: Mon, 4 Jul 2011 15:15:05 -0400 Subject: [PATCH] reconnect to games when client reconnects --- .../src/main/java/mage/server/Session.java | 1 + .../src/main/java/mage/server/User.java | 28 ++++++++-- .../java/mage/server/game/GameController.java | 50 +++++++---------- .../java/mage/server/game/GameSession.java | 55 ++++++++++++++----- .../java/mage/server/game/GameWatcher.java | 29 ++++++---- 5 files changed, 100 insertions(+), 63 deletions(-) diff --git a/Mage.Server/src/main/java/mage/server/Session.java b/Mage.Server/src/main/java/mage/server/Session.java index 9499a06441..1dc657efa0 100644 --- a/Mage.Server/src/main/java/mage/server/Session.java +++ b/Mage.Server/src/main/java/mage/server/Session.java @@ -106,6 +106,7 @@ public class Session { callbackHandler.handleCallbackOneway(new Callback(call)); } catch (HandleCallbackException ex) { logger.fatal("Session fireCallback error", ex); + kill(); } } diff --git a/Mage.Server/src/main/java/mage/server/User.java b/Mage.Server/src/main/java/mage/server/User.java index d63a3c4f36..3acabe1b22 100644 --- a/Mage.Server/src/main/java/mage/server/User.java +++ b/Mage.Server/src/main/java/mage/server/User.java @@ -28,10 +28,14 @@ package mage.server; import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; import java.util.UUID; -import java.util.concurrent.CountDownLatch; import mage.cards.decks.Deck; import mage.interfaces.callback.ClientCallback; +import mage.server.game.GameManager; +import mage.server.game.GameSession; import mage.view.TableClientMessage; /** @@ -39,7 +43,7 @@ import mage.view.TableClientMessage; * @author BetaSteward_at_googlemail.com */ public class User { - + public enum UserState { Created, Connected, Disconnected, Reconnected; } @@ -49,9 +53,8 @@ public class User { private String sessionId = ""; private String host; private Date connectionTime = new Date(); - private Date lastActivity = new Date(); private UserState userState; - private CountDownLatch connectionSignal = new CountDownLatch(1); + private Map gameSessions = new HashMap(); public User(String userName, String host) { this.userName = userName; @@ -88,7 +91,7 @@ public class User { } public boolean isConnected() { - return userState == UserState.Connected; + return userState == UserState.Connected || userState == UserState.Reconnected; } public Date getConnectionTime() { @@ -131,6 +134,19 @@ public class User { } private void reconnect() { - + for (Entry entry: gameSessions.entrySet()) { + gameStarted(entry.getValue().getGameId(), entry.getKey()); + entry.getValue().init(); + GameManager.getInstance().sendPlayerString(entry.getValue().getGameId(), userId, ""); + } } + + public void addGame(UUID playerId, GameSession gameSession) { + gameSessions.put(playerId, gameSession); + } + + public void removeGame(UUID playerId) { + gameSessions.remove(playerId); + } + } diff --git a/Mage.Server/src/main/java/mage/server/game/GameController.java b/Mage.Server/src/main/java/mage/server/game/GameController.java index b22fe71a7d..614da0a650 100644 --- a/Mage.Server/src/main/java/mage/server/game/GameController.java +++ b/Mage.Server/src/main/java/mage/server/game/GameController.java @@ -62,6 +62,7 @@ import mage.game.events.TableEvent; import mage.game.permanent.Permanent; import mage.players.Player; import mage.server.ChatManager; +import mage.server.UserManager; import mage.server.util.ThreadExecutor; import mage.sets.Sets; import mage.view.*; @@ -186,6 +187,7 @@ public class GameController implements GameCallback { UUID playerId = userPlayerMap.get(userId); GameSession gameSession = new GameSession(game, userId, playerId); gameSessions.put(playerId, gameSession); + UserManager.getInstance().getUser(userId).addGame(playerId, gameSession); logger.info("player " + playerId + " has joined game " + game.getId()); ChatManager.getInstance().broadcast(chatId, "", game.getPlayer(playerId).getName() + " has joined the game", MessageColor.BLACK); checkStart(); @@ -194,7 +196,7 @@ public class GameController implements GameCallback { private synchronized void startGame() { if (gameFuture == null) { for (final Entry entry: gameSessions.entrySet()) { - if (!entry.getValue().init(getGameView(entry.getKey()))) { + if (!entry.getValue().init()) { logger.fatal("Unable to initialize client"); //TODO: generate client error message return; @@ -227,9 +229,9 @@ public class GameController implements GameCallback { } public void watch(UUID userId) { - GameWatcher gameWatcher = new GameWatcher(userId, game.getId()); + GameWatcher gameWatcher = new GameWatcher(userId, game); watchers.put(userId, gameWatcher); - gameWatcher.init(getGameView()); + gameWatcher.init(); ChatManager.getInstance().broadcast(chatId, "", " has started watching", MessageColor.BLACK); } @@ -297,6 +299,7 @@ public class GameController implements GameCallback { public void endGame(final String message) throws MageException { for (final GameSession gameSession: gameSessions.values()) { gameSession.gameOver(message); + gameSession.removeGame(); } for (final GameWatcher gameWatcher: watchers.values()) { gameWatcher.gameOver(message); @@ -329,17 +332,17 @@ public class GameController implements GameCallback { } private synchronized void updateGame() { - for (final Entry entry: gameSessions.entrySet()) { - entry.getValue().update(getGameView(entry.getKey())); + for (final GameSession gameSession: gameSessions.values()) { + gameSession.update(); } for (final GameWatcher gameWatcher: watchers.values()) { - gameWatcher.update(getGameView()); + gameWatcher.update(); } } private synchronized void ask(UUID playerId, String question) throws MageException { if (gameSessions.containsKey(playerId)) - gameSessions.get(playerId).ask(question, getGameView(playerId)); + gameSessions.get(playerId).ask(question); informOthers(playerId); } @@ -358,41 +361,41 @@ public class GameController implements GameCallback { private synchronized void target(UUID playerId, String question, Cards cards, List perms, Set targets, boolean required, Map options) throws MageException { if (gameSessions.containsKey(playerId)) { if (cards != null) - gameSessions.get(playerId).target(question, new CardsView(cards.getCards(game)), targets, required, getGameView(playerId), options); + gameSessions.get(playerId).target(question, new CardsView(cards.getCards(game)), targets, required, options); else if (perms != null) { CardsView permsView = new CardsView(); for (Permanent perm: perms) { permsView.put(perm.getId(), new PermanentView(perm, game.getCard(perm.getId()))); } - gameSessions.get(playerId).target(question, permsView, targets, required, getGameView(playerId), options); + gameSessions.get(playerId).target(question, permsView, targets, required, options); } else - gameSessions.get(playerId).target(question, new CardsView(), targets, required, getGameView(playerId), options); + gameSessions.get(playerId).target(question, new CardsView(), targets, required, options); } informOthers(playerId); } private synchronized void target(UUID playerId, String question, Collection abilities, boolean required, Map options) throws MageException { if (gameSessions.containsKey(playerId)) - gameSessions.get(playerId).target(question, new CardsView(abilities, game), null, required, getGameView(playerId), options); + gameSessions.get(playerId).target(question, new CardsView(abilities, game), null, required, options); informOthers(playerId); } private synchronized void select(UUID playerId, String message) throws MageException { if (gameSessions.containsKey(playerId)) - gameSessions.get(playerId).select(message, getGameView(playerId)); + gameSessions.get(playerId).select(message); informOthers(playerId); } private synchronized void playMana(UUID playerId, String message) throws MageException { if (gameSessions.containsKey(playerId)) - gameSessions.get(playerId).playMana(message, getGameView(playerId)); + gameSessions.get(playerId).playMana(message); informOthers(playerId); } private synchronized void playXMana(UUID playerId, String message) throws MageException { if (gameSessions.containsKey(playerId)) - gameSessions.get(playerId).playXMana(message, getGameView(playerId)); + gameSessions.get(playerId).playXMana(message); informOthers(playerId); } @@ -417,11 +420,11 @@ public class GameController implements GameCallback { final String message = "Waiting for " + game.getPlayer(playerId).getName(); for (final Entry entry: gameSessions.entrySet()) { if (!entry.getKey().equals(playerId)) { - entry.getValue().inform(message, getGameView(entry.getKey())); + entry.getValue().inform(message); } } for (final GameWatcher watcher: watchers.values()) { - watcher.inform(message, getGameView()); + watcher.inform(message); } } @@ -431,21 +434,8 @@ public class GameController implements GameCallback { } } - private GameView getGameView() { - return new GameView(game.getState(), game); - } - public GameView getGameView(UUID playerId) { - GameView gameView = new GameView(game.getState(), game); - gameView.setHand(new CardsView(game.getPlayer(playerId).getHand().getCards(game))); - - List list = new ArrayList(); - for (Entry entry : game.getState().getLookedAt(playerId).entrySet()) { - list.add(new LookedAtView(entry.getKey(), entry.getValue(), game)); - } - gameView.setLookedAt(list); - - return gameView; + return gameSessions.get(playerId).getGameView(); } @Override diff --git a/Mage.Server/src/main/java/mage/server/game/GameSession.java b/Mage.Server/src/main/java/mage/server/game/GameSession.java index cefd849d7c..41eec5c57e 100644 --- a/Mage.Server/src/main/java/mage/server/game/GameSession.java +++ b/Mage.Server/src/main/java/mage/server/game/GameSession.java @@ -29,12 +29,16 @@ package mage.server.game; import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; import java.util.Map; +import java.util.Map.Entry; import java.util.Set; import java.util.UUID; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; +import mage.cards.Cards; import mage.game.Game; import mage.interfaces.callback.ClientCallback; import mage.server.User; @@ -45,6 +49,7 @@ import mage.view.AbilityPickerView; import mage.view.CardsView; import mage.view.GameClientMessage; import mage.view.GameView; +import mage.view.LookedAtView; /** * @@ -52,44 +57,42 @@ import mage.view.GameView; */ public class GameSession extends GameWatcher { - private Game game; private UUID playerId; private ScheduledFuture futureTimeout; protected static ScheduledExecutorService timeoutExecutor = ThreadExecutor.getInstance().getTimeoutExecutor(); public GameSession(Game game, UUID userId, UUID playerId) { - super(userId, game.getId()); - this.game = game; + super(userId, game); this.playerId = playerId; } - public void ask(final String question, final GameView gameView) { + public void ask(final String question) { if (!killed) { setupTimeout(); User user = UserManager.getInstance().getUser(userId); if (user != null) { - user.fireCallback(new ClientCallback("gameAsk", game.getId(), new GameClientMessage(gameView, question))); + user.fireCallback(new ClientCallback("gameAsk", game.getId(), new GameClientMessage(getGameView(), question))); } } } - public void target(final String question, final CardsView cardView, final Set targets, final boolean required, final GameView gameView, final Map options) { + public void target(final String question, final CardsView cardView, final Set targets, final boolean required, final Map options) { if (!killed) { setupTimeout(); User user = UserManager.getInstance().getUser(userId); if (user != null) { - user.fireCallback(new ClientCallback("gameTarget", game.getId(), new GameClientMessage(gameView, question, cardView, targets, required, options))); + user.fireCallback(new ClientCallback("gameTarget", game.getId(), new GameClientMessage(getGameView(), question, cardView, targets, required, options))); } } } - public void select(final String message, final GameView gameView) { + public void select(final String message) { if (!killed) { setupTimeout(); User user = UserManager.getInstance().getUser(userId); if (user != null) { - user.fireCallback(new ClientCallback("gameSelect", game.getId(), new GameClientMessage(gameView, message))); + user.fireCallback(new ClientCallback("gameSelect", game.getId(), new GameClientMessage(getGameView(), message))); } } } @@ -114,22 +117,22 @@ public class GameSession extends GameWatcher { } } - public void playMana(final String message, final GameView gameView) { + public void playMana(final String message) { if (!killed) { setupTimeout(); User user = UserManager.getInstance().getUser(userId); if (user != null) { - user.fireCallback(new ClientCallback("gamePlayMana", game.getId(), new GameClientMessage(gameView, message))); + user.fireCallback(new ClientCallback("gamePlayMana", game.getId(), new GameClientMessage(getGameView(), message))); } } } - public void playXMana(final String message, final GameView gameView) { + public void playXMana(final String message) { if (!killed) { setupTimeout(); User user = UserManager.getInstance().getUser(userId); if (user != null) { - user.fireCallback(new ClientCallback("gamePlayXMana", game.getId(), new GameClientMessage(gameView, message))); + user.fireCallback(new ClientCallback("gamePlayXMana", game.getId(), new GameClientMessage(getGameView(), message))); } } } @@ -153,14 +156,13 @@ public class GameSession extends GameWatcher { } } - private synchronized void setupTimeout() { cancelTimeout(); futureTimeout = timeoutExecutor.schedule( new Runnable() { @Override public void run() { - GameManager.getInstance().timeout(gameId, userId); + GameManager.getInstance().timeout(game.getId(), userId); } }, ConfigSettings.getInstance().getMaxSecondsIdle(), TimeUnit.SECONDS @@ -192,4 +194,27 @@ public class GameSession extends GameWatcher { cancelTimeout(); game.getPlayer(playerId).setResponseInteger(data); } + + @Override + public GameView getGameView() { + GameView gameView = new GameView(game.getState(), game); + gameView.setHand(new CardsView(game.getPlayer(playerId).getHand().getCards(game))); + + List list = new ArrayList(); + for (Entry entry : game.getState().getLookedAt(playerId).entrySet()) { + list.add(new LookedAtView(entry.getKey(), entry.getValue(), game)); + } + gameView.setLookedAt(list); + + return gameView; + } + + public void removeGame() { + UserManager.getInstance().getUser(userId).removeGame(playerId); + } + + public UUID getGameId() { + return game.getId(); + } + } diff --git a/Mage.Server/src/main/java/mage/server/game/GameWatcher.java b/Mage.Server/src/main/java/mage/server/game/GameWatcher.java index 5576e38a72..dbdd48e19c 100644 --- a/Mage.Server/src/main/java/mage/server/game/GameWatcher.java +++ b/Mage.Server/src/main/java/mage/server/game/GameWatcher.java @@ -30,6 +30,7 @@ package mage.server.game; import java.rmi.RemoteException; import java.util.UUID; +import mage.game.Game; import mage.interfaces.callback.ClientCallback; import mage.server.User; import mage.server.UserManager; @@ -46,39 +47,39 @@ public class GameWatcher { protected final static Logger logger = Logger.getLogger(GameWatcher.class); protected UUID userId; - protected UUID gameId; + protected Game game; protected boolean killed = false; - public GameWatcher(UUID userId, UUID gameId) { + public GameWatcher(UUID userId, Game game) { this.userId = userId; - this.gameId = gameId; + this.game = game; } - public boolean init(final GameView gameView) { + public boolean init() { if (!killed) { User user = UserManager.getInstance().getUser(userId); if (user != null) { - user.fireCallback(new ClientCallback("gameInit", gameId, gameView)); + user.fireCallback(new ClientCallback("gameInit", game.getId(), getGameView())); return true; } } return false; } - public void update(final GameView gameView) { + public void update() { if (!killed) { User user = UserManager.getInstance().getUser(userId); if (user != null) { - user.fireCallback(new ClientCallback("gameUpdate", gameId, gameView)); + user.fireCallback(new ClientCallback("gameUpdate", game.getId(), getGameView())); } } } - public void inform(final String message, final GameView gameView) { + public void inform(final String message) { if (!killed) { User user = UserManager.getInstance().getUser(userId); if (user != null) { - user.fireCallback(new ClientCallback("gameInform", gameId, new GameClientMessage(gameView, message))); + user.fireCallback(new ClientCallback("gameInform", game.getId(), new GameClientMessage(getGameView(), message))); } } } @@ -87,7 +88,7 @@ public class GameWatcher { if (!killed) { User user = UserManager.getInstance().getUser(userId); if (user != null) { - user.fireCallback(new ClientCallback("gameOver", gameId, message)); + user.fireCallback(new ClientCallback("gameOver", game.getId(), message)); } } } @@ -96,18 +97,22 @@ public class GameWatcher { if (!killed) { User user = UserManager.getInstance().getUser(userId); if (user != null) { - user.fireCallback(new ClientCallback("gameError", gameId, message)); + user.fireCallback(new ClientCallback("gameError", game.getId(), message)); } } } protected void handleRemoteException(RemoteException ex) { logger.fatal("GameWatcher error", ex); - GameManager.getInstance().kill(gameId, userId); + GameManager.getInstance().kill(game.getId(), userId); } public void setKilled() { killed = true; } + public GameView getGameView() { + return new GameView(game.getState(), game); + } + }