feat: implemented UserManager message forwarding

This commit is contained in:
Yannik Bretschneider 2021-06-06 17:44:53 +02:00
parent e689248f9e
commit 7af0fd40a1

View File

@ -8,15 +8,18 @@ import uulm.teamname.marvelous.gamelibrary.messages.ErrorMessage;
import uulm.teamname.marvelous.gamelibrary.messages.client.*;
import uulm.teamname.marvelous.gamelibrary.messages.server.HelloClientMessage;
import uulm.teamname.marvelous.server.Server;
import uulm.teamname.marvelous.server.lobbymanager.LobbyManager;
import uulm.teamname.marvelous.server.lobbymanager.Participant;
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>
/** Class that manages users. It is meant as an extension to the {@link MarvelousServer} class. 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.
* It is designed to be thread-safe. The Singleton of this class also contains a
* {@link LobbyManager}, which manages the lobbys.
*/
public class UserManager {
@ -33,6 +36,10 @@ public class UserManager {
return instance;
}
/** The {@link LobbyManager} associated with the {@link UserManager}. It is therefore a kind of extension
* to the current singleton, and may of course not be called from anywhere else */
private final LobbyManager lobbyManager;
/** A set of users that aren't assigned to lobbies or character selection yet */
private final HashSet<WebSocket> newUsers;
@ -64,13 +71,20 @@ public class UserManager {
this.readyToReconnect = new HashMap<>();
this.inGame = new HashMap<>();
this.activeParticipants = new HashMap<>();
Logger.trace("Instantiating LobbyManager with message sending callbacks");
this.lobbyManager = new LobbyManager(this::sendMessage, this::sendError);
Logger.trace("Instantiating JSON with the server's CharacterConfig");
this.json = new JSON(Server.getCharacterConfig());
}
/** Called on a new WebSocket connection. Places the WebSocket and its ResourceDescriptor in a HashMap. */
void connectUser(WebSocket conn) {
synchronized (newUsers) {
newUsers.add(conn);
}
}
/**
* Called on any received messages. The method checks the message for validity, and then relays it
@ -106,7 +120,15 @@ public class UserManager {
} else if (parsedMessage instanceof PlayerReadyMessage) {
Logger.trace("Message is instanceof PlayerReadyMessage, assigning lobby");
assignLobby(conn, (PlayerReadyMessage) parsedMessage);
} else {
} 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 {
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",
@ -186,13 +208,48 @@ public class UserManager {
}
void assignLobby(WebSocket conn, PlayerReadyMessage message) {
// TODO: Assign a lobby
if (readyToReconnect.containsKey(conn) || readyToConnect.containsKey(conn)) {
if (readyToConnect.containsKey(conn)) {
synchronized (readyToConnect) {
readyToConnect.remove(conn);
}
} else {
synchronized (readyToReconnect) {
readyToReconnect.remove(conn);
}
}
synchronized (inGame) {
var participant = lobbyManager.assignLobbyToConnection(conn, "SomeName", message);
inGame.put(conn, 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");
}
}
void charactersSelected(WebSocket conn, CharacterSelectionMessage message) {
if (inGame.containsKey(conn)) {
lobbyManager.relayMessageToLobby(inGame.get(conn), message);
} else {
Logger.debug(
"WebSocket {} sent CharacterSelectionMessage to server while not ingame, sending error",
conn);
sendError(conn, "Invalid message, as client is not ingame");
}
}
void relayRequestMessage(Participant conn, RequestMessage message) {
void relayRequestMessage(WebSocket conn, RequestMessage message) {
if (inGame.containsKey(conn)) {
lobbyManager.relayMessageToLobby(inGame.get(conn), message);
} else {
Logger.debug(
"WebSocket {} sent RequestMessage to server while not ingame, sending error",
conn);
sendError(conn, "Invalid message, as client is not ingame");
}
}
void disconnectUser(WebSocket conn, boolean closedByRemote) {
@ -200,12 +257,22 @@ public class UserManager {
synchronized (newUsers) {
newUsers.remove(conn);
}
synchronized (readyToConnect) {
readyToConnect.remove(conn);
}
synchronized (readyToReconnect) {
readyToReconnect.remove(conn);
}
synchronized (inGame) {
inGame.remove(conn);
}
}
public void sendMessage(WebSocket conn, BasicMessage message) {
void sendMessage(WebSocket conn, BasicMessage message) {
Logger.trace("Sending message to WebSocket {}", conn);
if (conn == null) {
Logger.debug("Message sent to non-existent websocket, ignoring");
} else {
var jsonRepresentingMessage = json.stringify(message);
if (jsonRepresentingMessage.isEmpty()) {
Logger.warn("Message {} could not be serialized!", message);
@ -213,9 +280,10 @@ public class UserManager {
conn.send(jsonRepresentingMessage.get());
}
}
}
/** Sends an {@link uulm.teamname.marvelous.gamelibrary.messages.ErrorMessage} to the specified user. */
public void sendError(WebSocket conn, String error) {
void sendError(WebSocket conn, String error) {
Logger.debug("Sending error message '{}' to WebSocket {}", error, conn);
var errorMessage = new ErrorMessage();
errorMessage.message = error;
@ -230,6 +298,7 @@ public class UserManager {
}
public int getUserCount() {
// FIXME: This is bugged at the moment
return newUsers.size() + readyToConnect.size() + readyToReconnect.size() + inGame.size();
}