From 4327d5bc70db49b72119773fc422d5e9b8954fc3 Mon Sep 17 00:00:00 2001 From: Timothée Floure Date: Mon, 2 May 2016 18:45:56 +0200 Subject: GameStateDeserializer Class --- .../epfl/xblast/client/GameStateDeserializer.java | 185 +++++++++++++++++++++ 1 file changed, 185 insertions(+) create mode 100644 src/ch/epfl/xblast/client/GameStateDeserializer.java diff --git a/src/ch/epfl/xblast/client/GameStateDeserializer.java b/src/ch/epfl/xblast/client/GameStateDeserializer.java new file mode 100644 index 0000000..f95c515 --- /dev/null +++ b/src/ch/epfl/xblast/client/GameStateDeserializer.java @@ -0,0 +1,185 @@ +package ch.epfl.xblast.client; + +import ch.epfl.xblast.PlayerID; +import ch.epfl.xblast.RunLengthEncoder; +import ch.epfl.xblast.SubCell; +import ch.epfl.xblast.client.GameState.Player; +import ch.epfl.xblast.server.Ticks; + +import java.util.ArrayList; +import java.util.List; +import java.awt.Image; +import java.util.stream.Collectors; + +/** + * @author Timothée FLOURE (257420) + */ +public final class GameStateDeserializer { + /** + * Image collections folders + */ + private final static String BOARD_IMAGES_FOLDER = "block"; + private final static String EXPLOSION_IMAGES_FOLDER = "explosion"; + private final static String PLAYER_IMAGES_FOLDER = "player"; + private final static String TIME_IMAGES_FOLDER = "score"; + private final static String SCORE_IMAGES_FOLDER = "score"; + + /** + * Serialized data chunks + */ + private final static int NUMBER_OF_PLAYERS = 4; + private final static int PLAYER_CHUNK_SIZE = 6; + private final static int PLAYER_SIZE = NUMBER_OF_PLAYERS * PLAYER_CHUNK_SIZE; + private final static int TIME_LINE_SIZE = (Ticks.GAME_DURATION / 2); + + /** + * Images ID + */ + private final static int TIME_LINE_LED_ON_IMAGE_ID = 21; + private final static int TIME_LINE_LED_OFF_IMAGE_ID = 20; + private final static int SCORE_TEXT_MIDDLE_IMAGE_ID = 10; + private final static int SCORE_TEXT_RIGHT_IMAGE_ID = 11; + private final static int SCORE_TILE_VOID_IMAGE_ID = 12; + + /** + * Deserialize an encoded chunk of data and link it to images. + * + * @param data serialized data + * @param imageCollection ImageCollection related to the type of data + * @return a list of Images corresponding to the serialized element + */ + private static List deserializeChunk(List data, ImageCollection imageCollection) { + return RunLengthEncoder.decode(data).stream() + .map(c -> imageCollection.imageOrNull(Byte.toUnsignedInt(c))) + .collect(Collectors.toList()); + } + + /** + * Build a list of players given the serialized data.. + * + * @param serializedPlayers the serialized players + * @return a list of players built from the serialized players + */ + private static List deserializePlayers(List serializedPlayers) { + List players = new ArrayList<>(); + + for (int i = 0; i < NUMBER_OF_PLAYERS; i++) { + players.add( + deserializePlayer( + serializedPlayers.subList(i * PLAYER_CHUNK_SIZE, (i+1) * PLAYER_CHUNK_SIZE), i + ) + ); + } + + return players; + } + + /** + * Generate a Player from the serialized data. + * + * @param serializedPlayer a serialized player + * @return a player built from the serialized player + */ + private static Player deserializePlayer(List serializedPlayer, int i) { + PlayerID id = PlayerID.values()[i]; + int lives = Byte.toUnsignedInt(serializedPlayer.get(0)); + SubCell position = new SubCell( + Byte.toUnsignedInt(serializedPlayer.get(1)), + Byte.toUnsignedInt(serializedPlayer.get(2)) + ); + Image image = (new ImageCollection(PLAYER_IMAGES_FOLDER)).imageOrNull(Byte.toUnsignedInt(serializedPlayer.get(3))); + + return new Player(id, lives, position, image); + } + + /** + * Generate the list of images composing the scores. + * + * @param players players + * @return the scores of the given players + */ + private static List buildScores(List players) { + List scores = new ArrayList<>(); + ImageCollection imageCollection = new ImageCollection(SCORE_IMAGES_FOLDER); + + scores.addAll(buildPlayerScore(players.get(0), imageCollection)); + + return scores; + } + + /** + * Generate the images composing the score of one player. + * + * @param player serialized data corresponding to the player + * @param imageCollection image collection related to the scores + * @return the score of the given player + */ + private static List buildPlayerScore(Player player, ImageCollection imageCollection) { + List playerScore = new ArrayList<>(); + + if (player.lives() < 1) + playerScore.add(imageCollection.imageOrNull(0 + (player.id().ordinal()*2))); + else + playerScore.add(imageCollection.imageOrNull(1 + (player.id().ordinal()*2))); + + playerScore.add(imageCollection.imageOrNull(SCORE_TEXT_MIDDLE_IMAGE_ID)); + playerScore.add(imageCollection.imageOrNull(SCORE_TEXT_RIGHT_IMAGE_ID)); + return playerScore; + } + /** + * Generate the list of images composing the time "line". + * + * @param time the remaining time + * @return the list of images composing the time "line" + */ + private static List buildTimeLine(Byte time) { + List ticks = new ArrayList<>(); + ImageCollection imageCollection = new ImageCollection(TIME_IMAGES_FOLDER); + + for (int i = 0; i < TIME_LINE_SIZE; i++) { + if (i < Byte.toUnsignedInt(time)) + ticks.add(imageCollection.imageOrNull(TIME_LINE_LED_ON_IMAGE_ID)); + else + ticks.add(imageCollection.imageOrNull(TIME_LINE_LED_OFF_IMAGE_ID)); + } + return ticks; + } + + /** + * Deserialize an incoming GameState. + * + * @param serializedData the serialized gameState + * @return a new GameState build from the serialized data. + */ + public static GameState deserialize(List serializedData) { + + // Indexes + int boardIndex = 1; + int boardSize = serializedData.get(boardIndex); + int explosionsIndex = boardIndex + boardSize; + int explosionsSize = serializedData.get(explosionsIndex); + int playersIndex = explosionsIndex + explosionsSize; + Byte time = serializedData.get(serializedData.size()); + + // Deserialize the Board + List board = deserializeChunk( + serializedData.subList(boardIndex, boardSize), + new ImageCollection(BOARD_IMAGES_FOLDER) + ); + + // Deserialize the explosions + List explosions = deserializeChunk( + serializedData.subList(boardIndex,boardSize), + new ImageCollection(EXPLOSION_IMAGES_FOLDER) + ); + + // Deserialize the players + List players = deserializePlayers(serializedData.subList(playersIndex,PLAYER_SIZE)); + + // Generate the scores and the time "line" + List scores = buildScores(players); + List timeLine = buildTimeLine(time); + + return new GameState(players, board, explosions, scores, timeLine); + } +} -- cgit v1.2.3