diff --git a/Mage.Client/src/main/java/mage/client/MageFrame.java b/Mage.Client/src/main/java/mage/client/MageFrame.java index 6cc05373d1f..4dfce042653 100644 --- a/Mage.Client/src/main/java/mage/client/MageFrame.java +++ b/Mage.Client/src/main/java/mage/client/MageFrame.java @@ -788,7 +788,7 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { if (connect(connection)) { return true; } else { - showMessage("Unable to connect to server"); + showMessage("Error Connecting", "Unable to connect to server"); } } finally { setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); @@ -974,7 +974,7 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { client.disconnect(false); tablesPane.clearChat(); setWindowTitle(); - showMessage("You have disconnected"); + showMessage("Disconnected", "You have disconnected"); } } else { connectDialog.showDialog(); @@ -1357,27 +1357,27 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { // } } - public void showMessage(final String message) { + public void showMessage(final String title, final String message) { if (SwingUtilities.isEventDispatchThread()) { - JOptionPane.showMessageDialog(desktopPane, message); + JOptionPane.showMessageDialog(desktopPane, message, title, JOptionPane.INFORMATION_MESSAGE); } else { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { - JOptionPane.showMessageDialog(desktopPane, message); + JOptionPane.showMessageDialog(desktopPane, message, title, JOptionPane.INFORMATION_MESSAGE); } }); } } - public void showError(final String message) { + public void showError(final String title, final String message) { if (SwingUtilities.isEventDispatchThread()) { - JOptionPane.showMessageDialog(desktopPane, message, "Error", JOptionPane.ERROR_MESSAGE); + JOptionPane.showMessageDialog(desktopPane, message, title, JOptionPane.ERROR_MESSAGE); } else { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { - JOptionPane.showMessageDialog(desktopPane, message, "Error", JOptionPane.ERROR_MESSAGE); + JOptionPane.showMessageDialog(desktopPane, message, title, JOptionPane.ERROR_MESSAGE); } }); } @@ -1389,12 +1389,12 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { // } @Override - public void inform(String message, MessageType type) { + public void inform(String title, String message, MessageType type) { if (type == MessageType.ERROR) { - showError(message); + showError(title, message); } else { - showMessage(message); + showMessage(title, message); } } diff --git a/Mage.Client/src/main/java/mage/client/remote/CallbackClientImpl.java b/Mage.Client/src/main/java/mage/client/remote/CallbackClientImpl.java index f706deffd71..1d9b47b7d18 100644 --- a/Mage.Client/src/main/java/mage/client/remote/CallbackClientImpl.java +++ b/Mage.Client/src/main/java/mage/client/remote/CallbackClientImpl.java @@ -507,6 +507,6 @@ public class CallbackClientImpl implements CallbackClient { private void handleException(Exception ex) { logger.fatal("Client error\n", ex); - frame.showError("Error: " + ex.getMessage()); +// frame.showError("Error: " + ex.getMessage()); } } diff --git a/Mage.Client/src/test/java/mage/client/game/MultiConnectTest.java b/Mage.Client/src/test/java/mage/client/game/MultiConnectTest.java index 99d7764055e..a8d5c4bb88b 100644 --- a/Mage.Client/src/test/java/mage/client/game/MultiConnectTest.java +++ b/Mage.Client/src/test/java/mage/client/game/MultiConnectTest.java @@ -94,7 +94,7 @@ public class MultiConnectTest { // } @Override - public void inform(String message, MessageType type) { + public void inform(String title, String message, MessageType type) { if (type == MessageType.ERROR) { showError(message); } diff --git a/Mage.Common/src/mage/interfaces/ServerState.java b/Mage.Common/src/mage/interfaces/ServerState.java index abf7fc00677..53c36f15b8b 100644 --- a/Mage.Common/src/mage/interfaces/ServerState.java +++ b/Mage.Common/src/mage/interfaces/ServerState.java @@ -42,6 +42,7 @@ import mage.view.TournamentTypeView; */ public class ServerState implements Serializable { + private final boolean valid; private final List gameTypes; private final List tournamentTypes; private final String[] playerTypes; @@ -57,6 +58,7 @@ public class ServerState implements Serializable { String[] playerTypes, String[] deckTypes, String[] draftCubes, boolean testMode, MageVersion version, long cardsContentVersion, long expansionsContentVersion, UUID mainRoomId) { + this.valid = true; this.gameTypes = gameTypes; this.tournamentTypes = tournamentTypes; this.playerTypes = playerTypes; @@ -69,6 +71,24 @@ public class ServerState implements Serializable { this.mainRoomId = mainRoomId; } + public ServerState() { + this.valid = false; + this.gameTypes = new ArrayList<>(); + this.tournamentTypes = new ArrayList<>();; + this.playerTypes = new String[1]; + this.deckTypes = new String[1]; + this.draftCubes = new String[1]; + this.testMode = false; + this.version = new MageVersion(0,0,0,"",""); + this.cardsContentVersion = 0; + this.expansionsContentVersion = 0; + this.mainRoomId = UUID.randomUUID(); + } + + public boolean isValid() { + return valid; + } + public List getGameTypes() { return gameTypes; } diff --git a/Mage.Common/src/mage/remote/DisconnectReason.java b/Mage.Common/src/mage/remote/DisconnectReason.java index be854c87ac7..585c0e9c411 100644 --- a/Mage.Common/src/mage/remote/DisconnectReason.java +++ b/Mage.Common/src/mage/remote/DisconnectReason.java @@ -6,5 +6,5 @@ package mage.remote; */ public enum DisconnectReason { - LostConnection, Disconnected, CleaningUp, ConnectingOtherInstance, AdminDisconnect, SessionExpired, Undefined; + LostConnection, Disconnected, CleaningUp, ConnectingOtherInstance, AdminDisconnect, SessionExpired, ValidationError, Undefined; } diff --git a/Mage.Network/src/main/java/org/mage/network/Client.java b/Mage.Network/src/main/java/org/mage/network/Client.java index 22bd57c9f5f..6608e342276 100644 --- a/Mage.Network/src/main/java/org/mage/network/Client.java +++ b/Mage.Network/src/main/java/org/mage/network/Client.java @@ -34,6 +34,7 @@ import mage.view.TableView; import mage.view.TournamentView; import mage.view.UserView; import org.apache.log4j.Logger; +import org.mage.network.handlers.ExceptionHandler; import org.mage.network.handlers.client.HeartbeatHandler; import org.mage.network.handlers.PingMessageHandler; import org.mage.network.handlers.client.ChatMessageHandler; @@ -41,8 +42,10 @@ import org.mage.network.handlers.client.ChatRoomHandler; import org.mage.network.handlers.client.ClientRegisteredMessageHandler; import org.mage.network.handlers.client.ConnectionHandler; import org.mage.network.handlers.client.InformClientMessageHandler; +import org.mage.network.handlers.client.JoinTableMessageHandler; import org.mage.network.handlers.client.ServerMessageHandler; import org.mage.network.handlers.client.RoomMessageHandler; +import org.mage.network.handlers.client.TableMessageHandler; import org.mage.network.interfaces.MageClient; import org.mage.network.model.MessageType; @@ -66,6 +69,10 @@ public class Client { private final ClientRegisteredMessageHandler clientRegisteredMessageHandler; private final ServerMessageHandler serverMessageHandler; private final RoomMessageHandler roomMessageHandler; + private final TableMessageHandler tableMessageHandler; + private final JoinTableMessageHandler joinTableMessageHandler; + + private final ExceptionHandler exceptionHandler; private SslContext sslCtx; private Channel channel; @@ -81,9 +88,13 @@ public class Client { chatRoomHandler = new ChatRoomHandler(); chatMessageHandler = new ChatMessageHandler(client); informClientMessageHandler = new InformClientMessageHandler(client); - clientRegisteredMessageHandler = new ClientRegisteredMessageHandler(client); + clientRegisteredMessageHandler = new ClientRegisteredMessageHandler(); serverMessageHandler = new ServerMessageHandler(); roomMessageHandler = new RoomMessageHandler(); + tableMessageHandler = new TableMessageHandler(); + joinTableMessageHandler = new JoinTableMessageHandler(); + + exceptionHandler = new ExceptionHandler(); } public boolean connect(String userName, String host, int port, boolean ssl, MageVersion version) { @@ -107,17 +118,23 @@ public class Client { clientRegisteredMessageHandler.setUserName(userName); clientRegisteredMessageHandler.setVersion(version); channel = b.connect(host, port).sync().channel(); - clientRegisteredMessageHandler.registerClient(); - client.connected(userName + "@" + host + ":" + port + " "); - return true; + ServerState state = clientRegisteredMessageHandler.registerClient(); + if (state.isValid()) { + client.clientRegistered(state); + client.connected(userName + "@" + host + ":" + port + " "); + return true; + } + else { + disconnect(false); + } } catch (SSLException | InterruptedException ex) { logger.fatal("Error connecting", ex); - client.inform("Error connecting", MessageType.ERROR); - group.shutdownGracefully(); + client.inform("Error", "Error connecting", MessageType.ERROR); + disconnect(false); } return false; } - + private class ClientInitializer extends ChannelInitializer { @Override @@ -140,8 +157,11 @@ public class Client { ch.pipeline().addLast("clientRegisteredMessageHandler", clientRegisteredMessageHandler); ch.pipeline().addLast("chatRoomHandler", chatRoomHandler); ch.pipeline().addLast("serverMessageHandler", serverMessageHandler); - ch.pipeline().addLast("tablesMessageHandler", roomMessageHandler); + ch.pipeline().addLast("roomMessageHandler", roomMessageHandler); + ch.pipeline().addLast("tableMessageHandler", tableMessageHandler); + ch.pipeline().addLast("joinTableMessageHandler", joinTableMessageHandler); + ch.pipeline().addLast("exceptionHandler", exceptionHandler); } } @@ -207,12 +227,22 @@ public class Client { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } - public boolean joinTable(UUID roomId, UUID tableId, String playerName, String human, int i, DeckCardLists importDeck, String text) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + public boolean joinTable(UUID roomId, UUID tableId, String playerName, String playerType, int skill, DeckCardLists deck, String password) { + try { + return joinTableMessageHandler.joinTable(roomId, tableId, playerName, playerType, skill, deck, password); + } catch (Exception ex) { + logger.error("Error creating table", ex); + } + return false; } public TableView createTable(UUID roomId, MatchOptions options) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + try { + return tableMessageHandler.createTable(roomId, options); + } catch (Exception ex) { + logger.error("Error creating table", ex); + } + return null; } public void removeTable(UUID roomId, UUID tableId) { diff --git a/Mage.Network/src/main/java/org/mage/network/Server.java b/Mage.Network/src/main/java/org/mage/network/Server.java index aff1012fba5..689e4f89dcc 100644 --- a/Mage.Network/src/main/java/org/mage/network/Server.java +++ b/Mage.Network/src/main/java/org/mage/network/Server.java @@ -23,16 +23,19 @@ import io.netty.util.concurrent.GlobalEventExecutor; import java.util.UUID; import mage.view.ChatMessage; import org.apache.log4j.Logger; +import org.mage.network.handlers.ExceptionHandler; import org.mage.network.handlers.server.HeartbeatHandler; import org.mage.network.handlers.PingMessageHandler; import org.mage.network.handlers.server.ChatMessageHandler; import org.mage.network.handlers.server.ChatRoomIdHandler; import org.mage.network.handlers.server.ConnectionHandler; import org.mage.network.handlers.server.JoinChatMessageHandler; +import org.mage.network.handlers.server.JoinTableMessageHandler; import org.mage.network.handlers.server.LeaveChatMessageHandler; import org.mage.network.handlers.server.RegisterClientMessageHandler; import org.mage.network.handlers.server.RoomMessageHandler; import org.mage.network.handlers.server.ServerMessageHandler; +import org.mage.network.handlers.server.TableMessageHandler; import org.mage.network.interfaces.MageServer; import org.mage.network.model.InformClientMessage; import org.mage.network.model.MessageType; @@ -66,6 +69,10 @@ public class Server { private final LeaveChatMessageHandler leaveChatMessageHandler; private final ServerMessageHandler serverMessageHandler; private final RoomMessageHandler roomMessageHandler; + private final TableMessageHandler tableMessageHandler; + private final JoinTableMessageHandler joinTableMessageHandler; + + private final ExceptionHandler exceptionHandler; public Server(MageServer server) { this.server = server; @@ -76,6 +83,10 @@ public class Server { chatRoomIdHandler = new ChatRoomIdHandler(server); serverMessageHandler = new ServerMessageHandler(server); roomMessageHandler = new RoomMessageHandler(server); + tableMessageHandler = new TableMessageHandler(server); + joinTableMessageHandler = new JoinTableMessageHandler(server); + + exceptionHandler = new ExceptionHandler(); } public void start(int port, boolean ssl) throws Exception { @@ -131,6 +142,10 @@ public class Server { ch.pipeline().addLast(handlersExecutor, "leaveChatMessageHandler", leaveChatMessageHandler); ch.pipeline().addLast(handlersExecutor, "serverMessageHandler", serverMessageHandler); ch.pipeline().addLast(handlersExecutor, "roomMessageHandler", roomMessageHandler); + ch.pipeline().addLast(handlersExecutor, "tableMessageHandler", tableMessageHandler); + ch.pipeline().addLast(handlersExecutor, "joinTableMessageHandler", joinTableMessageHandler); + + ch.pipeline().addLast("exceptionHandler", exceptionHandler); } } @@ -150,14 +165,14 @@ public class Server { ch.writeAndFlush(new ReceiveChatMessage(chatId, message)); } - public void informClient(String sessionId, String message, MessageType type) { + public void informClient(String sessionId, String title, String message, MessageType type) { Channel ch = findChannel(sessionId); if (ch != null) - ch.writeAndFlush(new InformClientMessage(message, type)); + ch.writeAndFlush(new InformClientMessage(title, message, type)); } - public void informClients(String message, MessageType type) { - clients.writeAndFlush(new InformClientMessage(message, type)); + public void informClients(String title, String message, MessageType type) { + clients.writeAndFlush(new InformClientMessage(title, message, type)); } public void pingClient(String sessionId) { diff --git a/Mage.Network/src/main/java/org/mage/network/handlers/ExceptionHandler.java b/Mage.Network/src/main/java/org/mage/network/handlers/ExceptionHandler.java new file mode 100644 index 00000000000..18c47b77bd2 --- /dev/null +++ b/Mage.Network/src/main/java/org/mage/network/handlers/ExceptionHandler.java @@ -0,0 +1,23 @@ +package org.mage.network.handlers; + +import io.netty.channel.ChannelHandler.Sharable; +import io.netty.channel.ChannelHandlerAdapter; +import io.netty.channel.ChannelHandlerContext; +import org.apache.log4j.Logger; + +/** + * + * @author BetaSteward + */ +@Sharable +public class ExceptionHandler extends ChannelHandlerAdapter { + + private static final Logger logger = Logger.getLogger(ExceptionHandler.class); + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { + logger.error("Communications error", cause); + ctx.close(); + } + +} diff --git a/Mage.Network/src/main/java/org/mage/network/handlers/client/ClientRegisteredMessageHandler.java b/Mage.Network/src/main/java/org/mage/network/handlers/client/ClientRegisteredMessageHandler.java index dcb4b287bd8..d97d74f4a46 100644 --- a/Mage.Network/src/main/java/org/mage/network/handlers/client/ClientRegisteredMessageHandler.java +++ b/Mage.Network/src/main/java/org/mage/network/handlers/client/ClientRegisteredMessageHandler.java @@ -17,19 +17,14 @@ import org.mage.network.model.RegisterClientMessage; */ public class ClientRegisteredMessageHandler extends SimpleChannelInboundHandler { - private final MageClient client; +// private final MageClient client; // private ChannelHandlerContext ctx; private final BlockingQueue queue = new LinkedBlockingQueue<>(); private String userName; private MageVersion version; - - public ClientRegisteredMessageHandler (MageClient client) { - this.client = client; - } @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { -// this.ctx = ctx; ctx.writeAndFlush(new RegisterClientMessage(userName, version)); super.channelActive(ctx); } @@ -47,8 +42,8 @@ public class ClientRegisteredMessageHandler extends SimpleChannelInboundHandler< this.version = version; } - public void registerClient() throws InterruptedException { - client.clientRegistered(queue.take()); + public ServerState registerClient() throws InterruptedException { + return queue.take(); } } diff --git a/Mage.Network/src/main/java/org/mage/network/handlers/client/ConnectionHandler.java b/Mage.Network/src/main/java/org/mage/network/handlers/client/ConnectionHandler.java index d88ce5086a8..4dca7e95753 100644 --- a/Mage.Network/src/main/java/org/mage/network/handlers/client/ConnectionHandler.java +++ b/Mage.Network/src/main/java/org/mage/network/handlers/client/ConnectionHandler.java @@ -4,7 +4,6 @@ import io.netty.channel.ChannelHandlerAdapter; import io.netty.channel.ChannelHandlerContext; import org.apache.log4j.Logger; import org.mage.network.interfaces.MageClient; -import org.mage.network.model.MessageType; /** * diff --git a/Mage.Network/src/main/java/org/mage/network/handlers/client/InformClientMessageHandler.java b/Mage.Network/src/main/java/org/mage/network/handlers/client/InformClientMessageHandler.java index 8d0aaf26539..03e8523307a 100644 --- a/Mage.Network/src/main/java/org/mage/network/handlers/client/InformClientMessageHandler.java +++ b/Mage.Network/src/main/java/org/mage/network/handlers/client/InformClientMessageHandler.java @@ -19,7 +19,7 @@ public class InformClientMessageHandler extends SimpleChannelInboundHandler { + + private ChannelHandlerContext ctx; + private final BlockingQueue queue = new LinkedBlockingQueue<>(); + + @Override + public void channelActive(ChannelHandlerContext ctx) throws Exception { + this.ctx = ctx; + super.channelActive(ctx); + } + + @Override + protected void messageReceived(ChannelHandlerContext ctx, JoinTableMessage msg) throws Exception { + queue.offer(msg.getSuccess()); + } + + public boolean joinTable(UUID roomId, UUID tableId, String name, String playerType, int skill, DeckCardLists deckList, String password) throws Exception { + ctx.writeAndFlush(new JoinTableRequest(roomId, tableId, name, playerType, skill, deckList, password)); + return queue.take(); + } + +} diff --git a/Mage.Network/src/main/java/org/mage/network/handlers/client/TableMessageHandler.java b/Mage.Network/src/main/java/org/mage/network/handlers/client/TableMessageHandler.java new file mode 100644 index 00000000000..8645bb54eff --- /dev/null +++ b/Mage.Network/src/main/java/org/mage/network/handlers/client/TableMessageHandler.java @@ -0,0 +1,39 @@ +package org.mage.network.handlers.client; + +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.SimpleChannelInboundHandler; +import java.util.UUID; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; +import mage.game.match.MatchOptions; +import mage.view.TableView; +import org.mage.network.model.CreateTableMessage; +import org.mage.network.model.CreateTableRequest; + + +/** + * + * @author BetaSteward + */ +public class TableMessageHandler extends SimpleChannelInboundHandler { + + private ChannelHandlerContext ctx; + private final BlockingQueue queue = new LinkedBlockingQueue<>(); + + @Override + public void channelActive(ChannelHandlerContext ctx) throws Exception { + this.ctx = ctx; + super.channelActive(ctx); + } + + @Override + protected void messageReceived(ChannelHandlerContext ctx, CreateTableMessage msg) throws Exception { + queue.offer(msg.getTable()); + } + + public TableView createTable(UUID roomId, MatchOptions options) throws Exception { + ctx.writeAndFlush(new CreateTableRequest(roomId, options)); + return queue.take(); + } + +} diff --git a/Mage.Network/src/main/java/org/mage/network/handlers/server/JoinTableMessageHandler.java b/Mage.Network/src/main/java/org/mage/network/handlers/server/JoinTableMessageHandler.java new file mode 100644 index 00000000000..e7ddae8e944 --- /dev/null +++ b/Mage.Network/src/main/java/org/mage/network/handlers/server/JoinTableMessageHandler.java @@ -0,0 +1,28 @@ +package org.mage.network.handlers.server; + +import io.netty.channel.ChannelHandler.Sharable; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.SimpleChannelInboundHandler; +import org.mage.network.interfaces.MageServer; +import org.mage.network.model.JoinTableMessage; +import org.mage.network.model.JoinTableRequest; + +/** + * + * @author BetaSteward + */ +@Sharable +public class JoinTableMessageHandler extends SimpleChannelInboundHandler { + + private final MageServer server; + + public JoinTableMessageHandler (MageServer server) { + this.server = server; + } + + @Override + public void messageReceived(ChannelHandlerContext ctx, JoinTableRequest msg) { + ctx.writeAndFlush(new JoinTableMessage(server.joinTable(ctx.channel().id().asLongText(), msg.getRoomId(), msg.gettableId(), msg.getName(), msg.getPlayerType(), msg.getSkill(), msg.getDeckCardLists(), msg.getPassword()))); + } + +} diff --git a/Mage.Network/src/main/java/org/mage/network/handlers/server/RegisterClientMessageHandler.java b/Mage.Network/src/main/java/org/mage/network/handlers/server/RegisterClientMessageHandler.java index 1bcfc442588..94fe28c6c23 100644 --- a/Mage.Network/src/main/java/org/mage/network/handlers/server/RegisterClientMessageHandler.java +++ b/Mage.Network/src/main/java/org/mage/network/handlers/server/RegisterClientMessageHandler.java @@ -3,6 +3,8 @@ package org.mage.network.handlers.server; import io.netty.channel.ChannelHandler.Sharable; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; +import java.net.InetSocketAddress; +import mage.interfaces.ServerState; import mage.remote.DisconnectReason; import org.mage.network.interfaces.MageServer; import org.mage.network.model.RegisterClientMessage; @@ -23,11 +25,14 @@ public class RegisterClientMessageHandler extends SimpleChannelInboundHandler { + + private final MageServer server; + + public TableMessageHandler (MageServer server) { + this.server = server; + } + + @Override + public void messageReceived(ChannelHandlerContext ctx, CreateTableRequest msg) { + ctx.writeAndFlush(new CreateTableMessage(server.createTable(ctx.channel().id().asLongText(), msg.getRoomId(), msg.getMatchOptions()))); + } + +} diff --git a/Mage.Network/src/main/java/org/mage/network/interfaces/MageClient.java b/Mage.Network/src/main/java/org/mage/network/interfaces/MageClient.java index 7f8c2d017e0..b45ada78463 100644 --- a/Mage.Network/src/main/java/org/mage/network/interfaces/MageClient.java +++ b/Mage.Network/src/main/java/org/mage/network/interfaces/MageClient.java @@ -14,7 +14,7 @@ public interface MageClient { void connected(String message); void disconnected(boolean error); - void inform(String message, MessageType type); + void inform(String title, String message, MessageType type); void receiveChatMessage(UUID chatId, ChatMessage message); void receiveBroadcastMessage(String message); diff --git a/Mage.Network/src/main/java/org/mage/network/interfaces/MageServer.java b/Mage.Network/src/main/java/org/mage/network/interfaces/MageServer.java index 86afda53c1c..e401e723804 100644 --- a/Mage.Network/src/main/java/org/mage/network/interfaces/MageServer.java +++ b/Mage.Network/src/main/java/org/mage/network/interfaces/MageServer.java @@ -2,10 +2,15 @@ package org.mage.network.interfaces; import java.util.List; import java.util.UUID; +import mage.MageException; +import mage.cards.decks.DeckCardLists; +import mage.game.GameException; +import mage.game.match.MatchOptions; import mage.interfaces.ServerState; import mage.remote.DisconnectReason; import mage.utils.MageVersion; import mage.view.RoomView; +import mage.view.TableView; /** * @@ -13,20 +18,21 @@ import mage.view.RoomView; */ public interface MageServer { - boolean registerClient(String userName, String sessionId, MageVersion version); + boolean registerClient(String userName, String sessionId, MageVersion version, String host); void disconnect(String sessionId, DisconnectReason reason); void receiveChatMessage(UUID chatId, String sessionId, String message); void joinChat(UUID chatId, String sessionId); void leaveChat(UUID chatId, String sessionId); UUID getRoomChatId(UUID roomId); - void receiveBroadcastMessage(String message, String sessionId); + void receiveBroadcastMessage(String title, String message, String sessionId); ServerState getServerState(); List getServerMessages(); RoomView getRoom(UUID roomId); - + TableView createTable(String sessionId, UUID roomId, MatchOptions options); + boolean joinTable(String sessionId, UUID roomId, UUID tableId, String name, String playerType, int skill, DeckCardLists deckList, String password); void pingTime(long milliSeconds, String sessionId); } diff --git a/Mage.Network/src/main/java/org/mage/network/model/CreateTableMessage.java b/Mage.Network/src/main/java/org/mage/network/model/CreateTableMessage.java new file mode 100644 index 00000000000..e761576c7b5 --- /dev/null +++ b/Mage.Network/src/main/java/org/mage/network/model/CreateTableMessage.java @@ -0,0 +1,22 @@ +package org.mage.network.model; + +import java.io.Serializable; +import mage.view.TableView; + +/** + * + * @author BetaSteward + */ +public class CreateTableMessage implements Serializable { + + private TableView table; + + public CreateTableMessage(TableView table) { + this.table = table; + } + + public TableView getTable() { + return table; + } + +} diff --git a/Mage.Network/src/main/java/org/mage/network/model/CreateTableRequest.java b/Mage.Network/src/main/java/org/mage/network/model/CreateTableRequest.java new file mode 100644 index 00000000000..5bf2c616cd2 --- /dev/null +++ b/Mage.Network/src/main/java/org/mage/network/model/CreateTableRequest.java @@ -0,0 +1,29 @@ +package org.mage.network.model; + +import java.io.Serializable; +import java.util.UUID; +import mage.game.match.MatchOptions; + +/** + * + * @author BetaSteward + */ +public class CreateTableRequest implements Serializable { + + private UUID roomId; + private MatchOptions options; + + public CreateTableRequest(UUID roomId, MatchOptions options) { + this.roomId = roomId; + this.options = options; + } + + public UUID getRoomId() { + return roomId; + } + + public MatchOptions getMatchOptions() { + return options; + } + +} diff --git a/Mage.Network/src/main/java/org/mage/network/model/InformClientMessage.java b/Mage.Network/src/main/java/org/mage/network/model/InformClientMessage.java index aef3c176b9c..b5b7a118081 100644 --- a/Mage.Network/src/main/java/org/mage/network/model/InformClientMessage.java +++ b/Mage.Network/src/main/java/org/mage/network/model/InformClientMessage.java @@ -8,14 +8,20 @@ import java.io.Serializable; */ public class InformClientMessage implements Serializable { + private String title; private String message; private MessageType type; - public InformClientMessage(String message, MessageType type) { + public InformClientMessage(String title, String message, MessageType type) { + this.title = title; this.message = message; this.type = type; } + public String getTitle() { + return title; + } + public String getMessage() { return message; } diff --git a/Mage.Network/src/main/java/org/mage/network/model/JoinTableMessage.java b/Mage.Network/src/main/java/org/mage/network/model/JoinTableMessage.java new file mode 100644 index 00000000000..4ea7d9e1492 --- /dev/null +++ b/Mage.Network/src/main/java/org/mage/network/model/JoinTableMessage.java @@ -0,0 +1,21 @@ +package org.mage.network.model; + +import java.io.Serializable; + +/** + * + * @author BetaSteward + */ +public class JoinTableMessage implements Serializable { + + private boolean success; + + public JoinTableMessage(boolean success) { + this.success = success; + } + + public boolean getSuccess() { + return success; + } + +} diff --git a/Mage.Network/src/main/java/org/mage/network/model/JoinTableRequest.java b/Mage.Network/src/main/java/org/mage/network/model/JoinTableRequest.java new file mode 100644 index 00000000000..5558ddf46eb --- /dev/null +++ b/Mage.Network/src/main/java/org/mage/network/model/JoinTableRequest.java @@ -0,0 +1,59 @@ +package org.mage.network.model; + +import java.io.Serializable; +import java.util.UUID; +import mage.cards.decks.DeckCardLists; + +/** + * + * @author BetaSteward + */ +public class JoinTableRequest implements Serializable { + + private UUID roomId; + private UUID tableId; + private String name; + private String playerType; + private int skill; + private DeckCardLists deckList; + private String password; + + public JoinTableRequest(UUID roomId, UUID tableId, String name, String playerType, int skill, DeckCardLists deckList, String password) { + this.roomId = roomId; + this.tableId = tableId; + this.name = name; + this.playerType = playerType; + this.skill = skill; + this.deckList = deckList; + this.password = password; + } + + public UUID getRoomId() { + return roomId; + } + + public UUID gettableId() { + return tableId; + } + + public String getName() { + return name; + } + + public String getPlayerType() { + return playerType; + } + + public int getSkill() { + return skill; + } + + public DeckCardLists getDeckCardLists() { + return deckList; + } + + public String getPassword() { + return password; + } + +} diff --git a/Mage.Server/src/main/java/mage/server/Main.java b/Mage.Server/src/main/java/mage/server/Main.java index a115bbce19f..f0ea450a81e 100644 --- a/Mage.Server/src/main/java/mage/server/Main.java +++ b/Mage.Server/src/main/java/mage/server/Main.java @@ -242,16 +242,16 @@ public class Main implements MageServer { } @Override - public boolean registerClient(String userName, String sessionId, MageVersion version) { + public boolean registerClient(String userName, String sessionId, MageVersion version, String host) { try { if (version.compareTo(Main.getVersion()) != 0) { logger.info("MageVersionException: userName=" + userName + ", version=" + version); LogServiceImpl.instance.log(LogKeys.KEY_WRONG_VERSION, userName, version.toString(), Main.getVersion().toString(), sessionId); - server.informClient(sessionId, "Wrong version", MessageType.ERROR); + String message = "Wrong client version " + version + ", expecting version " + Main.getVersion() + ". \r\n\r\nPlease download needed version from http://XMage.de or http://www.slightlymagic.net/forum/viewforum.php?f=70"; + server.informClient(sessionId, "Wrong version", message, MessageType.ERROR); return false; -// throw new MageVersionException(version, Main.getVersion()); } - return SessionManager.getInstance().registerUser(sessionId, userName); + return SessionManager.getInstance().registerUser(sessionId, userName, host); } catch (MageException ex) { // if (ex instanceof MageVersionException) { // throw (MageVersionException)ex; @@ -287,26 +287,26 @@ public class Main implements MageServer { // return false; // } // -// @Override -// public TableView createTable(final String sessionId, final UUID roomId, final MatchOptions options) throws MageException { + @Override + public TableView createTable(final String sessionId, final UUID roomId, final MatchOptions options) { // return executeWithResult("createTable", sessionId, new ActionWithTableViewResult() { // @Override // public TableView execute() throws MageException { -// UUID userId = SessionManager.getInstance().getSession(sessionId).getUserId(); -// TableView table = GamesRoomManager.getInstance().getRoom(roomId).createTable(userId, options); -// if (logger.isDebugEnabled()) { -// User user = UserManager.getInstance().getUser(userId); -// if (user != null) { -// logger.debug("TABLE created - tableId: " + table.getTableId() + " " + table.getTableName()); -// logger.debug("- " + user.getName() + " userId: " + user.getId()); -// logger.debug("- chatId: " + TableManager.getInstance().getChatId(table.getTableId())); -// } -// } -// LogServiceImpl.instance.log(LogKeys.KEY_TABLE_CREATED, sessionId, userId.toString(), table.getTableId().toString()); -// return table; + UUID userId = SessionManager.getInstance().getSession(sessionId).getUserId(); + TableView table = GamesRoomManager.getInstance().getRoom(roomId).createTable(userId, options); + if (logger.isDebugEnabled()) { + User user = UserManager.getInstance().getUser(userId); + if (user != null) { + logger.debug("TABLE created - tableId: " + table.getTableId() + " " + table.getTableName()); + logger.debug("- " + user.getName() + " userId: " + user.getId()); + logger.debug("- chatId: " + TableManager.getInstance().getChatId(table.getTableId())); + } + } + LogServiceImpl.instance.log(LogKeys.KEY_TABLE_CREATED, sessionId, userId.toString(), table.getTableId().toString()); + return table; // } // }); -// } + } // // @Override // public TableView createTournamentTable(final String sessionId, final UUID roomId, final TournamentOptions options) throws MageException { @@ -356,22 +356,22 @@ public class Main implements MageServer { // }); // } // -// @Override -// public boolean joinTable(final String sessionId, final UUID roomId, final UUID tableId, final String name, final String playerType, final int skill, final DeckCardLists deckList, final String password) throws MageException, GameException { + @Override + public boolean joinTable(final String sessionId, final UUID roomId, final UUID tableId, final String name, final String playerType, final int skill, final DeckCardLists deckList, final String password) { // return executeWithResult("joinTable", sessionId, new ActionWithBooleanResult() { // @Override // public Boolean execute() throws MageException { -// UUID userId = SessionManager.getInstance().getSession(sessionId).getUserId(); -// logger.debug(name + " joins tableId: " + tableId); -// if (userId == null) { -// logger.fatal("Got no userId from sessionId" + sessionId + " tableId" + tableId); -// return false; -// } -// boolean ret = GamesRoomManager.getInstance().getRoom(roomId).joinTable(userId, tableId, name, playerType, skill, deckList, password); -// return ret; + UUID userId = SessionManager.getInstance().getSession(sessionId).getUserId(); + logger.debug(name + " joins tableId: " + tableId); + if (userId == null) { + logger.fatal("Got no userId from sessionId" + sessionId + " tableId" + tableId); + return false; + } + boolean ret = GamesRoomManager.getInstance().getRoom(roomId).joinTable(userId, tableId, name, playerType, skill, deckList, password); + return ret; // } // }); -// } + } // // @Override // public boolean joinTournamentTable(final String sessionId, final UUID roomId, final UUID tableId, final String name, final String playerType, final int skill, final DeckCardLists deckList, final String password) throws MageException, GameException { @@ -586,14 +586,14 @@ public class Main implements MageServer { @Override public void receiveChatMessage(final UUID chatId, final String sessionId, final String message) { - execute("receiveChatMessage", sessionId, new Action() { - @Override - public void execute() { +// execute("receiveChatMessage", sessionId, new Action() { +// @Override +// public void execute() { User user = SessionManager.getInstance().getUser(sessionId); if (user != null) ChatManager.getInstance().broadcast(chatId, user, StringEscapeUtils.escapeHtml4(message), MessageColor.BLUE); - } - }); +// } +// }); // } // catch (Exception ex) { // handleException(sessionId, ex); @@ -1088,7 +1088,7 @@ public class Main implements MageServer { public void handleException(String sessionId, Exception ex) { if (!ex.getMessage().equals("No message")) { logger.fatal("", ex); - server.informClient(sessionId, "Server error: " + ex.getMessage(), MessageType.ERROR); + server.informClient(sessionId, "Server error", ex.getMessage(), MessageType.ERROR); // throw new MageException("Server error: " + ex.getMessage()); } } @@ -1219,57 +1219,57 @@ public class Main implements MageServer { // } @Override - public void receiveBroadcastMessage(String message, String sessionId) { + public void receiveBroadcastMessage(String title, String message, String sessionId) { if (SessionManager.getInstance().isAdmin(sessionId)) { if (message.toLowerCase(Locale.ENGLISH).startsWith("warn")) { - server.informClients(message, MessageType.WARNING); + server.informClients(title, message, MessageType.WARNING); } else { - server.informClients(message, MessageType.INFORMATION); + server.informClients(title, message, MessageType.INFORMATION); } } } - public void informClient(String sessionId, String mesage, MessageType type) { - server.informClient(sessionId, mesage, type); + public void informClient(String sessionId, String title, String message, MessageType type) { + server.informClient(sessionId, title, message, type); } - protected void execute(final String actionName, final String sessionId, final Action action, boolean checkAdminRights) throws MageException { - if (checkAdminRights) { - if (!SessionManager.getInstance().isAdmin(sessionId)) { - LogServiceImpl.instance.log(LogKeys.KEY_NOT_ADMIN, actionName, sessionId); - return; - } - } - execute(actionName, sessionId, action); - } - - protected void execute(final String actionName, final String sessionId, final Action action) { - if (SessionManager.getInstance().isValidSession(sessionId)) { - try { - callExecutor.execute( - new Runnable() { - @Override - public void run() { - if (SessionManager.getInstance().isValidSession(sessionId)) { - try { - action.execute(); - } catch (MageException me) { - throw new RuntimeException(me); - } - } else { - LogServiceImpl.instance.log(LogKeys.KEY_NOT_VALID_SESSION_INTERNAL, actionName, sessionId); - } - } - } - ); - } - catch (Exception ex) { - handleException(sessionId, ex); - } - } else { - LogServiceImpl.instance.log(LogKeys.KEY_NOT_VALID_SESSION, actionName, sessionId); - } - } +// protected void execute(final String actionName, final String sessionId, final Action action, boolean checkAdminRights) throws MageException { +// if (checkAdminRights) { +// if (!SessionManager.getInstance().isAdmin(sessionId)) { +// LogServiceImpl.instance.log(LogKeys.KEY_NOT_ADMIN, actionName, sessionId); +// return; +// } +// } +// execute(actionName, sessionId, action); +// } +// +// protected void execute(final String actionName, final String sessionId, final Action action) { +// if (SessionManager.getInstance().isValidSession(sessionId)) { +// try { +// callExecutor.execute( +// new Runnable() { +// @Override +// public void run() { +// if (SessionManager.getInstance().isValidSession(sessionId)) { +// try { +// action.execute(); +// } catch (MageException me) { +// throw new RuntimeException(me); +// } +// } else { +// LogServiceImpl.instance.log(LogKeys.KEY_NOT_VALID_SESSION_INTERNAL, actionName, sessionId); +// } +// } +// } +// ); +// } +// catch (Exception ex) { +// handleException(sessionId, ex); +// } +// } else { +// LogServiceImpl.instance.log(LogKeys.KEY_NOT_VALID_SESSION, actionName, sessionId); +// } +// } // protected T executeWithResult(String actionName, final String sessionId, final ActionWithResult action, boolean checkAdminRights) throws MageException { // if (checkAdminRights) { diff --git a/Mage.Server/src/main/java/mage/server/SessionManager.java b/Mage.Server/src/main/java/mage/server/SessionManager.java index cb71a73afa3..70d04fbdaa7 100644 --- a/Mage.Server/src/main/java/mage/server/SessionManager.java +++ b/Mage.Server/src/main/java/mage/server/SessionManager.java @@ -73,9 +73,10 @@ public class SessionManager { // sessions.put(sessionId, session); // } - public boolean registerUser(String sessionId, String userName) throws MageException { + public boolean registerUser(String sessionId, String userName, String host) throws MageException { Session session = new Session(sessionId); sessions.put(sessionId, session); + session.setHost(host); // Session session = sessions.get(sessionId); // if (session != null) { String returnMessage = session.registerUser(userName); @@ -89,7 +90,7 @@ public class SessionManager { return true; } logger.debug(userName + " not registered: " + returnMessage); - Main.getInstance().informClient(sessionId, returnMessage, MessageType.ERROR); + Main.getInstance().informClient(sessionId, "Connection Error", returnMessage, MessageType.ERROR); // Server.informClient(sessionId, returnMessage, MessageType.ERROR); // } else { diff --git a/Mage.Server/src/main/java/mage/server/TableController.java b/Mage.Server/src/main/java/mage/server/TableController.java index 3a93ff9222a..c0efb8744e0 100644 --- a/Mage.Server/src/main/java/mage/server/TableController.java +++ b/Mage.Server/src/main/java/mage/server/TableController.java @@ -35,6 +35,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; +import java.util.logging.Level; import mage.MageException; import mage.cards.decks.Deck; import mage.cards.decks.DeckCardLists; @@ -149,20 +150,21 @@ public class TableController { ); } - public synchronized boolean joinTournament(UUID userId, String name, String playerType, int skill, DeckCardLists deckList, String password) throws GameException { + public synchronized boolean joinTournament(UUID userId, String name, String playerType, int skill, DeckCardLists deckList, String password) { if (table.getState() != TableState.WAITING) { return false; } - Seat seat = table.getNextAvailableSeat(playerType); - if (seat == null) { - throw new GameException("No available seats."); - } User user = UserManager.getInstance().getUser(userId); if (user == null) { logger.fatal(new StringBuilder("couldn't get user ").append(name).append(" for join tournament userId = ").append(userId).toString()); return false; } + Seat seat = table.getNextAvailableSeat(playerType); + if (seat == null) { + user.showUserMessage("Join Table", "No available seats"); + return false; + } // check password if (!table.getTournament().getOptions().getPassword().isEmpty() && playerType.equals("Human")) { if (!table.getTournament().getOptions().getPassword().equals(password)) { @@ -176,8 +178,14 @@ public class TableController { } Deck deck = null; if (!table.getTournament().getTournamentType().isLimited()) { - if (deckList != null) { - deck = Deck.load(deckList, false, false); + if (deckList != null) { + try { + deck = Deck.load(deckList, false, false); + } catch (GameException ex) { + logger.error("Error loading deck", ex); + user.showUserMessage("Join Table", "Error loading deck"); + return false; + } } else { user.showUserMessage("Join Table", "No valid deck selected!"); return false; @@ -220,7 +228,8 @@ public class TableController { return true; } else { - throw new GameException("Playertype " + seat.getPlayerType() + " could not be created."); + logger.error("Playertype " + seat.getPlayerType() + " could not be created."); + return false; } } @@ -244,7 +253,7 @@ public class TableController { return true; } - public synchronized boolean joinTable(UUID userId, String name, String playerType, int skill, DeckCardLists deckList, String password) throws MageException { + public synchronized boolean joinTable(UUID userId, String name, String playerType, int skill, DeckCardLists deckList, String password) { User user = UserManager.getInstance().getUser(userId); if (user == null) { return false; @@ -269,7 +278,15 @@ public class TableController { user.showUserMessage("Join Table", "No available seats."); return false; } - Deck deck = Deck.load(deckList, false, false); + + Deck deck; + try { + deck = Deck.load(deckList, false, false); + } catch (GameException ex) { + logger.error("Error load deck", ex); + user.showUserMessage("Join Table", "Error loading deck"); + return false; + } if (!Main.getInstance().isTestMode() && !table.getValidator().validate(deck)) { StringBuilder sb = new StringBuilder("You (").append(name).append(") have an invalid deck for the selected ").append(table.getValidator().getName()).append(" Format. \n\n"); @@ -297,7 +314,10 @@ public class TableController { return false; } match.addPlayer(player, deck); - table.joinTable(player, seat); + if (table.joinTable(player, seat) == null) { + user.showUserMessage("Join Table", "Seat is occupied"); + return false; + } logger.trace(player.getName() + " joined tableId: " + table.getId()); //only inform human players and add them to sessionPlayerMap if (seat.getPlayer().isHuman()) { diff --git a/Mage.Server/src/main/java/mage/server/TableManager.java b/Mage.Server/src/main/java/mage/server/TableManager.java index 3c8c3a49e5d..7e05eb3a08b 100644 --- a/Mage.Server/src/main/java/mage/server/TableManager.java +++ b/Mage.Server/src/main/java/mage/server/TableManager.java @@ -140,14 +140,14 @@ public class TableManager { return controllers.get(tableId); } - public boolean joinTable(UUID userId, UUID tableId, String name, String playerType, int skill, DeckCardLists deckList, String password) throws MageException { + public boolean joinTable(UUID userId, UUID tableId, String name, String playerType, int skill, DeckCardLists deckList, String password) { if (controllers.containsKey(tableId)) { return controllers.get(tableId).joinTable(userId, name, playerType, skill, deckList, password); } return false; } - public boolean joinTournament(UUID userId, UUID tableId, String name, String playerType, int skill, DeckCardLists deckList, String password) throws GameException { + public boolean joinTournament(UUID userId, UUID tableId, String name, String playerType, int skill, DeckCardLists deckList, String password) { if (controllers.containsKey(tableId)) { return controllers.get(tableId).joinTournament(userId, name, playerType, skill, deckList, password); } diff --git a/Mage.Server/src/main/java/mage/server/User.java b/Mage.Server/src/main/java/mage/server/User.java index 43e8ac3deac..9af4d258001 100644 --- a/Mage.Server/src/main/java/mage/server/User.java +++ b/Mage.Server/src/main/java/mage/server/User.java @@ -53,6 +53,7 @@ import mage.server.tournament.TournamentSession; import mage.server.util.SystemUtil; import mage.view.TableClientMessage; import org.apache.log4j.Logger; +import org.mage.network.model.MessageType; /** @@ -220,11 +221,12 @@ public class User { fireCallback(new ClientCallback("showGameEndDialog", gameId)); } - public void showUserMessage(final String titel, String message) { - List messageData = new LinkedList<>(); - messageData.add(titel); - messageData.add(message); - fireCallback(new ClientCallback("showUserMessage", null, messageData )); + public void showUserMessage(final String title, String message) { +// List messageData = new LinkedList<>(); +// messageData.add(titel); +// messageData.add(message); +// fireCallback(new ClientCallback("showUserMessage", null, messageData )); + Main.getInstance().informClient(sessionId, title, message, MessageType.INFORMATION); } public boolean ccWatchGame(final UUID gameId) { diff --git a/Mage.Server/src/main/java/mage/server/game/GamesRoom.java b/Mage.Server/src/main/java/mage/server/game/GamesRoom.java index 949a3ca352c..4ec966ca7b2 100644 --- a/Mage.Server/src/main/java/mage/server/game/GamesRoom.java +++ b/Mage.Server/src/main/java/mage/server/game/GamesRoom.java @@ -49,8 +49,8 @@ public interface GamesRoom extends Room { List getTables(); List getFinished(); RoomUsersView getRoomUsersInfo(); - boolean joinTable(UUID userId, UUID tableId, String name, String playerType, int skill, DeckCardLists deckList, String password) throws MageException; - boolean joinTournamentTable(UUID userId, UUID tableId, String name, String playerType, int skill, DeckCardLists deckList, String password) throws GameException; + boolean joinTable(UUID userId, UUID tableId, String name, String playerType, int skill, DeckCardLists deckList, String password); + boolean joinTournamentTable(UUID userId, UUID tableId, String name, String playerType, int skill, DeckCardLists deckList, String password); TableView createTable(UUID userId, MatchOptions options); TableView createTournamentTable(UUID userId, TournamentOptions options); void removeTable(UUID userId, UUID 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 2295d0950ce..765b6a09be4 100644 --- a/Mage.Server/src/main/java/mage/server/game/GamesRoomImpl.java +++ b/Mage.Server/src/main/java/mage/server/game/GamesRoomImpl.java @@ -146,7 +146,7 @@ public class GamesRoomImpl extends RoomImpl implements GamesRoom, Serializable { } @Override - public boolean joinTable(UUID userId, UUID tableId, String name, String playerType, int skill, DeckCardLists deckList, String password) throws MageException { + public boolean joinTable(UUID userId, UUID tableId, String name, String playerType, int skill, DeckCardLists deckList, String password) { if (tables.containsKey(tableId)) { return TableManager.getInstance().joinTable(userId, tableId, name, playerType, skill, deckList, password); } else { @@ -162,7 +162,7 @@ public class GamesRoomImpl extends RoomImpl implements GamesRoom, Serializable { } @Override - public boolean joinTournamentTable(UUID userId, UUID tableId, String name, String playerType, int skill, DeckCardLists deckList, String password) throws GameException { + public boolean joinTournamentTable(UUID userId, UUID tableId, String name, String playerType, int skill, DeckCardLists deckList, String password) { if (tables.containsKey(tableId)) { return TableManager.getInstance().joinTournament(userId, tableId, name, playerType, skill, deckList, password); } else { diff --git a/Mage/src/mage/game/Table.java b/Mage/src/mage/game/Table.java index f5c714f95fe..66d09a8a39e 100644 --- a/Mage/src/mage/game/Table.java +++ b/Mage/src/mage/game/Table.java @@ -170,10 +170,10 @@ public class Table implements Serializable { public boolean isTournament() { return this.isTournament; } - - public UUID joinTable(Player player, Seat seat) throws GameException { + + public UUID joinTable(Player player, Seat seat) { if (seat.getPlayer() != null) { - throw new GameException("Seat is occupied."); + return null; } seat.setPlayer(player); if (isReady()) {