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 4a50a01..c02e45f 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 @@ -5,9 +5,10 @@ import org.tinylog.Logger; import uulm.teamname.marvelous.gamelibrary.messages.BasicMessage; import uulm.teamname.marvelous.gamelibrary.messages.ParticipantType; import uulm.teamname.marvelous.gamelibrary.messages.RoleEnum; +import uulm.teamname.marvelous.gamelibrary.messages.client.CharacterSelectionMessage; import uulm.teamname.marvelous.gamelibrary.messages.client.PlayerReadyMessage; -import uulm.teamname.marvelous.gamelibrary.messages.server.GameAssignmentMessage; -import uulm.teamname.marvelous.server.Server; +import uulm.teamname.marvelous.gamelibrary.messages.client.RequestMessage; +import uulm.teamname.marvelous.gamelibrary.messages.server.EventMessage; import uulm.teamname.marvelous.server.lobby.Lobby; import java.util.HashMap; @@ -18,10 +19,15 @@ public class LobbyManager { private final HashMap lobbies; private final HashMap resourceDescriptorToLobby; private String localResourceDescriptor; + private final BiConsumer sendMessageCallback; + private final BiConsumer sendErrorCallback; - public LobbyManager() { + public LobbyManager(BiConsumer sendMessageCallback, + BiConsumer sendErrorCallback) { this.lobbies = new HashMap<>(); this.resourceDescriptorToLobby = new HashMap<>(); + this.sendMessageCallback = sendMessageCallback; + this.sendErrorCallback = sendErrorCallback; } /** @@ -31,10 +37,12 @@ public class LobbyManager { * to a lobby with a similar resourceDescriptor if the lobby they requested is already full * @param playerName is the name of the player be assigned to a lobby * @param message is the {@link PlayerReadyMessage} sent by the participant that triggered the LobbyAssignment + * @return the {@link Participant} that was actually assigned to the lobby */ - public void assignLobbyToParticipant(WebSocket connection, String playerName, PlayerReadyMessage message) { + public Participant assignLobbyToConnection(WebSocket connection, String playerName, PlayerReadyMessage message) { Logger.info("Assigning lobby to player '{}'", playerName); + // If no resourceDescriptor is given, generate new one var resourceDescriptor = connection.getResourceDescriptor(); if (resourceDescriptor == null || resourceDescriptor.length() == 0) { Logger.trace("Resource descriptor is null, getting local one"); @@ -42,21 +50,30 @@ public class LobbyManager { } LobbyConnection targetedLobby = resourceDescriptorToLobby.get(resourceDescriptor); + Participant participant; - if (targetedLobby == null || !targetedLobby.hasFreePlayerSpot()) { + // If lobby is filled, generate a new ResourceDescriptor + + if (targetedLobby == null) { + if (LobbyRunner.getInstance().canAddLobby()) { + Logger.info("Lobby '{}' is non-existent, initializing lobby...", resourceDescriptor); + targetedLobby = initializeNewLobby(resourceDescriptor); + } else { + Logger.info("No free lobby spot available, sending error and disconnecting Client"); + + } + + } else if (targetedLobby.isFull() && !message.role.equals(RoleEnum.SPECTATOR)) { + Logger.info("Lobby '{}' is already full, assigning player '{}' to new lobby", + resourceDescriptor, + playerName); + resourceDescriptor = getLocalResourceDescriptor(); Logger.info("Lobby '{}' is non-existent, initializing lobby...", resourceDescriptor); targetedLobby = initializeNewLobby(resourceDescriptor); - Logger.info("Adding mapping from resourceDescriptor {} to new lobby...", resourceDescriptor); - synchronized (resourceDescriptorToLobby) { - resourceDescriptorToLobby.put(resourceDescriptor, targetedLobby); - } } Logger.trace("Obtaining lock on targetedLobby '{}'", targetedLobby.gameID); synchronized (targetedLobby) { - - Participant participant; - Logger.debug("Assigning participant to lobby"); if (message.role.equals(RoleEnum.SPECTATOR)) { Logger.trace("Generating new participant with type spectator"); @@ -78,19 +95,60 @@ public class LobbyManager { } } - Logger.trace("Adding mapping from participant '{}' to lobby {}", + Logger.trace("Adding mapping from participant '{}' to lobby '{}'", participant.name, targetedLobby.gameID); synchronized (lobbies) { lobbies.put(participant, targetedLobby); } - Logger.trace("Relaying message to newly created Lobby"); - targetedLobby.receiveMessage(participant, message); + if (targetedLobby.isFull() && !LobbyRunner.getInstance().isStarted(targetedLobby)) { + Logger.info("Lobby '{}' was full, starting...", targetedLobby.gameID); + LobbyRunner.getInstance().startLobby(targetedLobby); + } } - + return participant; } + public void relayMessageToLobby(Participant origin, CharacterSelectionMessage message) { + var targetedLobby = lobbies.get(origin); + if (targetedLobby == null) { + Logger.warn("Tried to send character selection message to non-existent lobby. This is probably a bug."); + } else if (!targetedLobby.isActive()) { + Logger.info("Tried sending message to inactive lobby, sending error..."); + sendErrorCallback.accept(origin.getConnection(), "message could not be processed as " + + "lobby has not yet started as you are the only player in the lobby at the moment"); + } else { + targetedLobby.receiveMessage(origin, message); + } + } + + public void relayMessageToLobby(Participant origin, RequestMessage message) { + var targetedLobby = lobbies.get(origin); + if (targetedLobby == null) { + Logger.warn("Tried to send event message to non-existent lobby. This is probably a bug."); + } else if (!targetedLobby.isActive()) { + Logger.info("Tried sending message to inactive lobby, sending error..."); + sendErrorCallback.accept(origin.getConnection(), "message could not be processed as " + + "lobby has not yet started as you are the only player in the lobby at the moment"); + } else { + targetedLobby.receiveMessage(origin, message); + } + } + + /** + * Initializes a new {@link LobbyConnection} with a not yet initialized {@link Lobby}. The {@link LobbyConnection} + * gets some GameID, and also the sendMessageCallback and sendErrorCallback from the + * {@link uulm.teamname.marvelous.server.netconnector.UserManager}. + * @param gameID is the ID that the {@link LobbyConnection} is initialized with. This is normally + * the resourceDescriptor. + * @return the newly initialized LobbyConnection + */ private LobbyConnection initializeNewLobby(String gameID) { - return new LobbyConnection(gameID); + var lobby = new LobbyConnection(gameID, sendMessageCallback, sendErrorCallback); + Logger.debug("Adding mapping from gameID (resourceDescriptor) '{}' to new lobby...", gameID); + synchronized (resourceDescriptorToLobby) { + resourceDescriptorToLobby.put(gameID, lobby); + } + return lobby; } /** @@ -106,7 +164,7 @@ public class LobbyManager { } var lobby = resourceDescriptorToLobby.get(localResourceDescriptor); if (lobby != null) { - if (!lobby.hasFreePlayerSpot()) { + if (lobby.isFull()) { Logger.debug("Lobby is full, generating new local resourceDescriptor"); while (resourceDescriptorToLobby.get(localResourceDescriptor) != null) { localResourceDescriptor = RandomWordGenerator.generateTwoWords();