state interrupts and transition packets

This commit is contained in:
austin 2024-08-02 15:57:11 -04:00
parent d319f05a2e
commit 2c42de3882
12 changed files with 216 additions and 6 deletions

View File

@ -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",

View File

@ -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
*/

View File

@ -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 {
});
}
/**
* <p> (Initially) Automatically Generated </p>
* <p>
* Performs a state transition on a client state variable.
* Will be triggered when a server performs a state change.
* </p>
* @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){

View File

@ -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));
}
/**
* <p> (initially) Automatically generated </p>

View File

@ -27,6 +27,7 @@ public class SynchronizationProtocol implements ClientProtocolTemplate<Synchroni
case UPDATECLIENTLONGSTATE:
case ATTACHTREE:
case DETATCHTREE:
case SERVERNOTIFYBTREETRANSITION:
Globals.clientSynchronizationManager.pushMessage(message);
break;
case LOADSCENE:

View File

@ -371,6 +371,11 @@ SYNCHRONIZATION_MESSAGE,
rVal = SynchronizationMessage.parseClientRequestBTreeActionMessage(byteBuffer);
}
break;
case TypeBytes.SYNCHRONIZATION_MESSAGE_TYPE_SERVERNOTIFYBTREETRANSITION:
if(SynchronizationMessage.canParseMessage(byteBuffer,secondByte)){
rVal = SynchronizationMessage.parseServerNotifyBTreeTransitionMessage(byteBuffer);
}
break;
case TypeBytes.SYNCHRONIZATION_MESSAGE_TYPE_ATTACHTREE:
if(SynchronizationMessage.canParseMessage(byteBuffer,secondByte)){
rVal = SynchronizationMessage.parseAttachTreeMessage(byteBuffer);

View File

@ -15,6 +15,7 @@ public class SynchronizationMessage extends NetworkMessage {
UPDATECLIENTFLOATSTATE,
UPDATECLIENTDOUBLESTATE,
CLIENTREQUESTBTREEACTION,
SERVERNOTIFYBTREETRANSITION,
ATTACHTREE,
DETATCHTREE,
LOADSCENE,
@ -156,6 +157,12 @@ public class SynchronizationMessage extends NetworkMessage {
} else {
return false;
}
case TypeBytes.SYNCHRONIZATION_MESSAGE_TYPE_SERVERNOTIFYBTREETRANSITION:
if(byteBuffer.getRemaining() >= 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

View File

@ -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;
}

View File

@ -24,6 +24,7 @@ public class SynchronizationProtocol implements ServerProtocolTemplate<Synchroni
case ATTACHTREE:
case DETATCHTREE:
case LOADSCENE:
case SERVERNOTIFYBTREETRANSITION:
//silently ignore
break;
}
@ -45,6 +46,7 @@ public class SynchronizationProtocol implements ServerProtocolTemplate<Synchroni
case ATTACHTREE:
case DETATCHTREE:
case LOADSCENE:
case SERVERNOTIFYBTREETRANSITION:
//silently ignore
break;
}

View File

@ -73,6 +73,12 @@ public class ClientSynchronizationManager {
Entity targetEntity = Globals.clientSceneWrapper.getEntityFromServerId(entityId);
updateEntityState(targetEntity,bTreeId,message);
} break;
case SERVERNOTIFYBTREETRANSITION: {
int bTreeId = message.getbTreeId();
int entityId = message.getentityId();
Entity targetEntity = Globals.clientSceneWrapper.getEntityFromServerId(entityId);
transitionBTree(targetEntity, bTreeId, message);
} break;
case ATTACHTREE:{
// int bTreeId = message.getbTreeId();
// int bTreeValue = message.getbTreeValue();
@ -216,5 +222,28 @@ public class ClientSynchronizationManager {
}
}
/**
* <p> Automatically generated </p>
* <p>
* Transitions a behavior tree to a new state
* </p>
* @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;
}
}
}

View File

@ -59,6 +59,7 @@ public class ServerSynchronizationManager {
case ATTACHTREE:
case DETATCHTREE:
case LOADSCENE:
case SERVERNOTIFYBTREETRANSITION:
//silently ignore
break;
}

View File

@ -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;
}