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

This commit is contained in:
austin 2025-06-05 12:14:13 -04:00
parent 8bc8fb464b
commit 25d2dcd943
13 changed files with 181 additions and 15 deletions

View File

@ -2120,6 +2120,8 @@ Fix projection matrix being sent to light manager
(06/05/2025)
voxel tests
Physics work
Debug rendering for facing vectors
Fix progressive pathfinding iteration

View File

@ -71,6 +71,9 @@ public class ImGuiRenderer {
if(ImGui.button("Draw Server Cell Colliders")){
Globals.gameConfigCurrent.getSettings().setGraphicsDebugDrawServerCellColliders(!Globals.gameConfigCurrent.getSettings().getGraphicsDebugDrawServerCellColliders());
}
if(ImGui.button("Draw Server Facing Vectors")){
Globals.gameConfigCurrent.getSettings().setGraphicsDebugDrawServerFacingVectors(!Globals.gameConfigCurrent.getSettings().getGraphicsDebugDrawServerFacingVectors());
}
ImGui.unindent();
}
if(ImGui.collapsingHeader("OpenGL Details")){

View File

@ -57,6 +57,7 @@ public class UserSettings {
boolean graphicsDebugDrawMacroColliders;
boolean graphicsDebugDrawClientCellColliders;
boolean graphicsDebugDrawServerCellColliders;
boolean graphicsDebugDrawServerFacingVectors;
//debug network
boolean netRunNetMonitor;
@ -256,6 +257,16 @@ public class UserSettings {
this.graphicsDebugDrawServerCellColliders = graphicsDebugDrawServerCellColliders;
}
public boolean getGraphicsDebugDrawServerFacingVectors() {
return graphicsDebugDrawServerFacingVectors;
}
public void setGraphicsDebugDrawServerFacingVectors(boolean graphicsDebugDrawServerFacingVectors) {
this.graphicsDebugDrawServerFacingVectors = graphicsDebugDrawServerFacingVectors;
}

View File

@ -35,6 +35,7 @@ import electrosphere.renderer.anim.Animation;
import electrosphere.server.ai.AI;
import electrosphere.server.datacell.utils.DataCellSearchUtils;
import electrosphere.server.utils.ServerScriptUtils;
import electrosphere.util.math.BasicMathUtils;
import electrosphere.util.math.SpatialMathUtils;
import java.util.LinkedList;
@ -52,6 +53,16 @@ Behavior tree for movement in an entity
*/
public class ServerGroundMovementTree implements BehaviorTree {
/**
* Denotes an invalid elevation to lerp non-body collidables towards
*/
public static final double INVALID_ELEVATION = -1;
/**
* Amount to lerp non-body collidable elevation by
*/
public static final double ELEVATION_LERP_FACTOR = 0.01;
/**
* Lock for handling threading with network messages
*/
@ -86,6 +97,11 @@ public class ServerGroundMovementTree implements BehaviorTree {
//the vector organizing the direction the entity will move in
Vector3d movementVector = new Vector3d(1,0,0);
/**
* Target elevation for specifically non-body collidables to lerp to organically
*/
private double collidableElevationTarget = -1;
private ServerGroundMovementTree(Entity e, Object ... params){
@ -106,8 +122,8 @@ public class ServerGroundMovementTree implements BehaviorTree {
* @param facing The facing dir to start with
*/
public void start(MovementRelativeFacing facing){
if(canStartMoving()){
setFacing(facing);
if(this.canStartMoving()){
this.setFacing(facing);
state = MovementTreeState.STARTUP;
//if we aren't the server, alert the server we intend to walk forward
Vector3d position = EntityUtils.getPosition(parent);
@ -241,11 +257,11 @@ public class ServerGroundMovementTree implements BehaviorTree {
//0 is startup
case 0: {
// System.out.println("Receive move packet from client treestate " + message.gettreeState());
start(ClientGroundMovementTree.getMovementRelativeFacingShortAsEnum((short)message.getpropertyValueInt()));
this.start(ClientGroundMovementTree.getMovementRelativeFacingShortAsEnum((short)message.getpropertyValueInt()));
} break;
case 2: {
// System.out.println("Receive move packet from client treestate " + message.gettreeState());
slowdown();
this.slowdown();
} break;
default: {
@ -294,6 +310,9 @@ public class ServerGroundMovementTree implements BehaviorTree {
Vector3d velVec = new Vector3d(movementVector);
velVec.mul(velocity * Globals.engineState.timekeeper.getSimFrameTime() * Timekeeper.ENGINE_STEP_SIZE);
velVec.add(position);
if(this.collidableElevationTarget != ServerGroundMovementTree.INVALID_ELEVATION){
velVec.y = BasicMathUtils.lerp(position.y, this.collidableElevationTarget, ServerGroundMovementTree.ELEVATION_LERP_FACTOR);
}
ServerEntityUtils.repositionEntity(parent, velVec);
} else {
body.enable();
@ -346,6 +365,9 @@ public class ServerGroundMovementTree implements BehaviorTree {
Vector3d velVec = new Vector3d(movementVector);
velVec.mul(velocity * Globals.engineState.timekeeper.getSimFrameTime() * Timekeeper.ENGINE_STEP_SIZE);
velVec.add(position);
if(this.collidableElevationTarget != ServerGroundMovementTree.INVALID_ELEVATION){
velVec.y = BasicMathUtils.lerp(position.y, this.collidableElevationTarget, ServerGroundMovementTree.ELEVATION_LERP_FACTOR);
}
ServerEntityUtils.repositionEntity(parent, velVec);
} else {
body.enable();
@ -417,6 +439,9 @@ public class ServerGroundMovementTree implements BehaviorTree {
Vector3d velVec = new Vector3d(movementVector);
velVec.mul(velocity * Globals.engineState.timekeeper.getSimFrameTime() * Timekeeper.ENGINE_STEP_SIZE);
velVec.add(position);
if(this.collidableElevationTarget != ServerGroundMovementTree.INVALID_ELEVATION){
velVec.y = BasicMathUtils.lerp(position.y, this.collidableElevationTarget, ServerGroundMovementTree.ELEVATION_LERP_FACTOR);
}
ServerEntityUtils.repositionEntity(parent, velVec);
} else {
body.enable();
@ -880,4 +905,12 @@ public class ServerGroundMovementTree implements BehaviorTree {
return entity.containsKey(EntityDataStrings.TREE_SERVERGROUNDMOVEMENTTREE);
}
/**
* Sets the target elevation for non-body collidables to lerp to
* @param collidableElevationTarget The target elevation
*/
public void setCollidableElevationTarget(double collidableElevationTarget){
this.collidableElevationTarget = collidableElevationTarget;
}
}

View File

@ -3,6 +3,7 @@ package electrosphere.entity.state.physicssync.upright;
import org.joml.Quaterniond;
import org.joml.Vector3d;
import org.ode4j.ode.DBody;
import org.ode4j.ode.DGeom;
import electrosphere.collision.PhysicsEntityUtils;
import electrosphere.collision.PhysicsUtils;
@ -12,6 +13,8 @@ import electrosphere.entity.EntityDataStrings;
import electrosphere.entity.EntityUtils;
import electrosphere.entity.btree.BehaviorTree;
import electrosphere.entity.state.physicssync.ClientPhysicsSyncTree;
import electrosphere.entity.types.creature.CreatureUtils;
import electrosphere.util.math.SpatialMathUtils;
public class ClientAlwaysUprightTree implements BehaviorTree {
@ -45,6 +48,23 @@ public class ClientAlwaysUprightTree implements BehaviorTree {
EntityUtils.getRotation(parent).set(sourceRotation);
PhysicsUtils.synchronizeData(Globals.clientState.clientSceneWrapper.getCollisionEngine(), body, position, sourceRotation, linearVelocity, angularVelocity, linearForce, angularForce);
}
DGeom geom = PhysicsEntityUtils.getDGeom(parent);
if(geom != null){
Vector3d position = EntityUtils.getPosition(parent);
Quaterniond sourceRotation = new Quaterniond(EntityUtils.getRotation(parent));
//make sure rotation is vertical
// sourceRotation = sourceRotation.mul(0.001, 0.001, 0.001, 1).normalize();
//calculate rotation based on facing vector
if(CreatureUtils.getFacingVector(parent) != null){
Vector3d facingVector = CreatureUtils.getFacingVector(parent);
sourceRotation = new Quaterniond().rotationTo(SpatialMathUtils.getOriginVector(), new Vector3d(facingVector.x,0,facingVector.z)).normalize();
}
EntityUtils.setPosition(parent, position);
EntityUtils.getRotation(parent).set(sourceRotation);
PhysicsUtils.setGeomTransform(Globals.clientState.clientSceneWrapper.getCollisionEngine(), position, sourceRotation, geom);
}
}
/**

View File

@ -3,6 +3,7 @@ package electrosphere.entity.state.physicssync.upright;
import org.joml.Quaterniond;
import org.joml.Vector3d;
import org.ode4j.ode.DBody;
import org.ode4j.ode.DGeom;
import electrosphere.collision.PhysicsEntityUtils;
import electrosphere.collision.PhysicsUtils;
@ -55,6 +56,24 @@ public class ServerAlwaysUprightTree implements BehaviorTree {
EntityUtils.getRotation(parent).set(sourceRotation);
PhysicsUtils.synchronizeData(realm.getCollisionEngine(), body, position, sourceRotation, linearVelocity, angularVelocity, linearForce, angularForce);
}
DGeom geom = PhysicsEntityUtils.getDGeom(parent);
if(geom != null){
Realm realm = Globals.serverState.realmManager.getEntityRealm(parent);
Vector3d position = EntityUtils.getPosition(parent);
Quaterniond sourceRotation = new Quaterniond(EntityUtils.getRotation(parent));
//make sure rotation is vertical
// sourceRotation = sourceRotation.mul(0.001, 0.001, 0.001, 1).normalize();
//calculate rotation based on facing vector
if(CreatureUtils.getFacingVector(parent) != null){
Vector3d facingVector = CreatureUtils.getFacingVector(parent);
sourceRotation = new Quaterniond().rotationTo(SpatialMathUtils.getOriginVector(), new Vector3d(facingVector.x,0,facingVector.z)).normalize();
}
EntityUtils.setPosition(parent, position);
EntityUtils.getRotation(parent).set(sourceRotation);
PhysicsUtils.setGeomTransform(realm.getCollisionEngine(), position, sourceRotation, geom);
}
}
/**

View File

@ -1,5 +1,6 @@
package electrosphere.renderer.pipelines.debug;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
@ -39,6 +40,7 @@ import electrosphere.entity.EntityUtils;
import electrosphere.entity.state.hitbox.HitboxCollectionState;
import electrosphere.entity.state.hitbox.HitboxCollectionState.HitboxState;
import electrosphere.entity.types.common.CommonEntityUtils;
import electrosphere.entity.types.creature.CreatureUtils;
import electrosphere.renderer.OpenGLState;
import electrosphere.renderer.RenderPipelineState;
import electrosphere.renderer.RenderingEngine;
@ -334,6 +336,18 @@ public class DebugContentPipeline implements RenderPipeline {
}
}
//
//Draw facing vectors
if(Globals.gameConfigCurrent.getSettings().getGraphicsDebugDrawServerFacingVectors()){
Realm realm = Globals.serverState.realmManager.first();
Collection<Entity> entities = realm.getDataCellManager().entityLookup(CameraEntityUtils.getCameraCenter(Globals.clientState.playerCamera), 100);
for(Entity ent : entities){
if(CreatureUtils.getFacingVector(ent) != null){
DebugContentPipeline.renderTube(openGLState, renderPipelineState, modelTransformMatrix, EntityUtils.getPosition(ent), new Vector3d(EntityUtils.getPosition(ent)).add(CreatureUtils.getFacingVector(ent)), 0.3, AssetDataStrings.TEXTURE_BLUE_TRANSPARENT);
}
}
}
//update pipeline state to use mats again
renderPipelineState.setUseMaterial(true);
@ -395,7 +409,7 @@ public class DebugContentPipeline implements RenderPipeline {
* @param physicsEntity The entity
* @param template The template
*/
static void renderCollidable(OpenGLState openGLState, RenderPipelineState renderPipelineState, Matrix4d modelTransformMatrix, Entity physicsEntity, CollidableTemplate template){
private static void renderCollidable(OpenGLState openGLState, RenderPipelineState renderPipelineState, Matrix4d modelTransformMatrix, Entity physicsEntity, CollidableTemplate template){
Model physicsGraphicsModel;
if((boolean)physicsEntity.getData(EntityDataStrings.DATA_STRING_DRAW)){
switch(template.getType()){
@ -469,7 +483,7 @@ public class DebugContentPipeline implements RenderPipeline {
* @param modelTransformMatrix The model transform matrix
* @param hitboxState The hitbox collection state
*/
static void renderHitboxes(OpenGLState openGLState, RenderPipelineState renderPipelineState, Matrix4d modelTransformMatrix, HitboxCollectionState hitboxState){
private static void renderHitboxes(OpenGLState openGLState, RenderPipelineState renderPipelineState, Matrix4d modelTransformMatrix, HitboxCollectionState hitboxState){
Model hitboxModel;
for(DGeom geom : hitboxState.getGeometries()){
if(geom instanceof DSphere){
@ -527,7 +541,7 @@ public class DebugContentPipeline implements RenderPipeline {
* @param modelTransformMatrix The model transform matrix
* @param areaSelection The area selection
*/
static void renderAreaSelection(OpenGLState openGLState, RenderPipelineState renderPipelineState, Matrix4d modelTransformMatrix, AreaSelection areaSelection, String texturePath){
private static void renderAreaSelection(OpenGLState openGLState, RenderPipelineState renderPipelineState, Matrix4d modelTransformMatrix, AreaSelection areaSelection, String texturePath){
Model model = Globals.assetManager.fetchModel(AssetDataStrings.UNITCUBE);
if(model != null){
Texture texture = Globals.assetManager.fetchTexture(texturePath);
@ -553,7 +567,7 @@ public class DebugContentPipeline implements RenderPipeline {
* @param modelTransformMatrix The model transform matrix
* @param areaSelection The area selection
*/
static void renderPoint(OpenGLState openGLState, RenderPipelineState renderPipelineState, Matrix4d modelTransformMatrix, Vector3d point, double size, String texturePath){
private static void renderPoint(OpenGLState openGLState, RenderPipelineState renderPipelineState, Matrix4d modelTransformMatrix, Vector3d point, double size, String texturePath){
Model model = Globals.assetManager.fetchModel(AssetDataStrings.UNITSPHERE);
if(model != null){
Texture texture = Globals.assetManager.fetchTexture(texturePath);
@ -577,7 +591,7 @@ public class DebugContentPipeline implements RenderPipeline {
* @param modelTransformMatrix The model transform matrix
* @param areaSelection The area selection
*/
static void renderAABB(OpenGLState openGLState, RenderPipelineState renderPipelineState, Matrix4d modelTransformMatrix, AABBd aabb, String texturePath){
private static void renderAABB(OpenGLState openGLState, RenderPipelineState renderPipelineState, Matrix4d modelTransformMatrix, AABBd aabb, String texturePath){
DebugContentPipeline.renderAABB(openGLState, renderPipelineState, modelTransformMatrix, new Vector3d(aabb.minX,aabb.minY,aabb.minZ), new Vector3d(aabb.maxX,aabb.maxY,aabb.maxZ), texturePath);
}
@ -588,7 +602,7 @@ public class DebugContentPipeline implements RenderPipeline {
* @param modelTransformMatrix The model transform matrix
* @param areaSelection The area selection
*/
static void renderAABB(OpenGLState openGLState, RenderPipelineState renderPipelineState, Matrix4d modelTransformMatrix, Vector3d start, Vector3d end, String texturePath){
private static void renderAABB(OpenGLState openGLState, RenderPipelineState renderPipelineState, Matrix4d modelTransformMatrix, Vector3d start, Vector3d end, String texturePath){
Model model = Globals.assetManager.fetchModel(AssetDataStrings.UNITCUBE);
if(model != null){
Texture texture = Globals.assetManager.fetchTexture(texturePath);
@ -612,7 +626,7 @@ public class DebugContentPipeline implements RenderPipeline {
* @param modelTransformMatrix The model transform matrix
* @param areaSelection The area selection
*/
static void renderTube(OpenGLState openGLState, RenderPipelineState renderPipelineState, Matrix4d modelTransformMatrix, Vector3d start, Vector3d end, double radius, String texturePath){
private static void renderTube(OpenGLState openGLState, RenderPipelineState renderPipelineState, Matrix4d modelTransformMatrix, Vector3d start, Vector3d end, double radius, String texturePath){
Model model = Globals.assetManager.fetchModel(AssetDataStrings.UNITCYLINDER);
if(model != null){
Texture texture = Globals.assetManager.fetchTexture(texturePath);

View File

@ -0,0 +1,55 @@
package electrosphere.server.ai.nodes.actions.move;
import org.joml.Vector3d;
import electrosphere.collision.PhysicsEntityUtils;
import electrosphere.entity.Entity;
import electrosphere.entity.EntityUtils;
import electrosphere.entity.state.movement.groundmove.ServerGroundMovementTree;
import electrosphere.server.ai.blackboard.Blackboard;
import electrosphere.server.ai.nodes.AITreeNode;
import electrosphere.server.macro.structure.VirtualStructure;
/**
* Lerps the elevation of non-body collidables
*/
public class CollidableElevationLerpNode implements AITreeNode {
/**
* The key to lookup the target under
*/
private String targetKey;
/**
* Constructor
* @param targetKey The key to lookup the target under
*/
public CollidableElevationLerpNode(String targetKey){
this.targetKey = targetKey;
}
@Override
public AITreeNodeResult evaluate(Entity entity, Blackboard blackboard) {
if(PhysicsEntityUtils.containsDGeom(entity)){
Object targetRaw = blackboard.get(this.targetKey);
Vector3d targetPos = null;
if(targetRaw == null){
throw new Error("Target undefined!");
}
if(targetRaw instanceof Vector3d){
targetPos = (Vector3d)targetRaw;
} else if(targetRaw instanceof Entity){
targetPos = EntityUtils.getPosition((Entity)targetRaw);
} else if(targetRaw instanceof VirtualStructure){
targetPos = ((VirtualStructure)targetRaw).getPos();
} else {
throw new Error("Unsupported target type " + targetRaw);
}
if(ServerGroundMovementTree.hasServerGroundMovementTree(entity)){
ServerGroundMovementTree tree = ServerGroundMovementTree.getServerGroundMovementTree(entity);
tree.setCollidableElevationTarget(targetPos.y);
}
}
return AITreeNodeResult.SUCCESS;
}
}

View File

@ -49,7 +49,8 @@ public class FaceTargetNode implements AITreeNode {
Vector3d parentPos = EntityUtils.getPosition(entity);
Quaterniond rotation = SpatialMathUtils.calculateRotationFromPointToPoint(parentPos, targetPos);
EntityUtils.getRotation(entity).set(rotation);
CreatureUtils.setFacingVector(entity, CameraEntityUtils.getFacingVec(rotation));
Vector3d faceVec = CameraEntityUtils.getFacingVec(rotation);
CreatureUtils.setFacingVector(entity, faceVec);
return AITreeNodeResult.SUCCESS;
}

View File

@ -25,12 +25,12 @@ public class MacroPathfindingNode implements AITreeNode {
/**
* The value used to check if the entity is close to a pathing point horizontally
*/
public static final double CLOSENESS_CHECK_BOUND_HORIZONTAL = 0.3f;
public static final double CLOSENESS_CHECK_BOUND_HORIZONTAL = 0.3;
/**
* The value used to check if the entity is close to a pathing point vertically
*/
public static final double CLOSENESS_CHECK_BOUND_VERTICAL = 0.7f;
public static final double CLOSENESS_CHECK_BOUND_VERTICAL = 0.7;
/**
* The blackboard key to lookup the target entity under
@ -129,6 +129,8 @@ public class MacroPathfindingNode implements AITreeNode {
){
pathingProgressiveData.setCurrentPoint(pathingProgressiveData.getCurrentPoint() + 1);
currentPathPos = pathingProgressiveData.getPoints().get(pathingProgressiveData.getCurrentPoint());
vertDist = Math.abs(currentPathPos.y - entityPos.y);
horizontalDist = Math.sqrt((currentPathPos.x - entityPos.x) * (currentPathPos.x - entityPos.x) + (currentPathPos.z - entityPos.z) * (currentPathPos.z - entityPos.z));
}
//if we're close enough to the final pathing point, always path to actual final point

View File

@ -126,6 +126,8 @@ public class PathfindingNode implements AITreeNode {
){
pathingProgressiveData.setCurrentPoint(pathingProgressiveData.getCurrentPoint() + 1);
currentPathPos = pathingProgressiveData.getPoints().get(pathingProgressiveData.getCurrentPoint());
vertDist = Math.abs(currentPathPos.y - entityPos.y);
horizontalDist = Math.sqrt((currentPathPos.x - entityPos.x) * (currentPathPos.x - entityPos.x) + (currentPathPos.z - entityPos.z) * (currentPathPos.z - entityPos.z));
}
//if we're close enough to the final pathing point, always path to actual final point

View File

@ -3,6 +3,7 @@ package electrosphere.server.ai.trees.creature;
import electrosphere.entity.state.movement.groundmove.ClientGroundMovementTree.MovementRelativeFacing;
import electrosphere.server.ai.blackboard.BlackboardKeys;
import electrosphere.server.ai.nodes.AITreeNode;
import electrosphere.server.ai.nodes.actions.move.CollidableElevationLerpNode;
import electrosphere.server.ai.nodes.actions.move.FaceTargetNode;
import electrosphere.server.ai.nodes.actions.move.MoveStartNode;
import electrosphere.server.ai.nodes.actions.move.MoveStopNode;
@ -53,7 +54,7 @@ public class MacroMoveToTree {
new SequenceNode(
"MacroMoveToTree",
//check if in range of target
new TargetRangeCheckNode(dist, targetKey),
new TargetRangeCheckNode(dist, targetKey),
new DataDeleteNode(BlackboardKeys.PATHFINDING_POINT),
new DataDeleteNode(BlackboardKeys.PATHFINDING_DATA),
//if in range, stop moving fowards and return SUCCESS
@ -65,6 +66,7 @@ public class MacroMoveToTree {
"MacroMoveToTree",
MacroPathfindingNode.createPathEntity(targetKey),
new FaceTargetNode(BlackboardKeys.PATHFINDING_POINT),
new CollidableElevationLerpNode(BlackboardKeys.PATHFINDING_POINT),
new RunnerNode(new MoveStartNode(MovementRelativeFacing.FORWARD))
)
);

View File

@ -3,6 +3,7 @@ package electrosphere.server.ai.trees.creature;
import electrosphere.entity.state.movement.groundmove.ClientGroundMovementTree.MovementRelativeFacing;
import electrosphere.server.ai.blackboard.BlackboardKeys;
import electrosphere.server.ai.nodes.AITreeNode;
import electrosphere.server.ai.nodes.actions.move.CollidableElevationLerpNode;
import electrosphere.server.ai.nodes.actions.move.FaceTargetNode;
import electrosphere.server.ai.nodes.actions.move.MoveStartNode;
import electrosphere.server.ai.nodes.actions.move.MoveStopNode;
@ -64,6 +65,7 @@ public class MoveToTree {
"MoveToTree",
PathfindingNode.createPathEntity(targetKey),
new FaceTargetNode(BlackboardKeys.PATHFINDING_POINT),
new CollidableElevationLerpNode(BlackboardKeys.PATHFINDING_POINT),
new RunnerNode(new MoveStartNode(MovementRelativeFacing.FORWARD))
)
);