feat: partially implemented GameAssignment
This commit is contained in:
		@ -12,32 +12,29 @@ public class MarvelousServer extends WebSocketServer {
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onOpen(WebSocket conn, ClientHandshake handshake) {
 | 
			
		||||
        Logger.info("New client connected. Adding new User.");
 | 
			
		||||
        userManager.connectUser(conn, handshake);
 | 
			
		||||
        // TODO: Send messages to UserManager, which then packages that stuff and sends it further
 | 
			
		||||
        userManager.connectUser(conn);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onClose(WebSocket conn, int code, String reason, boolean remote) {
 | 
			
		||||
        Logger.info("Client disconnected");
 | 
			
		||||
        userManager.disconnectUser(conn, remote);
 | 
			
		||||
        // TODO: Send messages to UserManager, which then removes the user and such
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onMessage(WebSocket conn, String message) {
 | 
			
		||||
        Logger.debug("Message received: {}", message);
 | 
			
		||||
        userManager.messageReceived(conn, message);
 | 
			
		||||
        // TODO: Send messages to UserManager, which then packages them and sends them further
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onError(WebSocket conn, Exception ex) {
 | 
			
		||||
        // TODO: Send errors to UserManager, which then answers with even more errors
 | 
			
		||||
        Logger.warn("WebSocket-Error occurred: {}", ex.getMessage());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onStart() {
 | 
			
		||||
        // TODO: Get the UserManager, and tell it that this thing is active
 | 
			
		||||
        Logger.info("MarvelousServer started on Address {}", this.getAddress().toString());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private final UserManager userManager;
 | 
			
		||||
 | 
			
		||||
@ -1,9 +1,8 @@
 | 
			
		||||
package uulm.teamname.marvelous.server.netconnector;
 | 
			
		||||
 | 
			
		||||
import org.java_websocket.handshake.ClientHandshake;
 | 
			
		||||
import org.tinylog.Logger;
 | 
			
		||||
import uulm.teamname.marvelous.gamelibrary.json.JSON;
 | 
			
		||||
import uulm.teamname.marvelous.gamelibrary.messages.BasicMessage;
 | 
			
		||||
import uulm.teamname.marvelous.gamelibrary.json.ValidationUtility;
 | 
			
		||||
import uulm.teamname.marvelous.gamelibrary.messages.ErrorMessage;
 | 
			
		||||
import uulm.teamname.marvelous.gamelibrary.messages.client.*;
 | 
			
		||||
import uulm.teamname.marvelous.server.lobbymanager.Participant;
 | 
			
		||||
@ -12,13 +11,17 @@ import org.java_websocket.WebSocket;
 | 
			
		||||
 | 
			
		||||
import java.util.*;
 | 
			
		||||
 | 
			
		||||
/** Class that manages users. It is meant as an extension to the {@link MarvelousServer} class, and should not be called
 | 
			
		||||
 * from anywhere else. This is the first place where messages are relayed to after they get received. This class is
 | 
			
		||||
 * responsible for handshakes, reconnects and WebSocket-to-Participant matching. <b>It is not thread-safe.</b>
 | 
			
		||||
 */
 | 
			
		||||
public class UserManager {
 | 
			
		||||
 | 
			
		||||
    /** A set of users that aren't assigned to lobbies or character selection yet */
 | 
			
		||||
    private final HashSet<WebSocket> newUsers;
 | 
			
		||||
 | 
			
		||||
    /** A set of users that can reconnect if they wish to do so, and their matching Participants */
 | 
			
		||||
    private final HashMap<WebSocket, Participant> readyToReconnect;
 | 
			
		||||
    private final HashMap<WebSocket, SUID> readyToReconnect;
 | 
			
		||||
 | 
			
		||||
    /** A set of users that only have to send the
 | 
			
		||||
     * {@link uulm.teamname.marvelous.gamelibrary.messages.client.PlayerReadyMessage} to be assigned
 | 
			
		||||
@ -49,24 +52,51 @@ public class UserManager {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Called on a new WebSocket connection. Places the WebSocket and its ResourceDescriptor in a HashMap. */
 | 
			
		||||
    public void connectUser(WebSocket conn, ClientHandshake handshake) {
 | 
			
		||||
        synchronized (newUsers) {
 | 
			
		||||
            newUsers.add(conn);
 | 
			
		||||
        }
 | 
			
		||||
    public void connectUser(WebSocket conn) {
 | 
			
		||||
        newUsers.add(conn);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Called on any received messages. The method checks the message for validity, and then relays it
 | 
			
		||||
     * accordingly. {@link HelloServerMessage HelloServerMessages} and {@link ReconnectMessage ReconnectMessages}
 | 
			
		||||
     * are handled in this component, whereby a handshake or reconnect is performed, respectively.
 | 
			
		||||
     * @param conn is the {@link WebSocket} that sent the message
 | 
			
		||||
     * @param message is the {@link String} sent by the connection
 | 
			
		||||
     */
 | 
			
		||||
    public void messageReceived(WebSocket conn, String message) {
 | 
			
		||||
        // TODO: Implement more than only a basic handshake
 | 
			
		||||
 | 
			
		||||
        Logger.trace("Parsing message...");
 | 
			
		||||
        var parsedMessageOptional = json.parse(message);
 | 
			
		||||
        if (parsedMessageOptional.isEmpty()) {
 | 
			
		||||
            Logger.debug("Invalid message '{}' received, sending error", message);
 | 
			
		||||
            Logger.debug("Message '{}' was invalid, sending error", message);
 | 
			
		||||
            sendError(conn, "Message could not be parsed");
 | 
			
		||||
        } else {
 | 
			
		||||
            var parsedMessage = parsedMessageOptional.get();
 | 
			
		||||
 | 
			
		||||
            if (parsedMessage instanceof HelloServerMessage)
 | 
			
		||||
                 handshake(conn, (HelloServerMessage) parsedMessage);
 | 
			
		||||
            Logger.trace("Validating message...");
 | 
			
		||||
            var violations = ValidationUtility.validate(parsedMessage);
 | 
			
		||||
 | 
			
		||||
            if (violations.isPresent()) {
 | 
			
		||||
                Logger.debug("Message '{}' was invalid: {}, sending error", message, violations.get());
 | 
			
		||||
                sendError(conn, violations.get());
 | 
			
		||||
            } else {
 | 
			
		||||
                Logger.trace("Message was valid. Checking type of message...");
 | 
			
		||||
 | 
			
		||||
                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);
 | 
			
		||||
                } 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",
 | 
			
		||||
                            message));
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -85,7 +115,7 @@ public class UserManager {
 | 
			
		||||
        var participant = activeParticipants.get(clientID);
 | 
			
		||||
        if (participant != null) {
 | 
			
		||||
            synchronized (readyToReconnect) {
 | 
			
		||||
                readyToReconnect.put(conn, participant);
 | 
			
		||||
                readyToReconnect.put(conn, clientID);
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            Logger.trace("removing handshaking user from newUsers");
 | 
			
		||||
@ -99,33 +129,37 @@ public class UserManager {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void reconnectClient(WebSocket conn, ReconnectMessage message) {
 | 
			
		||||
        if (!readyToConnect.containsKey(conn)) {
 | 
			
		||||
    void reconnectClient(WebSocket conn, ReconnectMessage message) {
 | 
			
		||||
        if (!readyToReconnect.containsKey(conn)) {
 | 
			
		||||
            Logger.debug("Non-reconnect-allowed client has sent reconnect message, sending error");
 | 
			
		||||
            sendError(conn, "Reconnect is not possible");
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        Logger.info("Reconnecting client {} to their lobby");
 | 
			
		||||
        var participantToRestore = readyToReconnect.get(conn);
 | 
			
		||||
        synchronized (participantToRestore) {
 | 
			
		||||
        } else if (message.reconnect) {
 | 
			
		||||
            Logger.info("Reconnecting client {} to their lobby", conn);
 | 
			
		||||
            var clientID = readyToReconnect.get(conn);
 | 
			
		||||
            var participantToRestore = activeParticipants.get(clientID);
 | 
			
		||||
 | 
			
		||||
            participantToRestore.setConnection(conn);
 | 
			
		||||
        }
 | 
			
		||||
        synchronized (readyToReconnect) {
 | 
			
		||||
            readyToReconnect.remove(conn);
 | 
			
		||||
            inGame.put(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",
 | 
			
		||||
                    conn);
 | 
			
		||||
 | 
			
		||||
            var clientID = readyToReconnect.get(conn);
 | 
			
		||||
            readyToConnect.put(conn, clientID);
 | 
			
		||||
            readyToReconnect.remove(conn);
 | 
			
		||||
        }
 | 
			
		||||
        synchronized (inGame) {
 | 
			
		||||
            inGame.put(conn, participantToRestore);
 | 
			
		||||
        }
 | 
			
		||||
        // activeParticipants remains the same, as no players have been removed from the game
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void assignLobby(WebSocket conn, PlayerReadyMessage message) {
 | 
			
		||||
    void assignLobby(WebSocket conn, PlayerReadyMessage message) {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void charactersSelected(WebSocket conn, CharacterSelectionMessage message) {
 | 
			
		||||
    void charactersSelected(WebSocket conn, CharacterSelectionMessage message) {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void relayRequestMessage(Participant conn, RequestMessage message) {
 | 
			
		||||
    void relayRequestMessage(Participant conn, RequestMessage message) {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Sends an {@link uulm.teamname.marvelous.gamelibrary.messages.ErrorMessage} to the specified user. */
 | 
			
		||||
@ -158,26 +192,31 @@ public class UserManager {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Package-private getter for mutable newUsers HashSet, meant for testing */
 | 
			
		||||
    @Deprecated
 | 
			
		||||
    HashSet<WebSocket> getNewUsers() {
 | 
			
		||||
        return newUsers;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Package-private getter for mutable readyToReconnect HashMap, meant for testing */
 | 
			
		||||
    HashMap<WebSocket, Participant> getReadyToReconnect() {
 | 
			
		||||
    @Deprecated
 | 
			
		||||
    HashMap<WebSocket, SUID> getReadyToReconnect() {
 | 
			
		||||
        return readyToReconnect;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Package-private getter for mutable readyToConnect HashMap, meant for testing */
 | 
			
		||||
    @Deprecated
 | 
			
		||||
    HashMap<WebSocket, SUID> getReadyToConnect() {
 | 
			
		||||
        return readyToConnect;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Package-private getter for mutable inGame HashMap, meant for testing */
 | 
			
		||||
    @Deprecated
 | 
			
		||||
    HashMap<WebSocket, Participant> getInGame() {
 | 
			
		||||
        return inGame;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Package-private getter for mutable activeParticipants HashMap, meant for testing */
 | 
			
		||||
    @Deprecated
 | 
			
		||||
    HashMap<SUID, Participant> getActiveParticipants() {
 | 
			
		||||
        return activeParticipants;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user