performance + ai work
All checks were successful
studiorailgun/Renderer/pipeline/head This commit looks good

This commit is contained in:
austin 2025-05-04 17:26:14 -04:00
parent 5d1aebeaf2
commit c9ac7496a5
11 changed files with 110 additions and 17 deletions

View File

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

View File

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

View File

@ -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<Integer,Integer> clientToServerIdMap = new HashMap<Integer,Integer>();
/**
* Translates server entity IDs to client IDs
*/
Map<Integer,Integer> serverToClientIdMap = new HashMap<Integer,Integer>();
//The list of server IDs that have been deleted
/**
* The list of server IDs that have been deleted
*/
Map<Integer,Boolean> deletedServerIds = new HashMap<Integer,Boolean>();
//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();
}

View File

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

View File

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

View File

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

View File

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

View File

@ -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<Integer> deletedEntityIds = new LinkedList<Integer>();
Map<Integer,Integer> deletedEntityIds = new HashMap<Integer,Integer>();
/**
* 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<Integer> 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);
}
}
/**

View File

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

View File

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

View File

@ -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))
)