diff --git a/docs/src/progress/renderertodo.md b/docs/src/progress/renderertodo.md index 0b9d5b0d..ca0dd64d 100644 --- a/docs/src/progress/renderertodo.md +++ b/docs/src/progress/renderertodo.md @@ -1649,6 +1649,7 @@ Fix blocks not saving to disk when being ejected from cache Block chunk memory pooling Rename MoveToTree Major pathfinding work -- breaking MoteToTree +Pathfinding tiling work diff --git a/src/main/java/electrosphere/engine/Globals.java b/src/main/java/electrosphere/engine/Globals.java index e65e7b99..34e87306 100644 --- a/src/main/java/electrosphere/engine/Globals.java +++ b/src/main/java/electrosphere/engine/Globals.java @@ -84,7 +84,6 @@ import electrosphere.server.datacell.EntityDataCellMapper; import electrosphere.server.datacell.RealmManager; import electrosphere.server.db.DatabaseController; import electrosphere.server.entity.poseactor.PoseModel; -import electrosphere.server.pathfinding.Pathfinder; import electrosphere.server.saves.Save; import electrosphere.server.simulation.MacroSimulation; import electrosphere.server.simulation.MicroSimulation; @@ -430,9 +429,6 @@ public class Globals { //drag item state public static Entity draggedItem = null; public static Object dragSourceInventory = null; - - //pathfinder - public static Pathfinder pathfinder; @@ -522,9 +518,6 @@ public class Globals { gameConfigCurrent = gameConfigDefault; NetConfig.readNetConfig(); - //pathfinder - Globals.pathfinder = new Pathfinder(); - // //Values that depend on the loaded config Globals.clientSelectedVoxelType = (VoxelType)gameConfigCurrent.getVoxelData().getTypes().toArray()[1]; diff --git a/src/main/java/electrosphere/server/datacell/gridded/GriddedDataCellManager.java b/src/main/java/electrosphere/server/datacell/gridded/GriddedDataCellManager.java index 9997fddb..54609edb 100644 --- a/src/main/java/electrosphere/server/datacell/gridded/GriddedDataCellManager.java +++ b/src/main/java/electrosphere/server/datacell/gridded/GriddedDataCellManager.java @@ -40,6 +40,7 @@ import electrosphere.server.datacell.physics.PhysicsDataCell; import electrosphere.server.entity.ServerContentManager; import electrosphere.server.entity.serialization.ContentSerialization; import electrosphere.server.pathfinding.NavMeshConstructor; +import electrosphere.server.pathfinding.Pathfinder; import electrosphere.server.physics.block.manager.ServerBlockManager; import electrosphere.server.physics.fluid.manager.ServerFluidChunk; import electrosphere.server.physics.fluid.manager.ServerFluidManager; @@ -158,6 +159,11 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager * Queue of cells that need to have their physics regenerated (ie on block edits) */ Map physicsQueue = new HashMap(); + + /** + * The pathfinder for the manager + */ + Pathfinder pathfinder; /** * Constructor @@ -188,6 +194,7 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager this.serverContentManager + " " ); } + this.pathfinder = new Pathfinder(); } /** @@ -369,6 +376,15 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager if(pathingMeshData == null){ throw new Error("Failed to build pathing data from existing vertices!"); } + pathingMeshData.header.x = worldPos.x; + pathingMeshData.header.y = worldPos.z; + pathingMeshData.header.bmin[0] = worldPos.x; + pathingMeshData.header.bmin[1] = worldPos.y; + pathingMeshData.header.bmin[2] = worldPos.z; + pathingMeshData.header.bmax[0] = worldPos.x + ServerTerrainChunk.CHUNK_PLACEMENT_OFFSET; + pathingMeshData.header.bmax[1] = worldPos.y + ServerTerrainChunk.CHUNK_PLACEMENT_OFFSET; + pathingMeshData.header.bmax[2] = worldPos.z + ServerTerrainChunk.CHUNK_PLACEMENT_OFFSET; + pathfinder.addTile(pathingMeshData); trackingData.setNavMeshData(pathingMeshData); } @@ -754,7 +770,8 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager Map posPhysicsMap, Map groundDataCells, Map cellTrackingMap, - Realm realm + Realm realm, + Pathfinder pathfinder ){ //get data to generate with Vector3d realPos = new Vector3d( @@ -811,6 +828,15 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager if(pathingMeshData == null){ throw new Error("Failed to build pathing data from existing vertices!"); } + pathingMeshData.header.x = worldPos.x; + pathingMeshData.header.y = worldPos.z; + pathingMeshData.header.bmin[0] = worldPos.x; + pathingMeshData.header.bmin[1] = worldPos.y; + pathingMeshData.header.bmin[2] = worldPos.z; + pathingMeshData.header.bmax[0] = worldPos.x + ServerTerrainChunk.CHUNK_PLACEMENT_OFFSET; + pathingMeshData.header.bmax[1] = worldPos.y + ServerTerrainChunk.CHUNK_PLACEMENT_OFFSET; + pathingMeshData.header.bmax[2] = worldPos.z + ServerTerrainChunk.CHUNK_PLACEMENT_OFFSET; + pathfinder.addTile(pathingMeshData); trackingData.setNavMeshData(pathingMeshData); } @@ -861,7 +887,7 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager //generates physics for the cell in a dedicated thread then finally registers loadedCellsLock.lock(); PhysicsDataCell cell = posPhysicsMap.get(key); - GriddedDataCellManager.runPhysicsGenerationThread(localWorldPos,key,cell,this.posPhysicsMap,this.groundDataCells,this.cellTrackingMap,this.parent); + GriddedDataCellManager.runPhysicsGenerationThread(localWorldPos,key,cell,this.posPhysicsMap,this.groundDataCells,this.cellTrackingMap,this.parent,this.pathfinder); loadedCellsLock.unlock(); @@ -1123,7 +1149,7 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager if(trackingMeshData == null){ throw new Error("Tracking mesh data is null!"); } - List points = Globals.pathfinder.solve(trackingMeshData, start, end); + List points = this.pathfinder.solve(trackingMeshData, start, end); return points; } diff --git a/src/main/java/electrosphere/server/pathfinding/Pathfinder.java b/src/main/java/electrosphere/server/pathfinding/Pathfinder.java index 6b9533ce..16700a3c 100644 --- a/src/main/java/electrosphere/server/pathfinding/Pathfinder.java +++ b/src/main/java/electrosphere/server/pathfinding/Pathfinder.java @@ -1,8 +1,11 @@ package electrosphere.server.pathfinding; +import java.util.HashMap; import java.util.LinkedList; import java.util.List; +import java.util.Map; import java.util.Objects; +import java.util.concurrent.locks.ReentrantLock; import org.joml.Vector3d; import org.joml.Vector3f; @@ -10,6 +13,7 @@ import org.recast4j.detour.DefaultQueryFilter; import org.recast4j.detour.FindNearestPolyResult; import org.recast4j.detour.MeshData; import org.recast4j.detour.NavMesh; +import org.recast4j.detour.NavMeshParams; import org.recast4j.detour.NavMeshQuery; import org.recast4j.detour.QueryFilter; import org.recast4j.detour.Result; @@ -27,6 +31,57 @@ public class Pathfinder { * Maximum points in a straight path */ static final int MAX_STRAIGHT_PATH_POINTS = 100; + + /** + * The root navmesh + */ + NavMesh navMesh; + + /** + * The map of ref -> nav tile + */ + Map meshRefMap = new HashMap(); + + /** + * The lock for thread safety + */ + ReentrantLock lock = new ReentrantLock(); + + /** + * Creates the pathfinder + */ + public Pathfinder(){ + NavMeshParams params = new NavMeshParams(); + params.tileHeight = ServerTerrainChunk.CHUNK_PLACEMENT_OFFSET; + params.tileWidth = ServerTerrainChunk.CHUNK_PLACEMENT_OFFSET; + params.orig[0] = 0; + params.orig[1] = 0; + params.orig[2] = 0; + params.maxTiles = 1000; + params.maxPolys = 100000; + this.navMesh = new NavMesh(params, NavMeshConstructor.RECAST_VERTS_PER_POLY); + } + + /** + * Adds a tile to the pathfinder + * @param tile The file + */ + public void addTile(MeshData tile){ + lock.lock(); + long ref = this.navMesh.addTile(tile, 0, 0); + meshRefMap.put(tile,ref); + lock.unlock(); + } + + /** + * Removes a tile from the navmesh + * @param tile The tile + */ + public void removeTile(MeshData tile){ + lock.lock(); + this.navMesh.removeTile(MAX_STRAIGHT_PATH_POINTS); + lock.unlock(); + } /** * Solves for a path @@ -36,6 +91,7 @@ public class Pathfinder { * @return The set of points to path along */ public List solve(MeshData mesh, Vector3d startPos, Vector3d endPos){ + lock.lock(); List rVal = new LinkedList(); if(mesh == null){ @@ -43,8 +99,7 @@ public class Pathfinder { } //construct objects - NavMesh navMesh = new NavMesh(mesh,6,0); - NavMeshQuery query = new NavMeshQuery(navMesh); + NavMeshQuery query = new NavMeshQuery(this.navMesh); QueryFilter filter = new DefaultQueryFilter(); //convert points to correct datatypes @@ -91,7 +146,7 @@ public class Pathfinder { message = "Failed to solve for path -- invalid param!\n" + "Message: " + pathResult.message + "\n" + "Status: " + pathResult.status + "\n" + - Pathfinder.checkInvalidParam(navMesh,startRef,endRef,startArr,endArr) + "\n" + + Pathfinder.checkInvalidParam(this.navMesh,startRef,endRef,startArr,endArr) + "\n" + "" ; } @@ -112,6 +167,8 @@ public class Pathfinder { rVal.add(new Vector3d(pathItem.getPos()[0],pathItem.getPos()[1],pathItem.getPos()[2])); } + lock.unlock(); + return rVal; }