diff --git a/docs/src/progress/renderertodo.md b/docs/src/progress/renderertodo.md index a393cc70..d121a706 100644 --- a/docs/src/progress/renderertodo.md +++ b/docs/src/progress/renderertodo.md @@ -1665,6 +1665,12 @@ Debugging pathfinding code New AI behaviors - Will explore for resources if local ones aren't available Async pathfinding +Fix interaction engine not properly destroying interaction data +ClientSynchronizationManager does not store deleted entity IDs forever +ClientSynchronizationManager un-deleted entity IDs when client receives creation message for an entity that was deleted +MoveTo tree doesn't overwrite published status +Fix AIManager.shutdown call not null checking +Small explore node height offset diff --git a/src/main/java/electrosphere/client/interact/ClientInteractionEngine.java b/src/main/java/electrosphere/client/interact/ClientInteractionEngine.java index c07d6658..b405b6c8 100644 --- a/src/main/java/electrosphere/client/interact/ClientInteractionEngine.java +++ b/src/main/java/electrosphere/client/interact/ClientInteractionEngine.java @@ -175,7 +175,21 @@ public class ClientInteractionEngine { public static void destroyCollidableTemplate(Entity rVal){ lock.lock(); CollisionEngine interactionEngine = Globals.clientSceneWrapper.getInteractionEngine(); - interactionEngine.destroyPhysics(rVal); + DBody body = null; + Collidable collidable = null; + if(rVal.containsKey(EntityDataStrings.INTERACTION_BODY)){ + body = (DBody)rVal.getData(EntityDataStrings.INTERACTION_BODY); + } + if(rVal.containsKey(EntityDataStrings.INTERACTION_COLLIDABLE)){ + collidable = (Collidable)rVal.getData(EntityDataStrings.INTERACTION_COLLIDABLE); + } + if(body != null){ + PhysicsUtils.destroyBody(interactionEngine, body); + if(collidable != null){ + interactionEngine.deregisterCollisionObject(body, collidable); + } + } + interactables.remove(rVal); lock.unlock(); } @@ -295,4 +309,27 @@ public class ClientInteractionEngine { } } + /** + * Gets the number of interactibles on the client + * @return The number of interactibles + */ + public static int getInteractiblesCount(){ + lock.lock(); + int rVal = interactables.size(); + lock.unlock(); + return rVal; + } + + /** + * Gets the number of interactibles on the client + * @return The number of interactibles + */ + public static int getCollidablesCount(){ + lock.lock(); + CollisionEngine interactionEngine = Globals.clientSceneWrapper.getInteractionEngine(); + int rVal = interactionEngine.getCollidables().size(); + lock.unlock(); + return rVal; + } + } diff --git a/src/main/java/electrosphere/client/scene/ClientSceneWrapper.java b/src/main/java/electrosphere/client/scene/ClientSceneWrapper.java index c659e15c..93193e5b 100644 --- a/src/main/java/electrosphere/client/scene/ClientSceneWrapper.java +++ b/src/main/java/electrosphere/client/scene/ClientSceneWrapper.java @@ -24,17 +24,29 @@ import electrosphere.logger.LoggerInterface; */ public class ClientSceneWrapper { - //entity id translation between server/client + /** + * Translates client entity IDs to server IDs + */ Map clientToServerIdMap = new HashMap(); + + /** + * Translates server entity IDs to client IDs + */ Map serverToClientIdMap = new HashMap(); - //The list of server IDs that have been deleted + /** + * The list of server IDs that have been deleted + */ Map deletedServerIds = new HashMap(); - //The scene backing the wrapper + /** + * The scene backing the wrapper + */ Scene scene; - //The engine used to back physics collision checks in client + /** + * The engine used to back physics collision checks in client + */ CollisionEngine collisionEngine; /** @@ -47,7 +59,9 @@ public class ClientSceneWrapper { */ CollisionEngine interactionEngine; - //The hitbox manager + /** + * The hitbox manager + */ HitboxManager hitboxManager; /** @@ -80,6 +94,7 @@ public class ClientSceneWrapper { lock.lock(); clientToServerIdMap.put(clientId, serverId); serverToClientIdMap.put(serverId, clientId); + Globals.clientSynchronizationManager.ejectDeletedKey(serverId); lock.unlock(); } diff --git a/src/main/java/electrosphere/client/ui/menu/debug/ImGuiClientServices.java b/src/main/java/electrosphere/client/ui/menu/debug/ImGuiClientServices.java index aa1d79b7..039efeb0 100644 --- a/src/main/java/electrosphere/client/ui/menu/debug/ImGuiClientServices.java +++ b/src/main/java/electrosphere/client/ui/menu/debug/ImGuiClientServices.java @@ -3,6 +3,7 @@ package electrosphere.client.ui.menu.debug; import org.joml.Vector3i; import electrosphere.client.entity.camera.CameraEntityUtils; +import electrosphere.client.interact.ClientInteractionEngine; import electrosphere.client.terrain.cache.ChunkData; import electrosphere.client.terrain.cells.DrawCell; import electrosphere.client.terrain.foliage.FoliageCell; @@ -83,7 +84,8 @@ public class ImGuiClientServices { if(ImGui.collapsingHeader("Interaction Engine")){ - + ImGui.text("Interactible count: " + ClientInteractionEngine.getInteractiblesCount()); + ImGui.text("Collidables count: " + ClientInteractionEngine.getCollidablesCount()); } } }); diff --git a/src/main/java/electrosphere/client/ui/menu/debug/ImGuiWindowMacros.java b/src/main/java/electrosphere/client/ui/menu/debug/ImGuiWindowMacros.java index 528f4635..ecb76a6d 100644 --- a/src/main/java/electrosphere/client/ui/menu/debug/ImGuiWindowMacros.java +++ b/src/main/java/electrosphere/client/ui/menu/debug/ImGuiWindowMacros.java @@ -181,7 +181,7 @@ public class ImGuiWindowMacros { if(ImGui.button("Network Monitor")){ ImGuiNetworkMonitor.netMonitorWindow.setOpen(true); } - if(ImGui.button("Client Draw Cell Utils")){ + if(ImGui.button("Client Services")){ ImGuiClientServices.clientServicesWindow.setOpen(true); } //close button diff --git a/src/main/java/electrosphere/collision/CollisionEngine.java b/src/main/java/electrosphere/collision/CollisionEngine.java index 1170b296..ad21f3a6 100644 --- a/src/main/java/electrosphere/collision/CollisionEngine.java +++ b/src/main/java/electrosphere/collision/CollisionEngine.java @@ -613,6 +613,7 @@ public class CollisionEngine { public void deregisterCollisionObject(DBody body, Collidable collidable){ spaceLock.lock(); bodyPointerMap.remove(body); + bodies.remove(body); collidableList.remove(collidable); spaceLock.unlock(); } diff --git a/src/main/java/electrosphere/engine/Globals.java b/src/main/java/electrosphere/engine/Globals.java index ff3a9485..b5eb96fc 100644 --- a/src/main/java/electrosphere/engine/Globals.java +++ b/src/main/java/electrosphere/engine/Globals.java @@ -728,7 +728,9 @@ public class Globals { Globals.clientSynchronizationManager = new ClientSynchronizationManager(); Globals.server = null; Globals.serverSynchronizationManager = new ServerSynchronizationManager(); - Globals.aiManager.shutdown(); + if(Globals.aiManager != null){ + Globals.aiManager.shutdown(); + } if(Globals.realmManager != null){ Globals.realmManager.reset(); } @@ -740,7 +742,9 @@ public class Globals { */ public static void resetGlobals(){ Globals.unloadScene(); - Globals.aiManager.shutdown(); + if(Globals.aiManager != null){ + Globals.aiManager.shutdown(); + } // //Actual globals to destroy Globals.assetManager = null; diff --git a/src/main/java/electrosphere/net/synchronization/client/ClientSynchronizationManager.java b/src/main/java/electrosphere/net/synchronization/client/ClientSynchronizationManager.java index 36a3a892..70f6bfcf 100644 --- a/src/main/java/electrosphere/net/synchronization/client/ClientSynchronizationManager.java +++ b/src/main/java/electrosphere/net/synchronization/client/ClientSynchronizationManager.java @@ -23,6 +23,7 @@ import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.concurrent.CopyOnWriteArrayList; import electrosphere.engine.Globals; @@ -42,6 +43,11 @@ public class ClientSynchronizationManager { */ static final int MESSAGE_BOUNCE_WARNING_COUNT = 100; + /** + * Number of frames to keep an entity deletion key around + */ + static final int DELETED_KEY_STORAGE_FRAMES = 10; + /** * The list of messages to loop through */ @@ -55,7 +61,7 @@ public class ClientSynchronizationManager { /** * The list of Ids that the server has said to destroy */ - List deletedEntityIds = new LinkedList(); + Map deletedEntityIds = new HashMap(); /** * Pushes a message into the queue to be processed @@ -80,7 +86,7 @@ public class ClientSynchronizationManager { } //remove sync messages if the entity was already deleted by the server - if(this.deletedEntityIds.contains(message.getentityId())){ + if(this.deletedEntityIds.containsKey(message.getentityId())){ messageBounceCount.remove(message); } @@ -182,6 +188,13 @@ public class ClientSynchronizationManager { messages.remove(message); Globals.clientConnection.release(message); } + Set deletionKeys = this.deletedEntityIds.keySet(); + for(int key : deletionKeys){ + int framesStored = this.deletedEntityIds.get(key); + if(framesStored > DELETED_KEY_STORAGE_FRAMES){ + this.deletedEntityIds.remove(key); + } + } } /** @@ -189,7 +202,7 @@ public class ClientSynchronizationManager { * @param id The id that was destroyed */ public void addDeletedId(int id){ - this.deletedEntityIds.add(id); + this.deletedEntityIds.put(id,1); } /** @@ -198,7 +211,17 @@ public class ClientSynchronizationManager { * @return true if it has been deleted, false otherwise */ public boolean isDeleted(int entityId){ - return this.deletedEntityIds.contains(entityId); + return this.deletedEntityIds.containsKey(entityId); + } + + /** + * Ejects a deleted key (ie if server tells us to create a deleted entity again) + * @param entityId The entity id to un-delete + */ + public void ejectDeletedKey(int entityId){ + if(this.deletedEntityIds.containsKey(entityId)){ + this.deletedEntityIds.remove(entityId); + } } /** diff --git a/src/main/java/electrosphere/server/ai/nodes/plan/PathfindingNode.java b/src/main/java/electrosphere/server/ai/nodes/plan/PathfindingNode.java index a91fc970..a0da99c0 100644 --- a/src/main/java/electrosphere/server/ai/nodes/plan/PathfindingNode.java +++ b/src/main/java/electrosphere/server/ai/nodes/plan/PathfindingNode.java @@ -5,6 +5,7 @@ import org.joml.Vector3d; import electrosphere.engine.Globals; import electrosphere.entity.Entity; import electrosphere.entity.EntityUtils; +import electrosphere.server.ai.AI; import electrosphere.server.ai.blackboard.Blackboard; import electrosphere.server.ai.blackboard.BlackboardKeys; import electrosphere.server.ai.nodes.AITreeNode; @@ -104,6 +105,7 @@ public class PathfindingNode implements AITreeNode { //check if the path has been found PathingProgressiveData pathingProgressiveData = PathfindingNode.getPathfindingData(blackboard); if(!pathingProgressiveData.isReady()){ + AI.getAI(entity).setStatus("Thinking about pathing"); return AITreeNodeResult.RUNNING; } diff --git a/src/main/java/electrosphere/server/ai/nodes/plan/TargetExploreNode.java b/src/main/java/electrosphere/server/ai/nodes/plan/TargetExploreNode.java index 1846ff0c..c37e9ed7 100644 --- a/src/main/java/electrosphere/server/ai/nodes/plan/TargetExploreNode.java +++ b/src/main/java/electrosphere/server/ai/nodes/plan/TargetExploreNode.java @@ -28,6 +28,11 @@ public class TargetExploreNode implements AITreeNode { */ static final double OFFSET_DIST = 50; + /** + * Offset applied to calculated height to align with voxel rasterization better + */ + static final double HEIGHT_OFFSET = 0.1f; + /** * constructor * @param targetKey The key to store the point under @@ -50,7 +55,7 @@ public class TargetExploreNode implements AITreeNode { Vector3i voxelPos = ServerWorldData.convertRealToVoxelSpace(targetPos); Vector3i chunkPos = ServerWorldData.convertRealToChunkSpace(targetPos); double height = realm.getServerWorldData().getServerTerrainManager().getElevation(chunkPos.x, chunkPos.z, voxelPos.x, voxelPos.z); - targetPos.y = height; + targetPos.y = height + HEIGHT_OFFSET; //store blackboard.put(targetKey, targetPos); diff --git a/src/main/java/electrosphere/server/ai/trees/creature/MoveToTree.java b/src/main/java/electrosphere/server/ai/trees/creature/MoveToTree.java index 7f8cd401..a13ee035 100644 --- a/src/main/java/electrosphere/server/ai/trees/creature/MoveToTree.java +++ b/src/main/java/electrosphere/server/ai/trees/creature/MoveToTree.java @@ -79,9 +79,7 @@ public class MoveToTree { //not in range of target, keep moving towards it new SequenceNode( - new PublishStatusNode("Thinking about pathing"), PathfindingNode.createPathEntity(targetKey), - new PublishStatusNode("Moving"), new FaceTargetNode(BlackboardKeys.PATHFINDING_POINT), new RunnerNode(new MoveStartNode(MovementRelativeFacing.FORWARD)) )