refactor: major refactor for UserManager, and comments for LobbyManager

This commit is contained in:
Yannik Bretschneider 2021-06-07 14:51:38 +02:00
parent 3ea1cc6cf5
commit e40218b2cf
2 changed files with 178 additions and 82 deletions

View File

@ -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;

View File

@ -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;