diff --git a/net/synchronization.json b/net/synchronization.json index 81d2cac4..51cda9a8 100644 --- a/net/synchronization.json +++ b/net/synchronization.json @@ -113,6 +113,16 @@ "bTreeValue" ] }, + { + "messageName" : "ServerNotifyBTreeTransition", + "description" : "Packet from the server to the client notifying the client that it should transition a btree from one state to another", + "data" : [ + "entityId", + "bTreeId", + "fieldId", + "bTreeValue" + ] + }, { "messageName" : "AttachTree", "description" : "Attaches a btree to an entity on the client", diff --git a/src/main/java/electrosphere/entity/btree/StateTransitionUtil.java b/src/main/java/electrosphere/entity/btree/StateTransitionUtil.java index 3f12e10c..022a3084 100644 --- a/src/main/java/electrosphere/entity/btree/StateTransitionUtil.java +++ b/src/main/java/electrosphere/entity/btree/StateTransitionUtil.java @@ -191,6 +191,87 @@ public class StateTransitionUtil { } } + /** + * Interrupts a given state + * @param stateEnum The state enum + */ + public void interrupt(Object stateEnum){ + StateTransitionUtilItem state = null; + for(StateTransitionUtilItem targetState : states){ + if(targetState.stateEnum == stateEnum){ + state = targetState; + break; + } + } + if(state == null){ + LoggerInterface.loggerEngine.DEBUG("Skipping state " + stateEnum + " because there is not a state registered to that enum value!"); + } else { + if(this.isServer){ + interruptServerState(this.parent,state); + } else { + interruptClientState(this.parent,state); + } + } + } + + /** + * Interrupts animation logic for client tree + * @param parent The parent entity + * @param state The state + */ + private static void interruptClientState(Entity parent, StateTransitionUtilItem state){ + Actor actor = EntityUtils.getActor(parent); + if(actor != null){ + + //get the animation to play + TreeDataAnimation animation = state.animation; + if(state.getAnimation != null && state.getAnimation.get() != null){ + animation = state.getAnimation.get(); + } + + + // + //Interrupt main animation + // + if(animation != null && actor.isPlayingAnimation() && actor.isPlayingAnimation(animation)){ + actor.interruptAnimation(animation, true); + } + + // + //Interrupt animation in first person + // + if(animation != null){ + FirstPersonTree.conditionallyInterruptAnimation(Globals.firstPersonEntity, animation); + } + } + } + + /** + * Interrupts animation logic for server tree + * @param parent The parent entity + * @param state The state + */ + private static void interruptServerState(Entity parent, StateTransitionUtilItem state){ + PoseActor poseActor = EntityUtils.getPoseActor(parent); + if(poseActor != null){ + + //get the animation to play + TreeDataAnimation animation = state.animation; + if(state.getAnimation != null && state.getAnimation.get() != null){ + animation = state.getAnimation.get(); + } + + + + // + //Interrupt main animation + // + if(animation != null && poseActor.isPlayingAnimation() && poseActor.isPlayingAnimation(animation)){ + poseActor.interruptAnimation(animation, true); + } + } + } + /** * A parameter used to construct a StateTransitionUtil */ diff --git a/src/main/java/electrosphere/entity/state/block/ClientBlockTree.java b/src/main/java/electrosphere/entity/state/block/ClientBlockTree.java index 581007af..59a9a852 100644 --- a/src/main/java/electrosphere/entity/state/block/ClientBlockTree.java +++ b/src/main/java/electrosphere/entity/state/block/ClientBlockTree.java @@ -31,7 +31,7 @@ public class ClientBlockTree implements BehaviorTree { NOT_BLOCKING, } - @SyncedField + @SyncedField(serverSendTransitionPacket = true) BlockState state = BlockState.NOT_BLOCKING; //the current state //the parent entity to this tree @@ -74,6 +74,31 @@ public class ClientBlockTree implements BehaviorTree { }); } + /** + *

(Initially) Automatically Generated

+ *

+ * Performs a state transition on a client state variable. + * Will be triggered when a server performs a state change. + *

+ * @param newState The new value of the state + */ + public void transitionState(BlockState newState){ + this.setState(newState); + switch(newState){ + case WIND_UP: { + } break; + case BLOCKING: { + this.stateTransitionUtil.interrupt(BlockState.WIND_UP); + } break; + case COOLDOWN: { + this.stateTransitionUtil.interrupt(BlockState.BLOCKING); + } break; + case NOT_BLOCKING: { + this.stateTransitionUtil.interrupt(BlockState.COOLDOWN); + } break; + } + } + @Override public void simulate(float deltaTime) { switch(state){ diff --git a/src/main/java/electrosphere/entity/state/block/ServerBlockTree.java b/src/main/java/electrosphere/entity/state/block/ServerBlockTree.java index b8792d79..9d9d95b4 100644 --- a/src/main/java/electrosphere/entity/state/block/ServerBlockTree.java +++ b/src/main/java/electrosphere/entity/state/block/ServerBlockTree.java @@ -26,7 +26,7 @@ import electrosphere.net.synchronization.annotation.SynchronizedBehaviorTree; */ public class ServerBlockTree implements BehaviorTree { - @SyncedField + @SyncedField(serverSendTransitionPacket = true) BlockState state = BlockState.NOT_BLOCKING; //the current state of the tree //the parent entity to this tree @@ -152,7 +152,7 @@ public class ServerBlockTree implements BehaviorTree { public void setState(BlockState state){ this.state = state; int value = ClientBlockTree.getBlockStateEnumAsShort(state); - DataCellSearchUtils.getEntityDataCell(parent).broadcastNetworkMessage(SynchronizationMessage.constructUpdateClientStateMessage(parent.getId(), BehaviorTreeIdEnums.BTREE_SERVERBLOCKTREE_ID, FieldIdEnums.TREE_SERVERBLOCKTREE_SYNCEDFIELD_STATE_ID, value)); + DataCellSearchUtils.getEntityDataCell(parent).broadcastNetworkMessage(SynchronizationMessage.constructServerNotifyBTreeTransitionMessage(parent.getId(), BehaviorTreeIdEnums.BTREE_SERVERBLOCKTREE_ID, FieldIdEnums.TREE_SERVERBLOCKTREE_SYNCEDFIELD_STATE_ID, value)); } /** *

(initially) Automatically generated

diff --git a/src/main/java/electrosphere/net/client/protocol/SynchronizationProtocol.java b/src/main/java/electrosphere/net/client/protocol/SynchronizationProtocol.java index 875cd7f1..b97efd57 100644 --- a/src/main/java/electrosphere/net/client/protocol/SynchronizationProtocol.java +++ b/src/main/java/electrosphere/net/client/protocol/SynchronizationProtocol.java @@ -27,6 +27,7 @@ public class SynchronizationProtocol implements ClientProtocolTemplate= TypeBytes.SYNCHRONIZATION_MESSAGE_TYPE_SERVERNOTIFYBTREETRANSITION_SIZE){ + return true; + } else { + return false; + } case TypeBytes.SYNCHRONIZATION_MESSAGE_TYPE_ATTACHTREE: if(byteBuffer.getRemaining() >= TypeBytes.SYNCHRONIZATION_MESSAGE_TYPE_ATTACHTREE_SIZE){ return true; @@ -340,6 +347,26 @@ public class SynchronizationMessage extends NetworkMessage { return rVal; } + public static SynchronizationMessage parseServerNotifyBTreeTransitionMessage(CircularByteBuffer byteBuffer){ + SynchronizationMessage rVal = new SynchronizationMessage(SynchronizationMessageType.SERVERNOTIFYBTREETRANSITION); + stripPacketHeader(byteBuffer); + rVal.setentityId(ByteStreamUtils.popIntFromByteQueue(byteBuffer)); + rVal.setbTreeId(ByteStreamUtils.popIntFromByteQueue(byteBuffer)); + rVal.setfieldId(ByteStreamUtils.popIntFromByteQueue(byteBuffer)); + rVal.setbTreeValue(ByteStreamUtils.popIntFromByteQueue(byteBuffer)); + return rVal; + } + + public static SynchronizationMessage constructServerNotifyBTreeTransitionMessage(int entityId,int bTreeId,int fieldId,int bTreeValue){ + SynchronizationMessage rVal = new SynchronizationMessage(SynchronizationMessageType.SERVERNOTIFYBTREETRANSITION); + rVal.setentityId(entityId); + rVal.setbTreeId(bTreeId); + rVal.setfieldId(fieldId); + rVal.setbTreeValue(bTreeValue); + rVal.serialize(); + return rVal; + } + public static SynchronizationMessage parseAttachTreeMessage(CircularByteBuffer byteBuffer){ SynchronizationMessage rVal = new SynchronizationMessage(SynchronizationMessageType.ATTACHTREE); stripPacketHeader(byteBuffer); @@ -570,6 +597,29 @@ public class SynchronizationMessage extends NetworkMessage { rawBytes[10+i] = intValues[i]; } break; + case SERVERNOTIFYBTREETRANSITION: + rawBytes = new byte[2+4+4+4+4]; + //message header + rawBytes[0] = TypeBytes.MESSAGE_TYPE_SYNCHRONIZATION; + //entity messaage header + rawBytes[1] = TypeBytes.SYNCHRONIZATION_MESSAGE_TYPE_SERVERNOTIFYBTREETRANSITION; + intValues = ByteStreamUtils.serializeIntToBytes(entityId); + for(int i = 0; i < 4; i++){ + rawBytes[2+i] = intValues[i]; + } + intValues = ByteStreamUtils.serializeIntToBytes(bTreeId); + for(int i = 0; i < 4; i++){ + rawBytes[6+i] = intValues[i]; + } + intValues = ByteStreamUtils.serializeIntToBytes(fieldId); + for(int i = 0; i < 4; i++){ + rawBytes[10+i] = intValues[i]; + } + intValues = ByteStreamUtils.serializeIntToBytes(bTreeValue); + for(int i = 0; i < 4; i++){ + rawBytes[14+i] = intValues[i]; + } + break; case ATTACHTREE: rawBytes = new byte[2+4+4]; //message header diff --git a/src/main/java/electrosphere/net/parser/net/message/TypeBytes.java b/src/main/java/electrosphere/net/parser/net/message/TypeBytes.java index d9243c79..4e3f70da 100644 --- a/src/main/java/electrosphere/net/parser/net/message/TypeBytes.java +++ b/src/main/java/electrosphere/net/parser/net/message/TypeBytes.java @@ -152,9 +152,10 @@ Message categories public static final byte SYNCHRONIZATION_MESSAGE_TYPE_UPDATECLIENTFLOATSTATE = 4; public static final byte SYNCHRONIZATION_MESSAGE_TYPE_UPDATECLIENTDOUBLESTATE = 5; public static final byte SYNCHRONIZATION_MESSAGE_TYPE_CLIENTREQUESTBTREEACTION = 6; - public static final byte SYNCHRONIZATION_MESSAGE_TYPE_ATTACHTREE = 7; - public static final byte SYNCHRONIZATION_MESSAGE_TYPE_DETATCHTREE = 8; - public static final byte SYNCHRONIZATION_MESSAGE_TYPE_LOADSCENE = 9; + public static final byte SYNCHRONIZATION_MESSAGE_TYPE_SERVERNOTIFYBTREETRANSITION = 7; + public static final byte SYNCHRONIZATION_MESSAGE_TYPE_ATTACHTREE = 8; + public static final byte SYNCHRONIZATION_MESSAGE_TYPE_DETATCHTREE = 9; + public static final byte SYNCHRONIZATION_MESSAGE_TYPE_LOADSCENE = 10; /* Synchronization packet sizes */ @@ -164,6 +165,7 @@ Message categories public static final byte SYNCHRONIZATION_MESSAGE_TYPE_UPDATECLIENTFLOATSTATE_SIZE = 18; public static final byte SYNCHRONIZATION_MESSAGE_TYPE_UPDATECLIENTDOUBLESTATE_SIZE = 22; public static final byte SYNCHRONIZATION_MESSAGE_TYPE_CLIENTREQUESTBTREEACTION_SIZE = 14; + public static final byte SYNCHRONIZATION_MESSAGE_TYPE_SERVERNOTIFYBTREETRANSITION_SIZE = 18; public static final byte SYNCHRONIZATION_MESSAGE_TYPE_ATTACHTREE_SIZE = 10; public static final byte SYNCHRONIZATION_MESSAGE_TYPE_DETATCHTREE_SIZE = 10; } diff --git a/src/main/java/electrosphere/net/server/protocol/SynchronizationProtocol.java b/src/main/java/electrosphere/net/server/protocol/SynchronizationProtocol.java index 0ff896f1..22a12359 100644 --- a/src/main/java/electrosphere/net/server/protocol/SynchronizationProtocol.java +++ b/src/main/java/electrosphere/net/server/protocol/SynchronizationProtocol.java @@ -24,6 +24,7 @@ public class SynchronizationProtocol implements ServerProtocolTemplate Automatically generated

+ *

+ * Transitions a behavior tree to a new state + *

+ * @param entity The entity + * @param bTreeId The id of the behavior tree + * @param message The raw synchronization message holding the update data + */ + private void transitionBTree(Entity entity, int bTreeId, SynchronizationMessage message){ + switch(bTreeId){ + case BehaviorTreeIdEnums.BTREE_SERVERBLOCKTREE_ID: { + switch(message.getfieldId()){ + case FieldIdEnums.TREE_SERVERBLOCKTREE_SYNCEDFIELD_STATE_ID:{ + ClientBlockTree tree = ClientBlockTree.getClientBlockTree(entity); + tree.transitionState(ClientBlockTree.getBlockStateShortAsEnum((short)message.getbTreeValue())); + } break; + } + } break; + + } + } } diff --git a/src/main/java/electrosphere/net/synchronization/ServerSynchronizationManager.java b/src/main/java/electrosphere/net/synchronization/ServerSynchronizationManager.java index d04d1311..0251ca90 100644 --- a/src/main/java/electrosphere/net/synchronization/ServerSynchronizationManager.java +++ b/src/main/java/electrosphere/net/synchronization/ServerSynchronizationManager.java @@ -59,6 +59,7 @@ public class ServerSynchronizationManager { case ATTACHTREE: case DETATCHTREE: case LOADSCENE: + case SERVERNOTIFYBTREETRANSITION: //silently ignore break; } diff --git a/src/main/java/electrosphere/net/synchronization/annotation/SyncedField.java b/src/main/java/electrosphere/net/synchronization/annotation/SyncedField.java index 9c1601a5..b1e59c87 100644 --- a/src/main/java/electrosphere/net/synchronization/annotation/SyncedField.java +++ b/src/main/java/electrosphere/net/synchronization/annotation/SyncedField.java @@ -23,4 +23,8 @@ public @interface SyncedField { //ie when idle state changes (to idle from not idle), tell the client the position of the entity when this update happened alongside the actual state update public boolean updatePositionOnStateChange() default false; + //Instructs the server to send a state-transition packet instead of an immediate update packet + //The state transition packet will invoke the transitionBTree function on the client instead of immediately overwriting the state's value + public boolean serverSendTransitionPacket() default false; + }