diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/main/java/org/luxons/sevenwonders/actions/JoinOrCreateGameAction.java (renamed from src/main/java/org/luxons/sevenwonders/actions/JoinGameAction.java) | 12 | ||||
-rw-r--r-- | src/main/java/org/luxons/sevenwonders/controllers/LobbyController.java | 98 | ||||
-rw-r--r-- | src/main/java/org/luxons/sevenwonders/controllers/UniqueIdAlreadyUsedException.java | 15 | ||||
-rw-r--r-- | src/main/java/org/luxons/sevenwonders/game/Lobby.java | 32 | ||||
-rw-r--r-- | src/main/java/org/luxons/sevenwonders/game/Player.java | 19 | ||||
-rw-r--r-- | src/main/resources/static/app.js | 49 | ||||
-rw-r--r-- | src/main/resources/static/index.html | 8 |
7 files changed, 174 insertions, 59 deletions
diff --git a/src/main/java/org/luxons/sevenwonders/actions/JoinGameAction.java b/src/main/java/org/luxons/sevenwonders/actions/JoinOrCreateGameAction.java index fc2e11d2..cf5596da 100644 --- a/src/main/java/org/luxons/sevenwonders/actions/JoinGameAction.java +++ b/src/main/java/org/luxons/sevenwonders/actions/JoinOrCreateGameAction.java @@ -3,22 +3,22 @@ package org.luxons.sevenwonders.actions; import javax.validation.constraints.NotNull; import javax.validation.constraints.Size; -public class JoinGameAction { +public class JoinOrCreateGameAction { @NotNull @Size(min=2, max=30) - private String gameId; + private String gameName; @NotNull @Size(min=2, max=20) private String playerName; - public String getGameId() { - return gameId; + public String getGameName() { + return gameName; } - public void setGameId(String gameId) { - this.gameId = gameId; + public void setGameName(String gameName) { + this.gameName = gameName; } public String getPlayerName() { diff --git a/src/main/java/org/luxons/sevenwonders/controllers/LobbyController.java b/src/main/java/org/luxons/sevenwonders/controllers/LobbyController.java index 312214d6..ea262c4e 100644 --- a/src/main/java/org/luxons/sevenwonders/controllers/LobbyController.java +++ b/src/main/java/org/luxons/sevenwonders/controllers/LobbyController.java @@ -4,7 +4,7 @@ import java.security.Principal; import java.util.HashMap; import java.util.Map; -import org.luxons.sevenwonders.actions.JoinGameAction; +import org.luxons.sevenwonders.actions.JoinOrCreateGameAction; import org.luxons.sevenwonders.game.Game; import org.luxons.sevenwonders.game.Lobby; import org.luxons.sevenwonders.game.Player; @@ -12,9 +12,11 @@ import org.luxons.sevenwonders.game.data.GameDefinitionLoader; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.messaging.handler.annotation.MessageExceptionHandler; import org.springframework.messaging.handler.annotation.MessageMapping; import org.springframework.messaging.handler.annotation.SendTo; import org.springframework.messaging.simp.SimpMessageHeaderAccessor; +import org.springframework.messaging.simp.annotation.SendToUser; import org.springframework.stereotype.Controller; import org.springframework.validation.annotation.Validated; @@ -24,6 +26,8 @@ public class LobbyController { private static final Logger logger = LoggerFactory.getLogger(LobbyController.class); + public static final String ATTR_LOBBY = "lobby"; + private final GameDefinitionLoader gameDefinitionLoader; private long lastGameId = 0; @@ -37,39 +41,87 @@ public class LobbyController { this.gameDefinitionLoader = gameDefinitionLoader; } + @MessageExceptionHandler + @SendToUser("/queue/errors") + public String handleException(Throwable exception) { + logger.error("An error occured during message handling", exception); + return exception.getClass().getSimpleName() + ": " + exception.getMessage(); + } + @MessageMapping("/create-game") @SendTo("/topic/games") - public String createGame(SimpMessageHeaderAccessor headerAccessor, Principal principal) { - long newId = lastGameId++; - String id = String.valueOf(newId); - - Lobby lobby = new Lobby(newId, gameDefinitionLoader.getGameDefinition()); - lobbies.put(id, lobby); - logger.info("Game {} created by {}", id, principal.getName()); - return id; + public Lobby createGame(SimpMessageHeaderAccessor headerAccessor, @Validated JoinOrCreateGameAction action, + Principal principal) { + Lobby lobby = (Lobby)headerAccessor.getSessionAttributes().get(ATTR_LOBBY); + if (lobby != null) { + logger.warn("Client already in game '{}', cannot create a new game", lobby.getName()); + return lobby; + } + + Player player = createPlayer(action.getPlayerName(), principal); + lobby = createGame(action.getGameName(), player); + + headerAccessor.getSessionAttributes().put(ATTR_LOBBY, lobby); + + logger.info("Game '{}' (id={}) created by {} ({})", lobby.getName(), lobby.getId(), player.getDisplayName(), + player.getUserName()); + return lobby; } @MessageMapping("/join-game") - @SendTo("/topic/players") - public Player joinGame(SimpMessageHeaderAccessor headerAccessor, @Validated JoinGameAction action, + @SendToUser("/queue/join-game") + public Lobby joinGame(SimpMessageHeaderAccessor headerAccessor, @Validated JoinOrCreateGameAction action, Principal principal) { - Player player = (Player)headerAccessor.getSessionAttributes().get("player"); - Lobby lobby = (Lobby)headerAccessor.getSessionAttributes().get("lobby"); - if (player != null && lobby != null) { - logger.warn("Client has already joined game {} under the name {}", lobby.getId(), player.getName()); - return player; + Lobby lobby = (Lobby)headerAccessor.getSessionAttributes().get(ATTR_LOBBY); + if (lobby != null) { + logger.warn("Client already in game '{}', cannot join a different game", lobby.getName()); + return lobby; + } + + lobby = lobbies.get(action.getGameName()); + if (lobby == null) { + throw new GameNotFoundException(action.getGameName()); } - lobby = lobbies.get(action.getGameId()); - Player newPlayer = new Player(action.getPlayerName()); - newPlayer.setUserName(principal.getName()); + Player newPlayer = createPlayer(action.getPlayerName(), principal); lobby.addPlayer(newPlayer); - headerAccessor.getSessionAttributes().put("player", newPlayer); - headerAccessor.getSessionAttributes().put("lobby", lobby); + headerAccessor.getSessionAttributes().put(ATTR_LOBBY, lobby); - logger.warn("Player {} joined game {}", action.getPlayerName(), action.getGameId()); + logger.warn("Player {} joined game {}", action.getPlayerName(), action.getGameName()); - return newPlayer; + return lobby; } + + private Player createPlayer(String name, Principal principal) { + Player player = new Player(name); + player.setUserName(principal.getName()); + return player; + } + + private Lobby createGame(String name, Player owner) { + if (lobbies.containsKey(name)) { + throw new GameNameAlreadyUsedException(name); + } + long id = lastGameId++; + Lobby lobby = new Lobby(id, name, owner, gameDefinitionLoader.getGameDefinition()); + lobbies.put(name, lobby); + return lobby; + } + + private class GameNotFoundException extends RuntimeException { + + public GameNotFoundException(String name) { + super(name); + } + + } + + private class GameNameAlreadyUsedException extends UniqueIdAlreadyUsedException { + + public GameNameAlreadyUsedException(String name) { + super(name); + } + } + } diff --git a/src/main/java/org/luxons/sevenwonders/controllers/UniqueIdAlreadyUsedException.java b/src/main/java/org/luxons/sevenwonders/controllers/UniqueIdAlreadyUsedException.java new file mode 100644 index 00000000..56c22655 --- /dev/null +++ b/src/main/java/org/luxons/sevenwonders/controllers/UniqueIdAlreadyUsedException.java @@ -0,0 +1,15 @@ +package org.luxons.sevenwonders.controllers; + +public class UniqueIdAlreadyUsedException extends RuntimeException { + + private String id; + + public UniqueIdAlreadyUsedException(String id) { + super("'" + id + "'"); + this.id = id; + } + + public String getUsedId() { + return id; + } +} diff --git a/src/main/java/org/luxons/sevenwonders/game/Lobby.java b/src/main/java/org/luxons/sevenwonders/game/Lobby.java index 24055c75..7256936c 100644 --- a/src/main/java/org/luxons/sevenwonders/game/Lobby.java +++ b/src/main/java/org/luxons/sevenwonders/game/Lobby.java @@ -3,28 +3,37 @@ package org.luxons.sevenwonders.game; import java.util.ArrayList; import java.util.List; +import org.luxons.sevenwonders.controllers.UniqueIdAlreadyUsedException; import org.luxons.sevenwonders.game.data.GameDefinition; public class Lobby { private final long id; + private final String name; + private final List<Player> players; private final GameDefinition gameDefinition; private State state = State.LOBBY; - public Lobby(long id, GameDefinition gameDefinition) { + public Lobby(long id, String name, Player owner, GameDefinition gameDefinition) { this.id = id; + this.name = name; this.gameDefinition = gameDefinition; - this.players = new ArrayList<>(3); + this.players = new ArrayList<>(gameDefinition.getMinPlayers()); + players.add(owner); } public long getId() { return id; } + public String getName() { + return name; + } + public synchronized int addPlayer(Player player) throws GameAlreadyStartedException, PlayerOverflowException { if (hasStarted()) { throw new GameAlreadyStartedException(); @@ -32,6 +41,9 @@ public class Lobby { if (maxPlayersReached()) { throw new PlayerOverflowException(); } + if (playerNameAlreadyUsed(player.getDisplayName())) { + throw new PlayerNameAlreadyUsedException(player.getDisplayName()); + } int playerId = players.size(); players.add(player); return playerId; @@ -45,6 +57,10 @@ public class Lobby { return players.size() >= gameDefinition.getMaxPlayers(); } + private boolean playerNameAlreadyUsed(String name) { + return players.stream().anyMatch(p -> p.getDisplayName().equals(name)); + } + public synchronized Game startGame(Settings settings) throws PlayerUnderflowException { if (!hasEnoughPlayers()) { throw new PlayerUnderflowException(); @@ -58,6 +74,11 @@ public class Lobby { return players.size() >= gameDefinition.getMinPlayers(); } + @Override + public String toString() { + return "Lobby{" + "id=" + id + ", name='" + name + '\'' + ", state=" + state + '}'; + } + public class GameAlreadyStartedException extends IllegalStateException { } @@ -66,4 +87,11 @@ public class Lobby { public class PlayerUnderflowException extends IllegalStateException { } + + public class PlayerNameAlreadyUsedException extends UniqueIdAlreadyUsedException { + + public PlayerNameAlreadyUsedException(String name) { + super(name); + } + } } diff --git a/src/main/java/org/luxons/sevenwonders/game/Player.java b/src/main/java/org/luxons/sevenwonders/game/Player.java index eafabf4a..fd2f254b 100644 --- a/src/main/java/org/luxons/sevenwonders/game/Player.java +++ b/src/main/java/org/luxons/sevenwonders/game/Player.java @@ -2,20 +2,20 @@ package org.luxons.sevenwonders.game; public class Player { - private String name; + private String displayName; private String userName; - public Player(String name) { - this.name = name; + public Player(String displayName) { + this.displayName = displayName; } - public String getName() { - return name; + public String getDisplayName() { + return displayName; } - public void setName(String name) { - this.name = name; + public void setDisplayName(String displayName) { + this.displayName = displayName; } public String getUserName() { @@ -25,4 +25,9 @@ public class Player { public void setUserName(String userName) { this.userName = userName; } + + @Override + public String toString() { + return "Player{" + "name='" + displayName + '\'' + ", userName='" + userName + '\'' + '}'; + } } diff --git a/src/main/resources/static/app.js b/src/main/resources/static/app.js index dfdcf934..b1881357 100644 --- a/src/main/resources/static/app.js +++ b/src/main/resources/static/app.js @@ -18,14 +18,20 @@ function connect() { setConnected(true); console.log('Connected: ' + frame); - stompClient.subscribe('/topic/games', function (gameId) { - console.log("Received new game: " + gameId); - addNewGame(gameId.body); + stompClient.subscribe('/user/queue/errors', function (msg) { + console.error(msg.body); }); - stompClient.subscribe('/topic/players', function (player) { - console.log("Received new player: " + player); - addNewPlayer(JSON.parse(player.body)); + stompClient.subscribe('/topic/games', function (msg) { + var game = JSON.parse(msg.body); + console.log("Received new game: " + game); + addNewGame(game); + }); + + stompClient.subscribe('/user/queue/join-game', function (msg) { + var game = JSON.parse(msg.body); + console.log("Joined game: " + game); + addNewPlayer(game); }); }); } @@ -38,20 +44,26 @@ function disconnect() { console.log("Disconnected"); } -function sendCreateGame() { - stompClient.send("/app/lobby/create-game", {}, ""); +function sendCreateGame(gameName, playerName) { + stompClient.send("/app/lobby/create-game", {}, JSON.stringify({ + 'gameName': gameName, + 'playerName': playerName + })); } -function sendJoinGame(gameId) { - stompClient.send("/app/lobby/join-game", {}, - JSON.stringify({'gameId': gameId, 'playerName': $("#player-name-field").val()})); +function sendJoinGame(gameName, playerName) { + stompClient.send("/app/lobby/join-game", {}, JSON.stringify({ + 'gameName': gameName, + 'playerName': playerName + })); } -function addNewGame(gameId) { - console.log(gameId); - $("#game-list-content").append('<tr><td>' + gameId + '</td><td><button id="join-' + gameId + '" type="submit">Join</button></td></tr>'); - $("#join-" + gameId).click(function () { - sendJoinGame(gameId); +function addNewGame(game) { + console.log(game); + $("#game-list-content").append('<tr><td>' + game.name + '</td><td><button id="join-' + game.id + + '" type="submit">Join</button></td></tr>'); + $("#join-" + game.id).click(function () { + sendJoinGame(game.name, $("#player-name-field").val()); }); } @@ -70,9 +82,6 @@ $(function () { disconnect(); }); $("#create-game").click(function () { - sendCreateGame(); - }); - $("#join-game").click(function () { - sendJoinGame(); + sendCreateGame($("#game-name-field").val(), $("#player-name-field").val()); }); });
\ No newline at end of file diff --git a/src/main/resources/static/index.html b/src/main/resources/static/index.html index 6131e912..d5ec178d 100644 --- a/src/main/resources/static/index.html +++ b/src/main/resources/static/index.html @@ -52,7 +52,13 @@ </tbody> </table> -<button id="create-game" class="btn btn-default" type="submit">Create Game</button> +<form class="form-inline"> + <div class="form-group"> + <label for="game-name-field">Game name</label> + <input id="game-name-field"> + <button id="create-game" class="btn btn-default" type="submit">Create</button> + </div> +</form> </body> </html>
\ No newline at end of file |