feat: improved UserManager

This commit is contained in:
Yannik Bretschneider 2021-06-07 01:45:51 +02:00
parent 0f559d09a5
commit 9e894a370e

View File

@ -1,5 +1,6 @@
package uulm.teamname.marvelous.server.netconnector; package uulm.teamname.marvelous.server.netconnector;
import org.java_websocket.framing.CloseFrame;
import org.tinylog.Logger; 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;
@ -114,21 +115,23 @@ public class UserManager {
if (parsedMessage instanceof HelloServerMessage) { if (parsedMessage instanceof HelloServerMessage) {
Logger.trace("Message is instanceof HelloServerMessage, initiating handshake"); Logger.trace("Message is instanceof HelloServerMessage, initiating handshake");
handshake(conn, (HelloServerMessage) parsedMessage); handshake(conn, (HelloServerMessage) parsedMessage);
} else if (parsedMessage instanceof ReconnectMessage) { } else if (parsedMessage instanceof ReconnectMessage) {
Logger.trace("Message is instanceof ReconnectMessage, initiating reconnect"); Logger.trace("Message is instanceof ReconnectMessage, initiating reconnect");
reconnectClient(conn, (ReconnectMessage) parsedMessage); reconnectClient(conn, (ReconnectMessage) parsedMessage);
} else if (parsedMessage instanceof PlayerReadyMessage) { } else if (parsedMessage instanceof PlayerReadyMessage) {
Logger.trace("Message is instanceof PlayerReadyMessage, assigning lobby"); Logger.trace("Message is instanceof PlayerReadyMessage, assigning lobby");
assignLobby(conn, (PlayerReadyMessage) parsedMessage); playerReady(conn, (PlayerReadyMessage) parsedMessage);
} else if (parsedMessage instanceof CharacterSelectionMessage) { } else if (parsedMessage instanceof CharacterSelectionMessage) {
Logger.trace("Message is instanceof CharacterSelectionMessage, passing to LobbyConnection"); Logger.trace("Message is instanceof CharacterSelectionMessage, passing to LobbyConnection");
charactersSelected(conn, (CharacterSelectionMessage) parsedMessage); charactersSelected(conn, (CharacterSelectionMessage) parsedMessage);
} else if (parsedMessage instanceof RequestMessage) { } else if (parsedMessage instanceof RequestMessage) {
Logger.trace("Message is instanceof RequestMessage, passing to LobbyConnection"); Logger.trace("Message is instanceof RequestMessage, passing to LobbyConnection");
relayRequestMessage(conn, (RequestMessage) parsedMessage); relayRequestMessage(conn, (RequestMessage) parsedMessage);
} } else {
else {
Logger.debug("Message '{}' has invalid type, Error will be sent"); Logger.debug("Message '{}' has invalid type, Error will be sent");
sendError(conn, String.format( sendError(conn, String.format(
"Message '%s' has invalid type, and cannot be processed on the server", "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 clientID = readyToReconnect.get(conn);
var participantToRestore = activeParticipants.get(clientID); var participantToRestore = activeParticipants.get(clientID);
participantToRestore.setConnection(conn); lobbyManager.restoreConnection(conn, participantToRestore);
synchronized (readyToReconnect) { synchronized (readyToReconnect) {
readyToReconnect.remove(conn); readyToReconnect.remove(conn);
@ -190,10 +193,10 @@ public class UserManager {
synchronized (inGame) { synchronized (inGame) {
inGame.put(conn, participantToRestore); inGame.put(conn, participantToRestore);
} }
lobbyManager.restoreConnection(conn, participantToRestore);
// activeParticipants remains the same, as no players have been removed from the game // activeParticipants remains the same, as no players have been removed from the game
} else { } else {
Logger.debug( Logger.debug("Client {} refused reconnection, will therefore be put into readyToConnect clients",
"Client {} refused reconnection, will therefore be put into readyToConnect clients",
conn); conn);
var clientID = readyToReconnect.get(conn); var clientID = readyToReconnect.get(conn);
@ -207,26 +210,40 @@ public class UserManager {
} }
} }
void assignLobby(WebSocket conn, PlayerReadyMessage message) { void playerReady(WebSocket conn, PlayerReadyMessage message) {
if (readyToReconnect.containsKey(conn) || readyToConnect.containsKey(conn)) { 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)) { if (readyToConnect.containsKey(conn)) {
Logger.trace("Client in readyToConnect state, removing from list");
synchronized (readyToConnect) { synchronized (readyToConnect) {
suid = readyToConnect.get(conn);
readyToConnect.remove(conn); readyToConnect.remove(conn);
} }
} else { } else {
Logger.trace("Client in readyToReconnect state, removing from list");
synchronized (readyToReconnect) { synchronized (readyToReconnect) {
suid = readyToReconnect.get(conn);
readyToReconnect.remove(conn); readyToReconnect.remove(conn);
} }
} }
Participant participant;
Logger.trace("Letting LobbyManager assign lobby to client");
synchronized (inGame) { synchronized (inGame) {
var participant = lobbyManager.assignLobbyToConnection(conn, "SomeName", message); participant = lobbyManager.assignLobbyToConnection(conn, suid.getName(), message);
inGame.put(conn, participant); inGame.put(conn, participant);
} }
Logger.trace("Adding participants to activeParticipants for reconnection possibilities");
synchronized (activeParticipants) {
activeParticipants.put(suid, participant);
}
} else { } else {
Logger.debug( Logger.debug(
"WebSocket {} sent PlayerReadyMessage to server while not ready to connect, sending error", "WebSocket {} sent PlayerReadyMessage to server while not in connection ready state, " +
conn); "sending error", conn);
sendError(conn, "Invalid message, as client is not ready to connect"); 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) { void disconnectUser(WebSocket conn, boolean closedByRemote) {
// TODO: notify clients and such if the connection was in fact closed by the remote. Also remove participant // TODO: notify clients and such if the connection was in fact closed by the remote. Also remove participant
synchronized (newUsers) { synchronized (newUsers) {