diff --git a/Mage.Client/src/main/java/mage/client/dialog/TableWaitingDialog.java b/Mage.Client/src/main/java/mage/client/dialog/TableWaitingDialog.java index 3759569a6d3..f7573ac718d 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/TableWaitingDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/TableWaitingDialog.java @@ -82,7 +82,7 @@ public class TableWaitingDialog extends MageDialog { try { if (table != null) { switch (table.getTableState()) { - case STARTING: + case READY_TO_START: this.btnStart.setEnabled(true); this.btnMoveDown.setEnabled(true); this.btnMoveUp.setEnabled(true); @@ -245,12 +245,15 @@ public class TableWaitingDialog extends MageDialog { private void btnStartActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnStartActionPerformed if (!isTournament) { - session.startMatch(roomId, tableId); + if (session.startMatch(roomId, tableId)) { + closeDialog(); + } } else { - session.startTournament(roomId, tableId); - } - closeDialog(); + if (session.startTournament(roomId, tableId)) { + closeDialog(); + } + } }//GEN-LAST:event_btnStartActionPerformed private void btnCancelActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnCancelActionPerformed @@ -258,7 +261,9 @@ public class TableWaitingDialog extends MageDialog { if (session.isTableOwner(roomId, tableId)) { session.removeTable(roomId, tableId); } else { - session.leaveTable(roomId, tableId); + if (!session.leaveTable(roomId, tableId)) { + return; // already started, so leave no more possible + } } } catch (Exception e) { //swallow exception diff --git a/Mage.Common/src/mage/interfaces/MageServer.java b/Mage.Common/src/mage/interfaces/MageServer.java index 8b0f341ccac..41ebd87139e 100644 --- a/Mage.Common/src/mage/interfaces/MageServer.java +++ b/Mage.Common/src/mage/interfaces/MageServer.java @@ -86,7 +86,7 @@ public interface MageServer { void updateDeck(String sessionId, UUID tableId, DeckCardLists deckList) throws MageException, GameException; boolean watchTable(String sessionId, UUID roomId, UUID tableId) throws MageException; boolean watchTournamentTable(String sessionId, UUID tableId) throws MageException; - void leaveTable(String sessionId, UUID roomId, UUID tableId) throws MageException; + boolean leaveTable(String sessionId, UUID roomId, UUID tableId) throws MageException; void swapSeats(String sessionId, UUID roomId, UUID tableId, int seatNum1, int seatNum2) throws MageException; void removeTable(String sessionId, UUID roomId, UUID tableId) throws MageException; boolean isTableOwner(String sessionId, UUID roomId, UUID tableId) throws MageException; @@ -106,7 +106,7 @@ public interface MageServer { UUID getMainRoomId() throws MageException; //game methods - void startMatch(String sessionId, UUID roomId, UUID tableId) throws MageException; + boolean startMatch(String sessionId, UUID roomId, UUID tableId) throws MageException; void joinGame(UUID gameId, String sessionId) throws MageException; void watchGame(UUID gameId, String sessionId) throws MageException; void stopWatching(UUID gameId, String sessionId) throws MageException; @@ -127,7 +127,7 @@ public interface MageServer { void restorePriority(UUID gameId, String sessionId) throws MageException; //tournament methods - void startTournament(String sessionId, UUID roomId, UUID tableId) throws MageException; + boolean startTournament(String sessionId, UUID roomId, UUID tableId) throws MageException; void joinTournament(UUID draftId, String sessionId) throws MageException; void quitTournament(UUID tournamentId, String sessionId) throws MageException; TournamentView getTournament(UUID tournamentId) throws MageException; diff --git a/Mage.Common/src/mage/remote/SessionImpl.java b/Mage.Common/src/mage/remote/SessionImpl.java index e26713ffc1c..a0d2d07c8c3 100644 --- a/Mage.Common/src/mage/remote/SessionImpl.java +++ b/Mage.Common/src/mage/remote/SessionImpl.java @@ -28,6 +28,20 @@ package mage.remote; +import java.net.Authenticator; +import java.net.ConnectException; +import java.net.MalformedURLException; +import java.net.PasswordAuthentication; +import java.net.SocketException; +import java.net.SocketTimeoutException; +import java.util.Collection; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.TimeUnit; import mage.MageException; import mage.cards.decks.DeckCardLists; import mage.cards.decks.InvalidDeckException; @@ -45,9 +59,22 @@ import mage.interfaces.MageServer; import mage.interfaces.ServerState; import mage.interfaces.callback.ClientCallback; import mage.utils.CompressUtil; -import mage.view.*; +import mage.view.DraftPickView; +import mage.view.GameTypeView; +import mage.view.MatchView; +import mage.view.RoomUsersView; +import mage.view.TableView; +import mage.view.TournamentTypeView; +import mage.view.TournamentView; +import mage.view.UserDataView; +import mage.view.UserView; import org.apache.log4j.Logger; -import org.jboss.remoting.*; +import org.jboss.remoting.CannotConnectException; +import org.jboss.remoting.Client; +import org.jboss.remoting.ConnectionListener; +import org.jboss.remoting.ConnectionValidator; +import org.jboss.remoting.InvokerLocator; +import org.jboss.remoting.Remoting; import org.jboss.remoting.callback.Callback; import org.jboss.remoting.callback.HandleCallbackException; import org.jboss.remoting.callback.InvokerCallbackHandler; @@ -55,11 +82,6 @@ import org.jboss.remoting.transport.bisocket.Bisocket; import org.jboss.remoting.transport.socket.SocketWrapper; import org.jboss.remoting.transporter.TransporterClient; -import java.net.*; -import java.util.*; -import java.util.concurrent.TimeUnit; - - /** * * @author BetaSteward_at_googlemail.com @@ -924,8 +946,7 @@ public class SessionImpl implements Session { @Override public boolean leaveTable(UUID roomId, UUID tableId) { try { - if (isConnected()) { - server.leaveTable(sessionId, roomId, tableId); + if (isConnected() && server.leaveTable(sessionId, roomId, tableId)) { return true; } } catch (MageException ex) { @@ -940,8 +961,7 @@ public class SessionImpl implements Session { public boolean startMatch(UUID roomId, UUID tableId) { try { if (isConnected()) { - server.startMatch(sessionId, roomId, tableId); - return true; + return (server.startMatch(sessionId, roomId, tableId)); } } catch (MageException ex) { handleMageException(ex); @@ -952,8 +972,7 @@ public class SessionImpl implements Session { @Override public boolean startTournament(UUID roomId, UUID tableId) { try { - if (isConnected()) { - server.startTournament(sessionId, roomId, tableId); + if (isConnected() && server.startTournament(sessionId, roomId, tableId)) { return true; } } catch (MageException ex) { diff --git a/Mage.Common/src/mage/view/TableView.java b/Mage.Common/src/mage/view/TableView.java index 5ba39a3ed44..5253b3d5b4d 100644 --- a/Mage.Common/src/mage/view/TableView.java +++ b/Mage.Common/src/mage/view/TableView.java @@ -125,6 +125,7 @@ public class TableView implements Serializable { StringBuilder sb = new StringBuilder("Seats: ").append(table.getTournament().getPlayers().size()).append("/").append(table.getNumberOfSeats()); switch (table.getState()) { case WAITING: + case READY_TO_START: case STARTING: sb.append(" Constr. Time: ").append(table.getTournament().getOptions().getLimitedOptions().getConstructionTime()/60).append(" Min."); break; diff --git a/Mage.Server/src/main/java/mage/server/MageServerImpl.java b/Mage.Server/src/main/java/mage/server/MageServerImpl.java index c12f018af16..8e5fc15cdb6 100644 --- a/Mage.Server/src/main/java/mage/server/MageServerImpl.java +++ b/Mage.Server/src/main/java/mage/server/MageServerImpl.java @@ -66,6 +66,7 @@ import java.util.Locale; import java.util.UUID; import java.util.concurrent.ExecutorService; import mage.constants.ManaType; +import mage.constants.TableState; /** * @@ -346,7 +347,10 @@ public class MageServerImpl implements MageServer { // } @Override - public void startMatch(final String sessionId, final UUID roomId, final UUID tableId) throws MageException { + public boolean startMatch(final String sessionId, final UUID roomId, final UUID tableId) throws MageException { + if (!TableManager.getInstance().getController(tableId).changeTableState(TableState.STARTING)) { + return false; + } execute("startMatch", sessionId, new Action() { @Override public void execute() { @@ -354,6 +358,7 @@ public class MageServerImpl implements MageServer { TableManager.getInstance().startMatch(userId, roomId, tableId); } }); + return true; } // @Override @@ -368,7 +373,10 @@ public class MageServerImpl implements MageServer { // } @Override - public void startTournament(final String sessionId, final UUID roomId, final UUID tableId) throws MageException { + public boolean startTournament(final String sessionId, final UUID roomId, final UUID tableId) throws MageException { + if (!TableManager.getInstance().getController(tableId).changeTableState(TableState.STARTING)) { + return false; + } execute("startTournament", sessionId, new Action() { @Override public void execute() { @@ -376,6 +384,7 @@ public class MageServerImpl implements MageServer { TableManager.getInstance().startTournament(userId, roomId, tableId); } }); + return true; } @Override @@ -477,7 +486,12 @@ public class MageServerImpl implements MageServer { } @Override - public void leaveTable(final String sessionId, final UUID roomId, final UUID tableId) throws MageException { + public boolean leaveTable(final String sessionId, final UUID roomId, final UUID tableId) throws MageException { + TableState tableState = TableManager.getInstance().getController(tableId).getTableState(); + if (!tableState.equals(TableState.WAITING) && !tableState.equals(TableState.READY_TO_START)) { + // table was already started, so player can't leave anymore now + return false; + } execute("leaveTable", sessionId, new Action() { @Override public void execute() { @@ -485,6 +499,7 @@ public class MageServerImpl implements MageServer { GamesRoomManager.getInstance().getRoom(roomId).leaveTable(userId, tableId); } }); + return true; } @Override diff --git a/Mage.Server/src/main/java/mage/server/TableController.java b/Mage.Server/src/main/java/mage/server/TableController.java index 1303a4d6a12..11c6da05503 100644 --- a/Mage.Server/src/main/java/mage/server/TableController.java +++ b/Mage.Server/src/main/java/mage/server/TableController.java @@ -28,12 +28,20 @@ package mage.server; +import java.util.Map; +import java.util.Map.Entry; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; import mage.MageException; import mage.cards.decks.Deck; import mage.cards.decks.DeckCardLists; import mage.cards.decks.InvalidDeckException; import mage.constants.RangeOfInfluence; import mage.constants.TableState; +import mage.game.Game; import mage.game.GameException; import mage.game.Seat; import mage.game.Table; @@ -41,6 +49,7 @@ import mage.game.draft.Draft; import mage.game.draft.DraftPlayer; import mage.game.events.Listener; import mage.game.events.TableEvent; +import static mage.game.events.TableEvent.EventType.SIDEBOARD; import mage.game.match.Match; import mage.game.match.MatchOptions; import mage.game.match.MatchPlayer; @@ -60,18 +69,8 @@ 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; - -import java.util.Map; -import java.util.Map.Entry; -import java.util.UUID; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.TimeUnit; -import mage.game.Game; import mage.view.ChatMessage; - +import org.apache.log4j.Logger; /** * @@ -377,45 +376,52 @@ public class TableController { logger.error("No tournament object - userId: " + userId + " table: " + table.getId()); return; } - UUID playerId = userPlayerMap.get(userId); - if (playerId != null) { - if (table.getState() == TableState.WAITING || table.getState() == TableState.STARTING) { - table.leaveNotStartedTable(playerId); - if (table.isTournament()) { - tournament.removePlayer(playerId); - } else { - match.leave(playerId); - } - User user = UserManager.getInstance().getUser(userId); - if (user != null) { - ChatManager.getInstance().broadcast(chatId, user.getName(), "has left the table", ChatMessage.MessageColor.BLUE, true, ChatMessage.MessageType.STATUS, ChatMessage.SoundToPlay.PlayerLeft); - user.removeTable(playerId); - } else { - logger.debug("User not found - userId: " + userId + " tableId:" + table.getId()); - } - userPlayerMap.remove(userId); - } else if (!table.getState().equals(TableState.FINISHED)) { - if (table.isTournament()) { - logger.debug("Quit tournament sub tables for userId: " + userId); - TableManager.getInstance().userQuitTournamentSubTables(userId); - logger.debug("Quit tournament Id: " + table.getTournament().getId()); - 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); - } - } + if (table != null + && this.userId.equals(userId) + && (table.getState().equals(TableState.WAITING) + || table.getState().equals(TableState.READY_TO_START))) { + // table not started yet and user is the owner, remove the table + TableManager.getInstance().removeTable(table.getId()); } else { - logger.error("No playerId found for userId: " + userId); + UUID playerId = userPlayerMap.get(userId); + if (playerId != null) { + if (table.getState() == TableState.WAITING || table.getState() == TableState.READY_TO_START) { + table.leaveNotStartedTable(playerId); + if (table.isTournament()) { + tournament.removePlayer(playerId); + } else { + match.leave(playerId); + } + User user = UserManager.getInstance().getUser(userId); + if (user != null) { + ChatManager.getInstance().broadcast(chatId, user.getName(), "has left the table", ChatMessage.MessageColor.BLUE, true, ChatMessage.MessageType.STATUS, ChatMessage.SoundToPlay.PlayerLeft); + user.removeTable(playerId); + } else { + logger.debug("User not found - userId: " + userId + " tableId:" + table.getId()); + } + userPlayerMap.remove(userId); + } else if (!table.getState().equals(TableState.FINISHED)) { + if (table.isTournament()) { + logger.debug("Quit tournament sub tables for userId: " + userId); + TableManager.getInstance().userQuitTournamentSubTables(userId); + logger.debug("Quit tournament Id: " + table.getTournament().getId()); + 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); + } + } + } else { + logger.error("No playerId found for userId: " + userId); + } } - } @@ -463,7 +469,7 @@ public class TableController { } public synchronized void startMatch() { - if (table.getState() == TableState.STARTING) { + if (table.getState().equals(TableState.STARTING)) { try { if (table.isTournamentSubTable()) { logger.info("Tourn. match started id:" + match.getId() + " tournId: " + table.getTournament().getId()); @@ -556,8 +562,8 @@ public class TableController { } public synchronized void startTournament(UUID userId) { - try { - if (userId.equals(this.userId) && table.getState() == TableState.STARTING) { + try { + if (userId.equals(this.userId) && table.getState().equals(TableState.STARTING)) { TournamentManager.getInstance().createTournamentSession(tournament, userPlayerMap, table.getId()); for (Entry entry: userPlayerMap.entrySet()) { User user = UserManager.getInstance().getUser(entry.getKey()); @@ -745,7 +751,7 @@ public class TableController { } public void swapSeats(int seatNum1, int seatNum2) { - if (table.getState() == TableState.STARTING) { + if (table.getState().equals(TableState.READY_TO_START)) { if (seatNum1 >= 0 && seatNum2 >= 0 && seatNum1 < table.getSeats().length && seatNum2 < table.getSeats().length) { Player swapPlayer = table.getSeats()[seatNum1].getPlayer(); String swapType = table.getSeats()[seatNum1].getPlayerType(); @@ -790,7 +796,7 @@ public class TableController { humanPlayers++; if (!matchPlayer.hasQuit()) { User user = UserManager.getInstance().getUser(userPlayerEntry.getKey()); - if (user != null) { + if (user != null && user.isExpired(null)) { validHumanPlayers++; } } @@ -805,4 +811,27 @@ public class TableController { void cleanUp() { ChatManager.getInstance().destroyChatSession(chatId); } + + public synchronized TableState getTableState() { + return getTable().getState(); + } + + public synchronized boolean changeTableState(TableState newTableState) { + switch (newTableState) { + case WAITING: + if (getTable().getState().equals(TableState.STARTING)){ + // tournament already started + return false; + } + break; + case STARTING: + if (!getTable().getState().equals(TableState.READY_TO_START)){ + // tournament is not ready, can't start + return false; + } + break; + } + getTable().setState(newTableState); + return true; + } } diff --git a/Mage.Server/src/main/java/mage/server/TableManager.java b/Mage.Server/src/main/java/mage/server/TableManager.java index 095e93d66d1..5fcc7a7f5e8 100644 --- a/Mage.Server/src/main/java/mage/server/TableManager.java +++ b/Mage.Server/src/main/java/mage/server/TableManager.java @@ -223,18 +223,7 @@ public class TableManager { public void leaveTable(UUID userId, UUID tableId) { TableController tableController = controllers.get(tableId); if (tableController != null) { - // table not started yet and user is the owner, remove the table - Table table = getTable(tableId); - if (table != null - && isTableOwner(tableId, userId) - && (table.getState().equals(TableState.WAITING) - || table.getState().equals(TableState.STARTING))) { - removeTable(tableId); - - } else { - logger.debug("TABLE leave - userId: " + userId + " tableId: " + tableId); - tableController.leaveTable(userId); - } + tableController.leaveTable(userId); } } @@ -275,9 +264,9 @@ public class TableManager { public void startTournament(UUID userId, UUID roomId, UUID tableId) { if (controllers.containsKey(tableId)) { controllers.get(tableId).startTournament(userId); - ChatManager.getInstance().destroyChatSession(controllers.get(tableId).getChatId()); + ChatManager.getInstance().destroyChatSession(controllers.get(tableId).getChatId()); + } } - } public void startDraft(UUID tableId, Draft draft) { if (controllers.containsKey(tableId)) { diff --git a/Mage.Server/src/main/java/mage/server/game/GamesRoomImpl.java b/Mage.Server/src/main/java/mage/server/game/GamesRoomImpl.java index 40651484ab6..9c8de496d1a 100644 --- a/Mage.Server/src/main/java/mage/server/game/GamesRoomImpl.java +++ b/Mage.Server/src/main/java/mage/server/game/GamesRoomImpl.java @@ -219,15 +219,15 @@ class TableListSorter implements Comparator { @Override public int compare(Table one, Table two) { // priority 1 - Not started yet - if (one.getState().equals(TableState.STARTING) || one.getState().equals(TableState.WAITING)) { - if (two.getState().equals(TableState.STARTING) || two.getState().equals(TableState.WAITING)) { + if (one.getState().equals(TableState.READY_TO_START) || one.getState().equals(TableState.WAITING)) { + if (two.getState().equals(TableState.READY_TO_START) || two.getState().equals(TableState.WAITING)) { return two.getCreateTime().compareTo(one.getCreateTime()); } else { return -1; // one has higher priority } } // priority 2 - Not finished yet -> Sorted by time started - if (two.getState().equals(TableState.STARTING) || two.getState().equals(TableState.WAITING)) { + if (two.getState().equals(TableState.READY_TO_START) || two.getState().equals(TableState.WAITING)) { return 1; // two has higher priority } else if (one.getEndTime() == null) { if (two.getEndTime() == null) { diff --git a/Mage/src/mage/constants/TableState.java b/Mage/src/mage/constants/TableState.java index 2c0e45bb5e7..e400dbf79c2 100644 --- a/Mage/src/mage/constants/TableState.java +++ b/Mage/src/mage/constants/TableState.java @@ -6,7 +6,8 @@ package mage.constants; */ public enum TableState { WAITING ("Waiting for players"), - STARTING ("Waiting to start"), + READY_TO_START("Waiting to start"), + STARTING ("Starting"), DRAFTING ("Drafting"), DUELING ("Dueling"), SIDEBOARDING ("Sideboarding"), diff --git a/Mage/src/mage/game/Table.java b/Mage/src/mage/game/Table.java index 4aa4490122f..db9e74d98e7 100644 --- a/Mage/src/mage/game/Table.java +++ b/Mage/src/mage/game/Table.java @@ -172,7 +172,7 @@ public class Table implements Serializable { } seat.setPlayer(player); if (isReady()) { - setState(TableState.STARTING); + setState(TableState.READY_TO_START); } return seat.getPlayer().getId(); } @@ -208,7 +208,7 @@ public class Table implements Serializable { Player player = seats[i].getPlayer(); if (player != null && player.getId().equals(playerId)) { seats[i].setPlayer(null); - if (getState().equals(TableState.STARTING)) { + if (getState().equals(TableState.READY_TO_START)) { setState(TableState.WAITING); } break; @@ -216,14 +216,14 @@ public class Table implements Serializable { } } - final public void setState(TableState state) { + final public synchronized void setState(TableState state) { this.state = state; if (isTournament()) { getTournament().setTournamentState(state.toString()); } } - public TableState getState() { + public synchronized TableState getState() { return state; }