package com.me.skifun; import java.nio.ByteBuffer; /* P2P (Player to Player) message used for sending messages over the wire. * * Right now the protocol demonstrates a way to pack the height position of each player, * but you can extend it to send information about the player position, velocity and acceleration. */ public abstract class P2PMessage { // General protocol constants private static class Constants { private static final byte INT_SIZE = 4; private static final byte FLOAT_SIZE = 4; } // Available message types public static class Types { public static final byte PLAYER_POSITION = 1; public static final byte PLAYER_SCORE=3; } // The type of the message public final byte type; // CTOR, initialize the message with its type private P2PMessage(byte type) { this.type = type; } // Try to decode the given message byte array into a P2PMessage. // @return null in case decode fail (invalid version, invalid size), Otherwise returns the P2PMessage object public static P2PMessage tryToDecodeOrNull(byte[] message) { if (message == null) return null; int msgType=ByteBuffer.wrap(message).getInt(0); P2PMessage decodedMessage = null; // Decode the message by its type if you can // Kind of Factory if you will. switch (msgType) { case Types.PLAYER_POSITION : { decodedMessage = PlayerPosition.tryToDecodeFromDataOrNull(message); break; } case Types.PLAYER_SCORE: { decodedMessage=PlayerScore.tryToDecodeFromDataOrNull(message); } default: break; } return decodedMessage; } // [byte][byte][int][*] // [version][type][data length][data] public byte[] encode() { byte[] data = getData(); return data; } // Abstract. Get the data of the subclass's members as byte array protected abstract byte[] getData(); /* * P2P Messages */ /* * Player movement message */ public static class PlayerScore extends P2PMessage{ public final int score; public PlayerScore(int score) { super(Types.PLAYER_SCORE); this.score=score; } protected byte[] getData() { return ByteBuffer.allocate(12).putInt(this.type).putInt(this.score).array(); } public static PlayerScore tryToDecodeFromDataOrNull(byte [] data) { if (data==null) { return null; } int dataLength=data.length; if (dataLength < Constants.INT_SIZE) { //System.out.println("data is too small for me dude"); return null; } int score = ByteBuffer.wrap(data).getInt(4); return new PlayerScore(score); } } public static class PlayerPosition extends P2PMessage { public final float x; public final float y; public final float state; // 0- alive 1- hit 2- dead // CTOR - initialize the player height message with heightSoFar public PlayerPosition(float x, float y, float state) { super(Types.PLAYER_POSITION); this.x = x; this.y= y; this.state=state; } @Override // [float] // [heightSoFar] protected byte[] getData() { return ByteBuffer.allocate(70).putInt(this.type).putFloat(this.x).putFloat(this.y).putFloat(this.state).array(); } // Decode the given data array into a valid message. // Return null in case the data length is invalid. public static PlayerPosition tryToDecodeFromDataOrNull(byte[] data) { if (data == null) { System.out.println("data is null, its not my fault"); return null; } int dataLength = data.length; // The minimum data type if (dataLength < Constants.FLOAT_SIZE) { System.out.println("data is too small for me dude"); return null; } // Position float x = ByteBuffer.wrap(data).getFloat(4); float y = ByteBuffer.wrap(data).getFloat(8); float state=ByteBuffer.wrap(data).getFloat(12); return new PlayerPosition(x,y,state); } } }