Skip to content

Instantly share code, notes, and snippets.

@Hadyn
Created July 15, 2016 10:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Hadyn/13dd47252f7e8c32e12969df8b919d31 to your computer and use it in GitHub Desktop.
Save Hadyn/13dd47252f7e8c32e12969df8b919d31 to your computer and use it in GitHub Desktop.
package com.evelus.galaxy;
import java.nio.ByteBuffer;
/**
* A message. All implementations of messages must inherit this class and provide functions
* to access various variables that are accessible from the buffer provided to the message.
*
* @author hadyn
*/
public class Message {
private ByteBuffer buffer;
private MessageStructure structure;
private OffsetTable offsets;
protected Message(ByteBuffer buffer, MessageStructure structure) {
this.buffer = buffer;
this.structure = structure;
offsets = structure.createOffsetTable(buffer);
}
/**
* Gets an integer variable from the message buffer.
*
* @param id the identifier of the variable to get.
* @return the integer variable value.
*/
protected int getInt(int id) {
if(!structure.isFieldType(id, MessageField.TYPE_INT)) {
throw new IllegalStateException("Expected field " + id + " to be an integer.");
}
buffer.position(offsets.getOffset(id));
return buffer.getInt();
}
}
package com.evelus.galaxy;
import java.nio.ByteBuffer;
/**
* @author hadyn
*/
public class MessageField {
public static final int TYPE_INT = 0;
private int id;
private String name;
private int type;
public MessageField(int id, String name, int type) {
this.id = id;
this.name = name;
this.type = type;
}
public int getId() {
return id;
}
public int getType() {
return type;
}
/**
* Gets the length of a data type in bytes.
*
* @param type the data type.
* @return the length in bytes.
*/
public static int getLength(ByteBuffer buffer, int offset, int type) {
switch (type) {
case TYPE_INT:
return 4;
default:
throw new UnsupportedOperationException("Unhandled data type.");
}
}
}
package com.evelus.galaxy;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
/**
* A structure which defines a message. Fields of a structure are parsed from buffers in ascending
* order of identifiers. For backwards compatibility updated structures are expected to retain the
* same identifiers for fields of previous versions. Fields being removed will break all backwards
* compatibility.
*
* @author hadyn
*/
public class MessageStructure {
/**
* The fields that comprise the structure.
*/
private Map<Integer, MessageField> fields = new HashMap<>();
/**
* Adds a field to the structure.
*
* @param field the field to add.
* @return the field that was replaced if one already existed for the provided field's identifier.
*/
public MessageField addField(MessageField field) {
return fields.put(field.getId(), field);
}
/**
* Gets a field.
*
* @param id the field identifier.
* @return the field.
*/
public MessageField getField(int id) {
return fields.get(id);
}
/**
* Gets if the structure contains a certain field.
*
* @param id the field identifier.
* @return if the structure has a field with the specified id.
*/
public boolean hasField(int id) {
return fields.containsKey(id);
}
/**
* Checks to see if a field is a certain type.
*
* @param id the identifier of the field.
* @param type the type to check.
* @return if the field is of the specified type.
*/
public boolean isFieldType(int id, int type) {
if (!hasField(id)) {
throw new NullPointerException("Field " + id + " does not exist.");
}
MessageField field = getField(id);
return field.getType() == type;
}
/**
* Creates an offset table for the structure. If the structure has variable length fields then the
* byte buffer will have to be read to determine the offsets of all of the variables.
*
* @param buffer the buffer to read from.
* @return the created offset table.
*/
public OffsetTable createOffsetTable(ByteBuffer buffer) {
OffsetTable table = new OffsetTable();
int offset = 0;
Set<Integer> ids = new TreeSet<>(fields.keySet());
for(int id : ids) {
MessageField field = fields.get(id);
table.addOffset(id, offset);
offset += MessageField.getLength(buffer, offset, field.getType());
}
return table;
}
}
package com.evelus.galaxy;
import java.util.HashMap;
import java.util.Map;
/**
* @author hadyn
*/
public class OffsetTable {
private Map<Integer, Integer> offsets = new HashMap<>();
public void addOffset(int id, int offset) {
offsets.put(id, offset);
}
public int getOffset(int id) {
if(!offsets.containsKey(id)) {
throw new IllegalArgumentException("Offset for variable " + id + " does not exist.");
}
return offsets.get(id);
}
}
package com.evelus.galaxy;
import java.nio.ByteBuffer;
/**
* @author hadyn
*/
public class SilabMessage extends Message {
public SilabMessage(ByteBuffer buffer, MessageStructure structure) {
super(buffer, structure);
}
public int getPowerLevel() {
return getInt(0);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment