diff --git a/docs/src/progress/renderertodo.md b/docs/src/progress/renderertodo.md index 83057570..96ecb7a9 100644 --- a/docs/src/progress/renderertodo.md +++ b/docs/src/progress/renderertodo.md @@ -533,6 +533,9 @@ Ability to serialize/deserialize a creature with equipped items - Send to client - Receive from server +(08/11/2024) +Sending initial synchronized state on player connect to chunk + # TODO diff --git a/src/main/java/electrosphere/entity/types/creature/CreatureTemplate.java b/src/main/java/electrosphere/entity/types/creature/CreatureTemplate.java index 17e12476..4ab9a74a 100644 --- a/src/main/java/electrosphere/entity/types/creature/CreatureTemplate.java +++ b/src/main/java/electrosphere/entity/types/creature/CreatureTemplate.java @@ -3,6 +3,8 @@ package electrosphere.entity.types.creature; import java.util.HashMap; import java.util.Map; +import electrosphere.net.synchronization.transport.StateCollection; + /** * The template used to construct the creature on the client */ @@ -23,6 +25,11 @@ public class CreatureTemplate { */ private CreatureEquipData equipData = new CreatureEquipData(); + /** + * The collection of synchronized values + */ + private StateCollection stateCollection; + /** * Creates the creature template * @param creatureType The type of creature @@ -77,6 +84,22 @@ public class CreatureTemplate { return this.equipData; } + /** + * Gets the state collection for the creature + * @return The collection of synchronized values + */ + public StateCollection getStateCollection(){ + return this.stateCollection; + } + + /** + * Sets the synchronized values for this creature + * @param stateCollection The synchronized values + */ + public void setStateCollection(StateCollection stateCollection){ + this.stateCollection = stateCollection; + } + /** * A visual attribute of a creature (ie how wide is their nose, what type of hairstyle do they have, etc) */ diff --git a/src/main/java/electrosphere/entity/types/creature/CreatureUtils.java b/src/main/java/electrosphere/entity/types/creature/CreatureUtils.java index 2733ae1c..c317f258 100644 --- a/src/main/java/electrosphere/entity/types/creature/CreatureUtils.java +++ b/src/main/java/electrosphere/entity/types/creature/CreatureUtils.java @@ -65,6 +65,7 @@ import electrosphere.net.NetUtils; import electrosphere.net.parser.net.message.EntityMessage; import electrosphere.net.parser.net.message.NetworkMessage; import electrosphere.net.server.player.Player; +import electrosphere.net.synchronization.transport.StateCollection; import electrosphere.renderer.actor.Actor; import electrosphere.renderer.actor.ActorBoneRotator; import electrosphere.renderer.actor.ActorStaticMorph; @@ -845,6 +846,7 @@ public class CreatureUtils { equipData.setSlotItem(point, new EquippedItem(item.getId(),ItemUtils.getType(item))); } } + template.setStateCollection(StateCollection.getStateCollection(e)); return template; } diff --git a/src/main/java/electrosphere/net/client/protocol/EntityProtocol.java b/src/main/java/electrosphere/net/client/protocol/EntityProtocol.java index f799676e..5c1ab014 100644 --- a/src/main/java/electrosphere/net/client/protocol/EntityProtocol.java +++ b/src/main/java/electrosphere/net/client/protocol/EntityProtocol.java @@ -25,6 +25,7 @@ import electrosphere.game.data.creature.type.ViewModelData; import electrosphere.logger.LoggerInterface; import electrosphere.net.parser.net.message.EntityMessage; import electrosphere.net.parser.net.message.EntityMessage.EntityMessageType; +import electrosphere.net.synchronization.transport.StateCollection; import electrosphere.net.template.ClientProtocolTemplate; import electrosphere.util.Utilities; @@ -110,6 +111,10 @@ public class EntityProtocol implements ClientProtocolTemplate { Globals.clientSceneWrapper.mapIdToId(itemInInventory.getId(), itemDefinition.getEntityId()); } } + //apply state synchronization if present + if(template != null && template.getStateCollection() != null && template.getStateCollection().getValues() != null){ + StateCollection.applyStateCollection(newlySpawnedEntity, template.getStateCollection()); + } } break; case SPAWNITEM: { LoggerInterface.loggerNetworking.DEBUG("Spawn Item " + message.getentityID() + " at " + message.getpositionX() + " " + message.getpositionY() + " " + message.getpositionZ()); diff --git a/src/main/java/electrosphere/net/synchronization/transport/StateCollection.java b/src/main/java/electrosphere/net/synchronization/transport/StateCollection.java new file mode 100644 index 00000000..5d7079b2 --- /dev/null +++ b/src/main/java/electrosphere/net/synchronization/transport/StateCollection.java @@ -0,0 +1,261 @@ +package electrosphere.net.synchronization.transport; + + +import electrosphere.entity.state.equip.ClientEquipState; +import java.util.LinkedList; +import java.util.List; + +import electrosphere.engine.Globals; +import electrosphere.entity.Entity; +import electrosphere.entity.state.attack.ClientAttackTree; +import electrosphere.entity.state.attack.ServerAttackTree; +import electrosphere.entity.state.block.ClientBlockTree; +import electrosphere.entity.state.block.ServerBlockTree; +import electrosphere.entity.state.equip.ServerEquipState; +import electrosphere.entity.state.gravity.ClientGravityTree; +import electrosphere.entity.state.gravity.ServerGravityTree; +import electrosphere.entity.state.idle.ClientIdleTree; +import electrosphere.entity.state.idle.ServerIdleTree; +import electrosphere.entity.state.life.ClientLifeTree; +import electrosphere.entity.state.life.ServerLifeTree; +import electrosphere.entity.state.movement.groundmove.ClientGroundMovementTree; +import electrosphere.entity.state.movement.groundmove.ServerGroundMovementTree; +import electrosphere.entity.state.movement.jump.ClientJumpTree; +import electrosphere.entity.state.movement.jump.ServerJumpTree; +import electrosphere.net.synchronization.enums.BehaviorTreeIdEnums; +import electrosphere.net.synchronization.enums.FieldIdEnums; + +/** + * A collection of values for synchronized variables. + * Used to transport data from server to client on initially loading a given entity. + */ +public class StateCollection { + + /** + * The synchronized values + */ + List values = new LinkedList(); + + /** + * Get the synchronized field's values + * @return The values + */ + public List getValues(){ + return values; + } + + /** + * Sets a given value + * @param value The value + */ + public void setValue(SynchronizedFieldValue value){ + this.values.add(value); + } + + /** + *

Automatically generated

+ *

+ * Gets the state collection for the given entity + *

+ * @param entity The entity + * @return The state collection + */ + public static StateCollection getStateCollection(Entity entity){ + StateCollection collection = new StateCollection(); + for(int treeId : Globals.entityValueTrackingService.getEntityTrees(entity)){ + switch(treeId){ + case BehaviorTreeIdEnums.BTREE_SERVERATTACKTREE_ID: { + ServerAttackTree tree = ServerAttackTree.getServerAttackTree(entity); + collection.setValue(new SynchronizedFieldValue(BehaviorTreeIdEnums.BTREE_SERVERATTACKTREE_ID,FieldIdEnums.TREE_SERVERATTACKTREE_SYNCEDFIELD_STATE_ID,ClientAttackTree.getAttackTreeStateEnumAsShort(tree.getState()))); + collection.setValue(new SynchronizedFieldValue(BehaviorTreeIdEnums.BTREE_SERVERATTACKTREE_ID,FieldIdEnums.TREE_SERVERATTACKTREE_SYNCEDFIELD_DRIFTSTATE_ID,ClientAttackTree.getAttackTreeDriftStateEnumAsShort(tree.getDriftState()))); + collection.setValue(new SynchronizedFieldValue(BehaviorTreeIdEnums.BTREE_SERVERATTACKTREE_ID,FieldIdEnums.TREE_SERVERATTACKTREE_SYNCEDFIELD_CURRENTMOVEID_ID,tree.getCurrentMoveId())); + } break; + case BehaviorTreeIdEnums.BTREE_SERVERBLOCKTREE_ID: { + ServerBlockTree tree = ServerBlockTree.getServerBlockTree(entity); + collection.setValue(new SynchronizedFieldValue(BehaviorTreeIdEnums.BTREE_SERVERBLOCKTREE_ID,FieldIdEnums.TREE_SERVERBLOCKTREE_SYNCEDFIELD_STATE_ID,ClientBlockTree.getBlockStateEnumAsShort(tree.getState()))); + collection.setValue(new SynchronizedFieldValue(BehaviorTreeIdEnums.BTREE_SERVERBLOCKTREE_ID,FieldIdEnums.TREE_SERVERBLOCKTREE_SYNCEDFIELD_CURRENTBLOCKVARIANT_ID,tree.getCurrentBlockVariant())); + } break; + case BehaviorTreeIdEnums.BTREE_SERVEREQUIPSTATE_ID: { + ServerEquipState tree = ServerEquipState.getServerEquipState(entity); + } break; + case BehaviorTreeIdEnums.BTREE_SERVERGRAVITY_ID: { + ServerGravityTree tree = ServerGravityTree.getServerGravityTree(entity); + collection.setValue(new SynchronizedFieldValue(BehaviorTreeIdEnums.BTREE_SERVERGRAVITY_ID,FieldIdEnums.TREE_SERVERGRAVITY_SYNCEDFIELD_STATE_ID,ClientGravityTree.getGravityTreeStateEnumAsShort(tree.getState()))); + } break; + case BehaviorTreeIdEnums.BTREE_SERVERIDLE_ID: { + ServerIdleTree tree = ServerIdleTree.getServerIdleTree(entity); + collection.setValue(new SynchronizedFieldValue(BehaviorTreeIdEnums.BTREE_SERVERIDLE_ID,FieldIdEnums.TREE_SERVERIDLE_SYNCEDFIELD_STATE_ID,ClientIdleTree.getIdleTreeStateEnumAsShort(tree.getState()))); + } break; + case BehaviorTreeIdEnums.BTREE_SERVERLIFETREE_ID: { + ServerLifeTree tree = ServerLifeTree.getServerLifeTree(entity); + collection.setValue(new SynchronizedFieldValue(BehaviorTreeIdEnums.BTREE_SERVERLIFETREE_ID,FieldIdEnums.TREE_SERVERLIFETREE_SYNCEDFIELD_STATE_ID,ClientLifeTree.getLifeStateEnumEnumAsShort(tree.getState()))); + } break; + case BehaviorTreeIdEnums.BTREE_SERVERGROUNDMOVEMENTTREE_ID: { + ServerGroundMovementTree tree = ServerGroundMovementTree.getServerGroundMovementTree(entity); + collection.setValue(new SynchronizedFieldValue(BehaviorTreeIdEnums.BTREE_SERVERGROUNDMOVEMENTTREE_ID,FieldIdEnums.TREE_SERVERGROUNDMOVEMENTTREE_SYNCEDFIELD_FACING_ID,ClientGroundMovementTree.getMovementRelativeFacingEnumAsShort(tree.getFacing()))); + } break; + case BehaviorTreeIdEnums.BTREE_SERVERJUMPTREE_ID: { + ServerJumpTree tree = ServerJumpTree.getServerJumpTree(entity); + collection.setValue(new SynchronizedFieldValue(BehaviorTreeIdEnums.BTREE_SERVERJUMPTREE_ID,FieldIdEnums.TREE_SERVERJUMPTREE_SYNCEDFIELD_STATE_ID,ClientJumpTree.getJumpStateEnumAsShort(tree.getState()))); + collection.setValue(new SynchronizedFieldValue(BehaviorTreeIdEnums.BTREE_SERVERJUMPTREE_ID,FieldIdEnums.TREE_SERVERJUMPTREE_SYNCEDFIELD_CURRENTFRAME_ID,tree.getCurrentFrame())); + collection.setValue(new SynchronizedFieldValue(BehaviorTreeIdEnums.BTREE_SERVERJUMPTREE_ID,FieldIdEnums.TREE_SERVERJUMPTREE_SYNCEDFIELD_CURRENTJUMPFORCE_ID,tree.getCurrentJumpForce())); + } break; + + } + } + return collection; + } + + /** + *

Automatically generated

+ *

+ * Applies the state collection to the given entity + *

+ * @param entity The entity + * @param collection The state collection + */ + public static void applyStateCollection(Entity entity, StateCollection collection){ + for(SynchronizedFieldValue syncedValue : collection.getValues()){ + switch(syncedValue.getBehaviorTreeId()){ + case BehaviorTreeIdEnums.BTREE_SERVERATTACKTREE_ID: { + ClientAttackTree tree = ClientAttackTree.getClientAttackTree(entity); + switch(syncedValue.getFieldId()){ + case(FieldIdEnums.TREE_SERVERATTACKTREE_SYNCEDFIELD_STATE_ID): { + tree.setState(ClientAttackTree.getAttackTreeStateShortAsEnum(((Double)syncedValue.getValue()).shortValue())); + } break; + case(FieldIdEnums.TREE_SERVERATTACKTREE_SYNCEDFIELD_DRIFTSTATE_ID): { + tree.setDriftState(ClientAttackTree.getAttackTreeDriftStateShortAsEnum(((Double)syncedValue.getValue()).shortValue())); + } break; + case(FieldIdEnums.TREE_SERVERATTACKTREE_SYNCEDFIELD_CURRENTMOVEID_ID): { + tree.setCurrentMoveId((String)syncedValue.getValue()); + } break; + } + } break; + case BehaviorTreeIdEnums.BTREE_SERVERBLOCKTREE_ID: { + ClientBlockTree tree = ClientBlockTree.getClientBlockTree(entity); + switch(syncedValue.getFieldId()){ + case(FieldIdEnums.TREE_SERVERBLOCKTREE_SYNCEDFIELD_STATE_ID): { + tree.setState(ClientBlockTree.getBlockStateShortAsEnum(((Double)syncedValue.getValue()).shortValue())); + } break; + case(FieldIdEnums.TREE_SERVERBLOCKTREE_SYNCEDFIELD_CURRENTBLOCKVARIANT_ID): { + tree.setCurrentBlockVariant((String)syncedValue.getValue()); + } break; + } + } break; + case BehaviorTreeIdEnums.BTREE_SERVEREQUIPSTATE_ID: { + ClientEquipState tree = ClientEquipState.getClientEquipState(entity); + switch(syncedValue.getFieldId()){ + } + } break; + case BehaviorTreeIdEnums.BTREE_SERVERGRAVITY_ID: { + ClientGravityTree tree = ClientGravityTree.getClientGravityTree(entity); + switch(syncedValue.getFieldId()){ + case(FieldIdEnums.TREE_SERVERGRAVITY_SYNCEDFIELD_STATE_ID): { + tree.setState(ClientGravityTree.getGravityTreeStateShortAsEnum(((Double)syncedValue.getValue()).shortValue())); + } break; + } + } break; + case BehaviorTreeIdEnums.BTREE_SERVERIDLE_ID: { + ClientIdleTree tree = ClientIdleTree.getClientIdleTree(entity); + switch(syncedValue.getFieldId()){ + case(FieldIdEnums.TREE_SERVERIDLE_SYNCEDFIELD_STATE_ID): { + tree.setState(ClientIdleTree.getIdleTreeStateShortAsEnum(((Double)syncedValue.getValue()).shortValue())); + } break; + } + } break; + case BehaviorTreeIdEnums.BTREE_SERVERLIFETREE_ID: { + ClientLifeTree tree = ClientLifeTree.getClientLifeTree(entity); + switch(syncedValue.getFieldId()){ + case(FieldIdEnums.TREE_SERVERLIFETREE_SYNCEDFIELD_STATE_ID): { + tree.setState(ClientLifeTree.getLifeStateEnumShortAsEnum(((Double)syncedValue.getValue()).shortValue())); + } break; + } + } break; + case BehaviorTreeIdEnums.BTREE_SERVERGROUNDMOVEMENTTREE_ID: { + ClientGroundMovementTree tree = ClientGroundMovementTree.getClientGroundMovementTree(entity); + switch(syncedValue.getFieldId()){ + case(FieldIdEnums.TREE_SERVERGROUNDMOVEMENTTREE_SYNCEDFIELD_FACING_ID): { + tree.setFacing(ClientGroundMovementTree.getMovementRelativeFacingShortAsEnum(((Double)syncedValue.getValue()).shortValue())); + } break; + } + } break; + case BehaviorTreeIdEnums.BTREE_SERVERJUMPTREE_ID: { + ClientJumpTree tree = ClientJumpTree.getClientJumpTree(entity); + switch(syncedValue.getFieldId()){ + case(FieldIdEnums.TREE_SERVERJUMPTREE_SYNCEDFIELD_STATE_ID): { + tree.setState(ClientJumpTree.getJumpStateShortAsEnum(((Double)syncedValue.getValue()).shortValue())); + } break; + case(FieldIdEnums.TREE_SERVERJUMPTREE_SYNCEDFIELD_CURRENTFRAME_ID): { + tree.setCurrentFrame(((Double)syncedValue.getValue()).intValue()); + } break; + case(FieldIdEnums.TREE_SERVERJUMPTREE_SYNCEDFIELD_CURRENTJUMPFORCE_ID): { + tree.setCurrentJumpForce(((Double)syncedValue.getValue()).floatValue()); + } break; + } + } break; + + } + } + } + + + + /** + * The value of a single synchronized field + */ + public static class SynchronizedFieldValue { + + /** + * The behavior tree this field is on + */ + int behaviorTreeId; + + /** + * The id of the field + */ + int fieldId; + + /** + * The value of the field + */ + Object value; + + /** + * Creates a synchronized value + * @param behaviorTreeId The behavior tree id of the field + * @param fieldId The field id of the field + * @param value The value of the field currently + */ + public SynchronizedFieldValue(int behaviorTreeId, int fieldId, Object value){ + this.behaviorTreeId = behaviorTreeId; + this.fieldId = fieldId; + this.value = value; + } + + /** + * Gets the behavior tree this field is in + * @return the id of the behavior tree + */ + public int getBehaviorTreeId(){ + return behaviorTreeId; + } + + /** + * Gets the id of the field + * @return The id + */ + public int getFieldId(){ + return fieldId; + } + + /** + * Gets the current value for this field + * @return The current value + */ + public Object getValue(){ + return value; + } + + } + +}