From 6e55b7ee18183b103a349857fa57e2052d8ad450 Mon Sep 17 00:00:00 2001 From: austin Date: Sat, 24 May 2025 16:56:31 -0400 Subject: [PATCH] LOD component --- docs/src/progress/renderertodo.md | 1 + .../entity/EntityDataStrings.java | 6 + .../entity/state/lod/ClientLODComponent.java | 143 ++++++++++++++ .../entity/state/lod/ServerLODComponent.java | 179 ++++++++++++++++++ .../types/common/CommonEntityUtils.java | 4 + .../client/ClientSynchronizationManager.java | 11 ++ .../enums/BehaviorTreeIdEnums.java | 2 + .../synchronization/enums/FieldIdEnums.java | 2 + .../transport/StateCollection.java | 22 +++ 9 files changed, 370 insertions(+) create mode 100644 src/main/java/electrosphere/entity/state/lod/ClientLODComponent.java create mode 100644 src/main/java/electrosphere/entity/state/lod/ServerLODComponent.java diff --git a/docs/src/progress/renderertodo.md b/docs/src/progress/renderertodo.md index 064db2be..fa1f78fc 100644 --- a/docs/src/progress/renderertodo.md +++ b/docs/src/progress/renderertodo.md @@ -1955,6 +1955,7 @@ Work on rotating structures Towns spawn a population of characters when they are max-res'd Hitbox synchronization work LOD emitter service +LOD component that destroys far-away physics diff --git a/src/main/java/electrosphere/entity/EntityDataStrings.java b/src/main/java/electrosphere/entity/EntityDataStrings.java index 8050aedd..3e272c2a 100644 --- a/src/main/java/electrosphere/entity/EntityDataStrings.java +++ b/src/main/java/electrosphere/entity/EntityDataStrings.java @@ -369,6 +369,12 @@ public class EntityDataStrings { public static final String TREE_SERVERGROWTH = "treeServerGrowth"; public static final String TREE_CLIENTGROWTH = "treeClientGrowth"; + /** + * LOD component + */ + public static final String TREE_CLIENTLODTREE = "treeClientLODTree"; + public static final String TREE_SERVERLODTREE = "treeServerLODTree"; + /** * Loot pool */ diff --git a/src/main/java/electrosphere/entity/state/lod/ClientLODComponent.java b/src/main/java/electrosphere/entity/state/lod/ClientLODComponent.java new file mode 100644 index 00000000..f0a9257e --- /dev/null +++ b/src/main/java/electrosphere/entity/state/lod/ClientLODComponent.java @@ -0,0 +1,143 @@ +package electrosphere.entity.state.lod; + + +import electrosphere.collision.PhysicsEntityUtils; +import electrosphere.collision.PhysicsUtils; +import electrosphere.engine.Globals; +import electrosphere.entity.EntityDataStrings; +import electrosphere.entity.Entity; +import electrosphere.net.synchronization.enums.BehaviorTreeIdEnums; +import electrosphere.entity.btree.BehaviorTree; +import electrosphere.net.synchronization.annotation.SyncedField; +import electrosphere.net.synchronization.annotation.SynchronizedBehaviorTree; + +/** + * Creates a client LOD component + */ +@SynchronizedBehaviorTree(name = "clientLODTree", isServer = false, correspondingTree="serverLODTree") +public class ClientLODComponent implements BehaviorTree { + + /** + * The current LOD level + */ + @SyncedField + private int lodLevel; + + /** + * The cached lod level from the most recent call + */ + private int cachedLodLevel; + + /** + * The parent entity + */ + private Entity parent; + + @Override + public void simulate(float deltaTime) { + if(cachedLodLevel != lodLevel){ + cachedLodLevel = lodLevel; + if(cachedLodLevel == ServerLODComponent.FULL_RES){ + + } else if(cachedLodLevel == ServerLODComponent.LOW_RES){ + if(PhysicsEntityUtils.containsDBody(this.parent)){ + PhysicsUtils.destroyPhysicsPair( + Globals.clientState.clientSceneWrapper.getCollisionEngine(), + PhysicsEntityUtils.getDBody(this.parent), + PhysicsEntityUtils.getCollidable(this.parent) + ); + } + } + } + } + + /** + *

(initially) Automatically generated

+ *

+ * Attaches this tree to the entity. + *

+ * @param entity The entity to attach to + * @param tree The behavior tree to attach + * @param params Optional parameters that will be provided to the constructor + */ + public static ClientLODComponent attachTree(Entity parent, Object ... params){ + ClientLODComponent rVal = new ClientLODComponent(parent,params); + //!!WARNING!! from here below should not be touched + //This was generated automatically to properly alert various systems that the btree exists and should be tracked + parent.putData(EntityDataStrings.TREE_CLIENTLODTREE, rVal); + Globals.clientState.clientSceneWrapper.getScene().registerBehaviorTree(rVal); + Globals.serverState.entityValueTrackingService.attachTreeToEntity(parent, BehaviorTreeIdEnums.BTREE_CLIENTLODTREE_ID); + return rVal; + } + + /** + *

Automatically generated

+ *

+ * Detatches this tree from the entity. + *

+ * @param entity The entity to detach to + * @param tree The behavior tree to detach + */ + public static void detachTree(Entity entity, BehaviorTree tree){ + Globals.serverState.entityValueTrackingService.detatchTreeFromEntity(entity, BehaviorTreeIdEnums.BTREE_CLIENTLODTREE_ID); + } + + /** + *

(initially) Automatically generated

+ *

Private constructor to enforce using the attach methods

+ *

+ * Constructor + *

+ * @param parent The parent entity of this tree + * @param params Optional parameters that can be provided when attaching the tree. All custom data required for creating this tree should be passed in this varargs. + */ + private ClientLODComponent(Entity parent, Object ... params){ + this.parent = parent; + this.lodLevel = ServerLODComponent.FULL_RES; + this.cachedLodLevel = ServerLODComponent.FULL_RES; + } + + /** + *

+ * Gets the ClientLODComponent of the entity + *

+ * @param entity the entity + * @return The ClientLODComponent + */ + public static ClientLODComponent getClientLODComponent(Entity entity){ + return (ClientLODComponent)entity.getData(EntityDataStrings.TREE_CLIENTLODTREE); + } + + /** + *

+ * Checks if the entity has a ClientLODComponent component + *

+ * @param entity the entity + * @return true if the entity contains the component, false otherwise + */ + public static boolean hasClientLODComponent(Entity entity){ + return entity.containsKey(EntityDataStrings.TREE_CLIENTLODTREE); + } + + /** + *

Automatically generated

+ *

+ * Sets lodLevel and handles the synchronization logic for it. + *

+ * @param lodLevel The value to set lodLevel to. + */ + public void setLodLevel(int lodLevel){ + this.lodLevel = lodLevel; + } + + /** + *

Automatically generated

+ *

+ * Gets lodLevel. + *

+ */ + public int getLodLevel(){ + return lodLevel; + } + +} diff --git a/src/main/java/electrosphere/entity/state/lod/ServerLODComponent.java b/src/main/java/electrosphere/entity/state/lod/ServerLODComponent.java new file mode 100644 index 00000000..8a3f534d --- /dev/null +++ b/src/main/java/electrosphere/entity/state/lod/ServerLODComponent.java @@ -0,0 +1,179 @@ +package electrosphere.entity.state.lod; + + +import org.joml.Vector3d; + +import electrosphere.collision.PhysicsEntityUtils; +import electrosphere.collision.PhysicsUtils; +import electrosphere.engine.Globals; +import electrosphere.entity.EntityDataStrings; +import electrosphere.entity.EntityUtils; +import electrosphere.net.synchronization.enums.FieldIdEnums; +import electrosphere.server.datacell.Realm; +import electrosphere.server.datacell.utils.DataCellSearchUtils; +import electrosphere.net.parser.net.message.SynchronizationMessage; +import electrosphere.entity.Entity; +import electrosphere.net.synchronization.enums.BehaviorTreeIdEnums; +import electrosphere.server.datacell.utils.ServerBehaviorTreeUtils; +import electrosphere.entity.btree.BehaviorTree; +import electrosphere.net.synchronization.annotation.SyncedField; +import electrosphere.net.synchronization.annotation.SynchronizedBehaviorTree; + +/** + * Creates a server LOD component + */ +@SynchronizedBehaviorTree(name = "serverLODTree", isServer = true, correspondingTree="clientLODTree") +public class ServerLODComponent implements BehaviorTree { + + /** + * Radius after which we reduce LOD + */ + public static final int LOD_RADIUS = 32; + + /** + * Full resolution LOD + */ + public static final int FULL_RES = 1; + + /** + * Low resolution + */ + public static final int LOW_RES = 0; + + /** + * The current LOD level + */ + @SyncedField + private int lodLevel; + + /** + * The parent entity + */ + private Entity parent; + + @Override + public void simulate(float deltaTime) { + Vector3d parentLoc = EntityUtils.getPosition(this.parent); + boolean fullRes = false; + for(Entity emitter : Globals.serverState.lodEmitterService.getEmitters()){ + Vector3d emitterLoc = EntityUtils.getPosition(emitter); + double dist = parentLoc.distance(emitterLoc); + if(dist < LOD_RADIUS){ + fullRes = true; + break; + } + } + if(fullRes){ + if(lodLevel != FULL_RES){ + //make full res + this.setLodLevel(FULL_RES); + } + } else { + if(lodLevel != LOW_RES){ + //make low res + this.setLodLevel(LOW_RES); + Realm realm = Globals.serverState.realmManager.getEntityRealm(this.parent); + if(PhysicsEntityUtils.containsDBody(this.parent)){ + PhysicsUtils.destroyPhysicsPair( + realm.getCollisionEngine(), + PhysicsEntityUtils.getDBody(this.parent), + PhysicsEntityUtils.getCollidable(this.parent) + ); + } + } + } + } + + + /** + *

(initially) Automatically generated

+ *

+ * Attaches this tree to the entity. + *

+ * @param entity The entity to attach to + * @param tree The behavior tree to attach + * @param params Optional parameters that will be provided to the constructor + */ + public static ServerLODComponent attachTree(Entity parent, Object ... params){ + ServerLODComponent rVal = new ServerLODComponent(parent,params); + //!!WARNING!! from here below should not be touched + //This was generated automatically to properly alert various systems that the btree exists and should be tracked + ServerBehaviorTreeUtils.attachBTreeToEntity(parent, rVal); + parent.putData(EntityDataStrings.TREE_SERVERLODTREE, rVal); + Globals.serverState.entityValueTrackingService.attachTreeToEntity(parent, BehaviorTreeIdEnums.BTREE_SERVERLODTREE_ID); + return rVal; + } + + /** + *

Automatically generated

+ *

+ * Detatches this tree from the entity. + *

+ * @param entity The entity to detach to + * @param tree The behavior tree to detach + */ + public static void detachTree(Entity entity, BehaviorTree tree){ + Globals.serverState.entityValueTrackingService.detatchTreeFromEntity(entity, BehaviorTreeIdEnums.BTREE_SERVERLODTREE_ID); + } + + /** + *

(initially) Automatically generated

+ *

Private constructor to enforce using the attach methods

+ *

+ * Constructor + *

+ * @param parent The parent entity of this tree + * @param params Optional parameters that can be provided when attaching the tree. All custom data required for creating this tree should be passed in this varargs. + */ + private ServerLODComponent(Entity parent, Object ... params){ + this.parent = parent; + this.lodLevel = ServerLODComponent.FULL_RES; + } + + /** + *

+ * Gets the ServerLODComponent of the entity + *

+ * @param entity the entity + * @return The ServerLODComponent + */ + public static ServerLODComponent getServerLODComponent(Entity entity){ + return (ServerLODComponent)entity.getData(EntityDataStrings.TREE_SERVERLODTREE); + } + + /** + *

+ * Checks if the entity has a ServerLODComponent component + *

+ * @param entity the entity + * @return true if the entity contains the component, false otherwise + */ + public static boolean hasServerLODComponent(Entity entity){ + return entity.containsKey(EntityDataStrings.TREE_SERVERLODTREE); + } + + /** + *

Automatically generated

+ *

+ * Sets lodLevel and handles the synchronization logic for it. + *

+ * @param lodLevel The value to set lodLevel to. + */ + public void setLodLevel(int lodLevel){ + this.lodLevel = lodLevel; + if(DataCellSearchUtils.getEntityDataCell(parent) != null){ + DataCellSearchUtils.getEntityDataCell(parent).broadcastNetworkMessage(SynchronizationMessage.constructUpdateClientIntStateMessage(parent.getId(), BehaviorTreeIdEnums.BTREE_SERVERLODTREE_ID, FieldIdEnums.TREE_SERVERLODTREE_SYNCEDFIELD_LODLEVEL_ID, lodLevel)); + } + } + + /** + *

Automatically generated

+ *

+ * Gets lodLevel. + *

+ */ + public int getLodLevel(){ + return lodLevel; + } + +} diff --git a/src/main/java/electrosphere/entity/types/common/CommonEntityUtils.java b/src/main/java/electrosphere/entity/types/common/CommonEntityUtils.java index 004694e1..31a5df5b 100644 --- a/src/main/java/electrosphere/entity/types/common/CommonEntityUtils.java +++ b/src/main/java/electrosphere/entity/types/common/CommonEntityUtils.java @@ -65,6 +65,8 @@ import electrosphere.entity.state.inventory.UnrelationalInventoryState; import electrosphere.entity.state.life.ClientLifeTree; import electrosphere.entity.state.life.ServerLifeTree; import electrosphere.entity.state.light.ClientPointLightComponent; +import electrosphere.entity.state.lod.ClientLODComponent; +import electrosphere.entity.state.lod.ServerLODComponent; import electrosphere.entity.state.movement.editor.ClientEditorMovementTree; import electrosphere.entity.state.movement.editor.ServerEditorMovementTree; import electrosphere.entity.state.movement.fall.ClientFallTree; @@ -217,6 +219,7 @@ public class CommonEntityUtils { if(rawType.getCollidable() != null){ CollidableTemplate physicsTemplate = rawType.getCollidable(); PhysicsEntityUtils.clientAttachCollidableTemplate(entity, physicsTemplate); + ClientLODComponent.attachTree(entity); } // @@ -539,6 +542,7 @@ public class CommonEntityUtils { if(rawType.getCollidable() != null){ CollidableTemplate physicsTemplate = rawType.getCollidable(); PhysicsEntityUtils.serverAttachCollidableTemplate(realm, entity, physicsTemplate); + ServerLODComponent.attachTree(entity); } // // diff --git a/src/main/java/electrosphere/net/synchronization/client/ClientSynchronizationManager.java b/src/main/java/electrosphere/net/synchronization/client/ClientSynchronizationManager.java index b3494984..10bb849f 100644 --- a/src/main/java/electrosphere/net/synchronization/client/ClientSynchronizationManager.java +++ b/src/main/java/electrosphere/net/synchronization/client/ClientSynchronizationManager.java @@ -1,6 +1,7 @@ package electrosphere.net.synchronization.client; +import electrosphere.entity.state.lod.ClientLODComponent; import electrosphere.entity.state.growth.ClientGrowthComponent; import electrosphere.entity.state.furniture.ClientDoorState; import electrosphere.entity.state.item.ClientChargeState; @@ -348,6 +349,16 @@ public class ClientSynchronizationManager { } break; } } break; + case BehaviorTreeIdEnums.BTREE_SERVERLODTREE_ID: { + switch(message.getfieldId()){ + case FieldIdEnums.TREE_SERVERLODTREE_SYNCEDFIELD_LODLEVEL_ID:{ + ClientLODComponent tree = ClientLODComponent.getClientLODComponent(entity); + if(tree != null){ + tree.setLodLevel(message.getintValue()); + } + } break; + } + } break; case BehaviorTreeIdEnums.BTREE_SERVERSTANCECOMPONENT_ID: { switch(message.getfieldId()){ case FieldIdEnums.TREE_SERVERSTANCECOMPONENT_SYNCEDFIELD_STATE_ID:{ diff --git a/src/main/java/electrosphere/net/synchronization/enums/BehaviorTreeIdEnums.java b/src/main/java/electrosphere/net/synchronization/enums/BehaviorTreeIdEnums.java index cdf58b5c..b1d46f02 100644 --- a/src/main/java/electrosphere/net/synchronization/enums/BehaviorTreeIdEnums.java +++ b/src/main/java/electrosphere/net/synchronization/enums/BehaviorTreeIdEnums.java @@ -25,6 +25,8 @@ public class BehaviorTreeIdEnums { public static final int BTREE_SERVERCHARGESTATE_ID = 27; public static final int BTREE_CLIENTLIFETREE_ID = 6; public static final int BTREE_SERVERLIFETREE_ID = 13; + public static final int BTREE_CLIENTLODTREE_ID = 32; + public static final int BTREE_SERVERLODTREE_ID = 33; public static final int BTREE_CLIENTSTANCECOMPONENT_ID = 20; public static final int BTREE_SERVERSTANCECOMPONENT_ID = 21; public static final int BTREE_CLIENTEDITORMOVEMENTTREE_ID = 24; diff --git a/src/main/java/electrosphere/net/synchronization/enums/FieldIdEnums.java b/src/main/java/electrosphere/net/synchronization/enums/FieldIdEnums.java index 86338533..5089f727 100644 --- a/src/main/java/electrosphere/net/synchronization/enums/FieldIdEnums.java +++ b/src/main/java/electrosphere/net/synchronization/enums/FieldIdEnums.java @@ -29,6 +29,8 @@ public class FieldIdEnums { public static final int TREE_SERVERCHARGESTATE_SYNCEDFIELD_CHARGES_ID = 35; public static final int TREE_CLIENTLIFETREE_SYNCEDFIELD_STATE_ID = 10; public static final int TREE_SERVERLIFETREE_SYNCEDFIELD_STATE_ID = 17; + public static final int TREE_CLIENTLODTREE_SYNCEDFIELD_LODLEVEL_ID = 40; + public static final int TREE_SERVERLODTREE_SYNCEDFIELD_LODLEVEL_ID = 41; public static final int TREE_CLIENTSTANCECOMPONENT_SYNCEDFIELD_STATE_ID = 28; public static final int TREE_SERVERSTANCECOMPONENT_SYNCEDFIELD_STATE_ID = 29; public static final int TREE_CLIENTEDITORMOVEMENTTREE_SYNCEDFIELD_FACING_ID = 32; diff --git a/src/main/java/electrosphere/net/synchronization/transport/StateCollection.java b/src/main/java/electrosphere/net/synchronization/transport/StateCollection.java index aa553506..4e2b5748 100644 --- a/src/main/java/electrosphere/net/synchronization/transport/StateCollection.java +++ b/src/main/java/electrosphere/net/synchronization/transport/StateCollection.java @@ -1,6 +1,8 @@ package electrosphere.net.synchronization.transport; +import electrosphere.entity.state.lod.ServerLODComponent; +import electrosphere.entity.state.lod.ClientLODComponent; import electrosphere.entity.state.growth.ServerGrowthComponent; import electrosphere.entity.state.growth.ClientGrowthComponent; import electrosphere.entity.state.furniture.ServerDoorState; @@ -126,6 +128,10 @@ public class StateCollection { 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_SERVERLODTREE_ID: { + ServerLODComponent tree = ServerLODComponent.getServerLODComponent(entity); + collection.setValue(new SynchronizedFieldValue(BehaviorTreeIdEnums.BTREE_SERVERLODTREE_ID,FieldIdEnums.TREE_SERVERLODTREE_SYNCEDFIELD_LODLEVEL_ID,tree.getLodLevel())); + } break; case BehaviorTreeIdEnums.BTREE_SERVERSTANCECOMPONENT_ID: { ServerStanceComponent tree = ServerStanceComponent.getServerStanceComponent(entity); collection.setValue(new SynchronizedFieldValue(BehaviorTreeIdEnums.BTREE_SERVERSTANCECOMPONENT_ID,FieldIdEnums.TREE_SERVERSTANCECOMPONENT_SYNCEDFIELD_STATE_ID,ClientStanceComponent.getCombatStanceEnumAsShort(tree.getState()))); @@ -250,6 +256,14 @@ public class StateCollection { } break; } } break; + case BehaviorTreeIdEnums.BTREE_SERVERLODTREE_ID: { + ClientLODComponent tree = ClientLODComponent.getClientLODComponent(entity); + switch(syncedValue.getFieldId()){ + case(FieldIdEnums.TREE_SERVERLODTREE_SYNCEDFIELD_LODLEVEL_ID): { + tree.setLodLevel(((Double)syncedValue.getValue()).intValue()); + } break; + } + } break; case BehaviorTreeIdEnums.BTREE_SERVERSTANCECOMPONENT_ID: { ClientStanceComponent tree = ClientStanceComponent.getClientStanceComponent(entity); switch(syncedValue.getFieldId()){ @@ -401,6 +415,14 @@ public class StateCollection { } break; } } break; + case BehaviorTreeIdEnums.BTREE_SERVERLODTREE_ID: { + ServerLODComponent tree = ServerLODComponent.getServerLODComponent(entity); + switch(syncedValue.getFieldId()){ + case(FieldIdEnums.TREE_SERVERLODTREE_SYNCEDFIELD_LODLEVEL_ID): { + tree.setLodLevel(((Double)syncedValue.getValue()).intValue()); + } break; + } + } break; case BehaviorTreeIdEnums.BTREE_SERVERSTANCECOMPONENT_ID: { ServerStanceComponent tree = ServerStanceComponent.getServerStanceComponent(entity); switch(syncedValue.getFieldId()){