feat: implemented lobby creation and general management
This commit is contained in:
parent
8b2805fcf1
commit
e7a8f0e1e4
@ -2,20 +2,28 @@ package uulm.teamname.marvelous.server.lobbymanager;
|
||||
|
||||
import org.java_websocket.WebSocket;
|
||||
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.PlayerReadyMessage;
|
||||
import uulm.teamname.marvelous.gamelibrary.messages.server.GameAssignmentMessage;
|
||||
import uulm.teamname.marvelous.server.Server;
|
||||
import uulm.teamname.marvelous.server.lobby.Lobby;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
public class LobbyManager {
|
||||
private final HashMap<Participant, LobbyConnection> lobbies;
|
||||
private final HashMap<String, LobbyConnection> resourceDescriptorToLobby;
|
||||
private final BiConsumer<Participant, BasicMessage> sendMessageCallback;
|
||||
private String localResourceDescriptor;
|
||||
|
||||
public LobbyManager() {
|
||||
public LobbyManager(BiConsumer<Participant, BasicMessage> sendMessageCallback) {
|
||||
this.sendMessageCallback = sendMessageCallback;
|
||||
this.lobbies = new HashMap<>();
|
||||
this.resourceDescriptorToLobby = new HashMap<>();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -30,10 +38,86 @@ public class LobbyManager {
|
||||
Logger.info("Assigning lobby to player '{}'", playerName);
|
||||
|
||||
var resourceDescriptor = connection.getResourceDescriptor();
|
||||
if (resourceDescriptor.length() == 0) {
|
||||
// TODO: generate new ResourceDescriptor
|
||||
if (resourceDescriptor == null || resourceDescriptor.length() == 0) {
|
||||
Logger.trace("Resource descriptor is null, getting local one");
|
||||
resourceDescriptor = getLocalResourceDescriptor();
|
||||
}
|
||||
|
||||
LobbyConnection targetedLobby = resourceDescriptorToLobby.get(resourceDescriptor);
|
||||
|
||||
if (targetedLobby == null || !targetedLobby.hasFreePlayerSpot()) {
|
||||
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");
|
||||
participant = new Participant(connection, ParticipantType.Spectator, playerName);
|
||||
targetedLobby.addSpectator(participant);
|
||||
|
||||
} else {
|
||||
Logger.trace("Checking whether Player1 or Player2 spot is free in lobby '{}'",
|
||||
targetedLobby.gameID);
|
||||
var participantType =
|
||||
!targetedLobby.hasPlayer1()
|
||||
? ParticipantType.PlayerOne
|
||||
: ParticipantType.PlayerTwo;
|
||||
|
||||
Logger.trace("Generating new participant with type {}", participantType);
|
||||
participant = new Participant(connection, participantType, playerName);
|
||||
if (!targetedLobby.addPlayer(participant)) {
|
||||
Logger.warn("Participant could not be added to lobby. This is probably a bug.");
|
||||
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private LobbyConnection initializeNewLobby(String gameID) {
|
||||
return new LobbyConnection(gameID, sendMessageCallback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the local resource descriptor if it is pointing to a not yet filled lobby (joinable lobby), or
|
||||
* generates a new one if the lobby described by the resourceDescriptor is full already
|
||||
*/
|
||||
private String getLocalResourceDescriptor() {
|
||||
Logger.trace("Getting local resourceDescriptor. Currently this is '{}'", localResourceDescriptor);
|
||||
if (localResourceDescriptor == null) {
|
||||
Logger.trace("local resourceDescriptor is null. Initializing local resourceDescriptor...");
|
||||
localResourceDescriptor = RandomWordGenerator.generateTwoWords();
|
||||
Logger.debug("Local resoucrceDescriptor initialized as '{}'", localResourceDescriptor);
|
||||
}
|
||||
var lobby = resourceDescriptorToLobby.get(localResourceDescriptor);
|
||||
if (lobby != null) {
|
||||
if (!lobby.hasFreePlayerSpot()) {
|
||||
Logger.debug("Lobby is full, generating new local resourceDescriptor");
|
||||
while (resourceDescriptorToLobby.get(localResourceDescriptor) != null) {
|
||||
localResourceDescriptor = RandomWordGenerator.generateTwoWords();
|
||||
}
|
||||
Logger.debug("New resourceDescriptor is '{}'", localResourceDescriptor);
|
||||
}
|
||||
}
|
||||
Logger.trace("Returning local resourceDescriptor");
|
||||
return localResourceDescriptor;
|
||||
|
||||
}
|
||||
|
||||
@ -42,4 +126,13 @@ public class LobbyManager {
|
||||
Map<Participant, LobbyConnection> getLobbies() {
|
||||
return lobbies;
|
||||
}
|
||||
|
||||
/**
|
||||
* A method to obtain the resourceDescriptorToLobby HashMap.
|
||||
* Meant for testing, and shouldn't be used anywhere else.
|
||||
*/
|
||||
@Deprecated
|
||||
Map<String, LobbyConnection> getResourceDescriptorToLobby() {
|
||||
return resourceDescriptorToLobby;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,195 @@
|
||||
package uulm.teamname.marvelous.server.lobbymanager;
|
||||
|
||||
import org.java_websocket.WebSocket;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.MockedStatic;
|
||||
import org.mockito.Mockito;
|
||||
import uulm.teamname.marvelous.gamelibrary.config.FieldType;
|
||||
import uulm.teamname.marvelous.gamelibrary.config.ScenarioConfig;
|
||||
import uulm.teamname.marvelous.gamelibrary.messages.ParticipantType;
|
||||
import uulm.teamname.marvelous.gamelibrary.messages.RoleEnum;
|
||||
import uulm.teamname.marvelous.gamelibrary.messages.client.PlayerReadyMessage;
|
||||
import uulm.teamname.marvelous.server.Server;
|
||||
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.mockito.Mockito.*;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
class LobbyManagerTest {
|
||||
|
||||
LobbyManager manager;
|
||||
WebSocket player1;
|
||||
WebSocket player2;
|
||||
WebSocket player3;
|
||||
WebSocket spectator;
|
||||
|
||||
PlayerReadyMessage playerReady;
|
||||
PlayerReadyMessage spectatorReady;
|
||||
PlayerReadyMessage aiReady;
|
||||
|
||||
Participant player1Participant;
|
||||
Participant player2Participant;
|
||||
Participant player3Participant;
|
||||
|
||||
@BeforeEach
|
||||
void beforeEach() {
|
||||
manager = new LobbyManager();
|
||||
|
||||
player1 = mock(WebSocket.class);
|
||||
player2 = mock(WebSocket.class);
|
||||
player3 = mock(WebSocket.class);
|
||||
spectator = mock(WebSocket.class);
|
||||
|
||||
playerReady = new PlayerReadyMessage();
|
||||
playerReady.role = RoleEnum.PLAYER;
|
||||
|
||||
spectatorReady = new PlayerReadyMessage();
|
||||
spectatorReady.role = RoleEnum.SPECTATOR;
|
||||
|
||||
aiReady = new PlayerReadyMessage();
|
||||
aiReady.role = RoleEnum.KI;
|
||||
|
||||
player1Participant = new Participant(
|
||||
player1,
|
||||
ParticipantType.PlayerOne,
|
||||
"AwesomePlayer");
|
||||
player2Participant = new Participant(
|
||||
player2,
|
||||
ParticipantType.PlayerTwo,
|
||||
"MoreAwesomePlayer");
|
||||
player3Participant = new Participant(
|
||||
player3,
|
||||
ParticipantType.PlayerOne,
|
||||
"AwesomestAwesomePlayer");
|
||||
}
|
||||
|
||||
@Test
|
||||
void lobbyManagerGetsCreatedEmpty() {
|
||||
assertThat(manager.getLobbies()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("When a participant is added, a new Lobby is created")
|
||||
void lobbyCreationTest() {
|
||||
var message = new PlayerReadyMessage();
|
||||
message.role = RoleEnum.PLAYER;
|
||||
|
||||
assertThat(manager.getLobbies()).isEmpty();
|
||||
|
||||
when(player1.getResourceDescriptor()).thenReturn("/ResourcesFTW");
|
||||
|
||||
manager.assignLobbyToParticipant(player1, "AwesomePlayer", message);
|
||||
|
||||
Participant player1Participant = new Participant(player1, ParticipantType.PlayerOne, "AwesomePlayer");
|
||||
|
||||
assertThat(manager.getLobbies()).containsOnlyKeys(player1Participant);
|
||||
assertThat(manager.getLobbies().get(player1Participant)).isNotNull();
|
||||
assertThat(manager.getLobbies().get(player1Participant).getPlayer1()).isEqualTo(player1Participant);
|
||||
|
||||
assertThat(manager.getResourceDescriptorToLobby()).containsOnlyKeys("/ResourcesFTW");
|
||||
assertThat(manager.getResourceDescriptorToLobby().get("/ResourcesFTW"))
|
||||
.isEqualTo(manager.getLobbies().get(player1Participant))
|
||||
.isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("when two participants with same ResourceDescriptor connect, they get assigned to the same lobby")
|
||||
void twoParticipantsSameLobbyTest() {
|
||||
|
||||
|
||||
|
||||
when(player1.getResourceDescriptor()).thenReturn("/fancyResourceDescriptor");
|
||||
when(player2.getResourceDescriptor()).thenReturn("/fancyResourceDescriptor");
|
||||
|
||||
manager.assignLobbyToParticipant(player1, "AwesomePlayer", playerReady);
|
||||
manager.assignLobbyToParticipant(player2, "MoreAwesomePlayer", playerReady);
|
||||
|
||||
Participant player1Participant = new Participant(
|
||||
player1, ParticipantType.PlayerOne, "AwesomePlayer");
|
||||
|
||||
Participant player2Participant = new Participant(
|
||||
player2, ParticipantType.PlayerTwo, "MoreAwesomePlayer");
|
||||
|
||||
assertThat(manager.getLobbies()).containsOnlyKeys(player1Participant, player2Participant);
|
||||
assertThat(manager.getLobbies().get(player1Participant))
|
||||
.isEqualTo(manager.getLobbies().get(player2Participant))
|
||||
.isNotNull();
|
||||
|
||||
assertThat(manager.getResourceDescriptorToLobby()).containsOnlyKeys("/fancyResourceDescriptor");
|
||||
assertThat(manager.getResourceDescriptorToLobby().get("/fancyResourceDescriptor"))
|
||||
.isEqualTo(manager.getLobbies().get(player1Participant))
|
||||
.isEqualTo(manager.getLobbies().get(player2Participant))
|
||||
.isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("On Participant without ResourceDescriptor random lobby gets generated")
|
||||
void randomLobbyTest() {
|
||||
when(player1.getResourceDescriptor()).thenReturn(null);
|
||||
|
||||
manager.assignLobbyToParticipant(player1, "AwesomePlayer", playerReady);
|
||||
|
||||
assertThat(manager.getLobbies()).hasSize(1);
|
||||
assertThat(manager.getLobbies().get(player1Participant)).isNotNull();
|
||||
assertThat(manager.getLobbies().get(player1Participant).gameID).isNotNull();
|
||||
|
||||
assertThat(manager.getResourceDescriptorToLobby()).hasSize(1);
|
||||
assertThat(manager.getResourceDescriptorToLobby().get(manager.getLobbies().get(player1Participant).gameID))
|
||||
.isNotNull()
|
||||
.isEqualTo(manager.getLobbies().get(player1Participant));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("When two people without ResourceDescriptor join, they get allocated to the same lobby")
|
||||
void randomLobbyTwoPlayerTest() {
|
||||
when(player1.getResourceDescriptor()).thenReturn(null);
|
||||
when(player2.getResourceDescriptor()).thenReturn(null);
|
||||
manager.assignLobbyToParticipant(player1, "AwesomePlayer", playerReady);
|
||||
manager.assignLobbyToParticipant(player2, "MoreAwesomePlayer", playerReady);
|
||||
|
||||
assertThat(manager.getLobbies()).hasSize(2);
|
||||
assertThat(manager.getLobbies().get(player1Participant))
|
||||
.isNotNull()
|
||||
.isEqualTo(manager.getLobbies().get(player2Participant));
|
||||
|
||||
assertThat(manager.getResourceDescriptorToLobby()).hasSize(1);
|
||||
assertThat(manager.getResourceDescriptorToLobby().get(manager.getLobbies().get(player1Participant).gameID))
|
||||
.isNotNull()
|
||||
.isEqualTo(manager.getLobbies().get(player1Participant))
|
||||
.isEqualTo(manager.getLobbies().get(player2Participant));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("When three players connect, a new lobby gets created")
|
||||
void randomLobbyThreePlayerTest() {
|
||||
when(player1.getResourceDescriptor()).thenReturn(null);
|
||||
when(player2.getResourceDescriptor()).thenReturn(null);
|
||||
when(player3.getResourceDescriptor()).thenReturn(null);
|
||||
manager.assignLobbyToParticipant(player1, "AwesomePlayer", playerReady);
|
||||
manager.assignLobbyToParticipant(player2, "MoreAwesomePlayer", playerReady);
|
||||
manager.assignLobbyToParticipant(player3, "AwesomestAwesomePlayer", playerReady);
|
||||
|
||||
assertThat(manager.getLobbies()).hasSize(3);
|
||||
assertThat(manager.getLobbies().get(player1Participant))
|
||||
.isNotNull()
|
||||
.isEqualTo(manager.getLobbies().get(player2Participant))
|
||||
.isNotEqualTo(manager.getLobbies().get(player3Participant));
|
||||
|
||||
assertThat(manager.getLobbies().get(player3Participant)).isNotNull();
|
||||
|
||||
assertThat(manager.getResourceDescriptorToLobby()).hasSize(2);
|
||||
assertThat(manager.getResourceDescriptorToLobby().get(manager.getLobbies().get(player1Participant).gameID))
|
||||
.isNotNull()
|
||||
.isEqualTo(manager.getLobbies().get(player1Participant))
|
||||
.isEqualTo(manager.getLobbies().get(player2Participant))
|
||||
.isNotEqualTo(manager.getLobbies().get(player3Participant));
|
||||
assertThat(manager.getResourceDescriptorToLobby().get(manager.getLobbies().get(player3Participant).gameID))
|
||||
.isNotNull()
|
||||
.isEqualTo(manager.getLobbies().get(player3Participant));
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user