mirror of
https://github.com/michaelrausch/Party-Parrots-At-Sea.git
synced 2026-05-09 06:18:44 +00:00
ac47e9d88a
#bug #refactor #implement #story[1118]
222 lines
5.7 KiB
Java
222 lines
5.7 KiB
Java
package seng302.gameServer.messages;
|
|
|
|
import java.nio.ByteBuffer;
|
|
import java.nio.ByteOrder;
|
|
import java.util.Arrays;
|
|
import java.util.zip.CRC32;
|
|
|
|
public abstract class Message {
|
|
private final int CRC_SIZE = 4;
|
|
private Header header;
|
|
private ByteBuffer buffer;
|
|
private int bufferPosition;
|
|
private CRC32 crc;
|
|
|
|
/**
|
|
* @param header Set the header for this message
|
|
*/
|
|
void setHeader(Header header){
|
|
this.header = header;
|
|
}
|
|
|
|
/**
|
|
* @return the header specified for this message
|
|
*/
|
|
Header getHeader(){
|
|
return header;
|
|
}
|
|
|
|
/**
|
|
* @return the size of the message
|
|
*/
|
|
public abstract int getSize();
|
|
|
|
/**
|
|
* Allocate byte buffer to correct size
|
|
*/
|
|
void allocateBuffer(){
|
|
buffer = ByteBuffer.allocate(Header.getSize() + getSize() + CRC_SIZE);
|
|
buffer.order(ByteOrder.LITTLE_ENDIAN);
|
|
bufferPosition = 0;
|
|
buffer.position(bufferPosition);
|
|
}
|
|
|
|
/**
|
|
* Write the set header to the byte buffer
|
|
*/
|
|
void writeHeaderToBuffer(){
|
|
buffer.put(getHeader().getByteBuffer().array());
|
|
bufferPosition += Header.getSize();
|
|
buffer.position(bufferPosition);
|
|
}
|
|
|
|
/**
|
|
* Move the buffer position by n bytes
|
|
* @param size Number of bytes to move the buffer by
|
|
*/
|
|
private void moveBufferPositionBy(int size){
|
|
bufferPosition += size;
|
|
buffer.position(bufferPosition);
|
|
}
|
|
|
|
/**
|
|
* Put an unsigned byte in the buffer
|
|
*/
|
|
void putUnsignedByte(byte b){
|
|
buffer.put(ByteBuffer.allocate(1).put((byte) (b & 0xff)).array());
|
|
moveBufferPositionBy(1);
|
|
}
|
|
|
|
/**
|
|
* Put an signed byte in the buffer
|
|
*/
|
|
void putByte(byte b){
|
|
buffer.put(ByteBuffer.allocate(1).put(b).array());
|
|
moveBufferPositionBy(1);
|
|
}
|
|
|
|
/**
|
|
* Place an unsigned integer of the specified length in the buffer
|
|
* @param val The integer value to add (Note: This must be long due to java not supporting unsigned integers)
|
|
* @param size The size of the int to be added to the buffer
|
|
*/
|
|
void putUnsignedInt(long val, int size){
|
|
if (size <= 1){
|
|
putUnsignedByte((byte) val);
|
|
|
|
}
|
|
else if (size < 4){
|
|
// Use short
|
|
byte[] tmp = Message.intToByteArray(val, size); //ByteBuffer.allocate(size).putShort((short) (val & 0xffff)).array();
|
|
reverse(tmp);
|
|
buffer.put(tmp);
|
|
moveBufferPositionBy(size);
|
|
}
|
|
else{
|
|
// Use int
|
|
byte[] tmp = Message.intToByteArray(val, size);
|
|
reverse(tmp);
|
|
moveBufferPositionBy(size);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Put a signed int of a specified length in the buffer
|
|
* @param val The integer value to add
|
|
* @param size The size of the integer to be added to the buffer
|
|
*/
|
|
void putInt(long val, int size){
|
|
if (size < 4){
|
|
byte[] tmp = Message.intToByteArray(val, size);
|
|
reverse(tmp);
|
|
buffer.put(tmp);
|
|
}
|
|
else{
|
|
byte[] tmp = Message.intToByteArray(val, size);
|
|
reverse(tmp);
|
|
buffer.put(tmp);
|
|
}
|
|
moveBufferPositionBy(size);
|
|
}
|
|
|
|
/**
|
|
* Write an array of bytes to the buffer
|
|
* @param bytes to write
|
|
*/
|
|
void putBytes(byte[] bytes){
|
|
buffer.put(bytes);
|
|
moveBufferPositionBy(bytes.length);
|
|
}
|
|
|
|
/**
|
|
* Write a ByteBuffer of bytes to the buffer
|
|
* @param bytes to write
|
|
* @param size number of bytes
|
|
*/
|
|
void putBytes(ByteBuffer bytes, int size){
|
|
buffer.put(bytes.array());
|
|
moveBufferPositionBy(size);
|
|
}
|
|
|
|
|
|
/**
|
|
* Calculate the CRC of the buffer and append it to the end of the buffer
|
|
*/
|
|
void writeCRC(){
|
|
crc = new CRC32();
|
|
|
|
buffer.position(0);
|
|
|
|
byte[] data = Arrays.copyOfRange(buffer.array(), 0, buffer.array().length-CRC_SIZE);
|
|
crc.update(data);
|
|
buffer.position(bufferPosition);
|
|
|
|
putInt((int) crc.getValue(), CRC_SIZE);
|
|
}
|
|
|
|
/**
|
|
* @return The current buffer as a byte array
|
|
*/
|
|
public byte[] getBuffer(){
|
|
return buffer.array();
|
|
}
|
|
|
|
/**
|
|
* Rewind the buffer to the beginning
|
|
*/
|
|
void rewind(){
|
|
buffer.flip();
|
|
}
|
|
|
|
/**
|
|
* Convert an integer to an array of bytes
|
|
* @param val The value to add
|
|
* @param len The width of the integer in the buffer
|
|
* @return A byte array to be sent
|
|
*/
|
|
public static byte[] intToByteArray(long val, int len){
|
|
int index = 0;
|
|
byte[] data = new byte[len];
|
|
|
|
for (int i = 0; i < len; i++){
|
|
data[len - index - 1] = (byte) (val & 0xFF);
|
|
val >>>= 8;
|
|
index++;
|
|
}
|
|
|
|
return data;
|
|
}
|
|
|
|
/**
|
|
* takes an array of up to 7 bytes in little endian format and
|
|
* returns a positive long constructed from the input bytes
|
|
*
|
|
* @param bytes the bytes to be converted to long
|
|
* @return a positive long if there is less than 8 bytes -1 otherwise
|
|
*/
|
|
public static long bytesToLong(byte[] bytes){
|
|
long partialLong = 0;
|
|
int index = 0;
|
|
for (byte b: bytes){
|
|
if (index > 6){
|
|
return -1;
|
|
}
|
|
partialLong = partialLong | (b & 0xFFL) << (index * 8);
|
|
index++;
|
|
}
|
|
return partialLong;
|
|
}
|
|
|
|
/**
|
|
* Reverse an array of bytes
|
|
* @param data The byte[] to reverse
|
|
*/
|
|
public static void reverse(byte[] data) {
|
|
for (int left = 0, right = data.length - 1; left < right; left++, right--) {
|
|
byte temp = (byte) (data[left] & 0xff);
|
|
data[left] = (byte) (data[right] & 0xff);
|
|
data[right] = (byte) (temp & 0xff);
|
|
}
|
|
}
|
|
}
|