refactor: major refactor for UserManager, and comments for LobbyManager
This commit is contained in:
		@ -34,6 +34,10 @@ public class LobbyManager {
 | 
				
			|||||||
    private final HashMap<SUID, Participant> participants = new HashMap<>();
 | 
					    private final HashMap<SUID, Participant> participants = new HashMap<>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Handles a newly connected Client, and returns whether the game is already running in the given {@link
 | 
				
			||||||
 | 
					     * AtomicBoolean}
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
    public boolean handleConnect(Client client, AtomicBoolean running) {
 | 
					    public boolean handleConnect(Client client, AtomicBoolean running) {
 | 
				
			||||||
        if (participants.containsKey(client.id)) {
 | 
					        if (participants.containsKey(client.id)) {
 | 
				
			||||||
            running.set(true);
 | 
					            running.set(true);
 | 
				
			||||||
@ -69,6 +73,14 @@ public class LobbyManager {
 | 
				
			|||||||
        return true;
 | 
					        return true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Handles a {@link CharacterSelectionMessage}, computes the characters that have been selected and relays that
 | 
				
			||||||
 | 
					     * information to the {@link LobbyConnection} concerned by this information.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param client  is the client that sent the message
 | 
				
			||||||
 | 
					     * @param message is the message sent by the client
 | 
				
			||||||
 | 
					     * @return true if handled successfully, and false otherwise
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
    public boolean handleSelection(Client client, CharacterSelectionMessage message) {
 | 
					    public boolean handleSelection(Client client, CharacterSelectionMessage message) {
 | 
				
			||||||
        if (!participants.containsKey(client.id)) {
 | 
					        if (!participants.containsKey(client.id)) {
 | 
				
			||||||
            return false;
 | 
					            return false;
 | 
				
			||||||
@ -116,6 +128,13 @@ public class LobbyManager {
 | 
				
			|||||||
        return true;
 | 
					        return true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Handles a requestMessage, and relays it to the Lobby if valid
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param client  is the client that sent the message
 | 
				
			||||||
 | 
					     * @param message is the message sent by the client
 | 
				
			||||||
 | 
					     * @return true if handled successfully, and false otherwise
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
    public boolean handleRequests(Client client, RequestMessage message) {
 | 
					    public boolean handleRequests(Client client, RequestMessage message) {
 | 
				
			||||||
        if (!participants.containsKey(client.id)) {
 | 
					        if (!participants.containsKey(client.id)) {
 | 
				
			||||||
            return false;
 | 
					            return false;
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,7 @@
 | 
				
			|||||||
package uulm.teamname.marvelous.server.netconnector;
 | 
					package uulm.teamname.marvelous.server.netconnector;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import org.java_websocket.framing.CloseFrame;
 | 
					import org.java_websocket.framing.CloseFrame;
 | 
				
			||||||
 | 
					import org.tinylog.Logger;
 | 
				
			||||||
import uulm.teamname.marvelous.gamelibrary.json.JSON;
 | 
					import uulm.teamname.marvelous.gamelibrary.json.JSON;
 | 
				
			||||||
import uulm.teamname.marvelous.gamelibrary.json.ValidationUtility;
 | 
					import uulm.teamname.marvelous.gamelibrary.json.ValidationUtility;
 | 
				
			||||||
import uulm.teamname.marvelous.gamelibrary.messages.BasicMessage;
 | 
					import uulm.teamname.marvelous.gamelibrary.messages.BasicMessage;
 | 
				
			||||||
@ -45,6 +46,7 @@ public class UserManager {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    /** Called on a new WebSocket connection. Places the WebSocket and its ResourceDescriptor in a HashMap. */
 | 
					    /** Called on a new WebSocket connection. Places the WebSocket and its ResourceDescriptor in a HashMap. */
 | 
				
			||||||
    void connectUser(WebSocket conn) {
 | 
					    void connectUser(WebSocket conn) {
 | 
				
			||||||
 | 
					        Logger.debug("Connected new user");
 | 
				
			||||||
        synchronized(clients) {
 | 
					        synchronized(clients) {
 | 
				
			||||||
            clients.put(conn, new Client(conn));
 | 
					            clients.put(conn, new Client(conn));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -56,15 +58,19 @@ public class UserManager {
 | 
				
			|||||||
     * @param message is the {@link String} sent by the connection
 | 
					     * @param message is the {@link String} sent by the connection
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    void messageReceived(WebSocket conn, String message) {
 | 
					    void messageReceived(WebSocket conn, String message) {
 | 
				
			||||||
 | 
					        Logger.debug("Message received from {}", conn);
 | 
				
			||||||
        Client client = clients.get(conn);
 | 
					        Client client = clients.get(conn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if(client == null) {
 | 
					        if(client == null) {
 | 
				
			||||||
 | 
					            Logger.warn("messageReceived called with null-valued client. This is probably a bug.");
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Logger.trace("Parsing message...");
 | 
				
			||||||
        Optional<BasicMessage> parsed = json.parse(message);
 | 
					        Optional<BasicMessage> parsed = json.parse(message);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if(parsed.isEmpty()) {
 | 
					        if(parsed.isEmpty()) {
 | 
				
			||||||
 | 
					            Logger.debug("Message couldn't be parsed, sending error...");
 | 
				
			||||||
            client.sendError("Message could not be parsed.");
 | 
					            client.sendError("Message could not be parsed.");
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -73,39 +79,77 @@ public class UserManager {
 | 
				
			|||||||
        Optional<String> violations = ValidationUtility.validate(data);
 | 
					        Optional<String> violations = ValidationUtility.validate(data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if(violations.isPresent()) {
 | 
					        if(violations.isPresent()) {
 | 
				
			||||||
 | 
					            Logger.debug("The message that client sent had structural violations: '{}'. Sending error...",
 | 
				
			||||||
 | 
					                    violations.get());
 | 
				
			||||||
            client.sendError(violations.get());
 | 
					            client.sendError(violations.get());
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Logger.trace("Handling message...");
 | 
				
			||||||
        handleMessage(client, data);
 | 
					        handleMessage(client, data);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /** Called on closed connection. */
 | 
					    /** Called on closed connection. */
 | 
				
			||||||
    void disconnectUser(WebSocket conn, boolean closedByRemote) {
 | 
					    void disconnectUser(WebSocket conn, boolean closedByRemote) {
 | 
				
			||||||
 | 
					        Logger.info("Disconnecting client '{}'", conn);
 | 
				
			||||||
        Client client = clients.get(conn);
 | 
					        Client client = clients.get(conn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if(client == null) {
 | 
					        if(client == null) {
 | 
				
			||||||
 | 
					            Logger.warn("disconnect called with null-valued client. This is probably a bug.");
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Logger.trace("Calling handleDisconnect on LobbyManager");
 | 
				
			||||||
        LobbyManager.getInstance().handleDisconnect(client, closedByRemote);
 | 
					        LobbyManager.getInstance().handleDisconnect(client, closedByRemote);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        synchronized(clients) {
 | 
					        synchronized(clients) {
 | 
				
			||||||
 | 
					            Logger.debug("Removing connections from clients HashMap");
 | 
				
			||||||
            clients.remove(conn);
 | 
					            clients.remove(conn);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** Checks type of a given message, and delegates its execution to the respective handler method */
 | 
				
			||||||
    private void handleMessage(Client client, BasicMessage data) {
 | 
					    private void handleMessage(Client client, BasicMessage data) {
 | 
				
			||||||
 | 
					        Logger.debug("Received message from client '{}'", client);
 | 
				
			||||||
        if(data instanceof HelloServerMessage) {
 | 
					        if(data instanceof HelloServerMessage) {
 | 
				
			||||||
 | 
					            Logger.trace("Message was instanceof HelloServerMessage");
 | 
				
			||||||
            HelloServerMessage message = (HelloServerMessage) data;
 | 
					            HelloServerMessage message = (HelloServerMessage) data;
 | 
				
			||||||
 | 
					            handleHelloServerMessage(client, message);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        } else if(data instanceof ReconnectMessage) {
 | 
				
			||||||
 | 
					            ReconnectMessage message = (ReconnectMessage) data;
 | 
				
			||||||
 | 
					            handleReconnectMessage(client, message);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        } else if(data instanceof PlayerReadyMessage) {
 | 
				
			||||||
 | 
					            Logger.trace("Message was instanceof PlayerReadyMessage");
 | 
				
			||||||
 | 
					            PlayerReadyMessage message = (PlayerReadyMessage) data;
 | 
				
			||||||
 | 
					            handlePlayerReadyMessage(client, message);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        } else if(data instanceof CharacterSelectionMessage) {
 | 
				
			||||||
 | 
					            Logger.trace("Message was instanceof CharacterSelectionMessage");
 | 
				
			||||||
 | 
					            CharacterSelectionMessage message = (CharacterSelectionMessage) data;
 | 
				
			||||||
 | 
					            handleCharacterSelectionMessage(client, message);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        } else if(data instanceof RequestMessage) {
 | 
				
			||||||
 | 
					            Logger.trace("Message was instanceof RequestMessage");
 | 
				
			||||||
 | 
					            RequestMessage message = (RequestMessage) data;
 | 
				
			||||||
 | 
					            handleRequestsMessage(client, message);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** Handles a HelloServerMessage */
 | 
				
			||||||
 | 
					    private void handleHelloServerMessage(Client client, HelloServerMessage message) {
 | 
				
			||||||
        if(client.state != ClientState.Blank) {
 | 
					        if(client.state != ClientState.Blank) {
 | 
				
			||||||
                client.sendError("Invalid message.");
 | 
					            Logger.debug("Disconnecting client as ClientState isn't Blank but {}", client.state);
 | 
				
			||||||
 | 
					            client.sendError("Invalid message, as handshake already completed.");
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        client.id = new SUID(message.name, message.deviceID);
 | 
					        client.id = new SUID(message.name, message.deviceID);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Logger.trace("forwarding message to the LobbyManager");
 | 
				
			||||||
        AtomicBoolean running = new AtomicBoolean(false);
 | 
					        AtomicBoolean running = new AtomicBoolean(false);
 | 
				
			||||||
        if(LobbyManager.getInstance().handleConnect(client, running)) {
 | 
					        if(LobbyManager.getInstance().handleConnect(client, running)) {
 | 
				
			||||||
            client.state = ClientState.Ready;
 | 
					            client.state = ClientState.Ready;
 | 
				
			||||||
@ -114,67 +158,100 @@ public class UserManager {
 | 
				
			|||||||
            response.runningGame = running.get();
 | 
					            response.runningGame = running.get();
 | 
				
			||||||
            client.sendMessage(response);
 | 
					            client.sendMessage(response);
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
                client.sendError("Invalid message.");
 | 
					            client.sendError("Message could not be processed.");
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        } else if(data instanceof ReconnectMessage) {
 | 
					    }
 | 
				
			||||||
            ReconnectMessage message = (ReconnectMessage) data;
 | 
					
 | 
				
			||||||
 | 
					    /** Handles a reconnectMessage, and reconnects the client if needed */
 | 
				
			||||||
 | 
					    private void handleReconnectMessage(Client client, ReconnectMessage message) {
 | 
				
			||||||
        if(client.state != ClientState.Ready) {
 | 
					        if(client.state != ClientState.Ready) {
 | 
				
			||||||
            client.sendError("Invalid message.");
 | 
					            client.sendError("Invalid message.");
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if(message.reconnect) {
 | 
					        if(message.reconnect) {
 | 
				
			||||||
 | 
					            Logger.trace("Reconnecting to lobby. Forwarding reconnect instruction to the LobbyManager");
 | 
				
			||||||
            if(LobbyManager.getInstance().handleReconnect(client)) {
 | 
					            if(LobbyManager.getInstance().handleReconnect(client)) {
 | 
				
			||||||
 | 
					                Logger.trace("Successfully reconnected client, changing state to Playing...");
 | 
				
			||||||
                client.state = ClientState.Playing;
 | 
					                client.state = ClientState.Playing;
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                    client.sendError("Invalid message.");
 | 
					                Logger.debug("The client couldn't be reconnected properly");
 | 
				
			||||||
 | 
					                client.sendError("You could not be reconnected to the Lobby");
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
 | 
					            Logger.trace("No reconnect requested, changing ClientState to blank");
 | 
				
			||||||
            client.state = ClientState.Blank;
 | 
					            client.state = ClientState.Blank;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        } else if(data instanceof PlayerReadyMessage) {
 | 
					    }
 | 
				
			||||||
            PlayerReadyMessage message = (PlayerReadyMessage) data;
 | 
					
 | 
				
			||||||
 | 
					    /** Handles a PlayerReadyMessage, and connects a client to a lobby if valid */
 | 
				
			||||||
 | 
					    private void handlePlayerReadyMessage(Client client, PlayerReadyMessage message) {
 | 
				
			||||||
 | 
					        Logger.trace("Handing PlayerReadyMessage...");
 | 
				
			||||||
        if(client.state != ClientState.Ready) {
 | 
					        if(client.state != ClientState.Ready) {
 | 
				
			||||||
                client.sendError("Invalid message.");
 | 
					            Logger.debug("Client wasn't in Ready state but instead in {} state, sending error...", client.state);
 | 
				
			||||||
 | 
					            client.sendError("Invalid message, as client is not in Ready state");
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Logger.trace("Relaying message to LobbyManager");
 | 
				
			||||||
        if(message.startGame) {
 | 
					        if(message.startGame) {
 | 
				
			||||||
            if(LobbyManager.getInstance().handleReady(client, message)) {
 | 
					            if(LobbyManager.getInstance().handleReady(client, message)) {
 | 
				
			||||||
                client.state = ClientState.Assigned;
 | 
					                client.state = ClientState.Assigned;
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
 | 
					                Logger.trace("Sending error to client as message couldn't be processed properly");
 | 
				
			||||||
                client.sendError("Invalid message.");
 | 
					                client.sendError("Invalid message.");
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
 | 
					            Logger.debug("Disconnecting client as game couldn't be started");
 | 
				
			||||||
            removeClient(client, "You got disconnected.");
 | 
					            removeClient(client, "You got disconnected.");
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        } else if(data instanceof CharacterSelectionMessage) {
 | 
					    }
 | 
				
			||||||
            CharacterSelectionMessage message = (CharacterSelectionMessage) data;
 | 
					
 | 
				
			||||||
 | 
					    /** Handles a characterSelectionMessage, and forwards it to the LobbyManager if valid */
 | 
				
			||||||
 | 
					    private void handleCharacterSelectionMessage(Client client, CharacterSelectionMessage message) {
 | 
				
			||||||
 | 
					        Logger.trace("Handling CharacterSelectionMessage");
 | 
				
			||||||
        if(client.state != ClientState.Assigned) {
 | 
					        if(client.state != ClientState.Assigned) {
 | 
				
			||||||
                client.sendError("Invalid message.");
 | 
					            Logger.debug("Couldn't handle CharacterSelectionMessage as client wasn't in assignedState but in {}",
 | 
				
			||||||
 | 
					                    client.state);
 | 
				
			||||||
 | 
					            client.sendError("Cannot select character, as client is not in the Character Selection phase");
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Logger.trace("relaying message to be handled by the LobbyManager...");
 | 
				
			||||||
        if(LobbyManager.getInstance().handleSelection(client, message)) {
 | 
					        if(LobbyManager.getInstance().handleSelection(client, message)) {
 | 
				
			||||||
 | 
					            Logger.trace("Handled successfully");
 | 
				
			||||||
            client.state = ClientState.Playing;
 | 
					            client.state = ClientState.Playing;
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            client.sendError("Invalid message.");
 | 
					            client.sendError("Invalid message.");
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        } else if(data instanceof RequestMessage) {
 | 
					    }
 | 
				
			||||||
            RequestMessage message = (RequestMessage) data;
 | 
					
 | 
				
			||||||
 | 
					    /** Handles a RequestMessage, and forwards it to the LobbyManager if valid */
 | 
				
			||||||
 | 
					    private void handleRequestsMessage(Client client, RequestMessage message) {
 | 
				
			||||||
 | 
					        Logger.trace("Handling RequestMessage");
 | 
				
			||||||
        if(client.state != ClientState.Playing) {
 | 
					        if(client.state != ClientState.Playing) {
 | 
				
			||||||
                client.sendError("Invalid message.");
 | 
					            Logger.debug("Couldn't handle RequestMessage as client wasn't in assignedState but in {}",
 | 
				
			||||||
 | 
					                    client.state);
 | 
				
			||||||
 | 
					                    client.sendError("Invalid message, as client is not ingame");
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Logger.trace("relaying message to be handled by the LobbyManager...");
 | 
				
			||||||
        if(LobbyManager.getInstance().handleRequests(client, message)) {
 | 
					        if(LobbyManager.getInstance().handleRequests(client, message)) {
 | 
				
			||||||
                //"👍 i approve" - the server
 | 
					            Logger.trace("Handled successfully");
 | 
				
			||||||
 | 
					            //"i approve" - the server
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
 | 
					            Logger.debug("Message couldn't be handled, sending error to client");
 | 
				
			||||||
            client.sendError("Invalid message.");
 | 
					            client.sendError("Invalid message.");
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Called when a client should be removed from the game.
 | 
				
			||||||
 | 
					     * @param client is the client to be removed
 | 
				
			||||||
 | 
					     * @param message is the message that is sent to the client in the accompanying {@link GoodbyeClientMessage}
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
    public void removeClient(Client client, String message) {
 | 
					    public void removeClient(Client client, String message) {
 | 
				
			||||||
        GoodbyeClientMessage response = new GoodbyeClientMessage();
 | 
					        GoodbyeClientMessage response = new GoodbyeClientMessage();
 | 
				
			||||||
        response.message = message;
 | 
					        response.message = message;
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user