feat: implemented UserManager message forwarding
This commit is contained in:
parent
e689248f9e
commit
7af0fd40a1
@ -8,15 +8,18 @@ import uulm.teamname.marvelous.gamelibrary.messages.ErrorMessage;
|
|||||||
import uulm.teamname.marvelous.gamelibrary.messages.client.*;
|
import uulm.teamname.marvelous.gamelibrary.messages.client.*;
|
||||||
import uulm.teamname.marvelous.gamelibrary.messages.server.HelloClientMessage;
|
import uulm.teamname.marvelous.gamelibrary.messages.server.HelloClientMessage;
|
||||||
import uulm.teamname.marvelous.server.Server;
|
import uulm.teamname.marvelous.server.Server;
|
||||||
|
import uulm.teamname.marvelous.server.lobbymanager.LobbyManager;
|
||||||
import uulm.teamname.marvelous.server.lobbymanager.Participant;
|
import uulm.teamname.marvelous.server.lobbymanager.Participant;
|
||||||
|
|
||||||
import org.java_websocket.WebSocket;
|
import org.java_websocket.WebSocket;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
/** Class that manages users. It is meant as an extension to the {@link MarvelousServer} class, and should not be called
|
/** Class that manages users. It is meant as an extension to the {@link MarvelousServer} class. This is the first
|
||||||
* from anywhere else. This is the first place where messages are relayed to after they get received. This class is
|
* 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>
|
* 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 {
|
public class UserManager {
|
||||||
|
|
||||||
@ -33,6 +36,10 @@ public class UserManager {
|
|||||||
return instance;
|
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 */
|
/** A set of users that aren't assigned to lobbies or character selection yet */
|
||||||
private final HashSet<WebSocket> newUsers;
|
private final HashSet<WebSocket> newUsers;
|
||||||
|
|
||||||
@ -64,12 +71,19 @@ public class UserManager {
|
|||||||
this.readyToReconnect = new HashMap<>();
|
this.readyToReconnect = new HashMap<>();
|
||||||
this.inGame = new HashMap<>();
|
this.inGame = new HashMap<>();
|
||||||
this.activeParticipants = 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());
|
this.json = new JSON(Server.getCharacterConfig());
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 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) {
|
||||||
newUsers.add(conn);
|
synchronized (newUsers) {
|
||||||
|
newUsers.add(conn);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -106,7 +120,15 @@ public class UserManager {
|
|||||||
} 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);
|
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");
|
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",
|
||||||
@ -186,13 +208,48 @@ public class UserManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void assignLobby(WebSocket conn, PlayerReadyMessage message) {
|
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) {
|
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) {
|
void disconnectUser(WebSocket conn, boolean closedByRemote) {
|
||||||
@ -200,22 +257,33 @@ public class UserManager {
|
|||||||
synchronized (newUsers) {
|
synchronized (newUsers) {
|
||||||
newUsers.remove(conn);
|
newUsers.remove(conn);
|
||||||
}
|
}
|
||||||
|
synchronized (readyToConnect) {
|
||||||
|
readyToConnect.remove(conn);
|
||||||
|
}
|
||||||
|
synchronized (readyToReconnect) {
|
||||||
|
readyToReconnect.remove(conn);
|
||||||
|
}
|
||||||
synchronized (inGame) {
|
synchronized (inGame) {
|
||||||
inGame.remove(conn);
|
inGame.remove(conn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sendMessage(WebSocket conn, BasicMessage message) {
|
void sendMessage(WebSocket conn, BasicMessage message) {
|
||||||
var jsonRepresentingMessage = json.stringify(message);
|
Logger.trace("Sending message to WebSocket {}", conn);
|
||||||
if (jsonRepresentingMessage.isEmpty()) {
|
if (conn == null) {
|
||||||
Logger.warn("Message {} could not be serialized!", message);
|
Logger.debug("Message sent to non-existent websocket, ignoring");
|
||||||
} else {
|
} else {
|
||||||
conn.send(jsonRepresentingMessage.get());
|
var jsonRepresentingMessage = json.stringify(message);
|
||||||
|
if (jsonRepresentingMessage.isEmpty()) {
|
||||||
|
Logger.warn("Message {} could not be serialized!", message);
|
||||||
|
} else {
|
||||||
|
conn.send(jsonRepresentingMessage.get());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Sends an {@link uulm.teamname.marvelous.gamelibrary.messages.ErrorMessage} to the specified user. */
|
/** 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);
|
Logger.debug("Sending error message '{}' to WebSocket {}", error, conn);
|
||||||
var errorMessage = new ErrorMessage();
|
var errorMessage = new ErrorMessage();
|
||||||
errorMessage.message = error;
|
errorMessage.message = error;
|
||||||
@ -230,6 +298,7 @@ public class UserManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public int getUserCount() {
|
public int getUserCount() {
|
||||||
|
// FIXME: This is bugged at the moment
|
||||||
return newUsers.size() + readyToConnect.size() + readyToReconnect.size() + inGame.size();
|
return newUsers.size() + readyToConnect.size() + readyToReconnect.size() + inGame.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user