macro pathfinding work
Some checks failed
studiorailgun/Renderer/pipeline/head There was a failure building this commit

This commit is contained in:
austin 2025-05-30 21:27:53 -04:00
parent 0d01a4c214
commit 57de3d5d81
7 changed files with 153 additions and 17 deletions

View File

@ -2085,6 +2085,7 @@ Synchronized time-of-day between server and client
Skybox reflects time of day Skybox reflects time of day
Standardize data sourcing in MacroTemporalData Standardize data sourcing in MacroTemporalData
Macro pathfinding scaffolding Macro pathfinding scaffolding
Macro pathfinding work

View File

@ -25,6 +25,11 @@ public class ThreadCounts {
*/ */
public static final int PATHFINDING_THREADS = 1; public static final int PATHFINDING_THREADS = 1;
/**
* Number of threads for solving macro pathfinding
*/
public static final int MACRO_PATHING_THREADS = 1;
/** /**
* Number of threads for gridded datacell manager chunk loading/unloading * Number of threads for gridded datacell manager chunk loading/unloading
*/ */

View File

@ -12,6 +12,7 @@ import electrosphere.server.db.DatabaseController;
import electrosphere.server.saves.Save; import electrosphere.server.saves.Save;
import electrosphere.server.service.CharacterService; import electrosphere.server.service.CharacterService;
import electrosphere.server.service.LODEmitterService; import electrosphere.server.service.LODEmitterService;
import electrosphere.server.service.MacroPathingService;
import electrosphere.server.service.StructureScanningService; import electrosphere.server.service.StructureScanningService;
import electrosphere.server.simulation.MicroSimulation; import electrosphere.server.simulation.MicroSimulation;
@ -65,6 +66,11 @@ public class ServerState {
*/ */
public final LODEmitterService lodEmitterService; public final LODEmitterService lodEmitterService;
/**
* The macro pathing service
*/
public final MacroPathingService macroPathingService;
/** /**
* behavior tree tracking service * behavior tree tracking service
*/ */
@ -92,6 +98,7 @@ public class ServerState {
this.characterService = (CharacterService)Globals.engineState.serviceManager.registerService(new CharacterService()); this.characterService = (CharacterService)Globals.engineState.serviceManager.registerService(new CharacterService());
this.structureScanningService = (StructureScanningService)Globals.engineState.serviceManager.registerService(new StructureScanningService()); this.structureScanningService = (StructureScanningService)Globals.engineState.serviceManager.registerService(new StructureScanningService());
this.lodEmitterService = (LODEmitterService)Globals.engineState.serviceManager.registerService(new LODEmitterService()); this.lodEmitterService = (LODEmitterService)Globals.engineState.serviceManager.registerService(new LODEmitterService());
this.macroPathingService = (MacroPathingService)Globals.engineState.serviceManager.registerService(new MacroPathingService());
} }
} }

View File

@ -9,7 +9,8 @@ import electrosphere.server.ai.AI;
import electrosphere.server.ai.blackboard.Blackboard; import electrosphere.server.ai.blackboard.Blackboard;
import electrosphere.server.ai.nodes.AITreeNode; import electrosphere.server.ai.nodes.AITreeNode;
import electrosphere.server.datacell.Realm; import electrosphere.server.datacell.Realm;
import electrosphere.server.datacell.interfaces.PathfindingManager; import electrosphere.server.macro.MacroData;
import electrosphere.server.macro.spatial.MacroAreaObject;
import electrosphere.server.macro.spatial.path.MacroPathNode; import electrosphere.server.macro.spatial.path.MacroPathNode;
import electrosphere.server.macro.structure.VirtualStructure; import electrosphere.server.macro.structure.VirtualStructure;
import electrosphere.server.pathfinding.recast.PathingProgressiveData; import electrosphere.server.pathfinding.recast.PathingProgressiveData;
@ -70,30 +71,32 @@ public class MacroPathfindingNode implements AITreeNode {
//create a path if we don't already have one //create a path if we don't already have one
if(!PathfindingNode.hasPathfindingData(blackboard)){ if(!PathfindingNode.hasPathfindingData(blackboard)){
//
//figure out what we're targeting
Object targetRaw = blackboard.get(this.targetEntityKey); Object targetRaw = blackboard.get(this.targetEntityKey);
Vector3d targetPos = null;
if(targetRaw == null){ if(targetRaw == null){
throw new Error("Target undefined!"); throw new Error("Target undefined!");
} }
if(targetRaw instanceof Vector3d){ if(targetRaw instanceof MacroAreaObject){
targetPos = (Vector3d)targetRaw;
} else if(targetRaw instanceof Entity){
targetPos = EntityUtils.getPosition((Entity)targetRaw);
} else if(targetRaw instanceof VirtualStructure){
targetPos = ((VirtualStructure)targetRaw).getPos();
} else { } else {
throw new Error("Unsupported target type " + targetRaw); throw new Error("Unsupported target type " + targetRaw);
} }
Realm realm = Globals.serverState.realmManager.getEntityRealm(entity); Realm realm = Globals.serverState.realmManager.getEntityRealm(entity);
PathfindingManager pathfindingManager = realm.getPathfindingManager(); MacroPathNode targetMacro = realm.getMacroData().getPathCache().getPathingNode(((MacroAreaObject)targetRaw).getPos());
Vector3d entityPos = EntityUtils.getPosition(entity);
PathingProgressiveData pathingProgressiveData = pathfindingManager.findPathAsync(entityPos, targetPos); //
//Find where the entity is currently
MacroPathNode currentPos = this.solveCurrentNode(entity);
//
//Queue the pathfinding operation
PathingProgressiveData pathingProgressiveData = Globals.serverState.macroPathingService.queuePathfinding(realm, currentPos, targetMacro);
PathfindingNode.setPathfindingData(blackboard, pathingProgressiveData); PathfindingNode.setPathfindingData(blackboard, pathingProgressiveData);
} }
//make sure we found a path
if(!PathfindingNode.hasPathfindingData(blackboard)){ if(!PathfindingNode.hasPathfindingData(blackboard)){
throw new Error("Failed to find path! Unhandled"); throw new Error("Failed to find path! Unhandled");
} }
@ -106,8 +109,9 @@ public class MacroPathfindingNode implements AITreeNode {
} }
//
//walk along the path if it exists
Vector3d entityPos = EntityUtils.getPosition(entity); Vector3d entityPos = EntityUtils.getPosition(entity);
Vector3d currentPathPos = null; Vector3d currentPathPos = null;
if(pathingProgressiveData.getCurrentPoint() < pathingProgressiveData.getPoints().size()){ if(pathingProgressiveData.getCurrentPoint() < pathingProgressiveData.getPoints().size()){
currentPathPos = pathingProgressiveData.getPoints().get(pathingProgressiveData.getCurrentPoint()); currentPathPos = pathingProgressiveData.getPoints().get(pathingProgressiveData.getCurrentPoint());
@ -152,4 +156,22 @@ public class MacroPathfindingNode implements AITreeNode {
return AITreeNodeResult.SUCCESS; return AITreeNodeResult.SUCCESS;
} }
/**
* Gets the pathing node of this entity
* @param entity The entity
* @return The pathing node
*/
private MacroPathNode solveCurrentNode(Entity entity){
Realm realm = Globals.serverState.realmManager.getEntityRealm(entity);
if(realm == null){
throw new Error("Entity is not attached to a realm!");
}
MacroData macroData = realm.getMacroData();
if(macroData == null){
throw new Error("Macro data undefined!");
}
Vector3d entityPos = EntityUtils.getPosition(entity);
return macroData.getPathCache().getPathingNode(entityPos);
}
} }

View File

@ -5,6 +5,8 @@ import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.joml.Vector3d;
import electrosphere.util.annotation.Exclude; import electrosphere.util.annotation.Exclude;
/** /**
@ -60,4 +62,22 @@ public class MacroPathCache {
idNodeMap.put(node.getId(),node); idNodeMap.put(node.getId(),node);
} }
/**
* Gets the pathing node at a given point
* @param point The point
* @return The corresponding pathing node
*/
public MacroPathNode getPathingNode(Vector3d point){
double minDist = 100;
MacroPathNode rVal = null;
for(MacroPathNode node : this.nodes){
double dist = point.distance(node.getPosition());
if(dist < minDist){
minDist = dist;
rVal = node;
}
}
return rVal;
}
} }

View File

@ -12,22 +12,22 @@ public class PathingProgressiveData {
/** /**
* The list of points that represent the path * The list of points that represent the path
*/ */
List<Vector3d> points; private List<Vector3d> points;
/** /**
* The current point to move towards (ie all previous points have already been pathed to) * The current point to move towards (ie all previous points have already been pathed to)
*/ */
int currentPoint; private int currentPoint;
/** /**
* The goal position * The goal position
*/ */
Vector3d goal; private Vector3d goal;
/** /**
* Tracks whether this data is ready to be used or not * Tracks whether this data is ready to be used or not
*/ */
boolean ready = false; private boolean ready = false;
/** /**

View File

@ -0,0 +1,81 @@
package electrosphere.server.service;
import java.util.List;
import java.util.concurrent.ExecutorService;
import org.joml.Vector3d;
import electrosphere.engine.signal.Signal.SignalType;
import electrosphere.engine.Globals;
import electrosphere.engine.signal.SignalServiceImpl;
import electrosphere.engine.threads.ThreadCounts;
import electrosphere.server.datacell.Realm;
import electrosphere.server.macro.MacroData;
import electrosphere.server.macro.spatial.path.MacroPathNode;
import electrosphere.server.pathfinding.recast.PathingProgressiveData;
/**
* Service for solving pathing between macro area objects
*/
public class MacroPathingService extends SignalServiceImpl {
/**
* The executor service
*/
final ExecutorService executorService;
/**
* Constructor
*/
public MacroPathingService() {
super("MacroPathingService", new SignalType[]{
});
this.executorService = Globals.engineState.threadManager.requestFixedThreadPool(ThreadCounts.MACRO_PATHING_THREADS);
}
/**
* Simulates the macro pathing service
*/
public void simulate(){
}
/**
* Queues a pathfinding job
* @param realm The realm
* @param start The start point
* @param end The end point
* @return The object that will eventually hold the pathfinding data
*/
public PathingProgressiveData queuePathfinding(Realm realm, MacroPathNode start, MacroPathNode end){
PathingProgressiveData rVal = new PathingProgressiveData(end.getPosition());
executorService.submit(() -> {
try {
List<Vector3d> points = this.findPath(realm.getMacroData(), start, end);
rVal.setPoints(points);
rVal.setReady(true);
} catch(Throwable e){
e.printStackTrace();
}
});
return rVal;
}
/**
* Halts all threads in the pathfinding service
*/
public void haltThreads(){
executorService.shutdownNow();
}
/**
* Finds a path between macro area objects
* @param macroData The macro data
* @param start The start area
* @param end The end area
* @return The path
*/
private List<Vector3d> findPath(MacroData macroData, MacroPathNode start, MacroPathNode end){
throw new Error("Not implemented yet!");
}
}