From 9e894a370e09bb71839fabbffff590359ba6fb98 Mon Sep 17 00:00:00 2001 From: Yannik Bretschneider Date: Mon, 7 Jun 2021 01:45:51 +0200 Subject: [PATCH] feat: improved UserManager --- .../server/netconnector/UserManager.java | 70 +++++++++++++++---- 1 file changed, 57 insertions(+), 13 deletions(-) diff --git a/Server/src/main/java/uulm/teamname/marvelous/server/netconnector/UserManager.java b/Server/src/main/java/uulm/teamname/marvelous/server/netconnector/UserManager.java index 627bd1a..83de343 100644 --- a/Server/src/main/java/uulm/teamname/marvelous/server/netconnector/UserManager.java +++ b/Server/src/main/java/uulm/teamname/marvelous/server/netconnector/UserManager.java @@ -1,5 +1,6 @@ package uulm.teamname.marvelous.server.netconnector; +import org.java_websocket.framing.CloseFrame; import org.tinylog.Logger; import uulm.teamname.marvelous.gamelibrary.json.JSON; import uulm.teamname.marvelous.gamelibrary.json.ValidationUtility; @@ -114,21 +115,23 @@ public class UserManager { if (parsedMessage instanceof HelloServerMessage) { Logger.trace("Message is instanceof HelloServerMessage, initiating handshake"); handshake(conn, (HelloServerMessage) parsedMessage); + } else if (parsedMessage instanceof ReconnectMessage) { Logger.trace("Message is instanceof ReconnectMessage, initiating reconnect"); reconnectClient(conn, (ReconnectMessage) parsedMessage); + } else if (parsedMessage instanceof PlayerReadyMessage) { Logger.trace("Message is instanceof PlayerReadyMessage, assigning lobby"); - assignLobby(conn, (PlayerReadyMessage) parsedMessage); + playerReady(conn, (PlayerReadyMessage) parsedMessage); + } else if (parsedMessage instanceof CharacterSelectionMessage) { Logger.trace("Message is instanceof CharacterSelectionMessage, passing to LobbyConnection"); charactersSelected(conn, (CharacterSelectionMessage) parsedMessage); + } else if (parsedMessage instanceof RequestMessage) { Logger.trace("Message is instanceof RequestMessage, passing to LobbyConnection"); relayRequestMessage(conn, (RequestMessage) parsedMessage); - } - - else { + } else { Logger.debug("Message '{}' has invalid type, Error will be sent"); sendError(conn, String.format( "Message '%s' has invalid type, and cannot be processed on the server", @@ -182,7 +185,7 @@ public class UserManager { var clientID = readyToReconnect.get(conn); var participantToRestore = activeParticipants.get(clientID); - participantToRestore.setConnection(conn); + lobbyManager.restoreConnection(conn, participantToRestore); synchronized (readyToReconnect) { readyToReconnect.remove(conn); @@ -190,10 +193,10 @@ public class UserManager { synchronized (inGame) { inGame.put(conn, participantToRestore); } + lobbyManager.restoreConnection(conn, participantToRestore); // activeParticipants remains the same, as no players have been removed from the game } else { - Logger.debug( - "Client {} refused reconnection, will therefore be put into readyToConnect clients", + Logger.debug("Client {} refused reconnection, will therefore be put into readyToConnect clients", conn); var clientID = readyToReconnect.get(conn); @@ -207,26 +210,40 @@ public class UserManager { } } - void assignLobby(WebSocket conn, PlayerReadyMessage message) { - if (readyToReconnect.containsKey(conn) || readyToConnect.containsKey(conn)) { + void playerReady(WebSocket conn, PlayerReadyMessage message) { + if (!message.startGame) { + removeUser(conn); + } else if (readyToReconnect.containsKey(conn) || readyToConnect.containsKey(conn)) { + Logger.trace("Connecting client to server"); + SUID suid; if (readyToConnect.containsKey(conn)) { + Logger.trace("Client in readyToConnect state, removing from list"); synchronized (readyToConnect) { + suid = readyToConnect.get(conn); readyToConnect.remove(conn); } } else { + Logger.trace("Client in readyToReconnect state, removing from list"); synchronized (readyToReconnect) { + suid = readyToReconnect.get(conn); readyToReconnect.remove(conn); } } + Participant participant; + Logger.trace("Letting LobbyManager assign lobby to client"); synchronized (inGame) { - var participant = lobbyManager.assignLobbyToConnection(conn, "SomeName", message); + participant = lobbyManager.assignLobbyToConnection(conn, suid.getName(), message); inGame.put(conn, participant); } + Logger.trace("Adding participants to activeParticipants for reconnection possibilities"); + synchronized (activeParticipants) { + activeParticipants.put(suid, participant); + } } else { Logger.debug( - "WebSocket {} sent PlayerReadyMessage to server while not ready to connect, sending error", - conn); - sendError(conn, "Invalid message, as client is not ready to connect"); + "WebSocket {} sent PlayerReadyMessage to server while not in connection ready state, " + + "sending error", conn); + sendError(conn, "Invalid message, as client is not in a connection-ready state"); } } @@ -252,6 +269,33 @@ public class UserManager { } } + /** + * Method to call when removing a user from the game, e.g. on player timeout, or end of match + * @param conn is the connection to close + */ + public void removeUser(WebSocket conn) { + Logger.debug("Removing user from game"); + if (conn == null) { + Logger.trace("Tried to remove user but connection was null, ignoring"); + } else if (!isUserConnected(conn)) { + Logger.warn("Tried to remove non-connected user. This is probably a bug."); + } else { + if (inGame.containsKey(conn)) { + var participant = inGame.get(conn); + Logger.debug("Removing reconnect possibility for participant '{}'", participant.name); + var suid = new SUID(participant.name, participant.deviceID); + activeParticipants.remove(suid); + } + conn.close(CloseFrame.NORMAL); + // this automatically calls disconnectUser through the MarvelousServer + } + } + + /** + * Method called exclusively from {@link MarvelousServer} on closed connection. + * @param conn + * @param closedByRemote + */ void disconnectUser(WebSocket conn, boolean closedByRemote) { // TODO: notify clients and such if the connection was in fact closed by the remote. Also remove participant synchronized (newUsers) {