diff --git a/wizard-client/wizard-client-cli/src/main/java/eu/jonahbauer/wizard/client/cli/state/AwaitingJoinSession.java b/wizard-client/wizard-client-cli/src/main/java/eu/jonahbauer/wizard/client/cli/state/AwaitingJoinSession.java index 7e04d4b..5450133 100644 --- a/wizard-client/wizard-client-cli/src/main/java/eu/jonahbauer/wizard/client/cli/state/AwaitingJoinSession.java +++ b/wizard-client/wizard-client-cli/src/main/java/eu/jonahbauer/wizard/client/cli/state/AwaitingJoinSession.java @@ -22,8 +22,11 @@ public final class AwaitingJoinSession extends Awaiting { case NackMessage.GAME_ALREADY_STARTED -> client.println("Error: Game has already started."); case NackMessage.SESSION_FULL -> client.println("Error: The session is full."); case NackMessage.SESSION_NOT_FOUND -> client.println("Error: Session not found."); - case NackMessage.NAME_TAKEN -> client.println("Error: Name already taken."); - default -> { return super.onMessage(client, message); } + case NackMessage.PLAYER_NAME_TAKEN -> client.println("Player name already taken."); + case NackMessage.PLAYER_NAME_NOT_ALLOWED -> client.println("Player name not allowed."); + case NackMessage.SESSION_NAME_TAKEN -> client.println("Session name already taken."); + case NackMessage.SESSION_NAME_NOT_ALLOWED -> client.println("Session name not allowed."); + default -> client.println("Nack " + nack.getCode() + ": " + nack.getMessage()); } return Optional.of(new AwaitingJoinLobby()); } else if (message instanceof SessionModifiedMessage || message instanceof SessionRemovedMessage) { diff --git a/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/screens/CreateGameScreen.java b/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/screens/CreateGameScreen.java index e589bb2..477e7d8 100644 --- a/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/screens/CreateGameScreen.java +++ b/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/screens/CreateGameScreen.java @@ -60,6 +60,7 @@ public class CreateGameScreen extends MenuScreen { sessionName = new TextField("", skin); sessionName.setPosition(WizardGame.WIDTH * 0.3f, WizardGame.HEIGHT * 0.5f); sessionName.setSize(0.4f * WizardGame.WIDTH, 64); + sessionName.setMaxLength(20); sessionName.addListener(errorListener); sessionName.setProgrammaticChangeEvents(true); diff --git a/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/screens/LobbyScreen.java b/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/screens/LobbyScreen.java index 45486d9..163b9e4 100644 --- a/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/screens/LobbyScreen.java +++ b/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/screens/LobbyScreen.java @@ -120,6 +120,7 @@ public class LobbyScreen extends MenuScreen { game.storage.playerName = playerName.getText(); } }); + playerName.setMaxLength(20); playerName.addListener(new ResetErrorListener(skin)); labelSessionName = new Label("", skin, "textfield"); diff --git a/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/state/AwaitingJoinSession.java b/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/state/AwaitingJoinSession.java index 36603b3..70170be 100644 --- a/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/state/AwaitingJoinSession.java +++ b/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/state/AwaitingJoinSession.java @@ -57,8 +57,11 @@ public final class AwaitingJoinSession extends Awaiting { case NackMessage.GAME_ALREADY_STARTED -> log.error("Game has already started."); case NackMessage.SESSION_FULL -> log.error("The session is full."); case NackMessage.SESSION_NOT_FOUND -> log.error("Session not found."); - case NackMessage.NAME_TAKEN -> log.error("Name already taken."); - default -> { return super.onMessage(client, message); } + case NackMessage.PLAYER_NAME_TAKEN -> log.error("Player name already taken."); + case NackMessage.PLAYER_NAME_NOT_ALLOWED -> log.error("Player name not allowed."); + case NackMessage.SESSION_NAME_TAKEN -> log.error("Session name already taken."); + case NackMessage.SESSION_NAME_NOT_ALLOWED -> log.error("Session name not allowed."); + default -> log.error("Nack {}: {}", nack.getCode(), nack.getMessage()); } return Optional.of(new AwaitingJoinLobby()); } else if (message instanceof SessionModifiedMessage || message instanceof SessionRemovedMessage) { diff --git a/wizard-common/src/main/java/eu/jonahbauer/wizard/common/messages/server/NackMessage.java b/wizard-common/src/main/java/eu/jonahbauer/wizard/common/messages/server/NackMessage.java index 1e15b1d..9ecb9dc 100644 --- a/wizard-common/src/main/java/eu/jonahbauer/wizard/common/messages/server/NackMessage.java +++ b/wizard-common/src/main/java/eu/jonahbauer/wizard/common/messages/server/NackMessage.java @@ -12,10 +12,13 @@ public final class NackMessage extends ServerMessage implements Response { public static final int UNEXPECTED_MESSAGE = 101; public static final int ILLEGAL_ARGUMENT = 200; - public static final int NAME_TAKEN = 201; public static final int NOT_FOUND = 210; public static final int SESSION_NOT_FOUND = 211; public static final int PLAYER_NOT_FOUND = 212; + public static final int PLAYER_NAME_TAKEN = 220; + public static final int PLAYER_NAME_NOT_ALLOWED = 221; + public static final int SESSION_NAME_TAKEN = 230; + public static final int SESSION_NAME_NOT_ALLOWED = 231; public static final int ILLEGAL_STATE = 300; public static final int GAME_ALREADY_STARTED = 301; diff --git a/wizard-server/src/main/java/eu/jonahbauer/wizard/server/Lobby.java b/wizard-server/src/main/java/eu/jonahbauer/wizard/server/Lobby.java index d353995..0d4dbca 100644 --- a/wizard-server/src/main/java/eu/jonahbauer/wizard/server/Lobby.java +++ b/wizard-server/src/main/java/eu/jonahbauer/wizard/server/Lobby.java @@ -1,12 +1,10 @@ package eu.jonahbauer.wizard.server; -import eu.jonahbauer.wizard.common.messages.server.ServerMessage; -import eu.jonahbauer.wizard.common.messages.server.SessionCreatedMessage; -import eu.jonahbauer.wizard.common.messages.server.SessionListMessage; -import eu.jonahbauer.wizard.common.messages.server.SessionRemovedMessage; +import eu.jonahbauer.wizard.common.messages.server.*; import eu.jonahbauer.wizard.common.model.Configuration; import eu.jonahbauer.wizard.server.debug.DebugSession; import eu.jonahbauer.wizard.server.machine.Player; +import org.intellij.lang.annotations.Language; import org.jetbrains.annotations.NotNull; import java.util.*; @@ -14,6 +12,8 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.locks.ReentrantReadWriteLock; public class Lobby { + @Language("RegExp") + private static final String SESSION_NAME_PATTERN = "[a-zA-Z0-9_ ]{1,20}"; private static final Lobby INSTANCE = new Lobby(); public static Lobby getInstance() { return INSTANCE; @@ -26,8 +26,16 @@ public class Lobby { private Lobby() {} public Session createSession(@NotNull String name, long timeout, @NotNull Configuration configuration) { + if (!name.matches(SESSION_NAME_PATTERN)) { + throw new NackException(NackMessage.SESSION_NAME_NOT_ALLOWED, "Session name is too short, too long or contains illegal characters."); + } + lock.readLock().lock(); try { + if (sessions.values().stream().anyMatch(s -> s.getName().equalsIgnoreCase(name))) { + throw new NackException(NackMessage.SESSION_NAME_TAKEN, "Session name is already taken."); + } + Session session; do { session = new Session(UUID.randomUUID(), name, timeout, configuration); diff --git a/wizard-server/src/main/java/eu/jonahbauer/wizard/server/Session.java b/wizard-server/src/main/java/eu/jonahbauer/wizard/server/Session.java index 97c548e..41bf777 100644 --- a/wizard-server/src/main/java/eu/jonahbauer/wizard/server/Session.java +++ b/wizard-server/src/main/java/eu/jonahbauer/wizard/server/Session.java @@ -16,6 +16,7 @@ import lombok.Data; import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.extern.log4j.Log4j2; +import org.intellij.lang.annotations.Language; import java.util.*; import java.util.concurrent.CompletableFuture; @@ -26,6 +27,8 @@ import java.util.concurrent.ThreadLocalRandom; @Log4j2 @EqualsAndHashCode(of = "uuid") public class Session implements Observer { + @Language("RegExp") + private static final String PLAYER_NAME_PATTERN = "[a-zA-Z0-9_ ]{1,20}"; protected static final int MIN_PLAYERS = 3; protected static final int MAX_PLAYERS = 6; @@ -63,7 +66,9 @@ public class Session implements Observer { } else if (players.size() == MAX_PLAYERS) { throw new NackException(NackMessage.SESSION_FULL, "Session is full."); } else if (players.values().stream().anyMatch(p -> p.getName().equalsIgnoreCase(name))) { - throw new NackException(NackMessage.NAME_TAKEN, "Name is already taken."); + throw new NackException(NackMessage.PLAYER_NAME_TAKEN, "Player name is already taken."); + } else if (!name.matches(PLAYER_NAME_PATTERN)) { + throw new NackException(NackMessage.PLAYER_NAME_NOT_ALLOWED, "Player name is too short, too long or contains illegal characters."); } SessionPlayer sessionPlayer; diff --git a/wizard-server/src/main/java/eu/jonahbauer/wizard/server/debug/DebugSession.java b/wizard-server/src/main/java/eu/jonahbauer/wizard/server/debug/DebugSession.java index 27ae085..e2b25e1 100644 --- a/wizard-server/src/main/java/eu/jonahbauer/wizard/server/debug/DebugSession.java +++ b/wizard-server/src/main/java/eu/jonahbauer/wizard/server/debug/DebugSession.java @@ -41,7 +41,7 @@ public class DebugSession extends Session { } else if (getPlayers().size() == MAX_PLAYERS) { throw new NackException(NackMessage.SESSION_FULL, "Session is full."); } else if (getPlayers().values().stream().anyMatch(p -> p.getName().equalsIgnoreCase(name))) { - throw new NackException(NackMessage.NAME_TAKEN, "Name is already taken."); + throw new NackException(NackMessage.PLAYER_NAME_TAKEN, "Player name is already taken."); } SessionPlayer sessionPlayer;