package electrosphere.net.parser.net.message;

import io.github.studiorailgun.CircularByteBuffer;
import electrosphere.net.parser.util.ByteStreamUtils;
import java.util.LinkedList;
import java.util.List;

public class EntityMessage extends NetworkMessage {

    /**
     * The types of messages available in this category.
     */
    public enum EntityMessageType {
        CREATE,
        MOVEUPDATE,
        ATTACKUPDATE,
        STARTATTACK,
        KILL,
        DESTROY,
        SETPROPERTY,
        ATTACHENTITYTOENTITY,
        UPDATEENTITYVIEWDIR,
        SYNCPHYSICS,
        INTERACT,
    }

    /**
     * The type of this message in particular.
     */
    EntityMessageType messageType;
    int entityCategory;
    String entitySubtype;
    int entityID;
    String creatureTemplate;
    double positionX;
    double positionY;
    double positionZ;
    double rotationX;
    double rotationY;
    double rotationZ;
    double rotationW;
    double linVelX;
    double linVelY;
    double linVelZ;
    double angVelX;
    double angVelY;
    double angVelZ;
    double linForceX;
    double linForceY;
    double linForceZ;
    double angForceX;
    double angForceY;
    double angForceZ;
    double yaw;
    double pitch;
    double velocity;
    int treeState;
    int propertyType;
    int propertyValue;
    long time;
    String bone;
    int targetID;
    int bTreeID;
    int propertyValueInt;
    String interactionSignal;

    /**
     * Constructor
     * @param messageType The type of this message
     */
    private EntityMessage(EntityMessageType messageType){
        this.type = MessageType.ENTITY_MESSAGE;
        this.messageType = messageType;
    }

    /**
     * Constructor
     */
    protected EntityMessage(){
        this.type = MessageType.ENTITY_MESSAGE;
    }

    public EntityMessageType getMessageSubtype(){
        return this.messageType;
    }

    /**
     * Gets entityCategory
     */
    public int getentityCategory() {
        return entityCategory;
    }

    /**
     * Sets entityCategory
     */
    public void setentityCategory(int entityCategory) {
        this.entityCategory = entityCategory;
    }

    /**
     * Gets entitySubtype
     */
    public String getentitySubtype() {
        return entitySubtype;
    }

    /**
     * Sets entitySubtype
     */
    public void setentitySubtype(String entitySubtype) {
        this.entitySubtype = entitySubtype;
    }

    /**
     * Gets entityID
     */
    public int getentityID() {
        return entityID;
    }

    /**
     * Sets entityID
     */
    public void setentityID(int entityID) {
        this.entityID = entityID;
    }

    /**
     * Gets creatureTemplate
     */
    public String getcreatureTemplate() {
        return creatureTemplate;
    }

    /**
     * Sets creatureTemplate
     */
    public void setcreatureTemplate(String creatureTemplate) {
        this.creatureTemplate = creatureTemplate;
    }

    /**
     * Gets positionX
     */
    public double getpositionX() {
        return positionX;
    }

    /**
     * Sets positionX
     */
    public void setpositionX(double positionX) {
        this.positionX = positionX;
    }

    /**
     * Gets positionY
     */
    public double getpositionY() {
        return positionY;
    }

    /**
     * Sets positionY
     */
    public void setpositionY(double positionY) {
        this.positionY = positionY;
    }

    /**
     * Gets positionZ
     */
    public double getpositionZ() {
        return positionZ;
    }

    /**
     * Sets positionZ
     */
    public void setpositionZ(double positionZ) {
        this.positionZ = positionZ;
    }

    /**
     * Gets rotationX
     */
    public double getrotationX() {
        return rotationX;
    }

    /**
     * Sets rotationX
     */
    public void setrotationX(double rotationX) {
        this.rotationX = rotationX;
    }

    /**
     * Gets rotationY
     */
    public double getrotationY() {
        return rotationY;
    }

    /**
     * Sets rotationY
     */
    public void setrotationY(double rotationY) {
        this.rotationY = rotationY;
    }

    /**
     * Gets rotationZ
     */
    public double getrotationZ() {
        return rotationZ;
    }

    /**
     * Sets rotationZ
     */
    public void setrotationZ(double rotationZ) {
        this.rotationZ = rotationZ;
    }

    /**
     * Gets rotationW
     */
    public double getrotationW() {
        return rotationW;
    }

    /**
     * Sets rotationW
     */
    public void setrotationW(double rotationW) {
        this.rotationW = rotationW;
    }

    /**
     * Gets linVelX
     */
    public double getlinVelX() {
        return linVelX;
    }

    /**
     * Sets linVelX
     */
    public void setlinVelX(double linVelX) {
        this.linVelX = linVelX;
    }

    /**
     * Gets linVelY
     */
    public double getlinVelY() {
        return linVelY;
    }

    /**
     * Sets linVelY
     */
    public void setlinVelY(double linVelY) {
        this.linVelY = linVelY;
    }

    /**
     * Gets linVelZ
     */
    public double getlinVelZ() {
        return linVelZ;
    }

    /**
     * Sets linVelZ
     */
    public void setlinVelZ(double linVelZ) {
        this.linVelZ = linVelZ;
    }

    /**
     * Gets angVelX
     */
    public double getangVelX() {
        return angVelX;
    }

    /**
     * Sets angVelX
     */
    public void setangVelX(double angVelX) {
        this.angVelX = angVelX;
    }

    /**
     * Gets angVelY
     */
    public double getangVelY() {
        return angVelY;
    }

    /**
     * Sets angVelY
     */
    public void setangVelY(double angVelY) {
        this.angVelY = angVelY;
    }

    /**
     * Gets angVelZ
     */
    public double getangVelZ() {
        return angVelZ;
    }

    /**
     * Sets angVelZ
     */
    public void setangVelZ(double angVelZ) {
        this.angVelZ = angVelZ;
    }

    /**
     * Gets linForceX
     */
    public double getlinForceX() {
        return linForceX;
    }

    /**
     * Sets linForceX
     */
    public void setlinForceX(double linForceX) {
        this.linForceX = linForceX;
    }

    /**
     * Gets linForceY
     */
    public double getlinForceY() {
        return linForceY;
    }

    /**
     * Sets linForceY
     */
    public void setlinForceY(double linForceY) {
        this.linForceY = linForceY;
    }

    /**
     * Gets linForceZ
     */
    public double getlinForceZ() {
        return linForceZ;
    }

    /**
     * Sets linForceZ
     */
    public void setlinForceZ(double linForceZ) {
        this.linForceZ = linForceZ;
    }

    /**
     * Gets angForceX
     */
    public double getangForceX() {
        return angForceX;
    }

    /**
     * Sets angForceX
     */
    public void setangForceX(double angForceX) {
        this.angForceX = angForceX;
    }

    /**
     * Gets angForceY
     */
    public double getangForceY() {
        return angForceY;
    }

    /**
     * Sets angForceY
     */
    public void setangForceY(double angForceY) {
        this.angForceY = angForceY;
    }

    /**
     * Gets angForceZ
     */
    public double getangForceZ() {
        return angForceZ;
    }

    /**
     * Sets angForceZ
     */
    public void setangForceZ(double angForceZ) {
        this.angForceZ = angForceZ;
    }

    /**
     * Gets yaw
     */
    public double getyaw() {
        return yaw;
    }

    /**
     * Sets yaw
     */
    public void setyaw(double yaw) {
        this.yaw = yaw;
    }

    /**
     * Gets pitch
     */
    public double getpitch() {
        return pitch;
    }

    /**
     * Sets pitch
     */
    public void setpitch(double pitch) {
        this.pitch = pitch;
    }

    /**
     * Gets velocity
     */
    public double getvelocity() {
        return velocity;
    }

    /**
     * Sets velocity
     */
    public void setvelocity(double velocity) {
        this.velocity = velocity;
    }

    /**
     * Gets treeState
     */
    public int gettreeState() {
        return treeState;
    }

    /**
     * Sets treeState
     */
    public void settreeState(int treeState) {
        this.treeState = treeState;
    }

    /**
     * Gets propertyType
     */
    public int getpropertyType() {
        return propertyType;
    }

    /**
     * Sets propertyType
     */
    public void setpropertyType(int propertyType) {
        this.propertyType = propertyType;
    }

    /**
     * Gets propertyValue
     */
    public int getpropertyValue() {
        return propertyValue;
    }

    /**
     * Sets propertyValue
     */
    public void setpropertyValue(int propertyValue) {
        this.propertyValue = propertyValue;
    }

    /**
     * Gets time
     */
    public long gettime() {
        return time;
    }

    /**
     * Sets time
     */
    public void settime(long time) {
        this.time = time;
    }

    /**
     * Gets bone
     */
    public String getbone() {
        return bone;
    }

    /**
     * Sets bone
     */
    public void setbone(String bone) {
        this.bone = bone;
    }

    /**
     * Gets targetID
     */
    public int gettargetID() {
        return targetID;
    }

    /**
     * Sets targetID
     */
    public void settargetID(int targetID) {
        this.targetID = targetID;
    }

    /**
     * Gets bTreeID
     */
    public int getbTreeID() {
        return bTreeID;
    }

    /**
     * Sets bTreeID
     */
    public void setbTreeID(int bTreeID) {
        this.bTreeID = bTreeID;
    }

    /**
     * Gets propertyValueInt
     */
    public int getpropertyValueInt() {
        return propertyValueInt;
    }

    /**
     * Sets propertyValueInt
     */
    public void setpropertyValueInt(int propertyValueInt) {
        this.propertyValueInt = propertyValueInt;
    }

    /**
     * Gets interactionSignal
     */
    public String getinteractionSignal() {
        return interactionSignal;
    }

    /**
     * Sets interactionSignal
     */
    public void setinteractionSignal(String interactionSignal) {
        this.interactionSignal = interactionSignal;
    }

    /**
     * Removes the packet header from the buffer
     * @param byteBuffer The buffer
     */
    static void stripPacketHeader(CircularByteBuffer byteBuffer){
        byteBuffer.read(2);
    }

    /**
     * Checks if this message can be parsed (ie are all bytes present)
     * @param byteBuffer The buffer
     * @param secondByte The second byte, signifying the subtype of the message
     * @return true if the message can be parsed, false otherwise
     */
    public static boolean canParseMessage(CircularByteBuffer byteBuffer, byte secondByte){
        switch(secondByte){
            case TypeBytes.ENTITY_MESSAGE_TYPE_CREATE:
                return EntityMessage.canParseCreateMessage(byteBuffer);
            case TypeBytes.ENTITY_MESSAGE_TYPE_MOVEUPDATE:
                if(byteBuffer.getRemaining() >= TypeBytes.ENTITY_MESSAGE_TYPE_MOVEUPDATE_SIZE){
                    return true;
                } else {
                    return false;
                }
            case TypeBytes.ENTITY_MESSAGE_TYPE_ATTACKUPDATE:
                if(byteBuffer.getRemaining() >= TypeBytes.ENTITY_MESSAGE_TYPE_ATTACKUPDATE_SIZE){
                    return true;
                } else {
                    return false;
                }
            case TypeBytes.ENTITY_MESSAGE_TYPE_STARTATTACK:
                if(byteBuffer.getRemaining() >= TypeBytes.ENTITY_MESSAGE_TYPE_STARTATTACK_SIZE){
                    return true;
                } else {
                    return false;
                }
            case TypeBytes.ENTITY_MESSAGE_TYPE_KILL:
                if(byteBuffer.getRemaining() >= TypeBytes.ENTITY_MESSAGE_TYPE_KILL_SIZE){
                    return true;
                } else {
                    return false;
                }
            case TypeBytes.ENTITY_MESSAGE_TYPE_DESTROY:
                if(byteBuffer.getRemaining() >= TypeBytes.ENTITY_MESSAGE_TYPE_DESTROY_SIZE){
                    return true;
                } else {
                    return false;
                }
            case TypeBytes.ENTITY_MESSAGE_TYPE_SETPROPERTY:
                if(byteBuffer.getRemaining() >= TypeBytes.ENTITY_MESSAGE_TYPE_SETPROPERTY_SIZE){
                    return true;
                } else {
                    return false;
                }
            case TypeBytes.ENTITY_MESSAGE_TYPE_ATTACHENTITYTOENTITY:
                return EntityMessage.canParseattachEntityToEntityMessage(byteBuffer);
            case TypeBytes.ENTITY_MESSAGE_TYPE_UPDATEENTITYVIEWDIR:
                if(byteBuffer.getRemaining() >= TypeBytes.ENTITY_MESSAGE_TYPE_UPDATEENTITYVIEWDIR_SIZE){
                    return true;
                } else {
                    return false;
                }
            case TypeBytes.ENTITY_MESSAGE_TYPE_SYNCPHYSICS:
                if(byteBuffer.getRemaining() >= TypeBytes.ENTITY_MESSAGE_TYPE_SYNCPHYSICS_SIZE){
                    return true;
                } else {
                    return false;
                }
            case TypeBytes.ENTITY_MESSAGE_TYPE_INTERACT:
                return EntityMessage.canParseinteractMessage(byteBuffer);
        }
        return false;
    }

    /**
     * Checks if a message of type Create can be parsed from the byte stream
     */
    public static boolean canParseCreateMessage(CircularByteBuffer byteBuffer){
        int currentStreamLength = byteBuffer.getRemaining();
        List<Byte> temporaryByteQueue = new LinkedList<Byte>();
        if(currentStreamLength < 6){
            return false;
        }
        if(currentStreamLength < 10){
            return false;
        }
        int entitySubtypeSize = 0;
        if(currentStreamLength < 14){
            return false;
        } else {
            temporaryByteQueue.add(byteBuffer.peek(10 + 0));
            temporaryByteQueue.add(byteBuffer.peek(10 + 1));
            temporaryByteQueue.add(byteBuffer.peek(10 + 2));
            temporaryByteQueue.add(byteBuffer.peek(10 + 3));
            entitySubtypeSize = ByteStreamUtils.popIntFromByteQueue(temporaryByteQueue);
        }
        if(currentStreamLength < 14 + entitySubtypeSize){
            return false;
        }
        int creatureTemplateSize = 0;
        if(currentStreamLength < 18){
            return false;
        } else {
            temporaryByteQueue.add(byteBuffer.peek(14 + entitySubtypeSize + 0));
            temporaryByteQueue.add(byteBuffer.peek(14 + entitySubtypeSize + 1));
            temporaryByteQueue.add(byteBuffer.peek(14 + entitySubtypeSize + 2));
            temporaryByteQueue.add(byteBuffer.peek(14 + entitySubtypeSize + 3));
            creatureTemplateSize = ByteStreamUtils.popIntFromByteQueue(temporaryByteQueue);
        }
        if(currentStreamLength < 18 + entitySubtypeSize + creatureTemplateSize){
            return false;
        }
        if(currentStreamLength < 26 + entitySubtypeSize + creatureTemplateSize){
            return false;
        }
        if(currentStreamLength < 34 + entitySubtypeSize + creatureTemplateSize){
            return false;
        }
        if(currentStreamLength < 42 + entitySubtypeSize + creatureTemplateSize){
            return false;
        }
        if(currentStreamLength < 50 + entitySubtypeSize + creatureTemplateSize){
            return false;
        }
        if(currentStreamLength < 58 + entitySubtypeSize + creatureTemplateSize){
            return false;
        }
        if(currentStreamLength < 66 + entitySubtypeSize + creatureTemplateSize){
            return false;
        }
        if(currentStreamLength < 74 + entitySubtypeSize + creatureTemplateSize){
            return false;
        }
        return true;
    }

    /**
     * Parses a message of type Create
     */
    public static EntityMessage parseCreateMessage(CircularByteBuffer byteBuffer, MessagePool pool){
        EntityMessage rVal = (EntityMessage)pool.get(MessageType.ENTITY_MESSAGE);
        rVal.messageType = EntityMessageType.CREATE;
        EntityMessage.stripPacketHeader(byteBuffer);
        rVal.setentityID(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
        rVal.setentityCategory(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
        rVal.setentitySubtype(ByteStreamUtils.popStringFromByteQueue(byteBuffer));
        rVal.setcreatureTemplate(ByteStreamUtils.popStringFromByteQueue(byteBuffer));
        rVal.setpositionX(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
        rVal.setpositionY(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
        rVal.setpositionZ(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
        rVal.setrotationX(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
        rVal.setrotationY(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
        rVal.setrotationZ(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
        rVal.setrotationW(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
        return rVal;
    }

    /**
     * Constructs a message of type Create
     */
    public static EntityMessage constructCreateMessage(int entityID,int entityCategory,String entitySubtype,String creatureTemplate,double positionX,double positionY,double positionZ,double rotationX,double rotationY,double rotationZ,double rotationW){
        EntityMessage rVal = new EntityMessage(EntityMessageType.CREATE);
        rVal.setentityID(entityID);
        rVal.setentityCategory(entityCategory);
        rVal.setentitySubtype(entitySubtype);
        rVal.setcreatureTemplate(creatureTemplate);
        rVal.setpositionX(positionX);
        rVal.setpositionY(positionY);
        rVal.setpositionZ(positionZ);
        rVal.setrotationX(rotationX);
        rVal.setrotationY(rotationY);
        rVal.setrotationZ(rotationZ);
        rVal.setrotationW(rotationW);
        rVal.serialize();
        return rVal;
    }

    /**
     * Parses a message of type moveUpdate
     */
    public static EntityMessage parsemoveUpdateMessage(CircularByteBuffer byteBuffer, MessagePool pool){
        EntityMessage rVal = (EntityMessage)pool.get(MessageType.ENTITY_MESSAGE);
        rVal.messageType = EntityMessageType.MOVEUPDATE;
        EntityMessage.stripPacketHeader(byteBuffer);
        rVal.setentityID(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
        rVal.settime(ByteStreamUtils.popLongFromByteQueue(byteBuffer));
        rVal.setpositionX(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
        rVal.setpositionY(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
        rVal.setpositionZ(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
        rVal.setrotationX(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
        rVal.setrotationY(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
        rVal.setrotationZ(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
        rVal.setrotationW(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
        rVal.setvelocity(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
        rVal.setpropertyValueInt(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
        rVal.settreeState(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
        return rVal;
    }

    /**
     * Constructs a message of type moveUpdate
     */
    public static EntityMessage constructmoveUpdateMessage(int entityID,long time,double positionX,double positionY,double positionZ,double rotationX,double rotationY,double rotationZ,double rotationW,double velocity,int propertyValueInt,int treeState){
        EntityMessage rVal = new EntityMessage(EntityMessageType.MOVEUPDATE);
        rVal.setentityID(entityID);
        rVal.settime(time);
        rVal.setpositionX(positionX);
        rVal.setpositionY(positionY);
        rVal.setpositionZ(positionZ);
        rVal.setrotationX(rotationX);
        rVal.setrotationY(rotationY);
        rVal.setrotationZ(rotationZ);
        rVal.setrotationW(rotationW);
        rVal.setvelocity(velocity);
        rVal.setpropertyValueInt(propertyValueInt);
        rVal.settreeState(treeState);
        rVal.serialize();
        return rVal;
    }

    /**
     * Parses a message of type attackUpdate
     */
    public static EntityMessage parseattackUpdateMessage(CircularByteBuffer byteBuffer, MessagePool pool){
        EntityMessage rVal = (EntityMessage)pool.get(MessageType.ENTITY_MESSAGE);
        rVal.messageType = EntityMessageType.ATTACKUPDATE;
        EntityMessage.stripPacketHeader(byteBuffer);
        rVal.setentityID(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
        rVal.settime(ByteStreamUtils.popLongFromByteQueue(byteBuffer));
        rVal.setpositionX(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
        rVal.setpositionY(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
        rVal.setpositionZ(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
        rVal.setrotationX(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
        rVal.setrotationY(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
        rVal.setrotationZ(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
        rVal.setvelocity(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
        rVal.settreeState(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
        return rVal;
    }

    /**
     * Constructs a message of type attackUpdate
     */
    public static EntityMessage constructattackUpdateMessage(int entityID,long time,double positionX,double positionY,double positionZ,double rotationX,double rotationY,double rotationZ,double velocity,int treeState){
        EntityMessage rVal = new EntityMessage(EntityMessageType.ATTACKUPDATE);
        rVal.setentityID(entityID);
        rVal.settime(time);
        rVal.setpositionX(positionX);
        rVal.setpositionY(positionY);
        rVal.setpositionZ(positionZ);
        rVal.setrotationX(rotationX);
        rVal.setrotationY(rotationY);
        rVal.setrotationZ(rotationZ);
        rVal.setvelocity(velocity);
        rVal.settreeState(treeState);
        rVal.serialize();
        return rVal;
    }

    /**
     * Parses a message of type startAttack
     */
    public static EntityMessage parsestartAttackMessage(CircularByteBuffer byteBuffer, MessagePool pool){
        EntityMessage rVal = (EntityMessage)pool.get(MessageType.ENTITY_MESSAGE);
        rVal.messageType = EntityMessageType.STARTATTACK;
        EntityMessage.stripPacketHeader(byteBuffer);
        return rVal;
    }

    /**
     * Constructs a message of type startAttack
     */
    public static EntityMessage constructstartAttackMessage(){
        EntityMessage rVal = new EntityMessage(EntityMessageType.STARTATTACK);
        rVal.serialize();
        return rVal;
    }

    /**
     * Parses a message of type Kill
     */
    public static EntityMessage parseKillMessage(CircularByteBuffer byteBuffer, MessagePool pool){
        EntityMessage rVal = (EntityMessage)pool.get(MessageType.ENTITY_MESSAGE);
        rVal.messageType = EntityMessageType.KILL;
        EntityMessage.stripPacketHeader(byteBuffer);
        rVal.settime(ByteStreamUtils.popLongFromByteQueue(byteBuffer));
        rVal.setentityID(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
        return rVal;
    }

    /**
     * Constructs a message of type Kill
     */
    public static EntityMessage constructKillMessage(long time,int entityID){
        EntityMessage rVal = new EntityMessage(EntityMessageType.KILL);
        rVal.settime(time);
        rVal.setentityID(entityID);
        rVal.serialize();
        return rVal;
    }

    /**
     * Parses a message of type Destroy
     */
    public static EntityMessage parseDestroyMessage(CircularByteBuffer byteBuffer, MessagePool pool){
        EntityMessage rVal = (EntityMessage)pool.get(MessageType.ENTITY_MESSAGE);
        rVal.messageType = EntityMessageType.DESTROY;
        EntityMessage.stripPacketHeader(byteBuffer);
        rVal.setentityID(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
        return rVal;
    }

    /**
     * Constructs a message of type Destroy
     */
    public static EntityMessage constructDestroyMessage(int entityID){
        EntityMessage rVal = new EntityMessage(EntityMessageType.DESTROY);
        rVal.setentityID(entityID);
        rVal.serialize();
        return rVal;
    }

    /**
     * Parses a message of type setProperty
     */
    public static EntityMessage parsesetPropertyMessage(CircularByteBuffer byteBuffer, MessagePool pool){
        EntityMessage rVal = (EntityMessage)pool.get(MessageType.ENTITY_MESSAGE);
        rVal.messageType = EntityMessageType.SETPROPERTY;
        EntityMessage.stripPacketHeader(byteBuffer);
        rVal.setentityID(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
        rVal.settime(ByteStreamUtils.popLongFromByteQueue(byteBuffer));
        rVal.setpropertyType(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
        rVal.setpropertyValue(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
        return rVal;
    }

    /**
     * Constructs a message of type setProperty
     */
    public static EntityMessage constructsetPropertyMessage(int entityID,long time,int propertyType,int propertyValue){
        EntityMessage rVal = new EntityMessage(EntityMessageType.SETPROPERTY);
        rVal.setentityID(entityID);
        rVal.settime(time);
        rVal.setpropertyType(propertyType);
        rVal.setpropertyValue(propertyValue);
        rVal.serialize();
        return rVal;
    }

    /**
     * Checks if a message of type attachEntityToEntity can be parsed from the byte stream
     */
    public static boolean canParseattachEntityToEntityMessage(CircularByteBuffer byteBuffer){
        int currentStreamLength = byteBuffer.getRemaining();
        List<Byte> temporaryByteQueue = new LinkedList<Byte>();
        if(currentStreamLength < 6){
            return false;
        }
        int boneSize = 0;
        if(currentStreamLength < 10){
            return false;
        } else {
            temporaryByteQueue.add(byteBuffer.peek(6 + 0));
            temporaryByteQueue.add(byteBuffer.peek(6 + 1));
            temporaryByteQueue.add(byteBuffer.peek(6 + 2));
            temporaryByteQueue.add(byteBuffer.peek(6 + 3));
            boneSize = ByteStreamUtils.popIntFromByteQueue(temporaryByteQueue);
        }
        if(currentStreamLength < 10 + boneSize){
            return false;
        }
        if(currentStreamLength < 14 + boneSize){
            return false;
        }
        return true;
    }

    /**
     * Parses a message of type attachEntityToEntity
     */
    public static EntityMessage parseattachEntityToEntityMessage(CircularByteBuffer byteBuffer, MessagePool pool){
        EntityMessage rVal = (EntityMessage)pool.get(MessageType.ENTITY_MESSAGE);
        rVal.messageType = EntityMessageType.ATTACHENTITYTOENTITY;
        EntityMessage.stripPacketHeader(byteBuffer);
        rVal.setentityID(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
        rVal.setbone(ByteStreamUtils.popStringFromByteQueue(byteBuffer));
        rVal.settargetID(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
        return rVal;
    }

    /**
     * Constructs a message of type attachEntityToEntity
     */
    public static EntityMessage constructattachEntityToEntityMessage(int entityID,String bone,int targetID){
        EntityMessage rVal = new EntityMessage(EntityMessageType.ATTACHENTITYTOENTITY);
        rVal.setentityID(entityID);
        rVal.setbone(bone);
        rVal.settargetID(targetID);
        rVal.serialize();
        return rVal;
    }

    /**
     * Parses a message of type updateEntityViewDir
     */
    public static EntityMessage parseupdateEntityViewDirMessage(CircularByteBuffer byteBuffer, MessagePool pool){
        EntityMessage rVal = (EntityMessage)pool.get(MessageType.ENTITY_MESSAGE);
        rVal.messageType = EntityMessageType.UPDATEENTITYVIEWDIR;
        EntityMessage.stripPacketHeader(byteBuffer);
        rVal.setentityID(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
        rVal.settime(ByteStreamUtils.popLongFromByteQueue(byteBuffer));
        rVal.setpropertyType(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
        rVal.setyaw(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
        rVal.setpitch(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
        return rVal;
    }

    /**
     * Constructs a message of type updateEntityViewDir
     */
    public static EntityMessage constructupdateEntityViewDirMessage(int entityID,long time,int propertyType,double yaw,double pitch){
        EntityMessage rVal = new EntityMessage(EntityMessageType.UPDATEENTITYVIEWDIR);
        rVal.setentityID(entityID);
        rVal.settime(time);
        rVal.setpropertyType(propertyType);
        rVal.setyaw(yaw);
        rVal.setpitch(pitch);
        rVal.serialize();
        return rVal;
    }

    /**
     * Parses a message of type syncPhysics
     */
    public static EntityMessage parsesyncPhysicsMessage(CircularByteBuffer byteBuffer, MessagePool pool){
        EntityMessage rVal = (EntityMessage)pool.get(MessageType.ENTITY_MESSAGE);
        rVal.messageType = EntityMessageType.SYNCPHYSICS;
        EntityMessage.stripPacketHeader(byteBuffer);
        rVal.setentityID(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
        rVal.settime(ByteStreamUtils.popLongFromByteQueue(byteBuffer));
        rVal.setpositionX(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
        rVal.setpositionY(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
        rVal.setpositionZ(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
        rVal.setrotationX(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
        rVal.setrotationY(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
        rVal.setrotationZ(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
        rVal.setrotationW(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
        rVal.setlinVelX(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
        rVal.setlinVelY(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
        rVal.setlinVelZ(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
        rVal.setangVelX(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
        rVal.setangVelY(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
        rVal.setangVelZ(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
        rVal.setlinForceX(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
        rVal.setlinForceY(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
        rVal.setlinForceZ(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
        rVal.setangForceX(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
        rVal.setangForceY(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
        rVal.setangForceZ(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
        return rVal;
    }

    /**
     * Constructs a message of type syncPhysics
     */
    public static EntityMessage constructsyncPhysicsMessage(int entityID,long time,double positionX,double positionY,double positionZ,double rotationX,double rotationY,double rotationZ,double rotationW,double linVelX,double linVelY,double linVelZ,double angVelX,double angVelY,double angVelZ,double linForceX,double linForceY,double linForceZ,double angForceX,double angForceY,double angForceZ){
        EntityMessage rVal = new EntityMessage(EntityMessageType.SYNCPHYSICS);
        rVal.setentityID(entityID);
        rVal.settime(time);
        rVal.setpositionX(positionX);
        rVal.setpositionY(positionY);
        rVal.setpositionZ(positionZ);
        rVal.setrotationX(rotationX);
        rVal.setrotationY(rotationY);
        rVal.setrotationZ(rotationZ);
        rVal.setrotationW(rotationW);
        rVal.setlinVelX(linVelX);
        rVal.setlinVelY(linVelY);
        rVal.setlinVelZ(linVelZ);
        rVal.setangVelX(angVelX);
        rVal.setangVelY(angVelY);
        rVal.setangVelZ(angVelZ);
        rVal.setlinForceX(linForceX);
        rVal.setlinForceY(linForceY);
        rVal.setlinForceZ(linForceZ);
        rVal.setangForceX(angForceX);
        rVal.setangForceY(angForceY);
        rVal.setangForceZ(angForceZ);
        rVal.serialize();
        return rVal;
    }

    /**
     * Checks if a message of type interact can be parsed from the byte stream
     */
    public static boolean canParseinteractMessage(CircularByteBuffer byteBuffer){
        int currentStreamLength = byteBuffer.getRemaining();
        List<Byte> temporaryByteQueue = new LinkedList<Byte>();
        if(currentStreamLength < 6){
            return false;
        }
        int interactionSignalSize = 0;
        if(currentStreamLength < 10){
            return false;
        } else {
            temporaryByteQueue.add(byteBuffer.peek(6 + 0));
            temporaryByteQueue.add(byteBuffer.peek(6 + 1));
            temporaryByteQueue.add(byteBuffer.peek(6 + 2));
            temporaryByteQueue.add(byteBuffer.peek(6 + 3));
            interactionSignalSize = ByteStreamUtils.popIntFromByteQueue(temporaryByteQueue);
        }
        if(currentStreamLength < 10 + interactionSignalSize){
            return false;
        }
        return true;
    }

    /**
     * Parses a message of type interact
     */
    public static EntityMessage parseinteractMessage(CircularByteBuffer byteBuffer, MessagePool pool){
        EntityMessage rVal = (EntityMessage)pool.get(MessageType.ENTITY_MESSAGE);
        rVal.messageType = EntityMessageType.INTERACT;
        EntityMessage.stripPacketHeader(byteBuffer);
        rVal.setentityID(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
        rVal.setinteractionSignal(ByteStreamUtils.popStringFromByteQueue(byteBuffer));
        return rVal;
    }

    /**
     * Constructs a message of type interact
     */
    public static EntityMessage constructinteractMessage(int entityID,String interactionSignal){
        EntityMessage rVal = new EntityMessage(EntityMessageType.INTERACT);
        rVal.setentityID(entityID);
        rVal.setinteractionSignal(interactionSignal);
        rVal.serialize();
        return rVal;
    }

    @Override
    void serialize(){
        byte[] intValues = new byte[8];
        byte[] stringBytes;
        switch(this.messageType){
            case CREATE:
                rawBytes = new byte[2+4+4+4+entitySubtype.length()+4+creatureTemplate.length()+8+8+8+8+8+8+8];
                //message header
                rawBytes[0] = TypeBytes.MESSAGE_TYPE_ENTITY;
                //entity messaage header
                rawBytes[1] = TypeBytes.ENTITY_MESSAGE_TYPE_CREATE;
                intValues = ByteStreamUtils.serializeIntToBytes(entityID);
                for(int i = 0; i < 4; i++){
                    rawBytes[2+i] = intValues[i];
                }
                intValues = ByteStreamUtils.serializeIntToBytes(entityCategory);
                for(int i = 0; i < 4; i++){
                    rawBytes[6+i] = intValues[i];
                }
                intValues = ByteStreamUtils.serializeIntToBytes(entitySubtype.length());
                for(int i = 0; i < 4; i++){
                    rawBytes[10+i] = intValues[i];
                }
                stringBytes = entitySubtype.getBytes();
                for(int i = 0; i < entitySubtype.length(); i++){
                    rawBytes[14+i] = stringBytes[i];
                }
                intValues = ByteStreamUtils.serializeIntToBytes(creatureTemplate.length());
                for(int i = 0; i < 4; i++){
                    rawBytes[14+entitySubtype.length()+i] = intValues[i];
                }
                stringBytes = creatureTemplate.getBytes();
                for(int i = 0; i < creatureTemplate.length(); i++){
                    rawBytes[18+entitySubtype.length()+i] = stringBytes[i];
                }
                intValues = ByteStreamUtils.serializeDoubleToBytes(positionX);
                for(int i = 0; i < 8; i++){
                    rawBytes[18+entitySubtype.length()+creatureTemplate.length()+i] = intValues[i];
                }
                intValues = ByteStreamUtils.serializeDoubleToBytes(positionY);
                for(int i = 0; i < 8; i++){
                    rawBytes[26+entitySubtype.length()+creatureTemplate.length()+i] = intValues[i];
                }
                intValues = ByteStreamUtils.serializeDoubleToBytes(positionZ);
                for(int i = 0; i < 8; i++){
                    rawBytes[34+entitySubtype.length()+creatureTemplate.length()+i] = intValues[i];
                }
                intValues = ByteStreamUtils.serializeDoubleToBytes(rotationX);
                for(int i = 0; i < 8; i++){
                    rawBytes[42+entitySubtype.length()+creatureTemplate.length()+i] = intValues[i];
                }
                intValues = ByteStreamUtils.serializeDoubleToBytes(rotationY);
                for(int i = 0; i < 8; i++){
                    rawBytes[50+entitySubtype.length()+creatureTemplate.length()+i] = intValues[i];
                }
                intValues = ByteStreamUtils.serializeDoubleToBytes(rotationZ);
                for(int i = 0; i < 8; i++){
                    rawBytes[58+entitySubtype.length()+creatureTemplate.length()+i] = intValues[i];
                }
                intValues = ByteStreamUtils.serializeDoubleToBytes(rotationW);
                for(int i = 0; i < 8; i++){
                    rawBytes[66+entitySubtype.length()+creatureTemplate.length()+i] = intValues[i];
                }
                break;
            case MOVEUPDATE:
                rawBytes = new byte[2+4+8+8+8+8+8+8+8+8+8+4+4];
                //message header
                rawBytes[0] = TypeBytes.MESSAGE_TYPE_ENTITY;
                //entity messaage header
                rawBytes[1] = TypeBytes.ENTITY_MESSAGE_TYPE_MOVEUPDATE;
                intValues = ByteStreamUtils.serializeIntToBytes(entityID);
                for(int i = 0; i < 4; i++){
                    rawBytes[2+i] = intValues[i];
                }
                intValues = ByteStreamUtils.serializeLongToBytes(time);
                for(int i = 0; i < 8; i++){
                    rawBytes[6+i] = intValues[i];
                }
                intValues = ByteStreamUtils.serializeDoubleToBytes(positionX);
                for(int i = 0; i < 8; i++){
                    rawBytes[14+i] = intValues[i];
                }
                intValues = ByteStreamUtils.serializeDoubleToBytes(positionY);
                for(int i = 0; i < 8; i++){
                    rawBytes[22+i] = intValues[i];
                }
                intValues = ByteStreamUtils.serializeDoubleToBytes(positionZ);
                for(int i = 0; i < 8; i++){
                    rawBytes[30+i] = intValues[i];
                }
                intValues = ByteStreamUtils.serializeDoubleToBytes(rotationX);
                for(int i = 0; i < 8; i++){
                    rawBytes[38+i] = intValues[i];
                }
                intValues = ByteStreamUtils.serializeDoubleToBytes(rotationY);
                for(int i = 0; i < 8; i++){
                    rawBytes[46+i] = intValues[i];
                }
                intValues = ByteStreamUtils.serializeDoubleToBytes(rotationZ);
                for(int i = 0; i < 8; i++){
                    rawBytes[54+i] = intValues[i];
                }
                intValues = ByteStreamUtils.serializeDoubleToBytes(rotationW);
                for(int i = 0; i < 8; i++){
                    rawBytes[62+i] = intValues[i];
                }
                intValues = ByteStreamUtils.serializeDoubleToBytes(velocity);
                for(int i = 0; i < 8; i++){
                    rawBytes[70+i] = intValues[i];
                }
                intValues = ByteStreamUtils.serializeIntToBytes(propertyValueInt);
                for(int i = 0; i < 4; i++){
                    rawBytes[78+i] = intValues[i];
                }
                intValues = ByteStreamUtils.serializeIntToBytes(treeState);
                for(int i = 0; i < 4; i++){
                    rawBytes[82+i] = intValues[i];
                }
                break;
            case ATTACKUPDATE:
                rawBytes = new byte[2+4+8+8+8+8+8+8+8+8+4];
                //message header
                rawBytes[0] = TypeBytes.MESSAGE_TYPE_ENTITY;
                //entity messaage header
                rawBytes[1] = TypeBytes.ENTITY_MESSAGE_TYPE_ATTACKUPDATE;
                intValues = ByteStreamUtils.serializeIntToBytes(entityID);
                for(int i = 0; i < 4; i++){
                    rawBytes[2+i] = intValues[i];
                }
                intValues = ByteStreamUtils.serializeLongToBytes(time);
                for(int i = 0; i < 8; i++){
                    rawBytes[6+i] = intValues[i];
                }
                intValues = ByteStreamUtils.serializeDoubleToBytes(positionX);
                for(int i = 0; i < 8; i++){
                    rawBytes[14+i] = intValues[i];
                }
                intValues = ByteStreamUtils.serializeDoubleToBytes(positionY);
                for(int i = 0; i < 8; i++){
                    rawBytes[22+i] = intValues[i];
                }
                intValues = ByteStreamUtils.serializeDoubleToBytes(positionZ);
                for(int i = 0; i < 8; i++){
                    rawBytes[30+i] = intValues[i];
                }
                intValues = ByteStreamUtils.serializeDoubleToBytes(rotationX);
                for(int i = 0; i < 8; i++){
                    rawBytes[38+i] = intValues[i];
                }
                intValues = ByteStreamUtils.serializeDoubleToBytes(rotationY);
                for(int i = 0; i < 8; i++){
                    rawBytes[46+i] = intValues[i];
                }
                intValues = ByteStreamUtils.serializeDoubleToBytes(rotationZ);
                for(int i = 0; i < 8; i++){
                    rawBytes[54+i] = intValues[i];
                }
                intValues = ByteStreamUtils.serializeDoubleToBytes(velocity);
                for(int i = 0; i < 8; i++){
                    rawBytes[62+i] = intValues[i];
                }
                intValues = ByteStreamUtils.serializeIntToBytes(treeState);
                for(int i = 0; i < 4; i++){
                    rawBytes[70+i] = intValues[i];
                }
                break;
            case STARTATTACK:
                rawBytes = new byte[2];
                //message header
                rawBytes[0] = TypeBytes.MESSAGE_TYPE_ENTITY;
                //entity messaage header
                rawBytes[1] = TypeBytes.ENTITY_MESSAGE_TYPE_STARTATTACK;
                break;
            case KILL:
                rawBytes = new byte[2+8+4];
                //message header
                rawBytes[0] = TypeBytes.MESSAGE_TYPE_ENTITY;
                //entity messaage header
                rawBytes[1] = TypeBytes.ENTITY_MESSAGE_TYPE_KILL;
                intValues = ByteStreamUtils.serializeLongToBytes(time);
                for(int i = 0; i < 8; i++){
                    rawBytes[2+i] = intValues[i];
                }
                intValues = ByteStreamUtils.serializeIntToBytes(entityID);
                for(int i = 0; i < 4; i++){
                    rawBytes[10+i] = intValues[i];
                }
                break;
            case DESTROY:
                rawBytes = new byte[2+4];
                //message header
                rawBytes[0] = TypeBytes.MESSAGE_TYPE_ENTITY;
                //entity messaage header
                rawBytes[1] = TypeBytes.ENTITY_MESSAGE_TYPE_DESTROY;
                intValues = ByteStreamUtils.serializeIntToBytes(entityID);
                for(int i = 0; i < 4; i++){
                    rawBytes[2+i] = intValues[i];
                }
                break;
            case SETPROPERTY:
                rawBytes = new byte[2+4+8+4+4];
                //message header
                rawBytes[0] = TypeBytes.MESSAGE_TYPE_ENTITY;
                //entity messaage header
                rawBytes[1] = TypeBytes.ENTITY_MESSAGE_TYPE_SETPROPERTY;
                intValues = ByteStreamUtils.serializeIntToBytes(entityID);
                for(int i = 0; i < 4; i++){
                    rawBytes[2+i] = intValues[i];
                }
                intValues = ByteStreamUtils.serializeLongToBytes(time);
                for(int i = 0; i < 8; i++){
                    rawBytes[6+i] = intValues[i];
                }
                intValues = ByteStreamUtils.serializeIntToBytes(propertyType);
                for(int i = 0; i < 4; i++){
                    rawBytes[14+i] = intValues[i];
                }
                intValues = ByteStreamUtils.serializeIntToBytes(propertyValue);
                for(int i = 0; i < 4; i++){
                    rawBytes[18+i] = intValues[i];
                }
                break;
            case ATTACHENTITYTOENTITY:
                rawBytes = new byte[2+4+4+bone.length()+4];
                //message header
                rawBytes[0] = TypeBytes.MESSAGE_TYPE_ENTITY;
                //entity messaage header
                rawBytes[1] = TypeBytes.ENTITY_MESSAGE_TYPE_ATTACHENTITYTOENTITY;
                intValues = ByteStreamUtils.serializeIntToBytes(entityID);
                for(int i = 0; i < 4; i++){
                    rawBytes[2+i] = intValues[i];
                }
                intValues = ByteStreamUtils.serializeIntToBytes(bone.length());
                for(int i = 0; i < 4; i++){
                    rawBytes[6+i] = intValues[i];
                }
                stringBytes = bone.getBytes();
                for(int i = 0; i < bone.length(); i++){
                    rawBytes[10+i] = stringBytes[i];
                }
                intValues = ByteStreamUtils.serializeIntToBytes(targetID);
                for(int i = 0; i < 4; i++){
                    rawBytes[10+bone.length()+i] = intValues[i];
                }
                break;
            case UPDATEENTITYVIEWDIR:
                rawBytes = new byte[2+4+8+4+8+8];
                //message header
                rawBytes[0] = TypeBytes.MESSAGE_TYPE_ENTITY;
                //entity messaage header
                rawBytes[1] = TypeBytes.ENTITY_MESSAGE_TYPE_UPDATEENTITYVIEWDIR;
                intValues = ByteStreamUtils.serializeIntToBytes(entityID);
                for(int i = 0; i < 4; i++){
                    rawBytes[2+i] = intValues[i];
                }
                intValues = ByteStreamUtils.serializeLongToBytes(time);
                for(int i = 0; i < 8; i++){
                    rawBytes[6+i] = intValues[i];
                }
                intValues = ByteStreamUtils.serializeIntToBytes(propertyType);
                for(int i = 0; i < 4; i++){
                    rawBytes[14+i] = intValues[i];
                }
                intValues = ByteStreamUtils.serializeDoubleToBytes(yaw);
                for(int i = 0; i < 8; i++){
                    rawBytes[18+i] = intValues[i];
                }
                intValues = ByteStreamUtils.serializeDoubleToBytes(pitch);
                for(int i = 0; i < 8; i++){
                    rawBytes[26+i] = intValues[i];
                }
                break;
            case SYNCPHYSICS:
                rawBytes = new byte[2+4+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8];
                //message header
                rawBytes[0] = TypeBytes.MESSAGE_TYPE_ENTITY;
                //entity messaage header
                rawBytes[1] = TypeBytes.ENTITY_MESSAGE_TYPE_SYNCPHYSICS;
                intValues = ByteStreamUtils.serializeIntToBytes(entityID);
                for(int i = 0; i < 4; i++){
                    rawBytes[2+i] = intValues[i];
                }
                intValues = ByteStreamUtils.serializeLongToBytes(time);
                for(int i = 0; i < 8; i++){
                    rawBytes[6+i] = intValues[i];
                }
                intValues = ByteStreamUtils.serializeDoubleToBytes(positionX);
                for(int i = 0; i < 8; i++){
                    rawBytes[14+i] = intValues[i];
                }
                intValues = ByteStreamUtils.serializeDoubleToBytes(positionY);
                for(int i = 0; i < 8; i++){
                    rawBytes[22+i] = intValues[i];
                }
                intValues = ByteStreamUtils.serializeDoubleToBytes(positionZ);
                for(int i = 0; i < 8; i++){
                    rawBytes[30+i] = intValues[i];
                }
                intValues = ByteStreamUtils.serializeDoubleToBytes(rotationX);
                for(int i = 0; i < 8; i++){
                    rawBytes[38+i] = intValues[i];
                }
                intValues = ByteStreamUtils.serializeDoubleToBytes(rotationY);
                for(int i = 0; i < 8; i++){
                    rawBytes[46+i] = intValues[i];
                }
                intValues = ByteStreamUtils.serializeDoubleToBytes(rotationZ);
                for(int i = 0; i < 8; i++){
                    rawBytes[54+i] = intValues[i];
                }
                intValues = ByteStreamUtils.serializeDoubleToBytes(rotationW);
                for(int i = 0; i < 8; i++){
                    rawBytes[62+i] = intValues[i];
                }
                intValues = ByteStreamUtils.serializeDoubleToBytes(linVelX);
                for(int i = 0; i < 8; i++){
                    rawBytes[70+i] = intValues[i];
                }
                intValues = ByteStreamUtils.serializeDoubleToBytes(linVelY);
                for(int i = 0; i < 8; i++){
                    rawBytes[78+i] = intValues[i];
                }
                intValues = ByteStreamUtils.serializeDoubleToBytes(linVelZ);
                for(int i = 0; i < 8; i++){
                    rawBytes[86+i] = intValues[i];
                }
                intValues = ByteStreamUtils.serializeDoubleToBytes(angVelX);
                for(int i = 0; i < 8; i++){
                    rawBytes[94+i] = intValues[i];
                }
                intValues = ByteStreamUtils.serializeDoubleToBytes(angVelY);
                for(int i = 0; i < 8; i++){
                    rawBytes[102+i] = intValues[i];
                }
                intValues = ByteStreamUtils.serializeDoubleToBytes(angVelZ);
                for(int i = 0; i < 8; i++){
                    rawBytes[110+i] = intValues[i];
                }
                intValues = ByteStreamUtils.serializeDoubleToBytes(linForceX);
                for(int i = 0; i < 8; i++){
                    rawBytes[118+i] = intValues[i];
                }
                intValues = ByteStreamUtils.serializeDoubleToBytes(linForceY);
                for(int i = 0; i < 8; i++){
                    rawBytes[126+i] = intValues[i];
                }
                intValues = ByteStreamUtils.serializeDoubleToBytes(linForceZ);
                for(int i = 0; i < 8; i++){
                    rawBytes[134+i] = intValues[i];
                }
                intValues = ByteStreamUtils.serializeDoubleToBytes(angForceX);
                for(int i = 0; i < 8; i++){
                    rawBytes[142+i] = intValues[i];
                }
                intValues = ByteStreamUtils.serializeDoubleToBytes(angForceY);
                for(int i = 0; i < 8; i++){
                    rawBytes[150+i] = intValues[i];
                }
                intValues = ByteStreamUtils.serializeDoubleToBytes(angForceZ);
                for(int i = 0; i < 8; i++){
                    rawBytes[158+i] = intValues[i];
                }
                break;
            case INTERACT:
                rawBytes = new byte[2+4+4+interactionSignal.length()];
                //message header
                rawBytes[0] = TypeBytes.MESSAGE_TYPE_ENTITY;
                //entity messaage header
                rawBytes[1] = TypeBytes.ENTITY_MESSAGE_TYPE_INTERACT;
                intValues = ByteStreamUtils.serializeIntToBytes(entityID);
                for(int i = 0; i < 4; i++){
                    rawBytes[2+i] = intValues[i];
                }
                intValues = ByteStreamUtils.serializeIntToBytes(interactionSignal.length());
                for(int i = 0; i < 4; i++){
                    rawBytes[6+i] = intValues[i];
                }
                stringBytes = interactionSignal.getBytes();
                for(int i = 0; i < interactionSignal.length(); i++){
                    rawBytes[10+i] = stringBytes[i];
                }
                break;
        }
        serialized = true;
    }

}
