pathfinding work + ai work
All checks were successful
studiorailgun/Renderer/pipeline/head This commit looks good
All checks were successful
studiorailgun/Renderer/pipeline/head This commit looks good
This commit is contained in:
parent
e59ab56e3f
commit
6339181aec
@ -1661,6 +1661,9 @@ Fix pathfinding voxel hashing calculating
|
|||||||
(05/04/2025)
|
(05/04/2025)
|
||||||
Path to nearest valid voxel instead of a non-walkable voxel
|
Path to nearest valid voxel instead of a non-walkable voxel
|
||||||
Blocks factor into voxel pathfinding
|
Blocks factor into voxel pathfinding
|
||||||
|
Debugging pathfinding code
|
||||||
|
New AI behaviors
|
||||||
|
- Will explore for resources if local ones aren't available
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -1728,6 +1731,8 @@ Rearchitecting
|
|||||||
- Main render is a ui element (that we can have multiple of)
|
- Main render is a ui element (that we can have multiple of)
|
||||||
- Shader injecting consts from the engine itself (ie max lights is dynamically injected, that way never have to worry about .glsl and .java not aligning)
|
- Shader injecting consts from the engine itself (ie max lights is dynamically injected, that way never have to worry about .glsl and .java not aligning)
|
||||||
- Cache busting for particle atlas cache
|
- Cache busting for particle atlas cache
|
||||||
|
- Convert behavior tree nodes to use static evaluation methods instead of constructing objects
|
||||||
|
- This will make stepping through the logic for a tree SIGNIFICANTLY more legible with debugger
|
||||||
|
|
||||||
Code cleanup
|
Code cleanup
|
||||||
- Rename "BehaviorTree" to be "Component" (what it actually is)
|
- Rename "BehaviorTree" to be "Component" (what it actually is)
|
||||||
|
|||||||
@ -22,9 +22,14 @@ public class PathfindingNode implements AITreeNode {
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The value used to check if the entity is close to a pathing point
|
* The value used to check if the entity is close to a pathing point horizontally
|
||||||
*/
|
*/
|
||||||
public static final double CLOSENESS_CHECK_BOUND = 0.3f;
|
public static final double CLOSENESS_CHECK_BOUND_HORIZONTAL = 0.3f;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The value used to check if the entity is close to a pathing point vertically
|
||||||
|
*/
|
||||||
|
public static final double CLOSENESS_CHECK_BOUND_VERTICAL = 0.5f;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The blackboard key to lookup the target entity under
|
* The blackboard key to lookup the target entity under
|
||||||
@ -44,6 +49,31 @@ public class PathfindingNode implements AITreeNode {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AITreeNodeResult evaluate(Entity entity, Blackboard blackboard){
|
public AITreeNodeResult evaluate(Entity entity, Blackboard blackboard){
|
||||||
|
//make sure that the solved pathfinding data is for the point we want
|
||||||
|
if(PathfindingNode.hasPathfindingData(blackboard)){
|
||||||
|
PathingProgressiveData pathingProgressiveData = PathfindingNode.getPathfindingData(blackboard);
|
||||||
|
Vector3d actualPoint = pathingProgressiveData.getPoints().get(pathingProgressiveData.getPoints().size() - 1);
|
||||||
|
Object targetRaw = blackboard.get(this.targetEntityKey);
|
||||||
|
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 Structure){
|
||||||
|
targetPos = ((Structure)targetRaw).getPos();
|
||||||
|
} else {
|
||||||
|
throw new Error("Unsupported target type " + targetRaw);
|
||||||
|
}
|
||||||
|
if(actualPoint.distance(targetPos) > CLOSENESS_CHECK_BOUND_HORIZONTAL){
|
||||||
|
PathfindingNode.clearPathfindingData(blackboard);
|
||||||
|
PathfindingNode.clearPathfindingPoint(blackboard);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//create a path if we don't already have one
|
||||||
if(!PathfindingNode.hasPathfindingData(blackboard)){
|
if(!PathfindingNode.hasPathfindingData(blackboard)){
|
||||||
Object targetRaw = blackboard.get(this.targetEntityKey);
|
Object targetRaw = blackboard.get(this.targetEntityKey);
|
||||||
Vector3d targetPos = null;
|
Vector3d targetPos = null;
|
||||||
@ -82,16 +112,41 @@ public class PathfindingNode implements AITreeNode {
|
|||||||
if(pathingProgressiveData.getCurrentPoint() < pathingProgressiveData.getPoints().size()){
|
if(pathingProgressiveData.getCurrentPoint() < pathingProgressiveData.getPoints().size()){
|
||||||
currentPathPos = pathingProgressiveData.getPoints().get(pathingProgressiveData.getCurrentPoint());
|
currentPathPos = pathingProgressiveData.getPoints().get(pathingProgressiveData.getCurrentPoint());
|
||||||
}
|
}
|
||||||
double dist = currentPathPos.distance(entityPos);
|
double vertDist = Math.abs(currentPathPos.y - entityPos.y);
|
||||||
|
double horizontalDist = Math.sqrt((currentPathPos.x - entityPos.x) * (currentPathPos.x - entityPos.x) + (currentPathPos.z - entityPos.z) * (currentPathPos.z - entityPos.z));
|
||||||
while(
|
while(
|
||||||
currentPathPos != null &&
|
currentPathPos != null &&
|
||||||
dist < CLOSENESS_CHECK_BOUND &&
|
vertDist < CLOSENESS_CHECK_BOUND_VERTICAL &&
|
||||||
|
horizontalDist < CLOSENESS_CHECK_BOUND_HORIZONTAL &&
|
||||||
pathingProgressiveData.getCurrentPoint() < pathingProgressiveData.getPoints().size() - 1
|
pathingProgressiveData.getCurrentPoint() < pathingProgressiveData.getPoints().size() - 1
|
||||||
){
|
){
|
||||||
pathingProgressiveData.setCurrentPoint(pathingProgressiveData.getCurrentPoint() + 1);
|
pathingProgressiveData.setCurrentPoint(pathingProgressiveData.getCurrentPoint() + 1);
|
||||||
currentPathPos = pathingProgressiveData.getPoints().get(pathingProgressiveData.getCurrentPoint());
|
currentPathPos = pathingProgressiveData.getPoints().get(pathingProgressiveData.getCurrentPoint());
|
||||||
dist = currentPathPos.distance(entityPos);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//if we're close enough to the final pathing point, always path to actual final point
|
||||||
|
if(
|
||||||
|
vertDist < CLOSENESS_CHECK_BOUND_VERTICAL &&
|
||||||
|
horizontalDist < CLOSENESS_CHECK_BOUND_HORIZONTAL &&
|
||||||
|
pathingProgressiveData.getCurrentPoint() == pathingProgressiveData.getPoints().size() - 1
|
||||||
|
){
|
||||||
|
Object targetRaw = blackboard.get(this.targetEntityKey);
|
||||||
|
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 Structure){
|
||||||
|
targetPos = ((Structure)targetRaw).getPos();
|
||||||
|
} else {
|
||||||
|
throw new Error("Unsupported target type " + targetRaw);
|
||||||
|
}
|
||||||
|
currentPathPos = targetPos;
|
||||||
|
}
|
||||||
|
|
||||||
PathfindingNode.setPathfindingPoint(blackboard, currentPathPos);
|
PathfindingNode.setPathfindingPoint(blackboard, currentPathPos);
|
||||||
|
|
||||||
return AITreeNodeResult.SUCCESS;
|
return AITreeNodeResult.SUCCESS;
|
||||||
|
|||||||
@ -0,0 +1,61 @@
|
|||||||
|
package electrosphere.server.ai.nodes.plan;
|
||||||
|
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
import org.joml.Vector3d;
|
||||||
|
import org.joml.Vector3i;
|
||||||
|
|
||||||
|
import electrosphere.engine.Globals;
|
||||||
|
import electrosphere.entity.Entity;
|
||||||
|
import electrosphere.entity.EntityUtils;
|
||||||
|
import electrosphere.server.ai.blackboard.Blackboard;
|
||||||
|
import electrosphere.server.ai.nodes.AITreeNode;
|
||||||
|
import electrosphere.server.datacell.Realm;
|
||||||
|
import electrosphere.server.datacell.ServerWorldData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a point to explore towards
|
||||||
|
*/
|
||||||
|
public class TargetExploreNode implements AITreeNode {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The key to store the point under
|
||||||
|
*/
|
||||||
|
String targetKey;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Distance to travel in whatever direction
|
||||||
|
*/
|
||||||
|
static final double OFFSET_DIST = 50;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* constructor
|
||||||
|
* @param targetKey The key to store the point under
|
||||||
|
*/
|
||||||
|
public TargetExploreNode(String targetKey){
|
||||||
|
this.targetKey = targetKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AITreeNodeResult evaluate(Entity entity, Blackboard blackboard){
|
||||||
|
Vector3d targetPos = null;
|
||||||
|
|
||||||
|
if(!blackboard.has(targetKey)){
|
||||||
|
Vector3d entPos = new Vector3d(EntityUtils.getPosition(entity));
|
||||||
|
Random rand = new Random();
|
||||||
|
Realm realm = Globals.realmManager.getEntityRealm(entity);
|
||||||
|
Vector3d offsetVec = new Vector3d(rand.nextDouble(),0,rand.nextDouble()).normalize().mul(OFFSET_DIST);
|
||||||
|
targetPos = entPos.add(offsetVec);
|
||||||
|
//solve for height via world data
|
||||||
|
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;
|
||||||
|
|
||||||
|
//store
|
||||||
|
blackboard.put(targetKey, targetPos);
|
||||||
|
}
|
||||||
|
return AITreeNodeResult.SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -24,6 +24,36 @@ public class MoveToTree {
|
|||||||
*/
|
*/
|
||||||
public static final String TREE_NAME = "MoveTo";
|
public static final String TREE_NAME = "MoveTo";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default distance to be within
|
||||||
|
*/
|
||||||
|
static final double DEFAULT_DIST = 0.5f;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a move-to-target tree
|
||||||
|
* @param targetKey The key to lookup the target under
|
||||||
|
* @return The root node of the move-to-target tree
|
||||||
|
*/
|
||||||
|
public static AITreeNode create(String targetKey){
|
||||||
|
return new SelectorNode(
|
||||||
|
new SequenceNode(
|
||||||
|
//check if in range of target
|
||||||
|
new TargetRangeCheckNode(DEFAULT_DIST, targetKey),
|
||||||
|
new DataDeleteNode(BlackboardKeys.PATHFINDING_POINT),
|
||||||
|
new DataDeleteNode(BlackboardKeys.PATHFINDING_DATA),
|
||||||
|
//if in range, stop moving fowards and return SUCCESS
|
||||||
|
new SucceederNode(new MoveStopNode())
|
||||||
|
),
|
||||||
|
|
||||||
|
//not in range of target, keep moving towards it
|
||||||
|
new SequenceNode(
|
||||||
|
PathfindingNode.createPathEntity(targetKey),
|
||||||
|
new FaceTargetNode(BlackboardKeys.PATHFINDING_POINT),
|
||||||
|
new RunnerNode(new MoveStartNode(MovementRelativeFacing.FORWARD))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a move-to-target tree
|
* Creates a move-to-target tree
|
||||||
* @param dist The target distance to be within
|
* @param dist The target distance to be within
|
||||||
@ -31,7 +61,7 @@ public class MoveToTree {
|
|||||||
* @return The root node of the move-to-target tree
|
* @return The root node of the move-to-target tree
|
||||||
*/
|
*/
|
||||||
public static AITreeNode create(double dist, String targetKey){
|
public static AITreeNode create(double dist, String targetKey){
|
||||||
if(dist < PathfindingNode.CLOSENESS_CHECK_BOUND){
|
if(dist < PathfindingNode.CLOSENESS_CHECK_BOUND_HORIZONTAL){
|
||||||
throw new Error("Dist less than minimal amount! " + dist);
|
throw new Error("Dist less than minimal amount! " + dist);
|
||||||
}
|
}
|
||||||
return new SelectorNode(
|
return new SelectorNode(
|
||||||
|
|||||||
@ -0,0 +1,37 @@
|
|||||||
|
package electrosphere.server.ai.trees.creature.explore;
|
||||||
|
|
||||||
|
import electrosphere.server.ai.blackboard.BlackboardKeys;
|
||||||
|
import electrosphere.server.ai.nodes.AITreeNode;
|
||||||
|
import electrosphere.server.ai.nodes.meta.DataDeleteNode;
|
||||||
|
import electrosphere.server.ai.nodes.meta.collections.SequenceNode;
|
||||||
|
import electrosphere.server.ai.nodes.meta.debug.PublishStatusNode;
|
||||||
|
import electrosphere.server.ai.nodes.plan.TargetExploreNode;
|
||||||
|
import electrosphere.server.ai.trees.creature.MoveToTree;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A tree for exploring new chunks
|
||||||
|
*/
|
||||||
|
public class ExploreTree {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name of the tree
|
||||||
|
*/
|
||||||
|
public static final String TREE_NAME = "ExploreTree";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an explore tree
|
||||||
|
* @return The root node of the explore tree
|
||||||
|
*/
|
||||||
|
public static AITreeNode create(){
|
||||||
|
return new SequenceNode(
|
||||||
|
new PublishStatusNode("Explore"),
|
||||||
|
//resolve point to explore towards
|
||||||
|
new TargetExploreNode(BlackboardKeys.MOVE_TO_TARGET),
|
||||||
|
//move towards the point
|
||||||
|
MoveToTree.create(BlackboardKeys.MOVE_TO_TARGET),
|
||||||
|
//clear position after moving towards it
|
||||||
|
new DataDeleteNode(BlackboardKeys.MOVE_TO_TARGET)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -16,6 +16,7 @@ import electrosphere.server.ai.nodes.meta.decorators.SucceederNode;
|
|||||||
import electrosphere.server.ai.nodes.plan.SolveSourcingTreeNode;
|
import electrosphere.server.ai.nodes.plan.SolveSourcingTreeNode;
|
||||||
import electrosphere.server.ai.nodes.plan.TargetEntityCategoryNode;
|
import electrosphere.server.ai.nodes.plan.TargetEntityCategoryNode;
|
||||||
import electrosphere.server.ai.trees.creature.MoveToTree;
|
import electrosphere.server.ai.trees.creature.MoveToTree;
|
||||||
|
import electrosphere.server.ai.trees.creature.explore.ExploreTree;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A tree to acquire an item
|
* A tree to acquire an item
|
||||||
@ -71,6 +72,11 @@ public class AcquireItemTree {
|
|||||||
new TargetEntityCategoryNode(BlackboardKeys.HARVEST_TARGET_TYPE),
|
new TargetEntityCategoryNode(BlackboardKeys.HARVEST_TARGET_TYPE),
|
||||||
FellTree.create(BlackboardKeys.ENTITY_TARGET),
|
FellTree.create(BlackboardKeys.ENTITY_TARGET),
|
||||||
new RunnerNode(null)
|
new RunnerNode(null)
|
||||||
|
),
|
||||||
|
new SequenceNode(
|
||||||
|
new PublishStatusNode("Explore new chunks for resources"),
|
||||||
|
//Failed to find sources of material in existing chunks, must move for new chunks
|
||||||
|
ExploreTree.create()
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
new SucceederNode(null)
|
new SucceederNode(null)
|
||||||
|
|||||||
@ -1097,6 +1097,10 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
|
|||||||
throw new Error("Failed to find tracking data for " + start);
|
throw new Error("Failed to find tracking data for " + start);
|
||||||
}
|
}
|
||||||
Vector3d nearestValidGoal = this.pathfinder.scanNearestWalkable(this, end, VoxelPathfinder.DEFAULT_MAX_TARGET_SCAN_DIST);
|
Vector3d nearestValidGoal = this.pathfinder.scanNearestWalkable(this, end, VoxelPathfinder.DEFAULT_MAX_TARGET_SCAN_DIST);
|
||||||
|
if(nearestValidGoal == null){
|
||||||
|
nearestValidGoal = this.pathfinder.scanNearestWalkable(this, end, VoxelPathfinder.DEFAULT_MAX_TARGET_SCAN_DIST);
|
||||||
|
throw new Error("Failed to resolve valid point near " + end.x + "," + end.y + "," + end.z);
|
||||||
|
}
|
||||||
List<Vector3d> points = this.pathfinder.findPath(this, start, nearestValidGoal, VoxelPathfinder.DEFAULT_MAX_COST);
|
List<Vector3d> points = this.pathfinder.findPath(this, start, nearestValidGoal, VoxelPathfinder.DEFAULT_MAX_COST);
|
||||||
return points;
|
return points;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -35,7 +35,7 @@ public class VoxelPathfinder {
|
|||||||
/**
|
/**
|
||||||
* Maximum distance to scan for a walkable position
|
* Maximum distance to scan for a walkable position
|
||||||
*/
|
*/
|
||||||
public static final double DEFAULT_MAX_TARGET_SCAN_DIST = 3;
|
public static final double DEFAULT_MAX_TARGET_SCAN_DIST = 5;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The heuristic lookup table
|
* The heuristic lookup table
|
||||||
@ -53,6 +53,9 @@ public class VoxelPathfinder {
|
|||||||
public List<Vector3d> findPath(VoxelCellManager voxelCellManager, Vector3d startPoint, Vector3d endPoint, long maxCost){
|
public List<Vector3d> findPath(VoxelCellManager voxelCellManager, Vector3d startPoint, Vector3d endPoint, long maxCost){
|
||||||
List<Vector3d> rVal = null;
|
List<Vector3d> rVal = null;
|
||||||
|
|
||||||
|
if(startPoint == null || endPoint == null){
|
||||||
|
throw new Error("Points undefined! " + startPoint + " " + endPoint);
|
||||||
|
}
|
||||||
if(startPoint.distance(endPoint) > MAX_DIST){
|
if(startPoint.distance(endPoint) > MAX_DIST){
|
||||||
throw new Error("Distance is outside range provided! " + startPoint.distance(endPoint) + " vs " + MAX_DIST);
|
throw new Error("Distance is outside range provided! " + startPoint.distance(endPoint) + " vs " + MAX_DIST);
|
||||||
}
|
}
|
||||||
@ -905,7 +908,7 @@ public class VoxelPathfinder {
|
|||||||
for(int x = 0; x < 4; x++){
|
for(int x = 0; x < 4; x++){
|
||||||
for(int y = 0; y < 4; y++){
|
for(int y = 0; y < 4; y++){
|
||||||
for(int z = 0; z < 4; z++){
|
for(int z = 0; z < 4; z++){
|
||||||
blockPos.set(voxelPos);
|
blockPos.set(voxelPos).mul(BlockChunkData.BLOCKS_PER_UNIT_DISTANCE);
|
||||||
currChunk.set(chunkPos);
|
currChunk.set(chunkPos);
|
||||||
offsets.set(
|
offsets.set(
|
||||||
x,
|
x,
|
||||||
@ -953,6 +956,7 @@ public class VoxelPathfinder {
|
|||||||
Vector3d realPos;
|
Vector3d realPos;
|
||||||
Vector3i offsets = new Vector3i();
|
Vector3i offsets = new Vector3i();
|
||||||
|
|
||||||
|
|
||||||
while(true){
|
while(true){
|
||||||
scanned = 0;
|
scanned = 0;
|
||||||
for(int x = -radius; x <= radius; x++){
|
for(int x = -radius; x <= radius; x++){
|
||||||
@ -961,7 +965,7 @@ public class VoxelPathfinder {
|
|||||||
currChunk.set(originChunk);
|
currChunk.set(originChunk);
|
||||||
offsets.set(-radius,x,y);
|
offsets.set(-radius,x,y);
|
||||||
VoxelPathfinder.clampVoxelOffsets(currVoxel, currChunk, offsets);
|
VoxelPathfinder.clampVoxelOffsets(currVoxel, currChunk, offsets);
|
||||||
realPos = ServerWorldData.convertVoxelToRealSpace(currVoxel.set(originVoxel).add(-radius,x,y), currChunk);
|
realPos = ServerWorldData.convertVoxelToRealSpace(currVoxel, currChunk);
|
||||||
if(realPos.distance(targetPoint) < maxScanRadius){
|
if(realPos.distance(targetPoint) < maxScanRadius){
|
||||||
scanned++;
|
scanned++;
|
||||||
if(this.isWalkable(voxelCellManager, currChunk, currVoxel)){
|
if(this.isWalkable(voxelCellManager, currChunk, currVoxel)){
|
||||||
@ -973,7 +977,7 @@ public class VoxelPathfinder {
|
|||||||
currChunk.set(originChunk);
|
currChunk.set(originChunk);
|
||||||
offsets.set(radius,x,y);
|
offsets.set(radius,x,y);
|
||||||
VoxelPathfinder.clampVoxelOffsets(currVoxel, currChunk, offsets);
|
VoxelPathfinder.clampVoxelOffsets(currVoxel, currChunk, offsets);
|
||||||
realPos = ServerWorldData.convertVoxelToRealSpace(currVoxel.set(originVoxel).add(-radius,x,y), currChunk);
|
realPos = ServerWorldData.convertVoxelToRealSpace(currVoxel, currChunk);
|
||||||
if(realPos.distance(targetPoint) < maxScanRadius){
|
if(realPos.distance(targetPoint) < maxScanRadius){
|
||||||
scanned++;
|
scanned++;
|
||||||
if(this.isWalkable(voxelCellManager, currChunk, currVoxel)){
|
if(this.isWalkable(voxelCellManager, currChunk, currVoxel)){
|
||||||
@ -985,7 +989,7 @@ public class VoxelPathfinder {
|
|||||||
currChunk.set(originChunk);
|
currChunk.set(originChunk);
|
||||||
offsets.set(x,-radius,y);
|
offsets.set(x,-radius,y);
|
||||||
VoxelPathfinder.clampVoxelOffsets(currVoxel, currChunk, offsets);
|
VoxelPathfinder.clampVoxelOffsets(currVoxel, currChunk, offsets);
|
||||||
realPos = ServerWorldData.convertVoxelToRealSpace(currVoxel.set(originVoxel).add(-radius,x,y), currChunk);
|
realPos = ServerWorldData.convertVoxelToRealSpace(currVoxel, currChunk);
|
||||||
if(realPos.distance(targetPoint) < maxScanRadius){
|
if(realPos.distance(targetPoint) < maxScanRadius){
|
||||||
scanned++;
|
scanned++;
|
||||||
if(this.isWalkable(voxelCellManager, currChunk, currVoxel)){
|
if(this.isWalkable(voxelCellManager, currChunk, currVoxel)){
|
||||||
@ -997,7 +1001,7 @@ public class VoxelPathfinder {
|
|||||||
currChunk.set(originChunk);
|
currChunk.set(originChunk);
|
||||||
offsets.set(x,radius,y);
|
offsets.set(x,radius,y);
|
||||||
VoxelPathfinder.clampVoxelOffsets(currVoxel, currChunk, offsets);
|
VoxelPathfinder.clampVoxelOffsets(currVoxel, currChunk, offsets);
|
||||||
realPos = ServerWorldData.convertVoxelToRealSpace(currVoxel.set(originVoxel).add(-radius,x,y), currChunk);
|
realPos = ServerWorldData.convertVoxelToRealSpace(currVoxel, currChunk);
|
||||||
if(realPos.distance(targetPoint) < maxScanRadius){
|
if(realPos.distance(targetPoint) < maxScanRadius){
|
||||||
scanned++;
|
scanned++;
|
||||||
if(this.isWalkable(voxelCellManager, currChunk, currVoxel)){
|
if(this.isWalkable(voxelCellManager, currChunk, currVoxel)){
|
||||||
@ -1009,7 +1013,7 @@ public class VoxelPathfinder {
|
|||||||
currChunk.set(originChunk);
|
currChunk.set(originChunk);
|
||||||
offsets.set(x,y,-radius);
|
offsets.set(x,y,-radius);
|
||||||
VoxelPathfinder.clampVoxelOffsets(currVoxel, currChunk, offsets);
|
VoxelPathfinder.clampVoxelOffsets(currVoxel, currChunk, offsets);
|
||||||
realPos = ServerWorldData.convertVoxelToRealSpace(currVoxel.set(originVoxel).add(-radius,x,y), currChunk);
|
realPos = ServerWorldData.convertVoxelToRealSpace(currVoxel, currChunk);
|
||||||
if(realPos.distance(targetPoint) < maxScanRadius){
|
if(realPos.distance(targetPoint) < maxScanRadius){
|
||||||
scanned++;
|
scanned++;
|
||||||
if(this.isWalkable(voxelCellManager, currChunk, currVoxel)){
|
if(this.isWalkable(voxelCellManager, currChunk, currVoxel)){
|
||||||
@ -1021,7 +1025,7 @@ public class VoxelPathfinder {
|
|||||||
currChunk.set(originChunk);
|
currChunk.set(originChunk);
|
||||||
offsets.set(x,y,radius);
|
offsets.set(x,y,radius);
|
||||||
VoxelPathfinder.clampVoxelOffsets(currVoxel, currChunk, offsets);
|
VoxelPathfinder.clampVoxelOffsets(currVoxel, currChunk, offsets);
|
||||||
realPos = ServerWorldData.convertVoxelToRealSpace(currVoxel.set(originVoxel).add(-radius,x,y), currChunk);
|
realPos = ServerWorldData.convertVoxelToRealSpace(currVoxel, currChunk);
|
||||||
if(realPos.distance(targetPoint) < maxScanRadius){
|
if(realPos.distance(targetPoint) < maxScanRadius){
|
||||||
scanned++;
|
scanned++;
|
||||||
if(this.isWalkable(voxelCellManager, currChunk, currVoxel)){
|
if(this.isWalkable(voxelCellManager, currChunk, currVoxel)){
|
||||||
@ -1047,31 +1051,45 @@ public class VoxelPathfinder {
|
|||||||
*/
|
*/
|
||||||
private static void clampVoxelOffsets(Vector3i voxelPos, Vector3i chunkPos, Vector3i offsets){
|
private static void clampVoxelOffsets(Vector3i voxelPos, Vector3i chunkPos, Vector3i offsets){
|
||||||
//calculate chunk offsets
|
//calculate chunk offsets
|
||||||
voxelPos.x = (voxelPos.x + offsets.x);
|
int storageX = (voxelPos.x + offsets.x);
|
||||||
voxelPos.y = (voxelPos.y + offsets.y);
|
int storageY = (voxelPos.y + offsets.y);
|
||||||
voxelPos.z = (voxelPos.z + offsets.z);
|
int storageZ = (voxelPos.z + offsets.z);
|
||||||
if(voxelPos.x < 0){
|
if(storageX < 0){
|
||||||
voxelPos.x = -1;
|
storageX = -1;
|
||||||
} else {
|
} else {
|
||||||
voxelPos.x = voxelPos.x / ServerTerrainChunk.CHUNK_PLACEMENT_OFFSET;
|
storageX = storageX / ServerTerrainChunk.CHUNK_PLACEMENT_OFFSET;
|
||||||
}
|
}
|
||||||
if(voxelPos.y < 0){
|
if(storageY < 0){
|
||||||
voxelPos.y = -1;
|
storageY = -1;
|
||||||
} else {
|
} else {
|
||||||
voxelPos.y = voxelPos.y / ServerTerrainChunk.CHUNK_PLACEMENT_OFFSET;
|
storageY = storageY / ServerTerrainChunk.CHUNK_PLACEMENT_OFFSET;
|
||||||
}
|
}
|
||||||
if(voxelPos.z < 0){
|
if(storageZ < 0){
|
||||||
voxelPos.z = -1;
|
storageZ = -1;
|
||||||
} else {
|
} else {
|
||||||
voxelPos.z = voxelPos.z / ServerTerrainChunk.CHUNK_PLACEMENT_OFFSET;
|
storageZ = storageZ / ServerTerrainChunk.CHUNK_PLACEMENT_OFFSET;
|
||||||
}
|
}
|
||||||
//update world position
|
//update world position
|
||||||
chunkPos.x = chunkPos.x + voxelPos.x;
|
chunkPos.x = chunkPos.x + storageX;
|
||||||
chunkPos.y = chunkPos.y + voxelPos.y;
|
chunkPos.y = chunkPos.y + storageY;
|
||||||
chunkPos.z = chunkPos.z + voxelPos.z;
|
chunkPos.z = chunkPos.z + storageZ;
|
||||||
voxelPos.x = (voxelPos.x + offsets.x + ServerTerrainChunk.CHUNK_PLACEMENT_OFFSET) % ServerTerrainChunk.CHUNK_PLACEMENT_OFFSET;
|
voxelPos.x = (voxelPos.x + offsets.x + ServerTerrainChunk.CHUNK_PLACEMENT_OFFSET) % ServerTerrainChunk.CHUNK_PLACEMENT_OFFSET;
|
||||||
voxelPos.y = (voxelPos.y + offsets.y + ServerTerrainChunk.CHUNK_PLACEMENT_OFFSET) % ServerTerrainChunk.CHUNK_PLACEMENT_OFFSET;
|
voxelPos.y = (voxelPos.y + offsets.y + ServerTerrainChunk.CHUNK_PLACEMENT_OFFSET) % ServerTerrainChunk.CHUNK_PLACEMENT_OFFSET;
|
||||||
voxelPos.z = (voxelPos.z + offsets.z + ServerTerrainChunk.CHUNK_PLACEMENT_OFFSET) % ServerTerrainChunk.CHUNK_PLACEMENT_OFFSET;
|
voxelPos.z = (voxelPos.z + offsets.z + ServerTerrainChunk.CHUNK_PLACEMENT_OFFSET) % ServerTerrainChunk.CHUNK_PLACEMENT_OFFSET;
|
||||||
|
|
||||||
|
if(
|
||||||
|
voxelPos.x < 0 || voxelPos.y < 0 || voxelPos.z < 0 ||
|
||||||
|
chunkPos.x < 0 || chunkPos.y < 0 || chunkPos.z < 0 ||
|
||||||
|
chunkPos.x > 65536 || chunkPos.y > 65536 || chunkPos.z > 65536
|
||||||
|
){
|
||||||
|
String message = "Failed to clamp \n" +
|
||||||
|
"voxelPos: " + voxelPos.x + "," + voxelPos.y + "," + voxelPos.z + "\n" +
|
||||||
|
"chunkPos: " + chunkPos.x + "," + chunkPos.y + "," + chunkPos.z + "\n" +
|
||||||
|
"offsets: " + offsets.x + "," + offsets.y + "," + offsets.z + "\n" +
|
||||||
|
"storage: " + storageX + "," + storageY + "," + storageZ + "\n" +
|
||||||
|
"";
|
||||||
|
throw new Error(message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1083,28 +1101,28 @@ public class VoxelPathfinder {
|
|||||||
*/
|
*/
|
||||||
private static void clampBlockOffsets(Vector3i blockPos, Vector3i chunkPos, Vector3i offsets){
|
private static void clampBlockOffsets(Vector3i blockPos, Vector3i chunkPos, Vector3i offsets){
|
||||||
//calculate chunk offsets
|
//calculate chunk offsets
|
||||||
blockPos.x = (blockPos.x + offsets.x);
|
int storageX = (blockPos.x + offsets.x);
|
||||||
blockPos.y = (blockPos.y + offsets.y);
|
int storageY = (blockPos.y + offsets.y);
|
||||||
blockPos.z = (blockPos.z + offsets.z);
|
int storageZ = (blockPos.z + offsets.z);
|
||||||
if(blockPos.x < 0){
|
if(storageX < 0){
|
||||||
blockPos.x = -1;
|
storageX = -1;
|
||||||
} else {
|
} else {
|
||||||
blockPos.x = blockPos.x / BlockChunkData.CHUNK_DATA_WIDTH;
|
storageX = storageX / BlockChunkData.CHUNK_DATA_WIDTH;
|
||||||
}
|
}
|
||||||
if(blockPos.y < 0){
|
if(storageY < 0){
|
||||||
blockPos.y = -1;
|
storageY = -1;
|
||||||
} else {
|
} else {
|
||||||
blockPos.y = blockPos.y / BlockChunkData.CHUNK_DATA_WIDTH;
|
storageY = storageY / BlockChunkData.CHUNK_DATA_WIDTH;
|
||||||
}
|
}
|
||||||
if(blockPos.z < 0){
|
if(storageZ < 0){
|
||||||
blockPos.z = -1;
|
storageZ = -1;
|
||||||
} else {
|
} else {
|
||||||
blockPos.z = blockPos.z / BlockChunkData.CHUNK_DATA_WIDTH;
|
storageZ = storageZ / BlockChunkData.CHUNK_DATA_WIDTH;
|
||||||
}
|
}
|
||||||
//update world position
|
//update world position
|
||||||
chunkPos.x = chunkPos.x + blockPos.x;
|
chunkPos.x = chunkPos.x + storageX;
|
||||||
chunkPos.y = chunkPos.y + blockPos.y;
|
chunkPos.y = chunkPos.y + storageY;
|
||||||
chunkPos.z = chunkPos.z + blockPos.z;
|
chunkPos.z = chunkPos.z + storageZ;
|
||||||
blockPos.x = (blockPos.x + offsets.x + BlockChunkData.CHUNK_DATA_WIDTH) % BlockChunkData.CHUNK_DATA_WIDTH;
|
blockPos.x = (blockPos.x + offsets.x + BlockChunkData.CHUNK_DATA_WIDTH) % BlockChunkData.CHUNK_DATA_WIDTH;
|
||||||
blockPos.y = (blockPos.y + offsets.y + BlockChunkData.CHUNK_DATA_WIDTH) % BlockChunkData.CHUNK_DATA_WIDTH;
|
blockPos.y = (blockPos.y + offsets.y + BlockChunkData.CHUNK_DATA_WIDTH) % BlockChunkData.CHUNK_DATA_WIDTH;
|
||||||
blockPos.z = (blockPos.z + offsets.z + BlockChunkData.CHUNK_DATA_WIDTH) % BlockChunkData.CHUNK_DATA_WIDTH;
|
blockPos.z = (blockPos.z + offsets.z + BlockChunkData.CHUNK_DATA_WIDTH) % BlockChunkData.CHUNK_DATA_WIDTH;
|
||||||
|
|||||||
@ -44,7 +44,7 @@ public class HashUtils {
|
|||||||
*/
|
*/
|
||||||
public static long hashIVec(int x, int y, int z){
|
public static long hashIVec(int x, int y, int z){
|
||||||
if (x < 0 || x > 65536 || y < 0 || y > 65536 || z < 0 || z > 65536) {
|
if (x < 0 || x > 65536 || y < 0 || y > 65536 || z < 0 || z > 65536) {
|
||||||
throw new IllegalArgumentException("Values must be in range [0, 65536]");
|
throw new IllegalArgumentException("Values must be in range [0, 65536] " + x + "," + y + "," + z);
|
||||||
}
|
}
|
||||||
return ((long) x) | ((long) y << SHIFT_Y) | ((long) z << SHIFT_Z);
|
return ((long) x) | ((long) y << SHIFT_Y) | ((long) z << SHIFT_Z);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user