From f8aa2c9bf27d42beff188a50d9fb27a761aa788c Mon Sep 17 00:00:00 2001 From: punchready Date: Tue, 6 Jul 2021 12:59:37 +0200 Subject: [PATCH] fix: destroy lobbies properly after ended games and during grouping --- .../server/lobby/TurnTimeoutTimer.java | 2 +- .../server/lobbymanager/LobbyConnection.java | 2 + .../server/lobbymanager/LobbyManager.java | 138 ++++++++++-------- .../server/lobbymanager/LobbyRunner.java | 2 - .../marvelous/server/netconnector/SUID.java | 5 +- .../server/netconnector/UserManager.java | 2 +- 6 files changed, 80 insertions(+), 71 deletions(-) diff --git a/Server/src/main/java/uulm/teamname/marvelous/server/lobby/TurnTimeoutTimer.java b/Server/src/main/java/uulm/teamname/marvelous/server/lobby/TurnTimeoutTimer.java index 1e45eb8..32cc414 100644 --- a/Server/src/main/java/uulm/teamname/marvelous/server/lobby/TurnTimeoutTimer.java +++ b/Server/src/main/java/uulm/teamname/marvelous/server/lobby/TurnTimeoutTimer.java @@ -56,7 +56,7 @@ public class TurnTimeoutTimer { public void clear() { Logger.trace("Clearing timer"); if (this.current != null) { - current.cancel(false); + current.cancel(true); } } } diff --git a/Server/src/main/java/uulm/teamname/marvelous/server/lobbymanager/LobbyConnection.java b/Server/src/main/java/uulm/teamname/marvelous/server/lobbymanager/LobbyConnection.java index 1f6f004..0163f46 100644 --- a/Server/src/main/java/uulm/teamname/marvelous/server/lobbymanager/LobbyConnection.java +++ b/Server/src/main/java/uulm/teamname/marvelous/server/lobbymanager/LobbyConnection.java @@ -211,6 +211,8 @@ public class LobbyConnection implements Runnable { } public void terminate() { + LobbyRunner.getInstance().removeLobby(this); + LobbyManager.getInstance().removeLobby(gameID); state = LobbyConnectionState.Aborted; removeParticipant(player1); removeParticipant(player2); diff --git a/Server/src/main/java/uulm/teamname/marvelous/server/lobbymanager/LobbyManager.java b/Server/src/main/java/uulm/teamname/marvelous/server/lobbymanager/LobbyManager.java index af46382..3b104c0 100644 --- a/Server/src/main/java/uulm/teamname/marvelous/server/lobbymanager/LobbyManager.java +++ b/Server/src/main/java/uulm/teamname/marvelous/server/lobbymanager/LobbyManager.java @@ -38,15 +38,19 @@ public class LobbyManager { /** * Handles a newly connected Client, and returns whether the game is already running in the given {@link - * AtomicBoolean} + * AtomicBoolean}. */ public boolean handleConnect(Client client, AtomicBoolean running) { - if (participants.containsKey(client.getId())) { - LobbyConnection lobby = lobbies.get(participants.get(client.getId()).lobby); + Logger.debug("Connecting new client"); + + Participant participant = participants.get(client.getId()); + if (participant != null) { + LobbyConnection lobby = lobbies.get(participant.lobby); if (lobby != null) { running.set(lobby.state == LobbyConnectionState.Started); } } + return true; } @@ -56,6 +60,7 @@ public class LobbyManager { } addParticipant(client, client.socket.getResourceDescriptor(), message.role); + return true; } @@ -78,62 +83,6 @@ public class LobbyManager { return true; } - /** - * Adds a participant to a lobby. If the maximum amount of lobbies is already filled, or if the lobby requested - * isn't free, the participant is disconnected. - */ - private void addParticipant(Client client, String lobbyID, RoleEnum role) { - Logger.trace("Adding participant '{}' to the lobby '{}'", client.getId().getName(), lobbyID); - if (!lobbies.containsKey(lobbyID)) { - if (!LobbyRunner.getInstance().canAddLobby()) { - Logger.info("Rejecting participant '{}' as server is already full", client.getId().getName()); - UserManager.getInstance().removeClient(client, "The server has currently its maximum" + - "lobby number. Please connect as a spectator instead."); - return; - } - Logger.info("Lobby '{}' didn't exist yet, initializing", lobbyID); - lobbies.put(lobbyID, new LobbyConnection(lobbyID)); - } - - LobbyConnection lobby = lobbies.get(lobbyID); - - if (!lobby.hasFreePlayerSlot() && role != RoleEnum.SPECTATOR) { - Logger.debug("No free player slots available, disconnecting client '{}'", client.getId().getName()); - UserManager.getInstance() - .removeClient(client, "The lobby your requested is already full. " + - "Please connect as a spectator instead."); - return; - } - - ParticipantType type; - - if (role == RoleEnum.SPECTATOR) { - type = ParticipantType.Spectator; - } else { - type = lobby.freeSlot(); - } - - Logger.trace("New participant '{}' has the role '{}'", client.getId().getName(), type); - - Participant participant = new Participant(client, lobbyID, type); - participants.put(client.getId(), participant); - - lobby.addParticipant(participant); - - if (type != ParticipantType.Spectator) { - Logger.debug("Sending GameAssignment message to user '{}'", client.getId().getName()); - GameAssignmentMessage response = new GameAssignmentMessage(); - response.gameID = lobby.gameID; - response.characterSelection = lobby.options.get(type); - participant.sendMessage(response); - } else { - Logger.debug("Sending GeneralAssignment message to user '{}'", client.getId().getName()); - GeneralAssignmentMessage response = new GeneralAssignmentMessage(); - response.gameID = lobby.gameID; - participant.sendMessage(response); - } - } - /** * Handles a {@link CharacterSelectionMessage}, computes the characters that have been selected and relays that * information to the {@link LobbyConnection} concerned by this information. @@ -228,27 +177,90 @@ public class LobbyManager { } /** - * Handles the disconnect of a WebSocket. Note that this is not a leave from the game, but instead just that: - * a reconnectable disconnect. + * Handles the disconnect of a WebSocket. */ public void handleDisconnect(Client client, boolean byRemote) { Logger.trace("Handling disconnect of Client"); + if (!participants.containsKey(client.getId())) { return; } Participant participant = participants.get(client.getId()); - LobbyConnection lobby = lobbies.get(participant.lobby); if (lobby == null) { return; } - lobby.handleDisconnect(participant); + if(lobby.state == LobbyConnectionState.Started) { + lobby.handleDisconnect(participant); + + }else { + Logger.debug("Deleting participant after leaving a non-started lobby"); + participants.remove(client.getId()); + + if(lobby.hasFreePlayerSlot()) { + Logger.debug("Destroying lobby after last player left"); + lobby.terminate(); + lobbies.remove(participant.lobby); + } + } } + public void removeLobby(String lobbyID) { + lobbies.remove(lobbyID); + } + + /** + * Adds a participant to a lobby. If the maximum amount of lobbies is already filled, or if the lobby requested + * isn't free, the participant is disconnected. + */ + private void addParticipant(Client client, String lobbyID, RoleEnum role) { + Logger.trace("Adding participant '{}' to the lobby '{}'", client.getId(), lobbyID); + + if (!lobbies.containsKey(lobbyID)) { + if (!LobbyRunner.getInstance().canAddLobby()) { + Logger.info("Rejecting participant '{}' as server is already full", client.getId()); + UserManager.getInstance().removeClient(client, "The server is currently full. Please connect as a spectator instead."); + return; + } + Logger.info("Lobby '{}' didn't exist yet, initializing", lobbyID); + lobbies.put(lobbyID, new LobbyConnection(lobbyID)); + } + + LobbyConnection lobby = lobbies.get(lobbyID); + + if (!lobby.hasFreePlayerSlot() && role != RoleEnum.SPECTATOR) { + Logger.debug("No free player slots available, disconnecting client '{}'", client.getId()); + UserManager.getInstance().removeClient(client, "The lobby your requested is already full. Please connect as a spectator instead."); + return; + } + + ParticipantType type = lobby.freeSlot(); + + Logger.trace("New participant '{}' has the role '{}'", client.getId(), type); + + Participant participant = new Participant(client, lobbyID, type); + participants.put(client.getId(), participant); + + lobby.addParticipant(participant); + + if (type != ParticipantType.Spectator) { + Logger.debug("Sending GameAssignment message to user '{}'", client.getId()); + GameAssignmentMessage response = new GameAssignmentMessage(); + response.gameID = lobby.gameID; + response.characterSelection = lobby.options.get(type); + participant.sendMessage(response); + } else { + Logger.debug("Sending GeneralAssignment message to user '{}'", client.getId()); + GeneralAssignmentMessage response = new GeneralAssignmentMessage(); + response.gameID = lobby.gameID; + participant.sendMessage(response); + } + } + /** * Removes a participant from the game entirely. This is done when for example a player gets removed from the * Lobby because of a timeout. diff --git a/Server/src/main/java/uulm/teamname/marvelous/server/lobbymanager/LobbyRunner.java b/Server/src/main/java/uulm/teamname/marvelous/server/lobbymanager/LobbyRunner.java index 77bff62..91f15c7 100644 --- a/Server/src/main/java/uulm/teamname/marvelous/server/lobbymanager/LobbyRunner.java +++ b/Server/src/main/java/uulm/teamname/marvelous/server/lobbymanager/LobbyRunner.java @@ -4,7 +4,6 @@ import org.tinylog.Logger; import uulm.teamname.marvelous.server.Server; import java.util.HashMap; -import java.util.concurrent.Future; /** * Class meant for running lobbies. It manages said lobbies, creates threads for it, and moves it into an executor @@ -54,7 +53,6 @@ public class LobbyRunner { Logger.warn("Tried to remove non-existent lobby thread. This is probably a bug."); } else { Logger.debug("Stopping and removing lobby '{}'", lobby.gameID); - lobby.terminate(); activeLobbies.remove(lobby); } } diff --git a/Server/src/main/java/uulm/teamname/marvelous/server/netconnector/SUID.java b/Server/src/main/java/uulm/teamname/marvelous/server/netconnector/SUID.java index 5e2d29d..d0d20dd 100644 --- a/Server/src/main/java/uulm/teamname/marvelous/server/netconnector/SUID.java +++ b/Server/src/main/java/uulm/teamname/marvelous/server/netconnector/SUID.java @@ -35,9 +35,6 @@ public class SUID { @Override public String toString() { - return "SUID{" + - "name='" + name + '\'' + - ", deviceID='" + deviceID + '\'' + - '}'; + return name + "#" + deviceID; } } diff --git a/Server/src/main/java/uulm/teamname/marvelous/server/netconnector/UserManager.java b/Server/src/main/java/uulm/teamname/marvelous/server/netconnector/UserManager.java index 9bfaa1b..9f69e1c 100644 --- a/Server/src/main/java/uulm/teamname/marvelous/server/netconnector/UserManager.java +++ b/Server/src/main/java/uulm/teamname/marvelous/server/netconnector/UserManager.java @@ -44,7 +44,7 @@ public class UserManager { 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. */ public void connectUser(WebSocket conn) { Logger.debug("Connected new user"); synchronized(clients) {