summaryrefslogtreecommitdiff
path: root/src/main/java
diff options
context:
space:
mode:
authorVictor Chabbert <chabbertvi@eisti.eu>2016-12-19 14:32:12 +0100
committerVictor Chabbert <chabbertvi@eisti.eu>2016-12-19 14:32:12 +0100
commit5fa35946cdc26506cac1b15ce7e816678a809c59 (patch)
tree5c67cd934c679ee9373bee735612a00cb9308c65 /src/main/java
parentWorking error saga (diff)
parentAdd react css librairies (diff)
downloadseven-wonders-5fa35946cdc26506cac1b15ce7e816678a809c59.tar.gz
seven-wonders-5fa35946cdc26506cac1b15ce7e816678a809c59.tar.bz2
seven-wonders-5fa35946cdc26506cac1b15ce7e816678a809c59.zip
Merge branch 'master' into feature/websockets-sagas
Diffstat (limited to 'src/main/java')
-rw-r--r--src/main/java/org/luxons/sevenwonders/actions/StartGameAction.java19
-rw-r--r--src/main/java/org/luxons/sevenwonders/config/WebSocketConfig.java5
-rw-r--r--src/main/java/org/luxons/sevenwonders/controllers/LobbyController.java64
-rw-r--r--src/main/java/org/luxons/sevenwonders/errors/ErrorFactory.java52
-rw-r--r--src/main/java/org/luxons/sevenwonders/errors/ErrorType.java7
-rw-r--r--src/main/java/org/luxons/sevenwonders/errors/UIError.java42
-rw-r--r--src/main/java/org/luxons/sevenwonders/errors/UniqueIdAlreadyUsedException.java (renamed from src/main/java/org/luxons/sevenwonders/controllers/UniqueIdAlreadyUsedException.java)2
-rw-r--r--src/main/java/org/luxons/sevenwonders/errors/UserInputException.java14
-rw-r--r--src/main/java/org/luxons/sevenwonders/game/Game.java35
-rw-r--r--src/main/java/org/luxons/sevenwonders/game/Lobby.java9
-rw-r--r--src/main/java/org/luxons/sevenwonders/game/Player.java15
-rw-r--r--src/main/java/org/luxons/sevenwonders/game/api/PlayerTurnInfo.java10
-rw-r--r--src/main/java/org/luxons/sevenwonders/session/SessionAttributes.java8
13 files changed, 249 insertions, 33 deletions
diff --git a/src/main/java/org/luxons/sevenwonders/actions/StartGameAction.java b/src/main/java/org/luxons/sevenwonders/actions/StartGameAction.java
new file mode 100644
index 00000000..632b80ef
--- /dev/null
+++ b/src/main/java/org/luxons/sevenwonders/actions/StartGameAction.java
@@ -0,0 +1,19 @@
+package org.luxons.sevenwonders.actions;
+
+import javax.validation.constraints.NotNull;
+
+import org.luxons.sevenwonders.game.Settings;
+
+public class StartGameAction {
+
+ @NotNull
+ private Settings settings;
+
+ public Settings getSettings() {
+ return settings;
+ }
+
+ public void setSettings(Settings settings) {
+ this.settings = settings;
+ }
+}
diff --git a/src/main/java/org/luxons/sevenwonders/config/WebSocketConfig.java b/src/main/java/org/luxons/sevenwonders/config/WebSocketConfig.java
index 81c90c9b..83629d6a 100644
--- a/src/main/java/org/luxons/sevenwonders/config/WebSocketConfig.java
+++ b/src/main/java/org/luxons/sevenwonders/config/WebSocketConfig.java
@@ -24,7 +24,10 @@ public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
- registry.addEndpoint("/seven-wonders-websocket").setHandshakeHandler(handshakeHandler()).withSockJS();
+ registry.addEndpoint("/seven-wonders-websocket")
+ .setHandshakeHandler(handshakeHandler())
+ .setAllowedOrigins("http://localhost:3000") // to allow frontend server proxy requests in dev mode
+ .withSockJS();
}
@Bean
diff --git a/src/main/java/org/luxons/sevenwonders/controllers/LobbyController.java b/src/main/java/org/luxons/sevenwonders/controllers/LobbyController.java
index ea262c4e..e15935d6 100644
--- a/src/main/java/org/luxons/sevenwonders/controllers/LobbyController.java
+++ b/src/main/java/org/luxons/sevenwonders/controllers/LobbyController.java
@@ -2,13 +2,20 @@ package org.luxons.sevenwonders.controllers;
import java.security.Principal;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import org.luxons.sevenwonders.actions.JoinOrCreateGameAction;
+import org.luxons.sevenwonders.actions.StartGameAction;
+import org.luxons.sevenwonders.errors.ErrorFactory;
+import org.luxons.sevenwonders.errors.UIError;
+import org.luxons.sevenwonders.errors.UniqueIdAlreadyUsedException;
import org.luxons.sevenwonders.game.Game;
import org.luxons.sevenwonders.game.Lobby;
import org.luxons.sevenwonders.game.Player;
+import org.luxons.sevenwonders.game.api.PlayerTurnInfo;
import org.luxons.sevenwonders.game.data.GameDefinitionLoader;
+import org.luxons.sevenwonders.session.SessionAttributes;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@@ -16,6 +23,7 @@ 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.SimpMessagingTemplate;
import org.springframework.messaging.simp.annotation.SendToUser;
import org.springframework.stereotype.Controller;
import org.springframework.validation.annotation.Validated;
@@ -26,10 +34,12 @@ public class LobbyController {
private static final Logger logger = LoggerFactory.getLogger(LobbyController.class);
- public static final String ATTR_LOBBY = "lobby";
-
private final GameDefinitionLoader gameDefinitionLoader;
+ private final SimpMessagingTemplate template;
+
+ private final ErrorFactory errorFactory;
+
private long lastGameId = 0;
private Map<String, Lobby> lobbies = new HashMap<>();
@@ -37,22 +47,25 @@ public class LobbyController {
private Map<String, Game> games = new HashMap<>();
@Autowired
- public LobbyController(GameDefinitionLoader gameDefinitionLoader) {
+ public LobbyController(GameDefinitionLoader gameDefinitionLoader, SimpMessagingTemplate template,
+ ErrorFactory errorFactory) {
this.gameDefinitionLoader = gameDefinitionLoader;
+ this.template = template;
+ this.errorFactory = errorFactory;
}
@MessageExceptionHandler
@SendToUser("/queue/errors")
- public String handleException(Throwable exception) {
+ public UIError handleException(Throwable exception) {
logger.error("An error occured during message handling", exception);
- return exception.getClass().getSimpleName() + ": " + exception.getMessage();
+ return errorFactory.createError(exception);
}
@MessageMapping("/create-game")
@SendTo("/topic/games")
public Lobby createGame(SimpMessageHeaderAccessor headerAccessor, @Validated JoinOrCreateGameAction action,
Principal principal) {
- Lobby lobby = (Lobby)headerAccessor.getSessionAttributes().get(ATTR_LOBBY);
+ Lobby lobby = (Lobby)headerAccessor.getSessionAttributes().get(SessionAttributes.ATTR_LOBBY);
if (lobby != null) {
logger.warn("Client already in game '{}', cannot create a new game", lobby.getName());
return lobby;
@@ -61,7 +74,7 @@ public class LobbyController {
Player player = createPlayer(action.getPlayerName(), principal);
lobby = createGame(action.getGameName(), player);
- headerAccessor.getSessionAttributes().put(ATTR_LOBBY, lobby);
+ headerAccessor.getSessionAttributes().put(SessionAttributes.ATTR_LOBBY, lobby);
logger.info("Game '{}' (id={}) created by {} ({})", lobby.getName(), lobby.getId(), player.getDisplayName(),
player.getUserName());
@@ -72,7 +85,7 @@ public class LobbyController {
@SendToUser("/queue/join-game")
public Lobby joinGame(SimpMessageHeaderAccessor headerAccessor, @Validated JoinOrCreateGameAction action,
Principal principal) {
- Lobby lobby = (Lobby)headerAccessor.getSessionAttributes().get(ATTR_LOBBY);
+ Lobby lobby = (Lobby)headerAccessor.getSessionAttributes().get(SessionAttributes.ATTR_LOBBY);
if (lobby != null) {
logger.warn("Client already in game '{}', cannot join a different game", lobby.getName());
return lobby;
@@ -86,17 +99,42 @@ public class LobbyController {
Player newPlayer = createPlayer(action.getPlayerName(), principal);
lobby.addPlayer(newPlayer);
- headerAccessor.getSessionAttributes().put(ATTR_LOBBY, lobby);
+ headerAccessor.getSessionAttributes().put(SessionAttributes.ATTR_LOBBY, lobby);
logger.warn("Player {} joined game {}", action.getPlayerName(), action.getGameName());
return lobby;
}
+ @MessageMapping("/start-game")
+ public void startGame(SimpMessageHeaderAccessor headerAccessor, @Validated StartGameAction action,
+ Principal principal) {
+ Lobby lobby = (Lobby)headerAccessor.getSessionAttributes().get(SessionAttributes.ATTR_LOBBY);
+ if (lobby == null) {
+ logger.error("User {} is not in a lobby", principal.getName());
+ template.convertAndSendToUser(principal.getName(), "/queue/errors", "No game to start");
+ return;
+ }
+
+ if (!lobby.isOwner(principal.getName())) {
+ logger.error("User {} is not the owner of the game '{}'", principal.getName(), lobby.getName());
+ template.convertAndSendToUser(principal.getName(), "/queue/errors", "Only the owner can start the game");
+ return;
+ }
+
+ Game game = lobby.startGame(action.getSettings());
+ logger.info("Game {} successfully started", game.getId());
+
+ List<PlayerTurnInfo> playerTurnInfos = game.startTurn();
+ for (PlayerTurnInfo playerTurnInfo : playerTurnInfos) {
+ Player player = playerTurnInfo.getTable().getPlayers().get(playerTurnInfo.getPlayerIndex());
+ String userName = player.getUserName();
+ template.convertAndSendToUser(userName, "/queue/game/turn", playerTurnInfo);
+ }
+ }
+
private Player createPlayer(String name, Principal principal) {
- Player player = new Player(name);
- player.setUserName(principal.getName());
- return player;
+ return new Player(name, principal.getName());
}
private Lobby createGame(String name, Player owner) {
@@ -114,7 +152,6 @@ public class LobbyController {
public GameNotFoundException(String name) {
super(name);
}
-
}
private class GameNameAlreadyUsedException extends UniqueIdAlreadyUsedException {
@@ -123,5 +160,4 @@ public class LobbyController {
super(name);
}
}
-
}
diff --git a/src/main/java/org/luxons/sevenwonders/errors/ErrorFactory.java b/src/main/java/org/luxons/sevenwonders/errors/ErrorFactory.java
new file mode 100644
index 00000000..2d3dcd0b
--- /dev/null
+++ b/src/main/java/org/luxons/sevenwonders/errors/ErrorFactory.java
@@ -0,0 +1,52 @@
+package org.luxons.sevenwonders.errors;
+
+import java.util.List;
+import java.util.Locale;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.MessageSource;
+import org.springframework.messaging.handler.annotation.support.MethodArgumentNotValidException;
+import org.springframework.stereotype.Component;
+import org.springframework.validation.ObjectError;
+
+@Component
+public class ErrorFactory {
+
+ private static final String ERROR_CODE_VALIDATION = "VALIDATION_ERROR";
+
+ private static final String ERROR_MSG_VALIDATION = "Input invalid";
+
+ private final MessageSource messageSource;
+
+ @Autowired
+ public ErrorFactory(MessageSource messageSource) {
+ this.messageSource = messageSource;
+ }
+
+ public UIError createError(Throwable exception) {
+ if (exception instanceof UserInputException) {
+ return createUserError((UserInputException)exception);
+ } else if (exception instanceof MethodArgumentNotValidException) {
+ return createValidationError((MethodArgumentNotValidException)exception);
+ } else {
+ return createInternalError(exception);
+ }
+ }
+
+ private UIError createUserError(UserInputException exception) {
+ String messageKey = exception.getMessageResourceKey();
+ String message = messageSource.getMessage(messageKey, null, messageKey, Locale.US);
+ return new UIError(messageKey, message, ErrorType.USER);
+ }
+
+ private UIError createInternalError(Throwable exception) {
+ return new UIError(exception.getClass().getSimpleName(), exception.getMessage(), ErrorType.INTERNAL);
+ }
+
+ private UIError createValidationError(MethodArgumentNotValidException exception) {
+ List<ObjectError> errors = exception.getBindingResult().getAllErrors();
+ UIError uiError = new UIError(ERROR_CODE_VALIDATION, ERROR_MSG_VALIDATION, ErrorType.VALIDATION);
+ uiError.setValidationErrors(errors);
+ return uiError;
+ }
+}
diff --git a/src/main/java/org/luxons/sevenwonders/errors/ErrorType.java b/src/main/java/org/luxons/sevenwonders/errors/ErrorType.java
new file mode 100644
index 00000000..71df185f
--- /dev/null
+++ b/src/main/java/org/luxons/sevenwonders/errors/ErrorType.java
@@ -0,0 +1,7 @@
+package org.luxons.sevenwonders.errors;
+
+public enum ErrorType {
+ USER,
+ VALIDATION,
+ INTERNAL
+}
diff --git a/src/main/java/org/luxons/sevenwonders/errors/UIError.java b/src/main/java/org/luxons/sevenwonders/errors/UIError.java
new file mode 100644
index 00000000..67802f22
--- /dev/null
+++ b/src/main/java/org/luxons/sevenwonders/errors/UIError.java
@@ -0,0 +1,42 @@
+package org.luxons.sevenwonders.errors;
+
+import java.util.List;
+
+import org.springframework.validation.ObjectError;
+
+public class UIError {
+
+ private final String code;
+
+ private final String message;
+
+ private final ErrorType type;
+
+ private List<ObjectError> validationErrors;
+
+ public UIError(String code, String message, ErrorType type) {
+ this.code = code;
+ this.message = message;
+ this.type = type;
+ }
+
+ public String getCode() {
+ return code;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public ErrorType getType() {
+ return type;
+ }
+
+ public List<ObjectError> getValidationErrors() {
+ return validationErrors;
+ }
+
+ public void setValidationErrors(List<ObjectError> validationErrors) {
+ this.validationErrors = validationErrors;
+ }
+}
diff --git a/src/main/java/org/luxons/sevenwonders/controllers/UniqueIdAlreadyUsedException.java b/src/main/java/org/luxons/sevenwonders/errors/UniqueIdAlreadyUsedException.java
index 56c22655..b1b00453 100644
--- a/src/main/java/org/luxons/sevenwonders/controllers/UniqueIdAlreadyUsedException.java
+++ b/src/main/java/org/luxons/sevenwonders/errors/UniqueIdAlreadyUsedException.java
@@ -1,4 +1,4 @@
-package org.luxons.sevenwonders.controllers;
+package org.luxons.sevenwonders.errors;
public class UniqueIdAlreadyUsedException extends RuntimeException {
diff --git a/src/main/java/org/luxons/sevenwonders/errors/UserInputException.java b/src/main/java/org/luxons/sevenwonders/errors/UserInputException.java
new file mode 100644
index 00000000..11f7f8f2
--- /dev/null
+++ b/src/main/java/org/luxons/sevenwonders/errors/UserInputException.java
@@ -0,0 +1,14 @@
+package org.luxons.sevenwonders.errors;
+
+public class UserInputException extends RuntimeException {
+
+ private final String messageResourceKey;
+
+ public UserInputException(String messageResourceKey) {
+ this.messageResourceKey = messageResourceKey;
+ }
+
+ public String getMessageResourceKey() {
+ return messageResourceKey;
+ }
+}
diff --git a/src/main/java/org/luxons/sevenwonders/game/Game.java b/src/main/java/org/luxons/sevenwonders/game/Game.java
index f4dac7ef..2a2fab27 100644
--- a/src/main/java/org/luxons/sevenwonders/game/Game.java
+++ b/src/main/java/org/luxons/sevenwonders/game/Game.java
@@ -37,22 +37,23 @@ public class Game {
this.discardedCards = new ArrayList<>();
this.hands = new HashMap<>();
this.preparedMoves = new HashMap<>();
+ startNewAge();
}
public long getId() {
return id;
}
- public int startNewAge() {
+ private void startNewAge() {
currentAge++;
hands = decks.deal(currentAge, table.getNbPlayers());
- return currentAge;
}
public List<PlayerTurnInfo> startTurn() {
return hands.entrySet()
.stream()
.map(e -> table.createPlayerTurnInfo(e.getKey(), e.getValue()))
+ .peek(ptu -> ptu.setCurrentAge(currentAge))
.collect(Collectors.toList());
}
@@ -69,10 +70,27 @@ public class Game {
return preparedMoves.size() == table.getPlayers().size();
}
- public void playTurn() {
+ public List<Move> playTurn() {
+ List<Move> playedMoves = mapToList(preparedMoves);
+
// cards need to be all placed first as some effects depend on just-played cards
placePreparedCards();
playPreparedCards();
+ preparedMoves.clear();
+
+ return playedMoves;
+ }
+
+ private static List<Move> mapToList(Map<Integer, Move> movesPerPlayer) {
+ List<Move> moves = new ArrayList<>(movesPerPlayer.size());
+ for (int p = 0; p < movesPerPlayer.size(); p++) {
+ Move move = movesPerPlayer.get(p);
+ if (move == null) {
+ throw new MissingPreparedMoveException(p);
+ }
+ moves.add(move);
+ }
+ return moves;
}
private void placePreparedCards() {
@@ -85,10 +103,10 @@ public class Game {
// TODO pre-upgrade the level of wonder without effect
break;
case DISCARD:
+ discardedCards.add(decks.getCard(move.getCardName()));
break;
}
});
-
}
private void playPreparedCards() {
@@ -108,6 +126,13 @@ public class Game {
}
- public class InvalidMoveException extends RuntimeException {
+ private static class MissingPreparedMoveException extends RuntimeException {
+
+ public MissingPreparedMoveException(int playerIndex) {
+ super("Player " + playerIndex + " is not ready to play");
+ }
+ }
+
+ private static class InvalidMoveException extends RuntimeException {
}
}
diff --git a/src/main/java/org/luxons/sevenwonders/game/Lobby.java b/src/main/java/org/luxons/sevenwonders/game/Lobby.java
index 7256936c..16d4e8a3 100644
--- a/src/main/java/org/luxons/sevenwonders/game/Lobby.java
+++ b/src/main/java/org/luxons/sevenwonders/game/Lobby.java
@@ -3,7 +3,7 @@ package org.luxons.sevenwonders.game;
import java.util.ArrayList;
import java.util.List;
-import org.luxons.sevenwonders.controllers.UniqueIdAlreadyUsedException;
+import org.luxons.sevenwonders.errors.UniqueIdAlreadyUsedException;
import org.luxons.sevenwonders.game.data.GameDefinition;
public class Lobby {
@@ -12,6 +12,8 @@ public class Lobby {
private final String name;
+ private final Player owner;
+
private final List<Player> players;
private final GameDefinition gameDefinition;
@@ -21,6 +23,7 @@ public class Lobby {
public Lobby(long id, String name, Player owner, GameDefinition gameDefinition) {
this.id = id;
this.name = name;
+ this.owner = owner;
this.gameDefinition = gameDefinition;
this.players = new ArrayList<>(gameDefinition.getMinPlayers());
players.add(owner);
@@ -79,6 +82,10 @@ public class Lobby {
return "Lobby{" + "id=" + id + ", name='" + name + '\'' + ", state=" + state + '}';
}
+ public boolean isOwner(String userName) {
+ return owner.getUserName().equals(userName);
+ }
+
public class GameAlreadyStartedException extends IllegalStateException {
}
diff --git a/src/main/java/org/luxons/sevenwonders/game/Player.java b/src/main/java/org/luxons/sevenwonders/game/Player.java
index fd2f254b..66ce566d 100644
--- a/src/main/java/org/luxons/sevenwonders/game/Player.java
+++ b/src/main/java/org/luxons/sevenwonders/game/Player.java
@@ -2,30 +2,23 @@ package org.luxons.sevenwonders.game;
public class Player {
- private String displayName;
+ private final String displayName;
- private String userName;
+ private final String userName;
- public Player(String displayName) {
+ public Player(String displayName, String userName) {
this.displayName = displayName;
+ this.userName = userName;
}
public String getDisplayName() {
return displayName;
}
- public void setDisplayName(String displayName) {
- this.displayName = displayName;
- }
-
public String getUserName() {
return userName;
}
- public void setUserName(String userName) {
- this.userName = userName;
- }
-
@Override
public String toString() {
return "Player{" + "name='" + displayName + '\'' + ", userName='" + userName + '\'' + '}';
diff --git a/src/main/java/org/luxons/sevenwonders/game/api/PlayerTurnInfo.java b/src/main/java/org/luxons/sevenwonders/game/api/PlayerTurnInfo.java
index ad9e6da9..b7090ff9 100644
--- a/src/main/java/org/luxons/sevenwonders/game/api/PlayerTurnInfo.java
+++ b/src/main/java/org/luxons/sevenwonders/game/api/PlayerTurnInfo.java
@@ -8,6 +8,8 @@ public class PlayerTurnInfo {
private final Table table;
+ private int currentAge;
+
private List<HandCard> hand;
private String message;
@@ -25,6 +27,14 @@ public class PlayerTurnInfo {
return table;
}
+ public int getCurrentAge() {
+ return currentAge;
+ }
+
+ public void setCurrentAge(int currentAge) {
+ this.currentAge = currentAge;
+ }
+
public List<HandCard> getHand() {
return hand;
}
diff --git a/src/main/java/org/luxons/sevenwonders/session/SessionAttributes.java b/src/main/java/org/luxons/sevenwonders/session/SessionAttributes.java
new file mode 100644
index 00000000..8c69d8c3
--- /dev/null
+++ b/src/main/java/org/luxons/sevenwonders/session/SessionAttributes.java
@@ -0,0 +1,8 @@
+package org.luxons.sevenwonders.session;
+
+public class SessionAttributes {
+
+ public static final String ATTR_LOBBY = "lobby";
+
+ public static final String ATTR_GAME = "game";
+}
bgstack15