From fe53f0e12433938f9d7696b1d2bf6bda691e55f3 Mon Sep 17 00:00:00 2001 From: Timothée Floure Date: Fri, 20 May 2016 14:16:36 +0200 Subject: Improve the documentation for the client package --- src/ch/epfl/xblast/client/Client.java | 131 +++++++++++++++++++++++++ src/ch/epfl/xblast/client/Main.java | 5 + src/ch/epfl/xblast/client/XBlastComponent.java | 96 ++++++++++++++++++ 3 files changed, 232 insertions(+) diff --git a/src/ch/epfl/xblast/client/Client.java b/src/ch/epfl/xblast/client/Client.java index b522312..8ccea00 100644 --- a/src/ch/epfl/xblast/client/Client.java +++ b/src/ch/epfl/xblast/client/Client.java @@ -26,13 +26,25 @@ import java.util.function.Consumer; */ public class Client { + /** + * Client's parameters. + */ private static final String DEFAULT_SERVER_HOST = "localhost"; private static final int DEFAULT_SERVER_PORT = Server.DEFAULT_PORT; private static final int PACKET_MAX_SIZE = 1000; private static final long REGISTER_PING_INTERVAL = 1 * Time.NS_PER_S; // ns + /** + * Communication channel. + */ private static class Channel { + /** + * Transform a buffer to a list of bytes. + * + * @param buf given buffer + * @return the list of bytes built from the given buffer + */ private static List bufferToList(ByteBuffer buf) { List l = new ArrayList<>(buf.remaining()); @@ -42,6 +54,11 @@ public class Client { return Collections.unmodifiableList(l); } + /** + * Create the UDP communication Channel. + * + * @return the UDP communication Channel + */ private static DatagramChannel openChannel() { try { return DatagramChannel.open(StandardProtocolFamily.INET); @@ -52,20 +69,37 @@ public class Client { } } + /** + * Parameters of the Channel. + */ private final SocketAddress serverAddr; private final DatagramChannel channel; + /** + * Instantiates a new Channel. + * + * @param iface socket + */ Channel(InetSocketAddress iface) { this.serverAddr = iface; this.channel = openChannel(); } + /** + * Instantiates a new Channel. + * + * @param host hostname + * @param port port + */ Channel(String host, Integer port) { this(new InetSocketAddress( Optional.ofNullable(host).orElse(DEFAULT_SERVER_HOST), Optional.ofNullable(port).orElse(DEFAULT_SERVER_PORT))); } + /** + * Close the Channel. + */ void closeChannel() { try { this.channel.close(); @@ -74,10 +108,21 @@ public class Client { } } + /** + * Send an action through the Channel. + * + * @param action action to send + */ void sendAction(PlayerAction action) { this.sendByte(action.toByte()); } + /** + * Receive a GameState through the Channel. + * + * @param block + * @return the received GameState + */ List receiveGameState(boolean block) { Optional> state; @@ -88,10 +133,20 @@ public class Client { return state.get(); } + /** + * Send a byte through the Channel. + * + * @param b byte to send + */ private void sendByte(byte b) { this.send(ByteBuffer.wrap(new byte[]{b})); } + /** + * Send the content of a buffer. + * + * @param b buffer containing the bytes to send + */ private void send(ByteBuffer b) { try { this.channel.send(b, this.serverAddr); @@ -100,6 +155,12 @@ public class Client { } } + /** + * Receive data from the Channel. + * + * @param block + * @return the received data + */ private Optional> receive(boolean block) { try { ByteBuffer buf = ByteBuffer.allocate(PACKET_MAX_SIZE); @@ -115,8 +176,17 @@ public class Client { } + /** + * The Graphical User Interface. + */ private static class GUI { + /** + * Build the window. + * + * @param content content of the window + * @return the frame + */ private static JFrame buildFrame(Container content) { JFrame frame = new JFrame(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); @@ -128,30 +198,58 @@ public class Client { return frame; } + /** + * Attach the keyboard events handler to the component. + * @param comp component + * @param actionConsumer actionConsumer corresponding to the keyboardEventHandler + */ private static void attachKeyboardHandler(Component comp, Consumer actionConsumer) { comp.addKeyListener(new KeyboardEventHandler(actionConsumer)); comp.requestFocusInWindow(); } + /** + * GUI's parameters. + */ private final XBlastComponent gameComponent; private final Consumer actionConsumer; + /** + * Instantiates a new GUI. + * + * @param actionConsumer actionConsumer corresponding to the keyboardEventHandler + */ GUI(Consumer actionConsumer) { this.gameComponent = new XBlastComponent(); this.actionConsumer = actionConsumer; } + /** + * Build and display the GUI. + */ public void display() { buildFrame(this.gameComponent); attachKeyboardHandler(this.gameComponent, this.actionConsumer); } + /** + * Update the displayed GameState. + * + * @param gs new GameState to be displayed + * @param p Player ID corresponding to the client + */ public void setGameState(GameState gs, PlayerID p) { this.gameComponent.setGameState(gs, p); } } + /** + * Deserialize the players' IDs. + * + * @param b a given byte + * @return the Player ID corresponding to the given byte + */ private static PlayerID deserializePlayerID(byte b) { if (b == Server.OBSERVER) return null; @@ -163,6 +261,12 @@ public class Client { } } + /** + * Deserialize a received GameState. + * + * @param b the serialized GameState + * @return the deserialized GameState + */ private static GameState deserializeGameState(List b) { try { return GameStateDeserializer.deserialize(b); @@ -171,14 +275,26 @@ public class Client { } } + /** + * Client's parameters. + */ private final Channel channel; private final GUI gui; + /** + * Instatiates a new client. + * + * @param host hostname + * @param port port + */ public Client(String host, Integer port) { this.channel = new Channel(host, port); this.gui = new GUI(this.channel::sendAction); } + /** + * Run the whole client. + */ public void run() { this.displayGUI(); this.establishConnection(); @@ -186,6 +302,9 @@ public class Client { this.channel.closeChannel(); } + /** + * Display the Graphical User Interface. + */ private void displayGUI() { try { SwingUtilities.invokeAndWait(this.gui::display); @@ -195,11 +314,17 @@ public class Client { } } + /** + * Launch the game. + */ private void runGame() { while (true) updateGameState(); } + /** + * Connect to the server and fetch the new GameState. + */ private void establishConnection() { Thread joinThread = new Thread(this::sendJoinRequest); joinThread.start(); @@ -207,6 +332,9 @@ public class Client { joinThread.interrupt(); } + /** + * Fetch the new GameState. + */ private void updateGameState() { List serializedGameState = this.channel.receiveGameState(true); if (serializedGameState.size() < 1) return; @@ -218,6 +346,9 @@ public class Client { this.gui.setGameState(gameState, player); } + /** + * Send a "Join" request to the server. + */ private void sendJoinRequest() { while (!Thread.currentThread().isInterrupted()) { this.channel.sendAction(PlayerAction.JOIN_GAME); diff --git a/src/ch/epfl/xblast/client/Main.java b/src/ch/epfl/xblast/client/Main.java index 19145c5..1a3cc6c 100644 --- a/src/ch/epfl/xblast/client/Main.java +++ b/src/ch/epfl/xblast/client/Main.java @@ -13,6 +13,11 @@ public final class Main { // Static class } + /** + * Start a new client. + * + * @param args arguments given to the client (i.e. port & address of the server) + */ public static void main(String[] args) { String host = ArgumentChecker.getOrNull(args, 0); Integer port = ArgumentChecker.parseIntOrNull(ArgumentChecker.getOrNull(args, 1)); diff --git a/src/ch/epfl/xblast/client/XBlastComponent.java b/src/ch/epfl/xblast/client/XBlastComponent.java index dfc0be5..42c7ab9 100644 --- a/src/ch/epfl/xblast/client/XBlastComponent.java +++ b/src/ch/epfl/xblast/client/XBlastComponent.java @@ -20,36 +20,69 @@ import java.util.stream.IntStream; */ public final class XBlastComponent extends JComponent { + /** + * Representation of the client's window as a grid. + */ private static class Grid { + /** + * Parameters of a grid. + */ private static final Dimension CELL_DIMENSION = new Dimension(64, 48); private static final Dimension SCORE_IMG_DIMENSION = new Dimension(48, 48); private static final Dimension TIME_LED_DIMENSION = new Dimension(16, 16); private static final Dimension FRAME_DIMENSION = totalDimension(); + /** + * Positions of the elements on the grid. + */ private static final List CELL_POSITIONS = buildCellGrid(CELL_DIMENSION); private static final List SCORE_BG_POSITIONS = buildScoreGrid(); private static final List TIME_LINE_POSITIONS = buildTimeLineGrid(); private static final Map SCORE_TXT_POSITIONS = buildScoreMap(659); + /** + * Returns the dimension of the grid. + * + * @return the dimension of the grid + */ private static Dimension totalDimension() { return new Dimension( CELL_DIMENSION.width * Cell.COLUMNS, CELL_DIMENSION.height * Cell.ROWS + SCORE_IMG_DIMENSION.height + TIME_LED_DIMENSION.height); } + /** + * Returns a list of positions of every cell on the grid. + * + * @param elementDim dimension of a cell + * @return a list of positions of every cell on the grid + */ private static List buildCellGrid(Dimension elementDim) { return Collections.unmodifiableList(Cell.ROW_MAJOR_ORDER.stream() .map(c -> new Point(c.x() * elementDim.width, c.y() * elementDim.height)) .collect(Collectors.toList())); } + /** + * Build a list containing the positions of the elements of a line. + * + * @param elementDim dimension of the every element of the line + * @param len length of the line + * @param shift shift + * @return list containing the positions of the elements of a line. + */ private static List buildLine(Dimension elementDim, int len, Point shift) { return Collections.unmodifiableList(IntStream.range(0, len) .mapToObj(x -> new Point(x * elementDim.width + shift.x, shift.y)) .collect(Collectors.toList())); } + /** + * Build the list of the positions of the scores' line elements. + * + * @return the list of the positions of the scores' line elements. + */ private static List buildScoreGrid() { return buildLine( SCORE_IMG_DIMENSION, @@ -57,6 +90,11 @@ public final class XBlastComponent extends JComponent { new Point(0, CELL_DIMENSION.height * Cell.ROWS)); } + /** + * Build the list of the positions of the time "line" elements. + * + * @return the list of the positions of the time "line" elements. + */ private static List buildTimeLineGrid() { return buildLine( TIME_LED_DIMENSION, @@ -64,6 +102,12 @@ public final class XBlastComponent extends JComponent { new Point(0, CELL_DIMENSION.height * Cell.ROWS + SCORE_IMG_DIMENSION.height)); } + /** + * Built the map linking the players' ID to the location of their scores on the grid. + * + * @param vShift vertical position of the scores on the grid + * @return map linking the players' ID to the location of their scores on the grid + */ private static Map buildScoreMap(int vShift) { Map m = new EnumMap<>(PlayerID.class); m.put(PlayerID.PLAYER_1, new Point(96, vShift)); @@ -73,6 +117,12 @@ public final class XBlastComponent extends JComponent { return m; } + /** + * Compute the position of a player on the grid. + * + * @param p given player + * @return the player's position on the grid + */ private static Point positionForPlayer(GameState.Player p) { return new Point( 4 * p.position().x() - 24, @@ -81,27 +131,59 @@ public final class XBlastComponent extends JComponent { } + /** + * Client's painter. + */ private static class Painter { + /** + * Painter's parameters. + */ private static final ImageObserver IMG_OBSERVER = null; private static final Font TXT_FONT = new Font("Arial", Font.BOLD, 25); private static final Color TXT_COLOR = Color.WHITE; + /** + * Draw a string on the graphic context at the given point. + * + * @param g the graphic context + * @param pos position on the graphic context + * @param str string to be draw + */ private static void drawString(Graphics2D g, Point pos, String str) { g.setColor(TXT_COLOR); g.setFont(TXT_FONT); g.drawString(str, pos.x, pos.y); } + /** + * Draw an image on the graphic at the given point. + * + * @param g the graphic context + * @param pos position on the graphic context. + * @param img image to be draw + */ private static void drawImage(Graphics2D g, Point pos, Image img) { g.drawImage(img, pos.x, pos.y, IMG_OBSERVER); } + /** + * Draw images given their location on the graphic context. + * + * @param g the graphic context + * @param m map linking images to points on the graphic context + */ private static void drawImageMap(Graphics2D g, Map m) { for (Map.Entry e : m.entrySet()) drawImage(g, e.getKey(), e.getValue()); } + /** + * Draw strings given their location on the graphic context. + * + * @param g the graphic context + * @param m map linking strings to their locations + */ private static void drawStringMap(Graphics2D g, Map m) { for (Map.Entry e : m.entrySet()) drawString(g, e.getKey(), e.getValue().toString()); @@ -120,6 +202,13 @@ public final class XBlastComponent extends JComponent { } + /** + * Sort the players in order to have the current player at first. + * + * @param players list of the players + * @param currentPlayerID player ID of the current player (the player playing on this client) + * @return the ordered list of players + */ private static List sortPlayers(List players, PlayerID currentPlayerID) { if (Objects.isNull(currentPlayerID)) return players; @@ -131,7 +220,14 @@ public final class XBlastComponent extends JComponent { .thenComparing(GameState.Player.idPushingComparator(currentPlayerID))); } + /** + * GameState to be displayed. + */ private GameState gameState; + + /** + * ID of the player related to this client. + */ private PlayerID playerID; /** -- cgit v1.2.3