From 4beb63343f658a17b9ccd6236fced501e5d15dea Mon Sep 17 00:00:00 2001 From: Joffrey BION Date: Sun, 11 Dec 2016 14:03:28 +0100 Subject: Add WS experiment test page This pages allows to test spring/STOMP config to see which messages are properly broadcasted to all users, which are just sent to the caller, and which are sent a specific user from the server. --- .../java/org/luxons/sevenwonders/SevenWonders.java | 12 ++++ .../org/luxons/sevenwonders/WebSocketConfig.java | 28 ++++++++ .../sevenwonders/actions/JoinGameAction.java | 24 +++++++ .../luxons/sevenwonders/app/LobbyController.java | 58 --------------- .../org/luxons/sevenwonders/app/SevenWonders.java | 12 ---- .../luxons/sevenwonders/app/WebSocketConfig.java | 24 ------- .../sevenwonders/app/actions/JoinGameAction.java | 24 ------- .../sevenwonders/controllers/LobbyController.java | 67 +++++++++++++++++ .../sevenwonders/controllers/TestController.java | 65 +++++++++++++++++ .../java/org/luxons/sevenwonders/game/Decks.java | 21 ++++++ .../java/org/luxons/sevenwonders/game/Game.java | 38 +++++----- .../org/luxons/sevenwonders/game/GameData.java | 46 ++++++++++++ .../org/luxons/sevenwonders/game/data/Decks.java | 57 --------------- .../luxons/sevenwonders/game/data/GameData.java | 49 ------------- .../sevenwonders/game/data/GameDataLoader.java | 81 --------------------- .../game/data/GameDefinitionLoader.java | 84 ++++++++++++++++++++++ .../game/data/definitions/DecksDefinition.java | 43 ++++++++++- .../game/data/definitions/GameDefinition.java | 43 +++++++++++ src/main/js/package.json | 4 +- src/main/js/src/test/GameData.js | 19 +++++ src/main/resources/static/index.html | 3 + src/main/resources/static/test-ws.js | 48 +++++++++++++ src/main/resources/static/test.html | 45 ++++++++++++ 23 files changed, 565 insertions(+), 330 deletions(-) create mode 100644 src/main/java/org/luxons/sevenwonders/SevenWonders.java create mode 100644 src/main/java/org/luxons/sevenwonders/WebSocketConfig.java create mode 100644 src/main/java/org/luxons/sevenwonders/actions/JoinGameAction.java delete mode 100644 src/main/java/org/luxons/sevenwonders/app/LobbyController.java delete mode 100644 src/main/java/org/luxons/sevenwonders/app/SevenWonders.java delete mode 100644 src/main/java/org/luxons/sevenwonders/app/WebSocketConfig.java delete mode 100644 src/main/java/org/luxons/sevenwonders/app/actions/JoinGameAction.java create mode 100644 src/main/java/org/luxons/sevenwonders/controllers/LobbyController.java create mode 100644 src/main/java/org/luxons/sevenwonders/controllers/TestController.java create mode 100644 src/main/java/org/luxons/sevenwonders/game/Decks.java create mode 100644 src/main/java/org/luxons/sevenwonders/game/GameData.java delete mode 100644 src/main/java/org/luxons/sevenwonders/game/data/Decks.java delete mode 100644 src/main/java/org/luxons/sevenwonders/game/data/GameData.java delete mode 100644 src/main/java/org/luxons/sevenwonders/game/data/GameDataLoader.java create mode 100644 src/main/java/org/luxons/sevenwonders/game/data/GameDefinitionLoader.java create mode 100644 src/main/java/org/luxons/sevenwonders/game/data/definitions/GameDefinition.java create mode 100644 src/main/js/src/test/GameData.js create mode 100644 src/main/resources/static/test-ws.js create mode 100644 src/main/resources/static/test.html (limited to 'src/main') diff --git a/src/main/java/org/luxons/sevenwonders/SevenWonders.java b/src/main/java/org/luxons/sevenwonders/SevenWonders.java new file mode 100644 index 00000000..2c20c5d3 --- /dev/null +++ b/src/main/java/org/luxons/sevenwonders/SevenWonders.java @@ -0,0 +1,12 @@ +package org.luxons.sevenwonders; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class SevenWonders { + + public static void main(String[] args) { + SpringApplication.run(SevenWonders.class, args); + } +} diff --git a/src/main/java/org/luxons/sevenwonders/WebSocketConfig.java b/src/main/java/org/luxons/sevenwonders/WebSocketConfig.java new file mode 100644 index 00000000..bbe91c16 --- /dev/null +++ b/src/main/java/org/luxons/sevenwonders/WebSocketConfig.java @@ -0,0 +1,28 @@ +package org.luxons.sevenwonders; + +import org.springframework.context.annotation.Configuration; +import org.springframework.messaging.simp.config.MessageBrokerRegistry; +import org.springframework.web.socket.config.annotation.AbstractWebSocketMessageBrokerConfigurer; +import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker; +import org.springframework.web.socket.config.annotation.StompEndpointRegistry; + +@Configuration +@EnableWebSocketMessageBroker +public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer { + + @Override + public void configureMessageBroker(MessageBrokerRegistry config) { + // prefixes for all subscriptions + config.enableSimpleBroker("/broadcast", "/queue", "/topic"); + config.setUserDestinationPrefix("/user"); + + // prefix for all calls from clients + config.setApplicationDestinationPrefixes("/app"); + } + + @Override + public void registerStompEndpoints(StompEndpointRegistry registry) { + registry.addEndpoint("/seven-wonders-websocket").withSockJS(); + } + +} \ No newline at end of file diff --git a/src/main/java/org/luxons/sevenwonders/actions/JoinGameAction.java b/src/main/java/org/luxons/sevenwonders/actions/JoinGameAction.java new file mode 100644 index 00000000..a9a84d78 --- /dev/null +++ b/src/main/java/org/luxons/sevenwonders/actions/JoinGameAction.java @@ -0,0 +1,24 @@ +package org.luxons.sevenwonders.actions; + +public class JoinGameAction { + + private String gameId; + + private String playerName; + + public String getGameId() { + return gameId; + } + + public void setGameId(String gameId) { + this.gameId = gameId; + } + + public String getPlayerName() { + return playerName; + } + + public void setPlayerName(String playerName) { + this.playerName = playerName; + } +} diff --git a/src/main/java/org/luxons/sevenwonders/app/LobbyController.java b/src/main/java/org/luxons/sevenwonders/app/LobbyController.java deleted file mode 100644 index a1358a58..00000000 --- a/src/main/java/org/luxons/sevenwonders/app/LobbyController.java +++ /dev/null @@ -1,58 +0,0 @@ -package org.luxons.sevenwonders.app; - -import java.util.HashMap; -import java.util.Map; - -import org.luxons.sevenwonders.app.actions.JoinGameAction; -import org.luxons.sevenwonders.game.Game; -import org.luxons.sevenwonders.game.Player; -import org.luxons.sevenwonders.game.Settings; -import org.luxons.sevenwonders.game.data.GameDataLoader; -import org.springframework.messaging.handler.annotation.MessageMapping; -import org.springframework.messaging.handler.annotation.SendTo; -import org.springframework.messaging.simp.SimpMessageHeaderAccessor; -import org.springframework.stereotype.Controller; - -@Controller -public class LobbyController { - - private long lastGameId = 0; - - private Map games = new HashMap<>(); - - @MessageMapping("/lobby/create-game") - @SendTo("/broadcast/games") - public String createGame(SimpMessageHeaderAccessor headerAccessor) throws Exception { - System.out.println("Received message: " + headerAccessor.getSessionId()); - Thread.sleep(1000); // simulated delay - - String id = String.valueOf(lastGameId++); - System.out.println("Creating game " + id); - - Settings settings = new Settings(); - Game game = new Game(settings, GameDataLoader.load(settings)); - games.put(id, game); - return id; - } - - @MessageMapping("/lobby/join-game") - @SendTo("/broadcast/players") - public Player joinGame(SimpMessageHeaderAccessor headerAccessor, JoinGameAction joinAction) throws Exception { - Thread.sleep(1000); // simulated delay - - Player player = (Player)headerAccessor.getSessionAttributes().get("player"); - if (player != null) { - System.out.println("Client has already joined game under the name " + player.getName()); - return player; - } - System.out.println("Player " + joinAction.getPlayerName() + " joined game " + joinAction.getGameId()); - - Game game = games.get(joinAction.getGameId()); - Player newPlayer = new Player(joinAction.getPlayerName()); - game.addPlayer(newPlayer); - - headerAccessor.getSessionAttributes().put("player", newPlayer); - - return newPlayer; - } -} diff --git a/src/main/java/org/luxons/sevenwonders/app/SevenWonders.java b/src/main/java/org/luxons/sevenwonders/app/SevenWonders.java deleted file mode 100644 index 48f10045..00000000 --- a/src/main/java/org/luxons/sevenwonders/app/SevenWonders.java +++ /dev/null @@ -1,12 +0,0 @@ -package org.luxons.sevenwonders.app; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -public class SevenWonders { - - public static void main(String[] args) { - SpringApplication.run(SevenWonders.class, args); - } -} diff --git a/src/main/java/org/luxons/sevenwonders/app/WebSocketConfig.java b/src/main/java/org/luxons/sevenwonders/app/WebSocketConfig.java deleted file mode 100644 index e969c44e..00000000 --- a/src/main/java/org/luxons/sevenwonders/app/WebSocketConfig.java +++ /dev/null @@ -1,24 +0,0 @@ -package org.luxons.sevenwonders.app; - -import org.springframework.context.annotation.Configuration; -import org.springframework.messaging.simp.config.MessageBrokerRegistry; -import org.springframework.web.socket.config.annotation.AbstractWebSocketMessageBrokerConfigurer; -import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker; -import org.springframework.web.socket.config.annotation.StompEndpointRegistry; - -@Configuration -@EnableWebSocketMessageBroker -public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer { - - @Override - public void configureMessageBroker(MessageBrokerRegistry config) { - config.enableSimpleBroker("/broadcast"); - config.setApplicationDestinationPrefixes("/app"); - } - - @Override - public void registerStompEndpoints(StompEndpointRegistry registry) { - registry.addEndpoint("/seven-wonders-websocket").withSockJS(); - } - -} \ No newline at end of file diff --git a/src/main/java/org/luxons/sevenwonders/app/actions/JoinGameAction.java b/src/main/java/org/luxons/sevenwonders/app/actions/JoinGameAction.java deleted file mode 100644 index 66476427..00000000 --- a/src/main/java/org/luxons/sevenwonders/app/actions/JoinGameAction.java +++ /dev/null @@ -1,24 +0,0 @@ -package org.luxons.sevenwonders.app.actions; - -public class JoinGameAction { - - private String gameId; - - private String playerName; - - public String getGameId() { - return gameId; - } - - public void setGameId(String gameId) { - this.gameId = gameId; - } - - public String getPlayerName() { - return playerName; - } - - public void setPlayerName(String playerName) { - this.playerName = playerName; - } -} diff --git a/src/main/java/org/luxons/sevenwonders/controllers/LobbyController.java b/src/main/java/org/luxons/sevenwonders/controllers/LobbyController.java new file mode 100644 index 00000000..f97c5fe2 --- /dev/null +++ b/src/main/java/org/luxons/sevenwonders/controllers/LobbyController.java @@ -0,0 +1,67 @@ +package org.luxons.sevenwonders.controllers; + +import java.util.HashMap; +import java.util.Map; + +import org.luxons.sevenwonders.actions.JoinGameAction; +import org.luxons.sevenwonders.game.Game; +import org.luxons.sevenwonders.game.Player; +import org.luxons.sevenwonders.game.Settings; +import org.luxons.sevenwonders.game.data.GameDefinitionLoader; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.messaging.handler.annotation.MessageMapping; +import org.springframework.messaging.handler.annotation.SendTo; +import org.springframework.messaging.simp.SimpMessageHeaderAccessor; +import org.springframework.stereotype.Controller; + +@Controller +//@MessageMapping("/lobby") +public class LobbyController { + + private final GameDefinitionLoader gameDefinitionLoader; + + private long lastGameId = 0; + + private Map games = new HashMap<>(); + + @Autowired + public LobbyController(GameDefinitionLoader gameDefinitionLoader) { + this.gameDefinitionLoader = gameDefinitionLoader; + } + + @MessageMapping("/create-game") + @SendTo("/broadcast/games") + public String createGame(SimpMessageHeaderAccessor headerAccessor) throws Exception { + System.out.println("Received message: " + headerAccessor.getSessionId()); + Thread.sleep(1000); // simulated delay + + String id = String.valueOf(lastGameId++); + System.out.println("Creating game " + id); + + Settings settings = new Settings(); + Game game = new Game(settings, GameDefinitionLoader.load().create(settings)); + games.put(id, game); + return id; + } + + @MessageMapping("/join-game") + @SendTo("/broadcast/players") + public Player joinGame(SimpMessageHeaderAccessor headerAccessor, JoinGameAction joinAction) throws Exception { + Thread.sleep(1000); // simulated delay + + Player player = (Player)headerAccessor.getSessionAttributes().get("player"); + if (player != null) { + System.out.println("Client has already joined game under the name " + player.getName()); + return player; + } + System.out.println("Player " + joinAction.getPlayerName() + " joined game " + joinAction.getGameId()); + + Game game = games.get(joinAction.getGameId()); + Player newPlayer = new Player(joinAction.getPlayerName()); + game.addPlayer(newPlayer); + + headerAccessor.getSessionAttributes().put("player", newPlayer); + + return newPlayer; + } +} diff --git a/src/main/java/org/luxons/sevenwonders/controllers/TestController.java b/src/main/java/org/luxons/sevenwonders/controllers/TestController.java new file mode 100644 index 00000000..06ebbdf3 --- /dev/null +++ b/src/main/java/org/luxons/sevenwonders/controllers/TestController.java @@ -0,0 +1,65 @@ +package org.luxons.sevenwonders.controllers; + +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; + +@Controller +public class TestController { + + // sent to subscribers of /topic/test1 + @MessageMapping("/test1") + public String test1(SimpMessageHeaderAccessor headerAccessor) throws Exception { + System.out.println("No annotation - " + headerAccessor.getSessionId()); + + return "success test1"; + } + + // sent to subscribers of /broadcast/test2 + @MessageMapping("/test2") + @SendTo("/broadcast/test2") + public String test2(SimpMessageHeaderAccessor headerAccessor) throws Exception { + System.out.println("@SendTo /broadcast/test2 - " + headerAccessor.getSessionId()); + + return "success test2"; + } + + @MessageMapping("/test3") + @SendToUser("/broadcast/test3") + public String test3(SimpMessageHeaderAccessor headerAccessor) throws Exception { + System.out.println("@SendToUser /broadcast/test3 - " + headerAccessor.getSessionId()); + + return "success test3"; + } + + @MessageMapping("/test4") + @SendToUser("/test4") + public String test4(SimpMessageHeaderAccessor headerAccessor) throws Exception { + System.out.println("@SendToUser /test4 - " + headerAccessor.getSessionId()); + + return "success test4"; + } + + // sent to the caller user if he subscribed to /user/queue/test5 + // other subscribers of /user/queue/test5 are NOT notified + @MessageMapping("/test5") + @SendToUser + public String test5(SimpMessageHeaderAccessor headerAccessor) throws Exception { + System.out.println("@SendToUser (no path) - " + headerAccessor.getSessionId()); + + return "success test5"; + } + + // sent to the caller user if he subscribed to /user/queue/test5 + // other subscribers of /user/queue/test5 are NOT notified + @MessageMapping("/test6") + // TODO + public String test6(SimpMessageHeaderAccessor headerAccessor) throws Exception { + // TODO + System.out.println("@SendToUser (no path) - " + headerAccessor.getSessionId()); + + return "success test6"; + } +} diff --git a/src/main/java/org/luxons/sevenwonders/game/Decks.java b/src/main/java/org/luxons/sevenwonders/game/Decks.java new file mode 100644 index 00000000..72dff4e9 --- /dev/null +++ b/src/main/java/org/luxons/sevenwonders/game/Decks.java @@ -0,0 +1,21 @@ +package org.luxons.sevenwonders.game; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.luxons.sevenwonders.game.cards.Card; + +public class Decks { + + private Map> cardsPerAge = new HashMap<>(); + + public Decks(Map> cardsPerAge) { + this.cardsPerAge = cardsPerAge; + } + + public List getCards(int age) { + return cardsPerAge.getOrDefault(age, Collections.emptyList()); + } +} diff --git a/src/main/java/org/luxons/sevenwonders/game/Game.java b/src/main/java/org/luxons/sevenwonders/game/Game.java index 08c34578..ec2665fe 100644 --- a/src/main/java/org/luxons/sevenwonders/game/Game.java +++ b/src/main/java/org/luxons/sevenwonders/game/Game.java @@ -5,7 +5,6 @@ import java.util.Collections; import java.util.List; import org.luxons.sevenwonders.game.boards.Board; -import org.luxons.sevenwonders.game.data.GameData; import org.luxons.sevenwonders.game.wonders.Wonder; public class Game { @@ -14,9 +13,9 @@ public class Game { private final Settings settings; - private List players; + private final List players; - private List boards; + private final List boards; private State state = State.LOBBY; @@ -36,10 +35,17 @@ public class Game { } int playerId = players.size(); players.add(player); - boards.add(new Board(pickWonder(), settings)); return playerId; } + public synchronized void startGame() { + if (!hasEnoughPlayers()) { + throw new PlayerUnderflowException(); + } + state = State.PLAYING; + randomizeBoards(); + } + private boolean hasStarted() { return state == State.PLAYING; } @@ -48,28 +54,16 @@ public class Game { return players.size() >= data.getMaxPlayers(); } - private Wonder pickWonder() { - List availableWonders = new ArrayList<>(data.getWonders()); - removeAlreadyUsedWondersFrom(availableWonders); - Collections.shuffle(availableWonders); - return availableWonders.get(0); - } - - private void removeAlreadyUsedWondersFrom(List wonders) { - boards.stream().map(Board::getWonder).forEach(wonders::remove); - } - - public synchronized void startGame() { - if (!hasEnoughPlayers()) { - throw new PlayerUnderflowException(); - } - state = State.PLAYING; - } - private boolean hasEnoughPlayers() { return players.size() >= data.getMinPlayers(); } + private void randomizeBoards() { + List randomizedWonders = new ArrayList<>(data.getWonders()); + Collections.shuffle(randomizedWonders, settings.getRandom()); + randomizedWonders.stream().map(w -> new Board(w, settings)).forEach(boards::add); + } + public class GameAlreadyStartedException extends IllegalStateException { } diff --git a/src/main/java/org/luxons/sevenwonders/game/GameData.java b/src/main/java/org/luxons/sevenwonders/game/GameData.java new file mode 100644 index 00000000..100389be --- /dev/null +++ b/src/main/java/org/luxons/sevenwonders/game/GameData.java @@ -0,0 +1,46 @@ +package org.luxons.sevenwonders.game; + +import java.util.ArrayList; +import java.util.List; + +import org.luxons.sevenwonders.game.wonders.Wonder; + +public class GameData { + + private final int minPlayers; + + private final int maxPlayers; + + private List wonders = new ArrayList<>(); + + private Decks decks; + + public GameData(int minPlayers, int maxPlayers) { + this.minPlayers = minPlayers; + this.maxPlayers = maxPlayers; + } + + public int getMinPlayers() { + return minPlayers; + } + + public int getMaxPlayers() { + return maxPlayers; + } + + public List getWonders() { + return wonders; + } + + public void setWonders(List wonders) { + this.wonders = wonders; + } + + public Decks getDecks() { + return decks; + } + + public void setDecks(Decks decks) { + this.decks = decks; + } +} diff --git a/src/main/java/org/luxons/sevenwonders/game/data/Decks.java b/src/main/java/org/luxons/sevenwonders/game/data/Decks.java deleted file mode 100644 index ea12ee8f..00000000 --- a/src/main/java/org/luxons/sevenwonders/game/data/Decks.java +++ /dev/null @@ -1,57 +0,0 @@ -package org.luxons.sevenwonders.game.data; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -import org.luxons.sevenwonders.game.Settings; -import org.luxons.sevenwonders.game.cards.Card; -import org.luxons.sevenwonders.game.data.definitions.CardDefinition; -import org.luxons.sevenwonders.game.data.definitions.DecksDefinition; - -public class Decks { - - private Map> cardsPerAge = new HashMap<>(); - - public Decks(DecksDefinition decksDefinition, Settings settings) { - cardsPerAge.put(1, prepareStandardDeck(decksDefinition.getAge1(), settings)); - cardsPerAge.put(2, prepareStandardDeck(decksDefinition.getAge2(), settings)); - cardsPerAge.put(3, prepareAge3Deck(decksDefinition, settings)); - } - - public List getCards(int age) { - return cardsPerAge.getOrDefault(age, Collections.emptyList()); - } - - private static List prepareStandardDeck(List defs, Settings settings) { - List cards = createDeck(defs, settings); - Collections.shuffle(cards, settings.getRandom()); - return cards; - } - - private static List prepareAge3Deck(DecksDefinition decksDefinition, Settings settings) { - List age3deck = createDeck(decksDefinition.getAge3(), settings); - age3deck.addAll(createGuildCards(decksDefinition.getGuildCards(), settings)); - Collections.shuffle(age3deck, settings.getRandom()); - return age3deck; - } - - private static List createDeck(List defs, Settings settings) { - List cards = new ArrayList<>(); - for (CardDefinition def : defs) { - for (int i = 0; i < def.getCountPerNbPlayer().get(settings.getNbPlayers()); i++) { - cards.add(def.create(settings)); - } - } - return cards; - } - - private static List createGuildCards(List defs, Settings settings) { - List guild = defs.stream().map((def) -> def.create(settings)).collect(Collectors.toList()); - Collections.shuffle(guild, settings.getRandom()); - return guild.subList(0, settings.getNbPlayers()); - } -} diff --git a/src/main/java/org/luxons/sevenwonders/game/data/GameData.java b/src/main/java/org/luxons/sevenwonders/game/data/GameData.java deleted file mode 100644 index 9abf69c4..00000000 --- a/src/main/java/org/luxons/sevenwonders/game/data/GameData.java +++ /dev/null @@ -1,49 +0,0 @@ -package org.luxons.sevenwonders.game.data; - -import java.util.ArrayList; -import java.util.List; - -import org.luxons.sevenwonders.game.wonders.Wonder; - -public class GameData { - - private int minPlayers = 3; - - private int maxPlayers = 7; - - private List wonders = new ArrayList<>(); - - private Decks decks; - - public int getMinPlayers() { - return minPlayers; - } - - public void setMinPlayers(int minPlayers) { - this.minPlayers = minPlayers; - } - - public int getMaxPlayers() { - return maxPlayers; - } - - public void setMaxPlayers(int maxPlayers) { - this.maxPlayers = maxPlayers; - } - - public List getWonders() { - return wonders; - } - - public void setWonders(List wonders) { - this.wonders = wonders; - } - - public Decks getDecks() { - return decks; - } - - public void setDecks(Decks decks) { - this.decks = decks; - } -} diff --git a/src/main/java/org/luxons/sevenwonders/game/data/GameDataLoader.java b/src/main/java/org/luxons/sevenwonders/game/data/GameDataLoader.java deleted file mode 100644 index a4c14a7b..00000000 --- a/src/main/java/org/luxons/sevenwonders/game/data/GameDataLoader.java +++ /dev/null @@ -1,81 +0,0 @@ -package org.luxons.sevenwonders.game.data; - -import java.io.BufferedReader; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.Reader; -import java.lang.reflect.Type; -import java.util.Arrays; -import java.util.List; -import java.util.stream.Collectors; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.reflect.TypeToken; -import org.luxons.sevenwonders.game.Settings; -import org.luxons.sevenwonders.game.data.definitions.DecksDefinition; -import org.luxons.sevenwonders.game.data.definitions.WonderDefinition; -import org.luxons.sevenwonders.game.data.serializers.NumericEffectSerializer; -import org.luxons.sevenwonders.game.data.serializers.ProductionIncreaseSerializer; -import org.luxons.sevenwonders.game.data.serializers.ResourceTypeSerializer; -import org.luxons.sevenwonders.game.data.serializers.ResourceTypesSerializer; -import org.luxons.sevenwonders.game.data.serializers.ResourcesSerializer; -import org.luxons.sevenwonders.game.data.serializers.ScienceProgressSerializer; -import org.luxons.sevenwonders.game.effects.GoldIncrease; -import org.luxons.sevenwonders.game.effects.MilitaryReinforcements; -import org.luxons.sevenwonders.game.effects.ProductionIncrease; -import org.luxons.sevenwonders.game.effects.RawPointsIncrease; -import org.luxons.sevenwonders.game.effects.ScienceProgress; -import org.luxons.sevenwonders.game.resources.ResourceType; -import org.luxons.sevenwonders.game.resources.Resources; - -public class GameDataLoader { - - private static final String BASE_PACKAGE = GameDataLoader.class.getPackage().getName(); - - private static final String BASE_PACKAGE_PATH = '/' + BASE_PACKAGE.replace('.', '/'); - - private static final String CARDS_FILE = "cards.json"; - - private static final String WONDERS_FILE = "wonders.json"; - - public static GameData load(Settings settings) { - GameData data = new GameData(); - - WonderDefinition[] wonders = loadWonders(); - data.setWonders(Arrays.stream(wonders).map(def -> def.create(settings)).collect(Collectors.toList())); - - DecksDefinition decksDefinition = loadDecks(); - data.setDecks(decksDefinition.create(settings)); - return data; - } - - private static WonderDefinition[] loadWonders() { - return readJsonFile(WONDERS_FILE, WonderDefinition[].class); - } - - private static DecksDefinition loadDecks() { - return readJsonFile(CARDS_FILE, DecksDefinition.class); - } - - private static T readJsonFile(String filename, Class clazz) { - InputStream in = GameDataLoader.class.getResourceAsStream(BASE_PACKAGE_PATH + '/' + filename); - Reader reader = new BufferedReader(new InputStreamReader(in)); - Gson gson = createGson(); - return gson.fromJson(reader, clazz); - } - - private static Gson createGson() { - Type resourceTypeList = new TypeToken>() {}.getType(); - return new GsonBuilder().disableHtmlEscaping() - .registerTypeAdapter(Resources.class, new ResourcesSerializer()) - .registerTypeAdapter(ResourceType.class, new ResourceTypeSerializer()) - .registerTypeAdapter(resourceTypeList, new ResourceTypesSerializer()) - .registerTypeAdapter(ProductionIncrease.class, new ProductionIncreaseSerializer()) - .registerTypeAdapter(MilitaryReinforcements.class, new NumericEffectSerializer()) - .registerTypeAdapter(RawPointsIncrease.class, new NumericEffectSerializer()) - .registerTypeAdapter(GoldIncrease.class, new NumericEffectSerializer()) - .registerTypeAdapter(ScienceProgress.class, new ScienceProgressSerializer()) - .create(); - } -} diff --git a/src/main/java/org/luxons/sevenwonders/game/data/GameDefinitionLoader.java b/src/main/java/org/luxons/sevenwonders/game/data/GameDefinitionLoader.java new file mode 100644 index 00000000..a2f39ed4 --- /dev/null +++ b/src/main/java/org/luxons/sevenwonders/game/data/GameDefinitionLoader.java @@ -0,0 +1,84 @@ +package org.luxons.sevenwonders.game.data; + +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.lang.reflect.Type; +import java.util.List; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.reflect.TypeToken; +import org.luxons.sevenwonders.game.data.definitions.DecksDefinition; +import org.luxons.sevenwonders.game.data.definitions.GameDefinition; +import org.luxons.sevenwonders.game.data.definitions.WonderDefinition; +import org.luxons.sevenwonders.game.data.serializers.NumericEffectSerializer; +import org.luxons.sevenwonders.game.data.serializers.ProductionIncreaseSerializer; +import org.luxons.sevenwonders.game.data.serializers.ResourceTypeSerializer; +import org.luxons.sevenwonders.game.data.serializers.ResourceTypesSerializer; +import org.luxons.sevenwonders.game.data.serializers.ResourcesSerializer; +import org.luxons.sevenwonders.game.data.serializers.ScienceProgressSerializer; +import org.luxons.sevenwonders.game.effects.GoldIncrease; +import org.luxons.sevenwonders.game.effects.MilitaryReinforcements; +import org.luxons.sevenwonders.game.effects.ProductionIncrease; +import org.luxons.sevenwonders.game.effects.RawPointsIncrease; +import org.luxons.sevenwonders.game.effects.ScienceProgress; +import org.luxons.sevenwonders.game.resources.ResourceType; +import org.luxons.sevenwonders.game.resources.Resources; +import org.springframework.stereotype.Component; + +@Component +public class GameDefinitionLoader { + + private static final String BASE_PACKAGE = GameDefinitionLoader.class.getPackage().getName(); + + private static final String BASE_PACKAGE_PATH = '/' + BASE_PACKAGE.replace('.', '/'); + + private static final String CARDS_FILE = "cards.json"; + + private static final String WONDERS_FILE = "wonders.json"; + + private final GameDefinition gameDefinition; + + public GameDefinitionLoader() { + gameDefinition = new GameDefinition(loadWonders(), loadDecks()); + } + + public GameDefinition getGameDefinition() { + return gameDefinition; + } + + public static GameDefinition load() { + return new GameDefinition(loadWonders(), loadDecks()); + } + + private static WonderDefinition[] loadWonders() { + return readJsonFile(WONDERS_FILE, WonderDefinition[].class); + } + + private static DecksDefinition loadDecks() { + return readJsonFile(CARDS_FILE, DecksDefinition.class); + } + + private static T readJsonFile(String filename, Class clazz) { + InputStream in = GameDefinitionLoader.class.getResourceAsStream(BASE_PACKAGE_PATH + '/' + filename); + Reader reader = new BufferedReader(new InputStreamReader(in)); + Gson gson = createGson(); + return gson.fromJson(reader, clazz); + } + + private static Gson createGson() { + Type resourceTypeList = new TypeToken>() {}.getType(); + return new GsonBuilder().disableHtmlEscaping() + .registerTypeAdapter(Resources.class, new ResourcesSerializer()) + .registerTypeAdapter(ResourceType.class, new ResourceTypeSerializer()) + .registerTypeAdapter(resourceTypeList, new ResourceTypesSerializer()) + .registerTypeAdapter(ProductionIncrease.class, new ProductionIncreaseSerializer()) + .registerTypeAdapter(MilitaryReinforcements.class, new NumericEffectSerializer()) + .registerTypeAdapter(RawPointsIncrease.class, new NumericEffectSerializer()) + .registerTypeAdapter(GoldIncrease.class, new NumericEffectSerializer()) + .registerTypeAdapter(ScienceProgress.class, new ScienceProgressSerializer()) + .create(); + } +} diff --git a/src/main/java/org/luxons/sevenwonders/game/data/definitions/DecksDefinition.java b/src/main/java/org/luxons/sevenwonders/game/data/definitions/DecksDefinition.java index bfe89d12..aaa44475 100644 --- a/src/main/java/org/luxons/sevenwonders/game/data/definitions/DecksDefinition.java +++ b/src/main/java/org/luxons/sevenwonders/game/data/definitions/DecksDefinition.java @@ -1,9 +1,15 @@ package org.luxons.sevenwonders.game.data.definitions; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; import org.luxons.sevenwonders.game.Settings; -import org.luxons.sevenwonders.game.data.Decks; +import org.luxons.sevenwonders.game.cards.Card; +import org.luxons.sevenwonders.game.Decks; public class DecksDefinition implements Definition { @@ -33,6 +39,39 @@ public class DecksDefinition implements Definition { @Override public Decks create(Settings settings) { - return new Decks(this, settings); + Map> cardsPerAge = new HashMap<>(); + cardsPerAge.put(1, prepareStandardDeck(age1, settings)); + cardsPerAge.put(2, prepareStandardDeck(age2, settings)); + cardsPerAge.put(3, prepareAge3Deck(settings)); + return new Decks(cardsPerAge); + } + + private static List prepareStandardDeck(List defs, Settings settings) { + List cards = createDeck(defs, settings); + Collections.shuffle(cards, settings.getRandom()); + return cards; + } + + private List prepareAge3Deck(Settings settings) { + List age3deck = createDeck(age3, settings); + age3deck.addAll(createGuildCards(guildCards, settings)); + Collections.shuffle(age3deck, settings.getRandom()); + return age3deck; + } + + private static List createDeck(List defs, Settings settings) { + List cards = new ArrayList<>(); + for (CardDefinition def : defs) { + for (int i = 0; i < def.getCountPerNbPlayer().get(settings.getNbPlayers()); i++) { + cards.add(def.create(settings)); + } + } + return cards; + } + + private static List createGuildCards(List defs, Settings settings) { + List guild = defs.stream().map((def) -> def.create(settings)).collect(Collectors.toList()); + Collections.shuffle(guild, settings.getRandom()); + return guild.subList(0, settings.getNbPlayers()); } } diff --git a/src/main/java/org/luxons/sevenwonders/game/data/definitions/GameDefinition.java b/src/main/java/org/luxons/sevenwonders/game/data/definitions/GameDefinition.java new file mode 100644 index 00000000..5947c547 --- /dev/null +++ b/src/main/java/org/luxons/sevenwonders/game/data/definitions/GameDefinition.java @@ -0,0 +1,43 @@ +package org.luxons.sevenwonders.game.data.definitions; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +import org.luxons.sevenwonders.game.Settings; +import org.luxons.sevenwonders.game.GameData; +import org.luxons.sevenwonders.game.wonders.Wonder; + +public class GameDefinition implements Definition { + + /** + * This value is heavily dependent on the JSON data. Any change must be carefully thought through. + */ + private static final int MIN_PLAYERS = 3; + + /** + * This value is heavily dependent on the JSON data. Any change must be carefully thought through. + */ + private static final int MAX_PLAYERS = 7; + + private WonderDefinition[] wonders; + + private DecksDefinition decks; + + public GameDefinition(WonderDefinition[] wonders, DecksDefinition decks) { + this.wonders = wonders; + this.decks = decks; + } + + @Override + public GameData create(Settings settings) { + GameData data = new GameData(MIN_PLAYERS, MAX_PLAYERS); + data.setWonders(createWonders(settings)); + data.setDecks(decks.create(settings)); + return data; + } + + private List createWonders(Settings settings) { + return Arrays.stream(wonders).map(def -> def.create(settings)).collect(Collectors.toList()); + } +} diff --git a/src/main/js/package.json b/src/main/js/package.json index fbee6711..d47c5f90 100644 --- a/src/main/js/package.json +++ b/src/main/js/package.json @@ -7,7 +7,9 @@ }, "dependencies": { "react": "^15.4.1", - "react-dom": "^15.4.1" + "react-dom": "^15.4.1", + "sockjs-client": "1.1.1", + "stomp-websocket": "2.3.4" }, "scripts": { "start": "react-scripts start", diff --git a/src/main/js/src/test/GameData.js b/src/main/js/src/test/GameData.js new file mode 100644 index 00000000..21b3a077 --- /dev/null +++ b/src/main/js/src/test/GameData.js @@ -0,0 +1,19 @@ +import React, { Component } from 'react'; +import logo from '../logo.svg'; +import '../App.css'; + +class GameData extends Component { + constructor(props) { + this.props = props; + } + render() { + let cardItems = this.props.cards.map(c => ); + return ( +
    + {cardItems} +
+ ); + } +} + +export default GameData; diff --git a/src/main/resources/static/index.html b/src/main/resources/static/index.html index 1b959d56..6131e912 100644 --- a/src/main/resources/static/index.html +++ b/src/main/resources/static/index.html @@ -19,6 +19,9 @@

This is a stub index page for the project, for the sake of vertical completeness. We will soon get to work on it!

+Go to WS test page + +

Connection

diff --git a/src/main/resources/static/test-ws.js b/src/main/resources/static/test-ws.js new file mode 100644 index 00000000..48104537 --- /dev/null +++ b/src/main/resources/static/test-ws.js @@ -0,0 +1,48 @@ +var stompClient = null; + +function connect() { + console.log('Connecting...'); + var socket = new SockJS('/seven-wonders-websocket'); + stompClient = Stomp.over(socket); + stompClient.connect({}, function (frame) { + console.log('Connected: ' + frame); + + for (var i = 1; i < 10; i++) { + subscribeTest(stompClient, '/test' + i); + subscribeTest(stompClient, '/topic/test' + i); + subscribeTest(stompClient, '/broadcast/test' + i); + subscribeTest(stompClient, '/queue/test' + i); + subscribeTest(stompClient, '/user/queue/test' + i); + subscribeTest(stompClient, '/user/queue/topic/test' + i); + subscribeTest(stompClient, '/user/queue/broadcast/test' + i); + } + }); +} + +function sendTest(indexes) { + for (var i = 0; i < indexes.length; i++) { + stompClient.send("/app/test" + indexes[i], {}, "test payload " + indexes[i]); + } +} + +function subscribeTest(stompClient, endpoint) { + var id = endpoint.replace(new RegExp('/', 'g'), '') + '-data'; + $("#test-feeds").append('' + endpoint + 'no data received yet'); + stompClient.subscribe(endpoint, function (data) { + console.log("Received event on " + endpoint + ": data.body=" + data.body); + $("#" + id).html('received "' + data.body + '"'); + }); +} + +$(function () { + $("form").on('submit', function (e) { + e.preventDefault(); + }); + $("#send-test").click(function () { + var indexesToSend = $("#test-index-field").val().split(','); + sendTest(indexesToSend); + }); +}); + +// auto-connect +connect(); \ No newline at end of file diff --git a/src/main/resources/static/test.html b/src/main/resources/static/test.html new file mode 100644 index 00000000..93c5d928 --- /dev/null +++ b/src/main/resources/static/test.html @@ -0,0 +1,45 @@ + + + + Seven Wonders + + + + + + + + + + +

Seven Wonders Test Page

+ +

WS messages tests

+ + +
+ + + +
+
+ +

Subscribed feeds

+ + + + + + + + + + +
EndpointData received
+ + + + \ No newline at end of file -- cgit