diff --git a/Mage.Client/src/main/java/mage/client/table/TablesPanel.java b/Mage.Client/src/main/java/mage/client/table/TablesPanel.java index f2bd481bbcc..167081b46db 100644 --- a/Mage.Client/src/main/java/mage/client/table/TablesPanel.java +++ b/Mage.Client/src/main/java/mage/client/table/TablesPanel.java @@ -189,8 +189,7 @@ public class TablesPanel extends javax.swing.JPanel { } } else if (action.equals("Replay")) { logger.info("Replaying game " + gameId); - // no replay because of memory leaks - // session.replayGame(gameId); + session.replayGame(gameId); } } }; @@ -201,8 +200,8 @@ public class TablesPanel extends javax.swing.JPanel { public void actionPerformed(ActionEvent e) { int modelRow = Integer.valueOf( e.getActionCommand() ); - if (matchesModel.getValueAt(modelRow, MatchesTableModel.ACTION_COLUMN) instanceof List) { - List games = (List)matchesModel.getValueAt(modelRow, MatchesTableModel.ACTION_COLUMN); + if (matchesModel.getValueAt(modelRow, MatchesTableModel.GAMES_LIST_COLUMN) instanceof List) { + List games = (List)matchesModel.getValueAt(modelRow, MatchesTableModel.GAMES_LIST_COLUMN); if (games.size() == 1) { session.replayGame(games.get(0)); } @@ -769,19 +768,16 @@ class TableTableModel extends AbstractTableModel { @Override public boolean isCellEditable(int rowIndex, int columnIndex) { - if (columnIndex != ACTION_COLUMN) { - return false; - } - return true; + return columnIndex == ACTION_COLUMN; } } class UpdateTablesTask extends SwingWorker> { - private Session session; - private UUID roomId; - private TablesPanel panel; + private final Session session; + private final UUID roomId; + private final TablesPanel panel; private static final Logger logger = Logger.getLogger(UpdateTablesTask.class); @@ -830,9 +826,9 @@ class UpdateTablesTask extends SwingWorker> { class UpdatePlayersTask extends SwingWorker> { - private Session session; - private UUID roomId; - private ChatPanel chat; + private final Session session; + private final UUID roomId; + private final ChatPanel chat; private static final Logger logger = Logger.getLogger(UpdatePlayersTask.class); @@ -872,8 +868,8 @@ class UpdatePlayersTask extends SwingWorker> { class MatchesTableModel extends AbstractTableModel { public static final int ACTION_COLUMN = 7; // column the action is located (starting with 0) - - private String[] columnNames = new String[]{"Match Name", "Game Type", "Deck Type", "Players", "Result", "Start Time", "End Time","Action"}; + public static final int GAMES_LIST_COLUMN = 8; + private final String[] columnNames = new String[]{"Match Name", "Game Type", "Deck Type", "Players", "Result", "Start Time", "End Time","Action"}; private MatchView[] matches = new MatchView[0]; private static final DateFormat timeFormatter = SimpleDateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT); @@ -914,7 +910,12 @@ class MatchesTableModel extends AbstractTableModel { return ""; } case 7: - return "None"; + if (matches[arg0].isReplayAvailable()) { + return "Replay"; + } else { + return "None"; + } + case 8: return matches[arg0].getGames(); } @@ -939,19 +940,16 @@ class MatchesTableModel extends AbstractTableModel { @Override public boolean isCellEditable(int rowIndex, int columnIndex) { - if (columnIndex != ACTION_COLUMN) { - return false; - } - return true; + return columnIndex == ACTION_COLUMN; } } class UpdateMatchesTask extends SwingWorker> { - private Session session; - private UUID roomId; - private TablesPanel panel; + private final Session session; + private final UUID roomId; + private final TablesPanel panel; private static final Logger logger = Logger.getLogger(UpdateTablesTask.class); @@ -1013,7 +1011,7 @@ class GameChooser extends JPopupMenu { private class GameChooserAction extends AbstractAction { - private UUID id; + private final UUID id; public GameChooserAction(UUID id, String choice) { this.id = id; diff --git a/Mage.Common/src/mage/remote/SessionImpl.java b/Mage.Common/src/mage/remote/SessionImpl.java index f8862ebabf8..3a96fc3301a 100644 --- a/Mage.Common/src/mage/remote/SessionImpl.java +++ b/Mage.Common/src/mage/remote/SessionImpl.java @@ -87,9 +87,10 @@ public class SessionImpl implements Session { private static final Logger logger = Logger.getLogger(SessionImpl.class); + private final MageClient client; + private String sessionId; private MageServer server; - private MageClient client; private Client callbackClient; private CallbackHandler callbackHandler; private ServerState serverState; @@ -828,6 +829,7 @@ public class SessionImpl implements Session { try { if (isConnected()) { server.removeTable(sessionId, roomId, tableId); + return true; } } catch (MageException ex) { @@ -1275,8 +1277,8 @@ public class SessionImpl implements Session { } class MageAuthenticator extends Authenticator { - private String username; - private String password; + private final String username; + private final String password; public MageAuthenticator(String username, String password) { this.username = username; diff --git a/Mage.Common/src/mage/view/MatchView.java b/Mage.Common/src/mage/view/MatchView.java index 4bb8d0c3cfa..2878439cba3 100644 --- a/Mage.Common/src/mage/view/MatchView.java +++ b/Mage.Common/src/mage/view/MatchView.java @@ -44,17 +44,18 @@ import mage.game.tournament.TournamentPlayer; */ public class MatchView implements Serializable { - private UUID matchId; - private String matchName; + private final UUID matchId; + private final String matchName; private String gameType; - private String deckType; + private final String deckType; - private List games = new ArrayList(); - private String result; - private String players; + private final List games = new ArrayList(); + private final String result; + private final String players; - private Date startTime; - private Date endTime; + private final Date startTime; + private final Date endTime; + private final Boolean replayAvailable; public MatchView(Match match) { this.matchId = match.getId(); @@ -79,6 +80,7 @@ public class MatchView implements Serializable { result = sb2.substring(0, sb2.length() - 2); this.startTime = match.getStartTime(); this.endTime = match.getEndTime(); + this.replayAvailable = match.isReplayAvailable(); } // used for tournaments @@ -107,6 +109,7 @@ public class MatchView implements Serializable { this.result = sb2.toString(); this.startTime = table.getTournament().getStartTime(); this.endTime = table.getTournament().getEndTime(); + this.replayAvailable = false; } public UUID getMatchId() { @@ -144,4 +147,13 @@ public class MatchView implements Serializable { public Date getEndTime() { return endTime; } + + public String getMatchName() { + return matchName; + } + + public Boolean isReplayAvailable() { + return replayAvailable; + } + } diff --git a/Mage.Server/config/config.xml b/Mage.Server/config/config.xml index 991e027f931..69365dfe9ab 100644 --- a/Mage.Server/config/config.xml +++ b/Mage.Server/config/config.xml @@ -10,6 +10,7 @@ maxUserNameLength="14" userNamePattern="[^a-z0-9_]" maxAiOpponents="3" + saveGameActivated="false" /> diff --git a/Mage.Server/release/config/config.xml b/Mage.Server/release/config/config.xml index cd36bc10a66..2dc38f31e47 100644 --- a/Mage.Server/release/config/config.xml +++ b/Mage.Server/release/config/config.xml @@ -1,7 +1,15 @@ - + diff --git a/Mage.Server/src/main/java/mage/server/MageServerImpl.java b/Mage.Server/src/main/java/mage/server/MageServerImpl.java index 48d43d27501..e4c4157f1d6 100644 --- a/Mage.Server/src/main/java/mage/server/MageServerImpl.java +++ b/Mage.Server/src/main/java/mage/server/MageServerImpl.java @@ -89,10 +89,10 @@ import org.apache.log4j.Logger; public class MageServerImpl implements MageServer { private static final Logger logger = Logger.getLogger(MageServerImpl.class); - private static ExecutorService callExecutor = ThreadExecutor.getInstance().getCallExecutor(); + private static final ExecutorService callExecutor = ThreadExecutor.getInstance().getCallExecutor(); - private String password; - private boolean testMode; + private final String password; + private final boolean testMode; public MageServerImpl(String password, boolean testMode) { this.password = password; @@ -187,7 +187,9 @@ public class MageServerImpl implements MageServer { logger.debug("Tournament table " + table.getTableId() + " created"); LogServiceImpl.instance.log(LogKeys.KEY_TOURNAMENT_TABLE_CREATED, sessionId, userId.toString(), table.getTableId().toString()); return table; - } catch (Exception ex) { + } catch (NumberFormatException ex) { + handleException(ex); + } catch (MageException ex) { handleException(ex); } return null; diff --git a/Mage.Server/src/main/java/mage/server/Main.java b/Mage.Server/src/main/java/mage/server/Main.java index b6c24a67f63..7af54f3fc1e 100644 --- a/Mage.Server/src/main/java/mage/server/Main.java +++ b/Mage.Server/src/main/java/mage/server/Main.java @@ -32,6 +32,7 @@ import java.io.File; import java.io.FilenameFilter; import java.io.IOException; import java.net.InetAddress; +import java.net.MalformedURLException; import java.util.HashMap; import java.util.Map; import javax.management.MBeanServer; @@ -76,12 +77,13 @@ import org.w3c.dom.Element; */ public class Main { - private static Logger logger = Logger.getLogger(Main.class); + private static final Logger logger = Logger.getLogger(Main.class); + private static final MageVersion version = new MageVersion(1, 3, 0, "dev2014-02-03"); private static final String testModeArg = "-testMode="; private static final String adminPasswordArg = "-adminPassword="; private static final String pluginFolder = "plugins"; - private static MageVersion version = new MageVersion(1, 3, 0, ""); + public static PluginClassLoader classLoader = new PluginClassLoader(); public static TransporterServer server; @@ -250,10 +252,9 @@ public class Main { @Override public void removeListener(InvokerCallbackHandler callbackHandler) { - logger.fatal("removeListener called"); -// ServerInvokerCallbackHandler handler = (ServerInvokerCallbackHandler) callbackHandler; -// String sessionId = handler.getCallbackClient().getSessionId(); -// SessionManager.getInstance().disconnect(sessionId); + ServerInvokerCallbackHandler handler = (ServerInvokerCallbackHandler) callbackHandler; + String sessionId = handler.getClientSessionId(); + SessionManager.getInstance().disconnect(sessionId, true); } } @@ -264,8 +265,8 @@ public class Main { logger.debug("Loading plugin: " + plugin.getClassName()); return Class.forName(plugin.getClassName(), true, classLoader); } catch (ClassNotFoundException ex) { - logger.warn(new StringBuilder("Plugin not Found: ").append(plugin.getClassName()).append(" - ").append(plugin.getJar()).append(" - check plugin folder")); - } catch (Exception ex) { + logger.warn(new StringBuilder("Plugin not Found: ").append(plugin.getClassName()).append(" - ").append(plugin.getJar()).append(" - check plugin folder"), ex); + } catch (MalformedURLException ex) { logger.fatal("Error loading plugin " + plugin.getJar(), ex); } return null; @@ -277,8 +278,12 @@ public class Main { logger.debug("Loading game type: " + plugin.getClassName()); return (MatchType) Class.forName(plugin.getTypeName(), true, classLoader).newInstance(); } catch (ClassNotFoundException ex) { - logger.warn("Game type not found:" + plugin.getJar() + " - check plugin folder"); - } catch (Exception ex) { + logger.warn("Game type not found:" + plugin.getJar() + " - check plugin folder", ex); + } catch (IllegalAccessException ex) { + logger.fatal("Error loading game type " + plugin.getJar(), ex); + } catch (InstantiationException ex) { + logger.fatal("Error loading game type " + plugin.getJar(), ex); + } catch (MalformedURLException ex) { logger.fatal("Error loading game type " + plugin.getJar(), ex); } return null; @@ -290,8 +295,12 @@ public class Main { logger.debug("Loading tournament type: " + plugin.getClassName()); return (TournamentType) Class.forName(plugin.getTypeName(), true, classLoader).newInstance(); } catch (ClassNotFoundException ex) { - logger.warn("Tournament type not found:" + plugin.getName() + " / "+ plugin.getJar() + " - check plugin folder"); - } catch (Exception ex) { + logger.warn("Tournament type not found:" + plugin.getName() + " / "+ plugin.getJar() + " - check plugin folder", ex); + } catch (IllegalAccessException ex) { + logger.fatal("Error loading game type " + plugin.getJar(), ex); + } catch (InstantiationException ex) { + logger.fatal("Error loading game type " + plugin.getJar(), ex); + } catch (MalformedURLException ex) { logger.fatal("Error loading game type " + plugin.getJar(), ex); } return null; diff --git a/Mage.Server/src/main/java/mage/server/TableController.java b/Mage.Server/src/main/java/mage/server/TableController.java index a80f053f4e0..c47cebfb312 100644 --- a/Mage.Server/src/main/java/mage/server/TableController.java +++ b/Mage.Server/src/main/java/mage/server/TableController.java @@ -67,6 +67,7 @@ import mage.server.services.LogKeys; import mage.server.services.impl.LogServiceImpl; import mage.server.tournament.TournamentFactory; import mage.server.tournament.TournamentManager; +import mage.server.util.ConfigSettings; import mage.server.util.ServerMessagesUtil; import mage.server.util.ThreadExecutor; import org.apache.log4j.Logger; @@ -80,15 +81,16 @@ public class TableController { private static final Logger logger = Logger.getLogger(TableController.class); - private UUID userId; - private UUID chatId; - private String controllerName; - private Table table; + private final UUID userId; + private final UUID chatId; + private final String controllerName; + private final Table table; + private final ConcurrentHashMap userPlayerMap = new ConcurrentHashMap(); + private Match match; private MatchOptions options; private Tournament tournament; - private ConcurrentHashMap userPlayerMap = new ConcurrentHashMap(); - + private ScheduledFuture futureTimeout; protected static ScheduledExecutorService timeoutExecutor = ThreadExecutor.getInstance().getTimeoutExecutor(); @@ -237,10 +239,10 @@ public class TableController { } match.addPlayer(player, deck); table.joinTable(player, seat); - user.addTable(player.getId(), table); - logger.debug("player joined " + player.getId()); + logger.debug("player joined " + player.getId() + " " + player.getName()); //only inform human players and add them to sessionPlayerMap if (seat.getPlayer().isHuman()) { + user.addTable(player.getId(), table); user.joinedTable(table.getRoomId(), table.getId(), false); userPlayerMap.put(userId, player.getId()); } @@ -383,6 +385,14 @@ public class TableController { TableManager.getInstance().userQuitTournamentSubTables(userId); TournamentManager.getInstance().quit(tournament.getId(), userId); } else { + MatchPlayer matchPlayer = match.getPlayer(playerId); + if (matchPlayer != null) { + if (table.getState().equals(TableState.SIDEBOARDING)) { + // submit deck to finish sideboarding and trigger match start / end + matchPlayer.submitDeck(matchPlayer.getDeck()); + } + matchPlayer.setQuit(true); + } match.leave(playerId); } } @@ -547,30 +557,6 @@ public class TableController { } } - private void sendMatchEndInfo(UUID playerId) { - for (Entry entry: userPlayerMap.entrySet()) { - if (entry.getValue().equals(playerId)) { - User user = UserManager.getInstance().getUser(entry.getKey()); - if (user != null) { - StringBuilder sb = new StringBuilder(); - if (table.isTournamentSubTable()) { - sb.append("Your tournament match of round "); - sb.append(table.getTournament().getRounds().size()); - sb.append(" is over. "); - } else { - sb.append("Match [").append(match.getName()).append("] is over. "); - } - if(match.getPlayers().size() > 2) { - sb.append("All your opponents have lost or quit the match."); - } else { - sb.append("Your opponent has quit the match."); - } - user.showUserMessage("Match info", sb.toString()); - } - break; - } - } - } public int getRemainingTime() { return (int) futureTimeout.getDelay(TimeUnit.SECONDS); } @@ -596,10 +582,11 @@ public class TableController { UUID choosingPlayerId = match.getChooser(); match.endGame(); table.endGame(); -// Saving of games caused memory leaks - so save is deactivated -// if (!match.getGame().isSimulation()) { -// GameManager.getInstance().saveGame(match.getGame().getId()); -// } + if (ConfigSettings.getInstance().isSaveGameActivated() && !match.getGame().isSimulation()) { + if (GameManager.getInstance().saveGame(match.getGame().getId())) { + match.setReplayAvailable(true); + } + } GameManager.getInstance().removeGame(match.getGame().getId()); try { if (!match.isMatchOver()) { @@ -610,23 +597,56 @@ public class TableController { if (!match.isMatchOver()) { startGame(choosingPlayerId); } else { + this.matchEnd(); + if (!ConfigSettings.getInstance().isSaveGameActivated() || match.getGame().isSimulation()) { + match.getGames().clear(); + } table.endGame(); - // opponent(s) left during sideboarding - for (MatchPlayer mPlayer :match.getPlayers()) { - if(!mPlayer.hasQuit()) { - this.sendMatchEndInfo(mPlayer.getPlayer().getId()); - } - } } } else { - match.getGames().clear(); + // if match has only one game + this.matchEnd(); + if (!ConfigSettings.getInstance().isSaveGameActivated() || match.getGame().isSimulation()) { + match.getGames().clear(); + } + table.endGame(); } } catch (GameException ex) { logger.fatal(null, ex); } } + private void matchEnd() { + for (Entry entry: userPlayerMap.entrySet()) { + MatchPlayer matchPlayer = match.getPlayer(entry.getValue()); + // opponent(s) left during sideboarding + if(!matchPlayer.hasQuit()) { + User user = UserManager.getInstance().getUser(entry.getKey()); + if (user != null) { + if (table.getState().equals(TableState.SIDEBOARDING)) { + StringBuilder sb = new StringBuilder(); + if (table.isTournamentSubTable()) { + sb.append("Your tournament match of round "); + sb.append(table.getTournament().getRounds().size()); + sb.append(" is over. "); + } else { + sb.append("Match [").append(match.getName()).append("] is over. "); + } + if (match.getPlayers().size() > 2) { + sb.append("All your opponents have lost or quit the match."); + } else { + sb.append("Your opponent has quit the match."); + } + user.showUserMessage("Match info", sb.toString()); + } + // remove table from user - table manager holds table for display of finished matches + user.removeTable(entry.getValue()); + } + } + } + } + private synchronized void setupTimeout(int seconds) { cancelTimeout(); if (seconds > 0) { diff --git a/Mage.Server/src/main/java/mage/server/TableManager.java b/Mage.Server/src/main/java/mage/server/TableManager.java index a69ba5b3816..8dab57b9121 100644 --- a/Mage.Server/src/main/java/mage/server/TableManager.java +++ b/Mage.Server/src/main/java/mage/server/TableManager.java @@ -62,8 +62,8 @@ public class TableManager { private static final TableManager INSTANCE = new TableManager(); private static final Logger logger = Logger.getLogger(TableManager.class); - private ConcurrentHashMap controllers = new ConcurrentHashMap(); - private ConcurrentHashMap tables = new ConcurrentHashMap(); + private final ConcurrentHashMap controllers = new ConcurrentHashMap(); + private final ConcurrentHashMap tables = new ConcurrentHashMap(); /** * Defines how often checking process should be run on server. @@ -184,6 +184,7 @@ public class TableManager { public boolean removeTable(UUID userId, UUID tableId) { if (isTableOwner(tableId, userId) || UserManager.getInstance().isAdmin(userId)) { + leaveTable(userId, tableId); removeTable(tableId); return true; } @@ -192,13 +193,14 @@ public class TableManager { public void leaveTable(UUID userId, UUID tableId) { if (controllers.containsKey(tableId)) { - controllers.get(tableId).leaveTable(userId); // table not started yet and user is the owner, remove the table - if (isTableOwner(tableId, userId)) { - if (getTable(tableId).getState().equals(TableState.WAITING) - || getTable(tableId).getState().equals(TableState.STARTING)) { - removeTable(tableId); - } + if (isTableOwner(tableId, userId) + && (getTable(tableId).getState().equals(TableState.WAITING) + || getTable(tableId).getState().equals(TableState.STARTING))) { + removeTable(tableId); + + } else { + controllers.get(tableId).leaveTable(userId); } } } diff --git a/Mage.Server/src/main/java/mage/server/User.java b/Mage.Server/src/main/java/mage/server/User.java index a8a6cf0188e..f574d49cbd4 100644 --- a/Mage.Server/src/main/java/mage/server/User.java +++ b/Mage.Server/src/main/java/mage/server/User.java @@ -28,7 +28,6 @@ package mage.server; import java.util.Date; -import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -36,6 +35,7 @@ import java.util.Map.Entry; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import mage.cards.decks.Deck; +import mage.constants.TableState; import mage.game.Table; import mage.interfaces.callback.ClientCallback; import mage.players.net.UserData; @@ -324,15 +324,47 @@ public class User { } public String getGameInfo() { - StringBuilder sb = new StringBuilder(); - if (gameSessions.size() > 0) { - sb.append("G: ").append(gameSessions.size()); - } - if (tournamentSessions.size() > 0) { - if (sb.length() > 0) { - sb.append(" "); + + StringBuilder sb = new StringBuilder(); + int draft = 0, match = 0, sideboard = 0, tournament = 0, construct = 0; + for (Table table : tables.values()) { + if (table.isTournament()) { + switch (table.getState()) { + case CONSTRUCTING: + construct++; + break; + case DRAFTING: + draft++; + break; + case DUELING: + tournament++; + break; + } + } else { + switch (table.getState()) { + case SIDEBOARDING: + sideboard++; + break; + case DUELING: + match++; + break; + } } - sb.append("T: ").append(tournamentSessions.size()); + } + if (match > 0) { + sb.append("MP: ").append(match).append(" "); + } + if (sideboard > 0) { + sb.append("MS: ").append(sideboard).append(" "); + } + if (draft > 0) { + sb.append("TD: ").append(draft).append(" "); + } + if (construct > 0) { + sb.append("TC: ").append(construct).append(" "); + } + if (tournament > 0) { + sb.append("TP: ").append(tournament).append(" "); } return sb.toString(); } diff --git a/Mage.Server/src/main/java/mage/server/UserManager.java b/Mage.Server/src/main/java/mage/server/UserManager.java index f45961970d2..1ad5e55989a 100644 --- a/Mage.Server/src/main/java/mage/server/UserManager.java +++ b/Mage.Server/src/main/java/mage/server/UserManager.java @@ -64,7 +64,7 @@ public class UserManager { }, 60, 60, TimeUnit.SECONDS); } - private ConcurrentHashMap users = new ConcurrentHashMap(); + private final ConcurrentHashMap users = new ConcurrentHashMap(); public User createUser(String userName, String host) { if (findUser(userName) != null) { @@ -95,8 +95,8 @@ public class UserManager { public boolean connectToSession(String sessionId, UUID userId) { if (users.containsKey(userId)) { users.get(userId).setSessionId(sessionId); - return true; - } + return true; + } return false; } 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 6888c760fd5..2026cdee660 100644 --- a/Mage.Server/src/main/java/mage/server/game/GameController.java +++ b/Mage.Server/src/main/java/mage/server/game/GameController.java @@ -694,7 +694,7 @@ public class GameController implements GameCallback { } } - public void saveGame() { + public boolean saveGame() { try { OutputStream file = new FileOutputStream("saved/" + game.getId().toString() + ".game"); OutputStream buffer = new BufferedOutputStream(file); @@ -707,10 +707,12 @@ public class GameController implements GameCallback { output.close(); } logger.debug("Saved game:" + game.getId()); + return true; } catch(IOException ex) { logger.fatal("Cannot save game.", ex); } + return false; } /** diff --git a/Mage.Server/src/main/java/mage/server/game/GameManager.java b/Mage.Server/src/main/java/mage/server/game/GameManager.java index 1581b8d78f0..343fdc7a122 100644 --- a/Mage.Server/src/main/java/mage/server/game/GameManager.java +++ b/Mage.Server/src/main/java/mage/server/game/GameManager.java @@ -180,10 +180,11 @@ public class GameManager { gameControllers.remove(gameId); } - public void saveGame(UUID gameId) { + public boolean saveGame(UUID gameId) { if (gameControllers.containsKey(gameId)) { - gameControllers.get(gameId).saveGame(); + return gameControllers.get(gameId).saveGame(); } + return false; } public GameView getGameView(UUID gameId, UUID userId, UUID playerId) { diff --git a/Mage.Server/src/main/java/mage/server/game/GameReplay.java b/Mage.Server/src/main/java/mage/server/game/GameReplay.java index 42f4c6b0071..d6e8b961584 100644 --- a/Mage.Server/src/main/java/mage/server/game/GameReplay.java +++ b/Mage.Server/src/main/java/mage/server/game/GameReplay.java @@ -35,11 +35,15 @@ import java.io.InputStream; import java.io.ObjectInput; import java.util.UUID; import java.util.zip.GZIPInputStream; -import mage.game.*; +import mage.game.Game; +import mage.game.GameState; +import mage.game.GameStates; import mage.server.Main; import mage.util.CopierObjectInputStream; import org.apache.log4j.Logger; + + /** * * @author BetaSteward_at_googlemail.com @@ -48,8 +52,8 @@ public class GameReplay { private static final Logger logger = Logger.getLogger(GameReplay.class); - private GameStates savedGame; - private Game game; + private final GameStates savedGame; + private final Game game; private int stateIndex; public GameReplay(UUID gameId) { 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 b94bc896d2d..65677f3e3b9 100644 --- a/Mage.Server/src/main/java/mage/server/game/GameSession.java +++ b/Mage.Server/src/main/java/mage/server/game/GameSession.java @@ -57,8 +57,8 @@ import mage.view.SimpleCardsView; */ public class GameSession extends GameWatcher { - private UUID playerId; - private boolean useTimeout; + private final UUID playerId; + private final boolean useTimeout; private ScheduledFuture futureTimeout; protected static ScheduledExecutorService timeoutExecutor = ThreadExecutor.getInstance().getTimeoutExecutor(); diff --git a/Mage.Server/src/main/java/mage/server/game/GameWorker.java b/Mage.Server/src/main/java/mage/server/game/GameWorker.java index d4819e54d40..7a66ff38e16 100644 --- a/Mage.Server/src/main/java/mage/server/game/GameWorker.java +++ b/Mage.Server/src/main/java/mage/server/game/GameWorker.java @@ -33,6 +33,7 @@ import org.apache.log4j.Logger; import java.util.UUID; import java.util.concurrent.Callable; +import mage.MageException; /** * @@ -42,9 +43,9 @@ public class GameWorker implements Callable { private static final Logger logger = Logger.getLogger(GameWorker.class); - private GameCallback result; - private Game game; - private UUID choosingPlayerId; + private final GameCallback result; + private final Game game; + private final UUID choosingPlayerId; public GameWorker(Game game, UUID choosingPlayerId, GameCallback result) { this.game = game; @@ -58,7 +59,7 @@ public class GameWorker implements Callable { game.start(choosingPlayerId); game.fireUpdatePlayersEvent(); result.gameResult(game.getWinner()); - } catch (Exception ex) { + } catch (MageException ex) { logger.fatal("GameWorker error ", ex); } return null; diff --git a/Mage.Server/src/main/java/mage/server/game/ReplayManager.java b/Mage.Server/src/main/java/mage/server/game/ReplayManager.java index 82395c5f871..d1cc31393a6 100644 --- a/Mage.Server/src/main/java/mage/server/game/ReplayManager.java +++ b/Mage.Server/src/main/java/mage/server/game/ReplayManager.java @@ -45,14 +45,12 @@ public class ReplayManager { private ReplayManager() {} - private ConcurrentHashMap replaySessions = new ConcurrentHashMap(); + private final ConcurrentHashMap replaySessions = new ConcurrentHashMap(); public void replayGame(UUID gameId, UUID userId) { - if (1 == 2) { // deactivated because replay causes memor leaks - ReplaySession replaySession = new ReplaySession(gameId, userId); - replaySessions.put(gameId.toString() + userId.toString(), replaySession); - UserManager.getInstance().getUser(userId).replayGame(gameId); - } + ReplaySession replaySession = new ReplaySession(gameId, userId); + replaySessions.put(gameId.toString() + userId.toString(), replaySession); + UserManager.getInstance().getUser(userId).replayGame(gameId); } public void startReplay(UUID gameId, UUID userId) { diff --git a/Mage.Server/src/main/java/mage/server/util/Config.java b/Mage.Server/src/main/java/mage/server/util/Config.java index 8fa802365ca..153941d3fe4 100644 --- a/Mage.Server/src/main/java/mage/server/util/Config.java +++ b/Mage.Server/src/main/java/mage/server/util/Config.java @@ -51,11 +51,19 @@ public class Config { remoteServer = p.getProperty("remote-server"); maxGameThreads = Integer.parseInt(p.getProperty("max-game-threads")); maxSecondsIdle = Integer.parseInt(p.getProperty("max-seconds-idle")); + minUserNameLength = Integer.parseInt(p.getProperty("minUserNameLength")); + maxUserNameLength = Integer.parseInt(p.getProperty("maxUserNameLength")); + userNamePattern = p.getProperty("userNamePattern"); + saveGameActivated = Boolean.parseBoolean(p.getProperty("saveGameActivated")); } public static final String remoteServer; public static final int port; public static final int maxGameThreads; public static final int maxSecondsIdle; + public static final int minUserNameLength; + public static final int maxUserNameLength; + public static final String userNamePattern; + public static final boolean saveGameActivated; } diff --git a/Mage.Server/src/main/java/mage/server/util/Config.xsd b/Mage.Server/src/main/java/mage/server/util/Config.xsd index 5d855fec821..edc8f421384 100644 --- a/Mage.Server/src/main/java/mage/server/util/Config.xsd +++ b/Mage.Server/src/main/java/mage/server/util/Config.xsd @@ -24,6 +24,8 @@ + + diff --git a/Mage.Server/src/main/java/mage/server/util/ConfigSettings.java b/Mage.Server/src/main/java/mage/server/util/ConfigSettings.java index 5553eea9ecf..3b9ac6bd867 100644 --- a/Mage.Server/src/main/java/mage/server/util/ConfigSettings.java +++ b/Mage.Server/src/main/java/mage/server/util/ConfigSettings.java @@ -99,6 +99,10 @@ public class ConfigSettings { return config.getServer().getMaxAiOpponents(); } + public Boolean isSaveGameActivated() { + return config.getServer().isSaveGameActivated(); +} + public List getPlayerTypes() { return config.getPlayerTypes().getPlayerType(); } diff --git a/Mage.Server/src/main/java/mage/server/util/resources/config.xml b/Mage.Server/src/main/java/mage/server/util/resources/config.xml index 7e290a38c4a..4070ed97870 100644 --- a/Mage.Server/src/main/java/mage/server/util/resources/config.xml +++ b/Mage.Server/src/main/java/mage/server/util/resources/config.xml @@ -1,7 +1,15 @@ - + diff --git a/Mage.Server/src/main/xml-resources/jaxb/Config/Config.xsd b/Mage.Server/src/main/xml-resources/jaxb/Config/Config.xsd index 246ffd40555..106f34a1d3d 100644 --- a/Mage.Server/src/main/xml-resources/jaxb/Config/Config.xsd +++ b/Mage.Server/src/main/xml-resources/jaxb/Config/Config.xsd @@ -22,10 +22,11 @@ - - - - + + + + + diff --git a/Mage/src/mage/game/match/Match.java b/Mage/src/mage/game/match/Match.java index 5722bb983f8..d218b72addb 100644 --- a/Mage/src/mage/game/match/Match.java +++ b/Mage/src/mage/game/match/Match.java @@ -76,4 +76,11 @@ public interface Match { // match times Date getStartTime(); Date getEndTime(); + /** + * Can the games of the match be replayed + * + * @return + */ + boolean isReplayAvailable(); + void setReplayAvailable(boolean replayAvailable); } diff --git a/Mage/src/mage/game/match/MatchImpl.java b/Mage/src/mage/game/match/MatchImpl.java index 8986a5c4c59..96883328269 100644 --- a/Mage/src/mage/game/match/MatchImpl.java +++ b/Mage/src/mage/game/match/MatchImpl.java @@ -60,9 +60,12 @@ public abstract class MatchImpl implements Match { protected Date startTime; protected Date endTime; + protected boolean replayAvailable; + public MatchImpl(MatchOptions options) { this.options = options; startTime = new Date(); + replayAvailable = false; } @Override @@ -316,4 +319,12 @@ public abstract class MatchImpl implements Match { return null; } + @Override + public boolean isReplayAvailable() { + return replayAvailable; + } + + public void setReplayAvailable(boolean replayAvailable) { + this.replayAvailable = replayAvailable; + } } diff --git a/Mage/src/mage/util/functions/ApplyToPermanent.java b/Mage/src/mage/util/functions/ApplyToPermanent.java index ee814db620f..bd926f7a58f 100644 --- a/Mage/src/mage/util/functions/ApplyToPermanent.java +++ b/Mage/src/mage/util/functions/ApplyToPermanent.java @@ -1,12 +1,13 @@ package mage.util.functions; +import java.io.Serializable; import mage.game.Game; import mage.game.permanent.Permanent; /** * @author noxx */ -public abstract class ApplyToPermanent { +public abstract class ApplyToPermanent implements Serializable { public abstract Boolean apply(Game game, Permanent permanent); }