From f64d360d14c7ce665df304be9c82553a2f65d716 Mon Sep 17 00:00:00 2001 From: austin Date: Wed, 16 Apr 2025 16:47:05 -0400 Subject: [PATCH] pathfinding work --- .vscode/settings.json | 4 +- buildNumber.properties | 4 +- docs/src/progress/renderertodo.md | 5 + ...re_server_fluid_manager_ServerFluidChunk.h | 49 -- ...luid_simulator_FluidAcceleratedSimulator.h | 41 -- ...r_physics_fluid_manager_ServerFluidChunk.h | 49 ++ ...luid_simulator_FluidAcceleratedSimulator.h | 41 ++ src/main/c/src/fluid/queue/javainterface.c | 12 +- src/main/c/src/fluid/sim/grid/fluidsim.c | 2 +- src/main/c/src/fluid/sim/grid2/grid2.c | 2 +- src/main/c/src/mem/fluidmem.c | 6 +- .../java/electrosphere/engine/Globals.java | 6 - .../entity/types/terrain/TerrainChunk.java | 19 +- .../pipelines/debug/DebugContentPipeline.java | 27 +- .../electrosphere/server/datacell/Realm.java | 51 +- .../server/datacell/RealmManager.java | 1 + .../server/datacell/ServerDataCell.java | 22 +- .../gridded/GriddedDataCellManager.java | 31 +- .../gridded/GriddedDataCellTrackingData.java | 23 +- .../interfaces/PathfindingManager.java | 20 + .../datacell/physics/PhysicsDataCell.java | 43 +- .../server/pathfinding/ChunkMeshList.java | 36 -- .../pathfinding/NavMeshConstructor.java | 150 ++++++ .../server/pathfinding/NavMeshManager.java | 51 -- .../server/pathfinding/NavMeshPathfinder.java | 452 ------------------ .../server/pathfinding/NavMeshUtils.java | 361 -------------- .../server/pathfinding/Pathfinder.java | 92 ++++ .../pathfinding/blocker/NavBlocker.java | 32 -- .../blocker/NavTerrainBlockerCache.java | 57 --- .../server/pathfinding/navmesh/NavCube.java | 54 --- .../server/pathfinding/navmesh/NavMesh.java | 43 -- .../server/pathfinding/navmesh/NavShape.java | 17 - .../server/pathfinding/path/Waypoint.java | 12 - .../terrain/manager/ServerTerrainManager.java | 6 +- 34 files changed, 519 insertions(+), 1302 deletions(-) delete mode 100644 src/main/c/includes/native/electrosphere_server_fluid_manager_ServerFluidChunk.h delete mode 100644 src/main/c/includes/native/electrosphere_server_fluid_simulator_FluidAcceleratedSimulator.h create mode 100644 src/main/c/includes/native/electrosphere_server_physics_fluid_manager_ServerFluidChunk.h create mode 100644 src/main/c/includes/native/electrosphere_server_physics_fluid_simulator_FluidAcceleratedSimulator.h create mode 100644 src/main/java/electrosphere/server/datacell/interfaces/PathfindingManager.java delete mode 100644 src/main/java/electrosphere/server/pathfinding/ChunkMeshList.java create mode 100644 src/main/java/electrosphere/server/pathfinding/NavMeshConstructor.java delete mode 100644 src/main/java/electrosphere/server/pathfinding/NavMeshManager.java delete mode 100644 src/main/java/electrosphere/server/pathfinding/NavMeshPathfinder.java delete mode 100644 src/main/java/electrosphere/server/pathfinding/NavMeshUtils.java create mode 100644 src/main/java/electrosphere/server/pathfinding/Pathfinder.java delete mode 100644 src/main/java/electrosphere/server/pathfinding/blocker/NavBlocker.java delete mode 100644 src/main/java/electrosphere/server/pathfinding/blocker/NavTerrainBlockerCache.java delete mode 100644 src/main/java/electrosphere/server/pathfinding/navmesh/NavCube.java delete mode 100644 src/main/java/electrosphere/server/pathfinding/navmesh/NavMesh.java delete mode 100644 src/main/java/electrosphere/server/pathfinding/navmesh/NavShape.java delete mode 100644 src/main/java/electrosphere/server/pathfinding/path/Waypoint.java diff --git a/.vscode/settings.json b/.vscode/settings.json index 2ba8b3bd..57694139 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -57,6 +57,8 @@ "navier_stokes.h": "c", "electrosphere_client_fluid_cache_fluidchunkdata.h": "c", "normalization.h": "c", - "bounds.h": "c" + "bounds.h": "c", + "electrosphere_server_physics_fluid_manager_serverfluidchunk.h": "c", + "electrosphere_server_physics_fluid_simulator_fluidacceleratedsimulator.h": "c" } } \ No newline at end of file diff --git a/buildNumber.properties b/buildNumber.properties index 5b8edeed..cccf3a84 100644 --- a/buildNumber.properties +++ b/buildNumber.properties @@ -1,3 +1,3 @@ #maven.buildNumber.plugin properties file -#Wed Apr 02 13:31:25 EDT 2025 -buildNumber=617 +#Wed Apr 16 16:24:00 EDT 2025 +buildNumber=619 diff --git a/docs/src/progress/renderertodo.md b/docs/src/progress/renderertodo.md index 101b86de..cbe2b6d4 100644 --- a/docs/src/progress/renderertodo.md +++ b/docs/src/progress/renderertodo.md @@ -1510,6 +1510,11 @@ Refactoring server classes under physics package Refactoring server classes under entity package Refactoring server macro data classes Refactoring some macro classes +Fix native code linking after refactoring +Obliterate old navmesh/pathfinding code +Integrate recast4j as pathfinding source +GriddedDataCellManager pathfinding solution +ServerTerrainManager nullcheck fix diff --git a/src/main/c/includes/native/electrosphere_server_fluid_manager_ServerFluidChunk.h b/src/main/c/includes/native/electrosphere_server_fluid_manager_ServerFluidChunk.h deleted file mode 100644 index 9b4e0db5..00000000 --- a/src/main/c/includes/native/electrosphere_server_fluid_manager_ServerFluidChunk.h +++ /dev/null @@ -1,49 +0,0 @@ -/* DO NOT EDIT THIS FILE - it is machine generated */ -#include -/* Header for class electrosphere_server_fluid_manager_ServerFluidChunk */ - -#ifndef _Included_electrosphere_server_fluid_manager_ServerFluidChunk -#define _Included_electrosphere_server_fluid_manager_ServerFluidChunk -#ifdef __cplusplus -extern "C" { -#endif -#undef electrosphere_server_fluid_manager_ServerFluidChunk_ARRAY_CT -#define electrosphere_server_fluid_manager_ServerFluidChunk_ARRAY_CT 27L -#undef electrosphere_server_fluid_manager_ServerFluidChunk_CENTER_BUFF -#define electrosphere_server_fluid_manager_ServerFluidChunk_CENTER_BUFF 13L -#undef electrosphere_server_fluid_manager_ServerFluidChunk_TRUE_DATA_DIM -#define electrosphere_server_fluid_manager_ServerFluidChunk_TRUE_DATA_DIM 16L -#undef electrosphere_server_fluid_manager_ServerFluidChunk_TRUE_DATA_GENERATOR_SIZE -#define electrosphere_server_fluid_manager_ServerFluidChunk_TRUE_DATA_GENERATOR_SIZE 17L -#undef electrosphere_server_fluid_manager_ServerFluidChunk_TRUE_DATA_OFFSET -#define electrosphere_server_fluid_manager_ServerFluidChunk_TRUE_DATA_OFFSET 1L -#undef electrosphere_server_fluid_manager_ServerFluidChunk_BUFFER_DIM -#define electrosphere_server_fluid_manager_ServerFluidChunk_BUFFER_DIM 18L -#undef electrosphere_server_fluid_manager_ServerFluidChunk_BUFFER_SIZE -#define electrosphere_server_fluid_manager_ServerFluidChunk_BUFFER_SIZE 5832L -#undef electrosphere_server_fluid_manager_ServerFluidChunk_IS_HOMOGENOUS -#define electrosphere_server_fluid_manager_ServerFluidChunk_IS_HOMOGENOUS 1.0f -#undef electrosphere_server_fluid_manager_ServerFluidChunk_IS_NOT_HOMOGENOUS -#define electrosphere_server_fluid_manager_ServerFluidChunk_IS_NOT_HOMOGENOUS 0.0f -#undef electrosphere_server_fluid_manager_ServerFluidChunk_HOMOGENOUS_BUFFER_SIZE -#define electrosphere_server_fluid_manager_ServerFluidChunk_HOMOGENOUS_BUFFER_SIZE 4L -/* - * Class: electrosphere_server_fluid_manager_ServerFluidChunk - * Method: allocate - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_electrosphere_server_fluid_manager_ServerFluidChunk_allocate - (JNIEnv *, jobject); - -/* - * Class: electrosphere_server_fluid_manager_ServerFluidChunk - * Method: free - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_electrosphere_server_fluid_manager_ServerFluidChunk_free - (JNIEnv *, jobject); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/src/main/c/includes/native/electrosphere_server_fluid_simulator_FluidAcceleratedSimulator.h b/src/main/c/includes/native/electrosphere_server_fluid_simulator_FluidAcceleratedSimulator.h deleted file mode 100644 index 6c0f565d..00000000 --- a/src/main/c/includes/native/electrosphere_server_fluid_simulator_FluidAcceleratedSimulator.h +++ /dev/null @@ -1,41 +0,0 @@ -/* DO NOT EDIT THIS FILE - it is machine generated */ -#include -/* Header for class electrosphere_server_fluid_simulator_FluidAcceleratedSimulator */ - -#ifndef _Included_electrosphere_server_fluid_simulator_FluidAcceleratedSimulator -#define _Included_electrosphere_server_fluid_simulator_FluidAcceleratedSimulator -#ifdef __cplusplus -extern "C" { -#endif -#undef electrosphere_server_fluid_simulator_FluidAcceleratedSimulator_SIMULATE_TIMESTEP -#define electrosphere_server_fluid_simulator_FluidAcceleratedSimulator_SIMULATE_TIMESTEP 0.1f -#undef electrosphere_server_fluid_simulator_FluidAcceleratedSimulator_GRAVITY_CONST -#define electrosphere_server_fluid_simulator_FluidAcceleratedSimulator_GRAVITY_CONST -100.0f -/* - * Class: electrosphere_server_fluid_simulator_FluidAcceleratedSimulator - * Method: init - * Signature: (F)V - */ -JNIEXPORT void JNICALL Java_electrosphere_server_fluid_simulator_FluidAcceleratedSimulator_init - (JNIEnv *, jclass, jfloat); - -/* - * Class: electrosphere_server_fluid_simulator_FluidAcceleratedSimulator - * Method: simulate - * Signature: (Ljava/util/List;F)V - */ -JNIEXPORT void JNICALL Java_electrosphere_server_fluid_simulator_FluidAcceleratedSimulator_simulate - (JNIEnv *, jclass, jobject, jfloat); - -/* - * Class: electrosphere_server_fluid_simulator_FluidAcceleratedSimulator - * Method: free - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_electrosphere_server_fluid_simulator_FluidAcceleratedSimulator_free - (JNIEnv *, jclass); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/src/main/c/includes/native/electrosphere_server_physics_fluid_manager_ServerFluidChunk.h b/src/main/c/includes/native/electrosphere_server_physics_fluid_manager_ServerFluidChunk.h new file mode 100644 index 00000000..b21be19a --- /dev/null +++ b/src/main/c/includes/native/electrosphere_server_physics_fluid_manager_ServerFluidChunk.h @@ -0,0 +1,49 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class electrosphere_server_physics_fluid_manager_ServerFluidChunk */ + +#ifndef _Included_electrosphere_server_physics_fluid_manager_ServerFluidChunk +#define _Included_electrosphere_server_physics_fluid_manager_ServerFluidChunk +#ifdef __cplusplus +extern "C" { +#endif +#undef electrosphere_server_physics_fluid_manager_ServerFluidChunk_ARRAY_CT +#define electrosphere_server_physics_fluid_manager_ServerFluidChunk_ARRAY_CT 27L +#undef electrosphere_server_physics_fluid_manager_ServerFluidChunk_CENTER_BUFF +#define electrosphere_server_physics_fluid_manager_ServerFluidChunk_CENTER_BUFF 13L +#undef electrosphere_server_physics_fluid_manager_ServerFluidChunk_TRUE_DATA_DIM +#define electrosphere_server_physics_fluid_manager_ServerFluidChunk_TRUE_DATA_DIM 16L +#undef electrosphere_server_physics_fluid_manager_ServerFluidChunk_TRUE_DATA_GENERATOR_SIZE +#define electrosphere_server_physics_fluid_manager_ServerFluidChunk_TRUE_DATA_GENERATOR_SIZE 17L +#undef electrosphere_server_physics_fluid_manager_ServerFluidChunk_TRUE_DATA_OFFSET +#define electrosphere_server_physics_fluid_manager_ServerFluidChunk_TRUE_DATA_OFFSET 1L +#undef electrosphere_server_physics_fluid_manager_ServerFluidChunk_BUFFER_DIM +#define electrosphere_server_physics_fluid_manager_ServerFluidChunk_BUFFER_DIM 18L +#undef electrosphere_server_physics_fluid_manager_ServerFluidChunk_BUFFER_SIZE +#define electrosphere_server_physics_fluid_manager_ServerFluidChunk_BUFFER_SIZE 5832L +#undef electrosphere_server_physics_fluid_manager_ServerFluidChunk_IS_HOMOGENOUS +#define electrosphere_server_physics_fluid_manager_ServerFluidChunk_IS_HOMOGENOUS 1.0f +#undef electrosphere_server_physics_fluid_manager_ServerFluidChunk_IS_NOT_HOMOGENOUS +#define electrosphere_server_physics_fluid_manager_ServerFluidChunk_IS_NOT_HOMOGENOUS 0.0f +#undef electrosphere_server_physics_fluid_manager_ServerFluidChunk_HOMOGENOUS_BUFFER_SIZE +#define electrosphere_server_physics_fluid_manager_ServerFluidChunk_HOMOGENOUS_BUFFER_SIZE 4L +/* + * Class: electrosphere_server_physics_fluid_manager_ServerFluidChunk + * Method: allocate + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_electrosphere_server_physics_fluid_manager_ServerFluidChunk_allocate + (JNIEnv *, jobject); + +/* + * Class: electrosphere_server_physics_fluid_manager_ServerFluidChunk + * Method: free + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_electrosphere_server_physics_fluid_manager_ServerFluidChunk_free + (JNIEnv *, jobject); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/main/c/includes/native/electrosphere_server_physics_fluid_simulator_FluidAcceleratedSimulator.h b/src/main/c/includes/native/electrosphere_server_physics_fluid_simulator_FluidAcceleratedSimulator.h new file mode 100644 index 00000000..5b394ad0 --- /dev/null +++ b/src/main/c/includes/native/electrosphere_server_physics_fluid_simulator_FluidAcceleratedSimulator.h @@ -0,0 +1,41 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class electrosphere_server_physics_fluid_simulator_FluidAcceleratedSimulator */ + +#ifndef _Included_electrosphere_server_physics_fluid_simulator_FluidAcceleratedSimulator +#define _Included_electrosphere_server_physics_fluid_simulator_FluidAcceleratedSimulator +#ifdef __cplusplus +extern "C" { +#endif +#undef electrosphere_server_physics_fluid_simulator_FluidAcceleratedSimulator_SIMULATE_TIMESTEP +#define electrosphere_server_physics_fluid_simulator_FluidAcceleratedSimulator_SIMULATE_TIMESTEP 0.1f +#undef electrosphere_server_physics_fluid_simulator_FluidAcceleratedSimulator_GRAVITY_CONST +#define electrosphere_server_physics_fluid_simulator_FluidAcceleratedSimulator_GRAVITY_CONST -100.0f +/* + * Class: electrosphere_server_physics_fluid_simulator_FluidAcceleratedSimulator + * Method: init + * Signature: (F)V + */ +JNIEXPORT void JNICALL Java_electrosphere_server_physics_fluid_simulator_FluidAcceleratedSimulator_init + (JNIEnv *, jclass, jfloat); + +/* + * Class: electrosphere_server_physics_fluid_simulator_FluidAcceleratedSimulator + * Method: simulate + * Signature: (Ljava/util/List;F)V + */ +JNIEXPORT void JNICALL Java_electrosphere_server_physics_fluid_simulator_FluidAcceleratedSimulator_simulate + (JNIEnv *, jclass, jobject, jfloat); + +/* + * Class: electrosphere_server_physics_fluid_simulator_FluidAcceleratedSimulator + * Method: free + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_electrosphere_server_physics_fluid_simulator_FluidAcceleratedSimulator_free + (JNIEnv *, jclass); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/main/c/src/fluid/queue/javainterface.c b/src/main/c/src/fluid/queue/javainterface.c index 9d4826d4..32939c51 100644 --- a/src/main/c/src/fluid/queue/javainterface.c +++ b/src/main/c/src/fluid/queue/javainterface.c @@ -51,7 +51,7 @@ Environment * environment = NULL; void * getArray(JNIEnv * env, jobjectArray arr, int index); -JNIEXPORT void JNICALL Java_electrosphere_server_fluid_simulator_FluidAcceleratedSimulator_simulate( +JNIEXPORT void JNICALL Java_electrosphere_server_physics_fluid_simulator_FluidAcceleratedSimulator_simulate( JNIEnv * env, jclass fluidSimClass, jobject chunkList, @@ -74,7 +74,7 @@ JNIEXPORT void JNICALL Java_electrosphere_server_fluid_simulator_FluidAccelerate /** * Should clean up all native allocations and state */ -JNIEXPORT void JNICALL Java_electrosphere_server_fluid_simulator_FluidAcceleratedSimulator_free( +JNIEXPORT void JNICALL Java_electrosphere_server_physics_fluid_simulator_FluidAcceleratedSimulator_free( JNIEnv * env, jclass fluidSimClass ){ @@ -94,7 +94,7 @@ JNIEXPORT void JNICALL Java_electrosphere_server_fluid_simulator_FluidAccelerate /** * Initializes the library */ -JNIEXPORT void JNICALL Java_electrosphere_server_fluid_simulator_FluidAcceleratedSimulator_init( +JNIEXPORT void JNICALL Java_electrosphere_server_physics_fluid_simulator_FluidAcceleratedSimulator_init( JNIEnv * env, jclass fluidSimClass, jfloat gravity @@ -114,7 +114,7 @@ JNIEXPORT void JNICALL Java_electrosphere_server_fluid_simulator_FluidAccelerate //store jni lookup tables jclass listClass = (*env)->FindClass(env,"java/util/List"); - jclass fluidSimStorageClass = (*env)->FindClass(env,"electrosphere/server/fluid/manager/ServerFluidChunk"); + jclass fluidSimStorageClass = (*env)->FindClass(env,"electrosphere/server/physics/fluid/manager/ServerFluidChunk"); environment->lookupTable.serverFluidChunkClass = fluidSimStorageClass; //JNIEnv *env, jclass clazz, const char *name, const char *sig environment->lookupTable.listTable.jListSize = (*env)->GetMethodID(env, listClass, "size", "()I"); @@ -135,7 +135,7 @@ JNIEXPORT void JNICALL Java_electrosphere_server_fluid_simulator_FluidAccelerate environment->lookupTable.serverFluidChunkTable.worldXId = (*env)->GetFieldID(env,fluidSimStorageClass,"worldX","I"); environment->lookupTable.serverFluidChunkTable.worldYId = (*env)->GetFieldID(env,fluidSimStorageClass,"worldY","I"); environment->lookupTable.serverFluidChunkTable.worldZId = (*env)->GetFieldID(env,fluidSimStorageClass,"worldZ","I"); - environment->lookupTable.serverFluidChunkTable.neighborsId = (*env)->GetFieldID(env,fluidSimStorageClass,"neighbors","[Lelectrosphere/server/fluid/manager/ServerFluidChunk;"); + environment->lookupTable.serverFluidChunkTable.neighborsId = (*env)->GetFieldID(env,fluidSimStorageClass,"neighbors","[Lelectrosphere/server/physics/fluid/manager/ServerFluidChunk;"); environment->lookupTable.serverFluidChunkTable.chunkmaskJId = (*env)->GetFieldID(env,fluidSimStorageClass,"chunkMask","I"); environment->lookupTable.serverFluidChunkTable.totalDensityId = (*env)->GetFieldID(env,fluidSimStorageClass,"totalDensity","F"); environment->lookupTable.serverFluidChunkTable.updatedId = (*env)->GetFieldID(env,fluidSimStorageClass,"updated","Z"); @@ -157,7 +157,7 @@ JNIEXPORT void JNICALL Java_electrosphere_server_fluid_simulator_FluidAccelerate */ int readInChunks(JNIEnv * env, jobject chunkList, Environment * environment){ jclass listClass = (*env)->FindClass(env,"java/util/List"); - jclass fluidSimClass = (*env)->FindClass(env,"electrosphere/server/fluid/manager/ServerFluidChunk"); + jclass fluidSimClass = (*env)->FindClass(env,"electrosphere/server/physics/fluid/manager/ServerFluidChunk"); //JNIEnv *env, jclass clazz, const char *name, const char *sig jmethodID jListSize = environment->lookupTable.listTable.jListSize; jmethodID jListGet = environment->lookupTable.listTable.jListGet; diff --git a/src/main/c/src/fluid/sim/grid/fluidsim.c b/src/main/c/src/fluid/sim/grid/fluidsim.c index ae48083b..b6350bb3 100644 --- a/src/main/c/src/fluid/sim/grid/fluidsim.c +++ b/src/main/c/src/fluid/sim/grid/fluidsim.c @@ -1,7 +1,7 @@ #include //native interfaces -#include "native/electrosphere_server_fluid_simulator_FluidAcceleratedSimulator.h" +#include "native/electrosphere_server_physics_fluid_simulator_FluidAcceleratedSimulator.h" //fluid lib #include "fluid/env/utilities.h" diff --git a/src/main/c/src/fluid/sim/grid2/grid2.c b/src/main/c/src/fluid/sim/grid2/grid2.c index 6fb029be..35493d34 100644 --- a/src/main/c/src/fluid/sim/grid2/grid2.c +++ b/src/main/c/src/fluid/sim/grid2/grid2.c @@ -4,7 +4,7 @@ #include //native interfaces -#include "native/electrosphere_server_fluid_simulator_FluidAcceleratedSimulator.h" +#include "native/electrosphere_server_physics_fluid_simulator_FluidAcceleratedSimulator.h" //fluid lib #include "fluid/env/utilities.h" diff --git a/src/main/c/src/mem/fluidmem.c b/src/main/c/src/mem/fluidmem.c index c9ed8840..9b11fe25 100644 --- a/src/main/c/src/mem/fluidmem.c +++ b/src/main/c/src/mem/fluidmem.c @@ -1,7 +1,7 @@ #include #include -#include "../../includes/native/electrosphere_server_fluid_manager_ServerFluidChunk.h" +#include "../../includes/native/electrosphere_server_physics_fluid_manager_ServerFluidChunk.h" #include "../../includes/native/electrosphere_client_fluid_cache_FluidChunkData.h" #include "fluid/queue/chunk.h" @@ -65,7 +65,7 @@ void freeField(JNIEnv * env, jobject fluidObj, jfieldID arrFieldId); * @param env The JNI env * @param fluidObj The fluid object */ -JNIEXPORT void JNICALL Java_electrosphere_server_fluid_manager_ServerFluidChunk_allocate( +JNIEXPORT void JNICALL Java_electrosphere_server_physics_fluid_manager_ServerFluidChunk_allocate( JNIEnv * env, jobject fluidObj ){ @@ -136,7 +136,7 @@ void allocateCenterField(JNIEnv * env, jobject fluidObj, jfieldID arrFieldId){ * @param env The JNI env * @param fluidObj The fluid object */ -JNIEXPORT void JNICALL Java_electrosphere_server_fluid_manager_ServerFluidChunk_free( +JNIEXPORT void JNICALL Java_electrosphere_server_physics_fluid_manager_ServerFluidChunk_free( JNIEnv * env, jobject fluidObj ){ diff --git a/src/main/java/electrosphere/engine/Globals.java b/src/main/java/electrosphere/engine/Globals.java index ec864413..474710eb 100644 --- a/src/main/java/electrosphere/engine/Globals.java +++ b/src/main/java/electrosphere/engine/Globals.java @@ -84,7 +84,6 @@ import electrosphere.server.db.DatabaseController; import electrosphere.server.entity.poseactor.PoseModel; import electrosphere.server.macro.MacroData; import electrosphere.server.macro.structure.StructureManager; -import electrosphere.server.pathfinding.NavMeshManager; import electrosphere.server.saves.Save; import electrosphere.server.simulation.MacroSimulation; import electrosphere.server.simulation.MicroSimulation; @@ -378,9 +377,6 @@ public class Globals { //fluid cell manager public static FluidCellManager fluidCellManager; - //navmesh manager - public static NavMeshManager navMeshManager; - //famous fuckin last words, but temporary solution //global arraylist of values for the skybox colors //edit(6/1/21): :upside_down_smile: @@ -515,8 +511,6 @@ public class Globals { //realm & data cell manager realmManager = new RealmManager(); entityDataCellMapper = new EntityDataCellMapper(); - //nav mesh manager - navMeshManager = new NavMeshManager(); //gridded managers Globals.clientTerrainManager = new ClientTerrainManager(); Globals.clientFluidManager = new ClientFluidManager(); diff --git a/src/main/java/electrosphere/entity/types/terrain/TerrainChunk.java b/src/main/java/electrosphere/entity/types/terrain/TerrainChunk.java index 66a26a5c..2db2f396 100644 --- a/src/main/java/electrosphere/entity/types/terrain/TerrainChunk.java +++ b/src/main/java/electrosphere/entity/types/terrain/TerrainChunk.java @@ -107,16 +107,23 @@ public class TerrainChunk { } /** - * Creates a terrain chunk entity on the server - * @param entity The entity to populate - * @param weights The weights for the terrain chunk - * @param values The values of each voxel in the chunk + * Generates terrain chunk data from a set of weights and values + * @param weights The weights + * @param values The values + * @return The terrain chunk data */ - public static void serverCreateTerrainChunkEntity(Entity entity, float[][][] weights, int[][][] values){ - + public static TerrainChunkData serverGenerateTerrainChunkData(float[][][] weights, int[][][] values){ TransvoxelChunkData chunkData = new TransvoxelChunkData(weights, values, ClientDrawCellManager.FULL_RES_LOD); TerrainChunkData data = TransvoxelModelGeneration.generateTerrainChunkData(chunkData); + return data; + } + /** + * Creates a terrain chunk entity on the server + * @param entity The entity to populate + * @param data The terrain chunk data + */ + public static void serverCreateTerrainChunkEntity(Entity entity, TerrainChunkData data){ if(data.getVertices().length > 0){ PhysicsEntityUtils.serverAttachTriGeomRigidBody(entity, data); Realm realm = Globals.realmManager.getEntityRealm(entity); diff --git a/src/main/java/electrosphere/renderer/pipelines/debug/DebugContentPipeline.java b/src/main/java/electrosphere/renderer/pipelines/debug/DebugContentPipeline.java index dd0724f6..58781829 100644 --- a/src/main/java/electrosphere/renderer/pipelines/debug/DebugContentPipeline.java +++ b/src/main/java/electrosphere/renderer/pipelines/debug/DebugContentPipeline.java @@ -5,7 +5,6 @@ import java.util.List; import org.joml.Matrix4d; import org.joml.Quaterniond; -import org.joml.Quaternionf; import org.joml.Vector3d; import org.lwjgl.opengl.GL40; import org.ode4j.ode.DCapsule; @@ -32,9 +31,6 @@ import electrosphere.renderer.pipelines.RenderPipeline; import electrosphere.renderer.texture.Texture; import electrosphere.server.datacell.Realm; import electrosphere.server.datacell.utils.EntityLookupUtils; -import electrosphere.server.pathfinding.navmesh.NavCube; -import electrosphere.server.pathfinding.navmesh.NavMesh; -import electrosphere.server.pathfinding.navmesh.NavShape; /** * Pipeline for rendering content to assist debugging @@ -236,28 +232,7 @@ public class DebugContentPipeline implements RenderPipeline { renderPipelineState.setUseMaterial(true); if(Globals.userSettings.graphicsDebugDrawNavmesh()){ - Model shapeGraphicsModel; - for(NavMesh mesh : Globals.navMeshManager.getMeshes()){ - for(NavShape shape : mesh.getNodes()){ - if(shape instanceof NavCube){ - if((shapeGraphicsModel = Globals.assetManager.fetchModel(AssetDataStrings.UNITCUBE)) != null){ - NavCube cube = (NavCube)shape; - Vector3d position = new Vector3d(cube.getMinPoint()).add(cube.getMaxPoint()).mul(0.5); - Vector3d scale = new Vector3d((float)(cube.getMaxPoint().x-cube.getMinPoint().x)/2,(float)(cube.getMaxPoint().y-cube.getMinPoint().y)/2,(float)(cube.getMaxPoint().z-cube.getMinPoint().z)/2); - Quaternionf rotation = new Quaternionf(); - //calculate camera-modified vector3d - Vector3d cameraModifiedPosition = new Vector3d(position).sub(CameraEntityUtils.getCameraCenter(Globals.playerCamera)); - modelTransformMatrix.identity(); - modelTransformMatrix.translate(cameraModifiedPosition); - modelTransformMatrix.rotate(rotation); - // modelTransformMatrix.translate(template.getOffsetX(),template.getOffsetY(),template.getOffsetZ()); //center sphere - modelTransformMatrix.scale(new Vector3d(scale)); - shapeGraphicsModel.setModelMatrix(modelTransformMatrix); - shapeGraphicsModel.draw(renderPipelineState,openGLState); - } - } - } - } + throw new Error("Not yet implemented!"); } debugBonesPipeline.render(openGLState, renderPipelineState); diff --git a/src/main/java/electrosphere/server/datacell/Realm.java b/src/main/java/electrosphere/server/datacell/Realm.java index fc2a1344..9701c0bb 100644 --- a/src/main/java/electrosphere/server/datacell/Realm.java +++ b/src/main/java/electrosphere/server/datacell/Realm.java @@ -9,6 +9,7 @@ import electrosphere.entity.scene.Scene; import electrosphere.net.parser.net.message.NetworkMessage; import electrosphere.script.ScriptEngine; import electrosphere.server.datacell.interfaces.DataCellManager; +import electrosphere.server.datacell.interfaces.PathfindingManager; import electrosphere.server.entity.ServerContentManager; import java.util.HashSet; @@ -29,10 +30,14 @@ public class Realm { */ public static final int NO_SCENE_INSTANCE = -1; - //The set containing all data cells loaded into this realm + /** + * The set containing all data cells loaded into this realm + */ Set loadedDataCells = new HashSet(); - //this is the cell that all players loading into the game (via connection startup, death, etc) reside in + /** + * this is the cell that all players loading into the game (via connection startup, death, etc) reside in + */ ServerDataCell loadingCell = new ServerDataCell(new Scene()); /** @@ -40,13 +45,24 @@ public class Realm { */ ServerDataCell inventoryCell = new ServerDataCell(new Scene()); - //resolver for entity -> data cell within this realm + /** + * resolver for entity -> data cell within this realm + */ EntityDataCellMapper entityDataCellMapper; - //provides functions for relating data cells to physical locations (eg creating cells, deleting cells, etc) + /** + * provides functions for relating data cells to physical locations (eg creating cells, deleting cells, etc) + */ DataCellManager dataCellManager; - //Main entity physics collision checking engine + /** + * The pathfinding manager + */ + PathfindingManager pathfindingManager; + + /** + * Main entity physics collision checking engine + */ CollisionEngine collisionEngine; /** @@ -54,7 +70,9 @@ public class Realm { */ CollisionEngine chemistryEngine; - //Hitbox manager for the realm + /** + * Hitbox manager for the realm + */ HitboxManager hitboxManager; /** @@ -172,6 +190,22 @@ public class Realm { this.dataCellManager = dataCellManager; } + /** + * Gets the pathfinding manager + * @return The pathfinding manager + */ + public PathfindingManager getPathfindingManager(){ + return pathfindingManager; + } + + /** + * Sets the pathfinding manager + * @param pathfindingManager The pathfinding manager + */ + protected void setPathfindingManager(PathfindingManager pathfindingManager){ + this.pathfindingManager = pathfindingManager; + } + /** * Gets the collision engine for physics collision checking in this realm * @return The collision engine @@ -208,11 +242,6 @@ public class Realm { //main simulation dataCellManager.simulate(); // - //data cell manager update misc variables (player positions, unload not-in-use cells) - if(dataCellManager != null){ - // dataCellManager.unloadPlayerlessChunks(); - } - // //clear collidable impulse lists collisionEngine.clearCollidableImpulseLists(); chemistryEngine.clearCollidableImpulseLists(); diff --git a/src/main/java/electrosphere/server/datacell/RealmManager.java b/src/main/java/electrosphere/server/datacell/RealmManager.java index 061bbb3e..92ac63bc 100644 --- a/src/main/java/electrosphere/server/datacell/RealmManager.java +++ b/src/main/java/electrosphere/server/datacell/RealmManager.java @@ -94,6 +94,7 @@ public class RealmManager { GriddedDataCellManager griddedDataCellManager = new GriddedDataCellManager(realm); //add function classes to realm realm.setDataCellManager(griddedDataCellManager); + realm.setPathfindingManager(griddedDataCellManager); //register within the manager realms.add(realm); return realm; diff --git a/src/main/java/electrosphere/server/datacell/ServerDataCell.java b/src/main/java/electrosphere/server/datacell/ServerDataCell.java index 2b269cb8..f861a3a6 100644 --- a/src/main/java/electrosphere/server/datacell/ServerDataCell.java +++ b/src/main/java/electrosphere/server/datacell/ServerDataCell.java @@ -12,7 +12,6 @@ import electrosphere.net.parser.net.message.EntityMessage; import electrosphere.net.parser.net.message.NetworkMessage; import electrosphere.net.server.player.Player; import electrosphere.server.macro.character.Character; -import electrosphere.server.pathfinding.navmesh.NavMesh; import java.util.HashSet; import java.util.List; @@ -32,29 +31,24 @@ public class ServerDataCell { /** * All players attached to this server data cell */ - Set activePlayers = new HashSet(); - - /** - * The navmesh for the data cell - */ - NavMesh navMesh; + private Set activePlayers = new HashSet(); /** * The scene backing the server data cell */ - Scene scene; + private Scene scene; /** * Controls whether the server data cell simulates its entities or not */ - boolean ready = false; + private boolean ready = false; /** * Constructs a datacell based on a virtual cell. Should be used when a player * first comes into range of the cell. * @param virtualCell */ - ServerDataCell(Scene scene){ + protected ServerDataCell(Scene scene){ this.scene = scene; } @@ -247,14 +241,6 @@ public class ServerDataCell { return scene; } - /** - * Sets the nav mesh of this server data cell - * @param navMesh The nav mesh to store - */ - public void setNavMesh(NavMesh navMesh){ - this.navMesh = navMesh; - } - /** * Gets the simulation ready status of the server data cell * @return True if ready, false otherwise diff --git a/src/main/java/electrosphere/server/datacell/gridded/GriddedDataCellManager.java b/src/main/java/electrosphere/server/datacell/gridded/GriddedDataCellManager.java index ad61986c..28674c2d 100644 --- a/src/main/java/electrosphere/server/datacell/gridded/GriddedDataCellManager.java +++ b/src/main/java/electrosphere/server/datacell/gridded/GriddedDataCellManager.java @@ -17,6 +17,7 @@ import org.joml.Vector3d; import org.joml.Vector3i; import electrosphere.client.block.BlockChunkData; +import electrosphere.client.terrain.data.TerrainChunkData; import electrosphere.engine.Globals; import electrosphere.entity.Entity; import electrosphere.entity.EntityCreationUtils; @@ -32,10 +33,12 @@ import electrosphere.server.datacell.Realm; import electrosphere.server.datacell.ServerDataCell; import electrosphere.server.datacell.ServerWorldData; import electrosphere.server.datacell.interfaces.DataCellManager; +import electrosphere.server.datacell.interfaces.PathfindingManager; import electrosphere.server.datacell.interfaces.VoxelCellManager; 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.physics.block.manager.ServerBlockManager; import electrosphere.server.physics.fluid.manager.ServerFluidChunk; import electrosphere.server.physics.fluid.manager.ServerFluidManager; @@ -47,7 +50,7 @@ import electrosphere.util.math.HashUtils; /** * Implementation of DataCellManager that lays out cells in a logical grid (array). Useful for eg 3d terrain gridded world. */ -public class GriddedDataCellManager implements DataCellManager, VoxelCellManager { +public class GriddedDataCellManager implements DataCellManager, VoxelCellManager, PathfindingManager { /** * The minimum grid size allowed @@ -349,6 +352,13 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager cell.setTerrainChunk(terrainChunk); cell.setBlockChunk(blockChunkData); cell.generatePhysics(); + + //create pathfinding mesh + TerrainChunkData terrainMeshData = cell.getTerrainChunkData(); + ServerDataCell serverDataCell = this.groundDataCells.get(key); + GriddedDataCellTrackingData trackingData = this.cellTrackingMap.get(serverDataCell); + trackingData.setNavMeshData(NavMeshConstructor.constructNavmesh(terrainMeshData)); + loadedCellsLock.lock(); posPhysicsMap.put(key, cell); loadedCellsLock.unlock(); @@ -716,6 +726,7 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager PhysicsDataCell cell, Map posPhysicsMap, Map groundDataCells, + Map cellTrackingMap, Realm realm ){ //get data to generate with @@ -746,18 +757,29 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager ServerEntityUtils.destroyEntity(blockEntity); } + //get advanced tracking data for the data cell + GriddedDataCellTrackingData trackingData = cellTrackingMap.get(dataCell); + generationService.submit(() -> { BlockChunkData blockChunkData = realm.getServerWorldData().getServerBlockManager().getChunk(worldPos.x, worldPos.y, worldPos.z); ServerTerrainChunk terrainChunk = realm.getServerWorldData().getServerTerrainManager().getChunk(worldPos.x, worldPos.y, worldPos.z); targetCell.setTerrainChunk(terrainChunk); targetCell.setBlockChunk(blockChunkData); + + TerrainChunkData terrainMeshData; //create physics entities if(cell != null){ cell.retireCell(); cell.generatePhysics(); + terrainMeshData = cell.getTerrainChunkData(); } else { targetCell.generatePhysics(); + terrainMeshData = targetCell.getTerrainChunkData(); } + + //create pathfinding mesh + trackingData.setNavMeshData(NavMeshConstructor.constructNavmesh(terrainMeshData)); + //set ready dataCell.setReady(true); }); @@ -800,7 +822,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.parent); + GriddedDataCellManager.runPhysicsGenerationThread(localWorldPos,key,cell,this.posPhysicsMap,this.groundDataCells,this.cellTrackingMap,this.parent); loadedCellsLock.unlock(); @@ -1047,4 +1069,9 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager return cellPlayerlessFrameMap; } + @Override + public List findPath(Vector3d start, Vector3d end) { + throw new UnsupportedOperationException("Unimplemented method 'findPath'"); + } + } diff --git a/src/main/java/electrosphere/server/datacell/gridded/GriddedDataCellTrackingData.java b/src/main/java/electrosphere/server/datacell/gridded/GriddedDataCellTrackingData.java index fddab20d..e33b83cf 100644 --- a/src/main/java/electrosphere/server/datacell/gridded/GriddedDataCellTrackingData.java +++ b/src/main/java/electrosphere/server/datacell/gridded/GriddedDataCellTrackingData.java @@ -1,5 +1,7 @@ package electrosphere.server.datacell.gridded; +import org.recast4j.detour.MeshData; + /** * Data associated with a ServerDataCell by the GriddedDataCellManager */ @@ -15,6 +17,11 @@ public class GriddedDataCellTrackingData { */ double closestPlayer; + /** + * The nav mesh data + */ + MeshData navMeshData; + /** * Gets the distance from the cell to the closest player * @return The distance @@ -31,6 +38,20 @@ public class GriddedDataCellTrackingData { this.closestPlayer = closestPlayer; } - + /** + * Gets the nav mesh data + * @return The nav mesh data + */ + public MeshData getNavMeshData() { + return navMeshData; + } + + /** + * Sets the nav mesh data + * @param navMeshData The nav mesh data + */ + public void setNavMeshData(MeshData navMeshData) { + this.navMeshData = navMeshData; + } } diff --git a/src/main/java/electrosphere/server/datacell/interfaces/PathfindingManager.java b/src/main/java/electrosphere/server/datacell/interfaces/PathfindingManager.java new file mode 100644 index 00000000..73a4f60f --- /dev/null +++ b/src/main/java/electrosphere/server/datacell/interfaces/PathfindingManager.java @@ -0,0 +1,20 @@ +package electrosphere.server.datacell.interfaces; + +import java.util.List; + +import org.joml.Vector3d; + +/** + * Performs pathfinding + */ +public interface PathfindingManager { + + /** + * Solves a path + * @param start The start point + * @param end The end point + * @return The path if it exists, null otherwise + */ + public List findPath(Vector3d start, Vector3d end); + +} diff --git a/src/main/java/electrosphere/server/datacell/physics/PhysicsDataCell.java b/src/main/java/electrosphere/server/datacell/physics/PhysicsDataCell.java index d145f209..35d0658b 100644 --- a/src/main/java/electrosphere/server/datacell/physics/PhysicsDataCell.java +++ b/src/main/java/electrosphere/server/datacell/physics/PhysicsDataCell.java @@ -2,6 +2,7 @@ package electrosphere.server.datacell.physics; import electrosphere.client.block.BlockChunkData; import electrosphere.client.terrain.cache.ChunkData; +import electrosphere.client.terrain.data.TerrainChunkData; import electrosphere.engine.Globals; import electrosphere.entity.Entity; import electrosphere.entity.EntityDataStrings; @@ -33,11 +34,16 @@ public class PhysicsDataCell { float[][][] weights = new float[ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE][ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE][ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE]; int[][][] types = new int[ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE][ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE][ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE]; - - - PhysicsDataCell(){ - - } + + /** + * The terrain vertex data + */ + TerrainChunkData terrainChunkData; + + /** + * The block vertex data + */ + BlockMeshData blockData; /** * Creates a physics cell @@ -79,11 +85,12 @@ public class PhysicsDataCell { // this.fillInData(); - TerrainChunk.serverCreateTerrainChunkEntity(physicsEntity, weights, types); - physicsEntity.putData(EntityDataStrings.TERRAIN_IS_TERRAIN, true); - BlockMeshData meshData = BlockMeshgen.rasterize(blockChunk); - BlockChunkEntity.serverCreateBlockChunkEntity(blockPhysicsEntity, meshData); - blockPhysicsEntity.putData(EntityDataStrings.TERRAIN_IS_TERRAIN, true); + this.terrainChunkData = TerrainChunk.serverGenerateTerrainChunkData(weights, types); + TerrainChunk.serverCreateTerrainChunkEntity(this.physicsEntity, this.terrainChunkData); + this.physicsEntity.putData(EntityDataStrings.TERRAIN_IS_TERRAIN, true); + this.blockData = BlockMeshgen.rasterize(this.blockChunk); + BlockChunkEntity.serverCreateBlockChunkEntity(this.blockPhysicsEntity, this.blockData); + this.blockPhysicsEntity.putData(EntityDataStrings.TERRAIN_IS_TERRAIN, true); // //then actually perform the attach // physicsObject = PhysicsUtils.attachTerrainRigidBody(physicsEntity,heightmap,true); // Realm realm = Globals.realmManager.getEntityRealm(physicsEntity); @@ -244,6 +251,20 @@ public class PhysicsDataCell { this.blockChunk = blockChunk; } - + /** + * Gets the terrain vertex data + * @return The terrain vertex data + */ + public TerrainChunkData getTerrainChunkData() { + return terrainChunkData; + } + + /** + * Gets the block vertex data + * @return The block vertex data + */ + public BlockMeshData getBlockData() { + return blockData; + } } diff --git a/src/main/java/electrosphere/server/pathfinding/ChunkMeshList.java b/src/main/java/electrosphere/server/pathfinding/ChunkMeshList.java deleted file mode 100644 index ab03181a..00000000 --- a/src/main/java/electrosphere/server/pathfinding/ChunkMeshList.java +++ /dev/null @@ -1,36 +0,0 @@ -package electrosphere.server.pathfinding; - -import electrosphere.server.pathfinding.navmesh.NavMesh; -import electrosphere.server.physics.terrain.manager.ServerTerrainChunk; - -import java.util.LinkedList; -import java.util.List; - -/** - * - * @author satellite - */ -public class ChunkMeshList { - - ServerTerrainChunk chunk; - List meshes = new LinkedList(); - - public ChunkMeshList(ServerTerrainChunk parent){ - chunk = parent; - } - - public void addMesh(NavMesh mesh){ - meshes.add(mesh); - } - - public List getMeshes(){ - return meshes; - } - - public ServerTerrainChunk getChunk(){ - return chunk; - } - - - -} diff --git a/src/main/java/electrosphere/server/pathfinding/NavMeshConstructor.java b/src/main/java/electrosphere/server/pathfinding/NavMeshConstructor.java new file mode 100644 index 00000000..10706288 --- /dev/null +++ b/src/main/java/electrosphere/server/pathfinding/NavMeshConstructor.java @@ -0,0 +1,150 @@ +package electrosphere.server.pathfinding; + +import org.recast4j.detour.MeshData; +import org.recast4j.detour.NavMeshBuilder; +import org.recast4j.detour.NavMeshDataCreateParams; +import org.recast4j.recast.AreaModification; +import org.recast4j.recast.PolyMesh; +import org.recast4j.recast.PolyMeshDetail; +import org.recast4j.recast.RecastBuilder; +import org.recast4j.recast.RecastBuilder.RecastBuilderResult; +import org.recast4j.recast.RecastConstants.PartitionType; +import org.recast4j.recast.RecastBuilderConfig; +import org.recast4j.recast.RecastConfig; +import org.recast4j.recast.geom.SingleTrimeshInputGeomProvider; + +import electrosphere.client.terrain.data.TerrainChunkData; + +/** + * Constructor methods for nav meshes + */ +public class NavMeshConstructor { + + /** + * Size of a recast cell + */ + static final float RECAST_CELL_SIZE = 1.0f; + + /** + * Height of a recast cell + */ + static final float RECAST_CELL_HEIGHT = 1.0f; + + /** + * Size of a recast agent + */ + static final float RECAST_AGENT_SIZE = 1.0f; + + /** + * Height of a recast agent + */ + static final float RECAST_AGENT_HEIGHT = 1.0f; + + /** + * Maximum height a recast agent can climb + */ + static final float RECAST_AGENT_MAX_CLIMB = 0.1f; + + /** + * Maximum slope a recast agent can handle + */ + static final float RECAST_AGENT_MAX_SLOPE = 0.4f; + + /** + * Minimum size of a recast region + */ + static final int RECAST_MIN_REGION_SIZE = 1; + + /** + * Merge size of a recast region + */ + static final int RECAST_REGION_MERGE_SIZE = 1; + + static final float RECAST_REGION_EDGE_MAX_LEN = 1.0f; + + static final float RECAST_REGION_EDGE_MAX_ERROR = 1.0f; + + static final int RECAST_VERTS_PER_POLY = 3; + + static final float RECAST_DETAIL_SAMPLE_DIST = 0.1f; + + static final float RECAST_DETAIL_SAMPLE_MAX_ERROR = 0.1f; + + /** + * Constructs a navmesh + * @param terrainChunk The terrain chunk + * @return the MeshData + */ + public static MeshData constructNavmesh(TerrainChunkData terrainChunkData){ + RecastConfig recastConfig = new RecastConfig( + PartitionType.MONOTONE, + RECAST_CELL_SIZE, + RECAST_CELL_HEIGHT, + RECAST_AGENT_HEIGHT, + RECAST_AGENT_SIZE, + RECAST_AGENT_MAX_CLIMB, + RECAST_AGENT_MAX_SLOPE, + RECAST_MIN_REGION_SIZE, + RECAST_REGION_MERGE_SIZE, + RECAST_REGION_EDGE_MAX_LEN, + RECAST_REGION_EDGE_MAX_ERROR, + RECAST_VERTS_PER_POLY, + RECAST_DETAIL_SAMPLE_DIST, + RECAST_DETAIL_SAMPLE_MAX_ERROR, + new AreaModification(0) + ); + SingleTrimeshInputGeomProvider geomProvider = new SingleTrimeshInputGeomProvider(terrainChunkData.getVertices(), terrainChunkData.getFaceElements()); + RecastBuilderConfig recastBuilderConfig = new RecastBuilderConfig(recastConfig, geomProvider.getMeshBoundsMin(), geomProvider.getMeshBoundsMax()); + RecastBuilder recastBuilder = new RecastBuilder(); + RecastBuilderResult recastBuilderResult = recastBuilder.build(geomProvider, recastBuilderConfig); + PolyMesh polyMesh = recastBuilderResult.getMesh(); + for(int i = 0; i < polyMesh.npolys; i++){ + polyMesh.flags[i] = 1; + } + PolyMeshDetail polyMeshDetail = recastBuilderResult.getMeshDetail(); + NavMeshDataCreateParams params = new NavMeshDataCreateParams(); + params.verts = polyMesh.verts; + params.vertCount = polyMesh.nverts; + params.polys = polyMesh.polys; + params.polyAreas = polyMesh.areas; + params.polyFlags = polyMesh.flags; + params.polyCount = polyMesh.npolys; + params.nvp = polyMesh.nvp; + params.detailMeshes = polyMeshDetail.meshes; + params.detailVerts = polyMeshDetail.verts; + params.detailVertsCount = polyMeshDetail.nverts; + params.detailTris = polyMeshDetail.tris; + params.detailTriCount = polyMeshDetail.ntris; + params.walkableHeight = RECAST_AGENT_HEIGHT; + params.walkableRadius = RECAST_AGENT_SIZE; + params.walkableClimb = RECAST_AGENT_MAX_CLIMB; + params.bmin = polyMesh.bmin; + params.bmax = polyMesh.bmax; + params.cs = RECAST_CELL_SIZE; + params.ch = RECAST_CELL_HEIGHT; + params.buildBvTree = true; + + // params.offMeshConVerts = new float[6]; + // params.offMeshConVerts[0] = 0.1f; + // params.offMeshConVerts[1] = 0.2f; + // params.offMeshConVerts[2] = 0.3f; + // params.offMeshConVerts[3] = 0.4f; + // params.offMeshConVerts[4] = 0.5f; + // params.offMeshConVerts[5] = 0.6f; + // params.offMeshConRad = new float[1]; + // params.offMeshConRad[0] = 0.1f; + // params.offMeshConDir = new int[1]; + // params.offMeshConDir[0] = 1; + // params.offMeshConAreas = new int[1]; + // params.offMeshConAreas[0] = 2; + // params.offMeshConFlags = new int[1]; + // params.offMeshConFlags[0] = 12; + // params.offMeshConUserID = new int[1]; + // params.offMeshConUserID[0] = 0x4567; + // params.offMeshConCount = 1; + MeshData meshData = NavMeshBuilder.createNavMeshData(params); + + return meshData; + } + +} diff --git a/src/main/java/electrosphere/server/pathfinding/NavMeshManager.java b/src/main/java/electrosphere/server/pathfinding/NavMeshManager.java deleted file mode 100644 index dc9dbfde..00000000 --- a/src/main/java/electrosphere/server/pathfinding/NavMeshManager.java +++ /dev/null @@ -1,51 +0,0 @@ -package electrosphere.server.pathfinding; - -import electrosphere.server.pathfinding.blocker.NavBlocker; -import electrosphere.server.pathfinding.blocker.NavTerrainBlockerCache; -import electrosphere.server.pathfinding.navmesh.NavMesh; -import electrosphere.server.physics.terrain.manager.ServerTerrainChunk; - -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; - -/** - * - * @author satellite - */ -public class NavMeshManager { - - List meshes = new LinkedList(); - Map chunkToMeshListMap = new HashMap(); - NavTerrainBlockerCache blockerCache = new NavTerrainBlockerCache(); - - public NavMesh createNavMesh(){ - NavMesh rVal = new NavMesh(); - meshes.add(rVal); - return rVal; - } - - public void addMesh(NavMesh mesh){ - meshes.add(mesh); - } - - public List getMeshes(){ - return meshes; - } - - public List navigateMeshToMesh(NavMesh startMesh, NavMesh endMesh){ - List rVal = null; - return rVal; - } - - public NavBlocker getNavBlockerForChunk(int x, int y){ - NavBlocker rVal = null; - return rVal; - } - - public NavTerrainBlockerCache getBlockerCache(){ - return blockerCache; - } - -} diff --git a/src/main/java/electrosphere/server/pathfinding/NavMeshPathfinder.java b/src/main/java/electrosphere/server/pathfinding/NavMeshPathfinder.java deleted file mode 100644 index 16f55976..00000000 --- a/src/main/java/electrosphere/server/pathfinding/NavMeshPathfinder.java +++ /dev/null @@ -1,452 +0,0 @@ -package electrosphere.server.pathfinding; - -import electrosphere.entity.Entity; -import electrosphere.entity.EntityCreationUtils; -import electrosphere.entity.EntityUtils; -import electrosphere.server.pathfinding.navmesh.NavCube; -import electrosphere.server.pathfinding.navmesh.NavMesh; -import electrosphere.server.pathfinding.navmesh.NavShape; -import electrosphere.server.pathfinding.path.Waypoint; - -import java.awt.geom.Line2D; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.PriorityQueue; -import org.joml.Vector3d; - -/** - * Navmesh pathfinding functions - */ -public class NavMeshPathfinder { - - //TODO: add movement type mask to this function - public static List navigatePointToPointInMesh(NavMesh mesh, Vector3d start, Vector3d end){ - - List rVal = new LinkedList(); - - NavShape startNode = null; - NavShape endNode = null; - - for(NavShape node : mesh.getNodes()){ - if(node.containsPoint(start.x, start.y, start.z)){ - startNode = node; - } - if(node.containsPoint(end.x, end.y, end.z)){ - endNode = node; - } - if(startNode != null && endNode != null){ - break; - } - } - //if the start and end nodes aren't both present, exit - //need to do broadphase still - if(startNode == null || endNode == null){ - return null; - } - - //theta * - List openSet = new LinkedList(); - List closedSet = new LinkedList(); - PriorityQueue pathItemsQueue = new PriorityQueue(); - Map pathItems = new HashMap(); - - openSet.add(startNode); - SetItem startSetItem = new SetItem(null,startNode,0,start); - startSetItem.currentPos = start; - pathItems.put(startNode, startSetItem); - pathItemsQueue.add(startSetItem); - - while(!openSet.isEmpty()){ - //get lowest cost item - SetItem currentItem = pathItemsQueue.poll(); - NavShape currentNode = currentItem.getNode(); - openSet.remove(currentNode); - - //return path if found end - if(currentNode == endNode){ - // System.out.println("Found path!"); - //TODO: return path - while(currentItem != null){ - if(currentItem.node == endNode){ - Entity waypoint = EntityCreationUtils.createClientSpatialEntity(); - EntityCreationUtils.makeEntityDrawable(waypoint, "Models/waypoint1.fbx"); - // System.out.println(end); - EntityUtils.getPosition(waypoint).set(end.x,end.y + 1,end.z); - EntityUtils.getRotation(waypoint).rotateLocalX(-(float)Math.PI/2.0f); - } else { - Entity waypoint = EntityCreationUtils.createClientSpatialEntity(); - EntityCreationUtils.makeEntityDrawable(waypoint, "Models/waypoint1.fbx"); - // System.out.println(currentItem.currentPos); - EntityUtils.getPosition(waypoint).set(currentItem.currentPos.x,currentItem.currentPos.y + 1,currentItem.currentPos.z); - EntityUtils.getRotation(waypoint).rotateLocalX(-(float)Math.PI/2.0f); - } - currentItem = currentItem.parent; - } - break; - } - closedSet.add(currentNode); - for(NavShape neighbor : currentNode.getNodeNeighbors()){ - if(!closedSet.contains(neighbor)){ - if(!openSet.contains(neighbor)){ - Vector3d centerPoint = calculateCenterOfShape(neighbor); - SetItem newSetItem = new SetItem(currentItem,neighbor,currentItem.getCost() + (float)currentItem.currentPos.distance(centerPoint),centerPoint); - pathItems.put(neighbor, newSetItem); - pathItemsQueue.add(newSetItem); - openSet.add(neighbor); - } - //update vertex - updateVertices(currentItem, pathItems.get(neighbor),pathItemsQueue); - } - } - } - return null; - } - - static void updateVertices(SetItem current, SetItem neighbor, PriorityQueue queue){ - // This part of the algorithm is the main difference between A* and Theta* - if(current.getParent() != null){ - LOSResult losResult = null; - Vector3d neighborCenter = calculateCenterOfShape(neighbor.node); - if(current.getParent().currentPos == null){ - current.getParent().currentPos = calculateCenterOfShape(current.getParent().node); - } - Vector3d parentPos = current.getParent().currentPos; - if((losResult = lineOfSight(current.getParent(), current, neighbor))==null){ -// Vector3d neighborCenter = calculateCenterOfShape(neighbor.node); -// Vector3d parentPos = current.getParent().currentPos; - float dist = (float)neighborCenter.distance(parentPos); - // If there is line-of-sight between parent(s) and neighbor - // then ignore s and use the path from parent(s) to neighbor - if(current.getParent().cost + dist < neighbor.cost){ - // c(s, neighbor) is the Euclidean distance from s to neighbor - neighbor.cost = current.getParent().cost + dist; - neighbor.parent = current.getParent(); - - //update prio q - queue.remove(neighbor); - queue.add(neighbor); -// if(neighbor in open){ -// open.remove(neighbor); -// } -// open.insert(neighbor, gScore(neighbor) + heuristic(neighbor)); - } - } else { - //find midpoint -// Vector3d neighborCenter = calculateCenterOfShape(neighbor.node); -// Vector3d parentPos = current.getParent().currentPos; - if(losResult.hit){ - float distToMidpoint = (float)neighborCenter.distance(losResult.currentPos); - float distToParent = (float)losResult.currentPos.distance(losResult.parentPos); - float dist = distToMidpoint + distToParent; - // If the length of the path from start to s and from s to - // neighbor is shorter than the shortest currently known distance - // from start to neighbor, then update node with the new distance - if(current.cost + dist < neighbor.cost){ - neighbor.cost = current.cost + dist; - neighbor.parent = current; - - //update prio q - queue.remove(neighbor); - queue.add(neighbor); - - current.getParent().currentPos = losResult.parentPos; - current.currentPos = losResult.currentPos; - - } - } else { - float dist = (float)neighborCenter.distance(parentPos); - // If there is line-of-sight between parent(s) and neighbor - // then ignore s and use the path from parent(s) to neighbor - if(current.getParent().cost + dist < neighbor.cost){ - // c(s, neighbor) is the Euclidean distance from s to neighbor - neighbor.cost = current.getParent().cost + dist; - neighbor.parent = current.getParent(); - - //update prio q - queue.remove(neighbor); - queue.add(neighbor); - } - } - } - } - } - - static class LOSResult{ - Vector3d parentPos; - Vector3d currentPos; - boolean hit; - } - - //calculates the line of sight ACROSS current FROM PARENT TO NEIGHBOR - static LOSResult lineOfSight(SetItem parent, SetItem current, SetItem neighbor){ - if(parent.node instanceof NavCube && current.node instanceof NavCube && neighbor.node instanceof NavCube){ - //get points on border of current and neighbor, this is one of the lines - double borderMinX = 0; - double borderMinZ = 0; - double borderMaxX = 0; - double borderMaxZ = 0; - NavCube parentCube = (NavCube)parent.node; - NavCube currentCube = (NavCube)current.node; - NavCube neighborCube = (NavCube)neighbor.node; - //resolve min/max pos -// Vector3d currentMin = currentCube.getMinPoint(); -// Vector3d currentMax = currentCube.getMaxPoint(); -// Vector3d neighborMin = neighborCube.getMinPoint(); -// Vector3d neighborMax = neighborCube.getMaxPoint(); - - BoxInternalBorder parentCurrentBorder = getBoxInternalBorder(parentCube.getMinPoint(),parentCube.getMaxPoint(),currentCube.getMinPoint(),currentCube.getMaxPoint()); - BoxInternalBorder currentChildBorder = getBoxInternalBorder(currentCube.getMinPoint(),currentCube.getMaxPoint(),neighborCube.getMinPoint(),neighborCube.getMaxPoint()); - - boolean intersectsParentBorder = Line2D.linesIntersect( - parentCurrentBorder.minPoint.x, parentCurrentBorder.minPoint.z, - parentCurrentBorder.maxPoint.x, parentCurrentBorder.maxPoint.z, - neighbor.currentPos.x, neighbor.currentPos.z, - parent.currentPos.x, parent.currentPos.z - ); - boolean intersectsChildBorder = Line2D.linesIntersect( - currentChildBorder.minPoint.x, currentChildBorder.minPoint.z, - currentChildBorder.maxPoint.x, currentChildBorder.maxPoint.z, - neighbor.currentPos.x, neighbor.currentPos.z, - parent.currentPos.x, parent.currentPos.z - ); - - LOSResult rVal = new LOSResult(); - - if(intersectsParentBorder && intersectsChildBorder){ - rVal.hit = false; - } else { - rVal.hit = true; -// rVal.currentPos = new Vector3d(); - if(neighbor.currentPos.distance(currentChildBorder.minPoint) < neighbor.currentPos.distance(currentChildBorder.maxPoint)){ - rVal.currentPos = currentChildBorder.minPoint; - } else { - rVal.currentPos = currentChildBorder.maxPoint; - } - if(parent.currentPos.distance(parentCurrentBorder.minPoint) < parent.currentPos.distance(parentCurrentBorder.maxPoint)){ - rVal.parentPos = parentCurrentBorder.minPoint; - } else { - rVal.parentPos = parentCurrentBorder.maxPoint; - } - } - - return rVal; - - //the other line comes from earlier -// if(Line2D.linesIntersect(borderMinX, borderMinZ, borderMaxX, borderMaxZ, rayStart.x, rayStart.z, rayEnd.x, rayEnd.z)){ -// return null; -// } else { -// double distMin = Line2D.ptLineDist(rayStart.x, rayStart.z, rayEnd.x, rayEnd.z, borderMinX, borderMinZ); -// double distMax = Line2D.ptLineDist(rayStart.x, rayStart.z, rayEnd.x, rayEnd.z, borderMaxX, borderMaxZ); -// if(distMin < distMax){ -// return new Vector3d(borderMinX, 0, borderMinZ); -// } else { -// return new Vector3d(borderMaxX, 0, borderMaxZ); -// } -// } - } - return null; - } - - static class BoxInternalBorder { - Vector3d minPoint = new Vector3d(); - Vector3d maxPoint = new Vector3d(); - } - - static BoxInternalBorder getBoxInternalBorder(Vector3d currentMin, Vector3d currentMax, Vector3d neighborMin, Vector3d neighborMax){ - BoxInternalBorder rVal = new BoxInternalBorder(); - if(currentMin.x == neighborMax.x){ - double targetX = currentMin.x; - if(currentMin.z >= neighborMin.z && currentMax.z <= neighborMax.z){ - rVal.minPoint.x = targetX; - rVal.minPoint.z = currentMin.z; - rVal.maxPoint.x = targetX; - rVal.maxPoint.z = currentMax.z; - } else if(neighborMin.z >= currentMin.z && neighborMax.z <= currentMax.z){ - rVal.minPoint.x = targetX; - rVal.minPoint.z = neighborMin.z; - rVal.maxPoint.x = targetX; - rVal.maxPoint.z = neighborMax.z; - } else if(currentMin.z >= neighborMin.z){ - rVal.minPoint.x = targetX; - rVal.minPoint.z = currentMin.z; - rVal.maxPoint.x = targetX; - rVal.maxPoint.z = neighborMax.z; - } else if(neighborMin.z >= currentMin.z){ - rVal.minPoint.x = targetX; - rVal.minPoint.z = neighborMin.z; - rVal.maxPoint.x = targetX; - rVal.maxPoint.z = currentMax.z; - } else { - //they all line up or something - rVal.minPoint.x = targetX; - rVal.minPoint.z = currentMin.z; - rVal.maxPoint.x = targetX; - rVal.maxPoint.z = currentMax.z; - } - } - if(currentMax.x == neighborMin.x){ - double targetX = currentMax.x; - if(currentMin.z >= neighborMin.z && currentMax.z <= neighborMax.z){ - rVal.minPoint.x = targetX; - rVal.minPoint.z = currentMin.z; - rVal.maxPoint.x = targetX; - rVal.maxPoint.z = currentMax.z; - } else if(neighborMin.z >= currentMin.z && neighborMax.z <= currentMax.z){ - rVal.minPoint.x = targetX; - rVal.minPoint.z = neighborMin.z; - rVal.maxPoint.x = targetX; - rVal.maxPoint.z = neighborMax.z; - } else if(currentMin.z >= neighborMin.z){ - rVal.minPoint.x = targetX; - rVal.minPoint.z = currentMin.z; - rVal.maxPoint.x = targetX; - rVal.maxPoint.z = neighborMax.z; - } else if(neighborMin.z >= currentMin.z){ - rVal.minPoint.x = targetX; - rVal.minPoint.z = neighborMin.z; - rVal.maxPoint.x = targetX; - rVal.maxPoint.z = currentMax.z; - } else { - //they all line up or something - rVal.minPoint.x = targetX; - rVal.minPoint.z = currentMin.z; - rVal.maxPoint.x = targetX; - rVal.maxPoint.z = currentMax.z; - } - } - if(currentMin.z == neighborMax.z){ - double targetZ = currentMin.x; - if(currentMin.x >= neighborMin.x && currentMax.x <= neighborMax.x){ - rVal.minPoint.x = currentMin.x; - rVal.minPoint.z = targetZ; - rVal.maxPoint.x = currentMax.x; - rVal.maxPoint.z = targetZ; - } else if(neighborMin.x >= currentMin.x && neighborMax.x <= currentMax.x){ - rVal.minPoint.x = neighborMin.x; - rVal.minPoint.z = targetZ; - rVal.maxPoint.x = neighborMax.x; - rVal.maxPoint.z = targetZ; - } else if(currentMin.x >= neighborMin.x){ - rVal.minPoint.x = currentMin.x; - rVal.minPoint.z = targetZ; - rVal.maxPoint.x = neighborMax.x; - rVal.maxPoint.z = targetZ; - } else if(neighborMin.x >= currentMin.x){ - rVal.minPoint.x = neighborMin.x; - rVal.minPoint.z = targetZ; - rVal.maxPoint.x = currentMax.x; - rVal.maxPoint.z = targetZ; - } else { - //they all line up or something - rVal.minPoint.x = currentMin.x; - rVal.minPoint.z = targetZ; - rVal.maxPoint.x = currentMax.x; - rVal.maxPoint.z = targetZ; - } - } - if(currentMax.z == neighborMin.z){ - double targetZ = currentMax.x; - if(currentMin.x >= neighborMin.x && currentMax.x <= neighborMax.x){ - rVal.minPoint.x = currentMin.x; - rVal.minPoint.z = targetZ; - rVal.maxPoint.x = currentMax.x; - rVal.maxPoint.z = targetZ; - } else if(neighborMin.x >= currentMin.x && neighborMax.x <= currentMax.x){ - rVal.minPoint.x = neighborMin.x; - rVal.minPoint.z = targetZ; - rVal.maxPoint.x = neighborMax.x; - rVal.maxPoint.z = targetZ; - } else if(currentMin.x >= neighborMin.x){ - rVal.minPoint.x = currentMin.x; - rVal.minPoint.z = targetZ; - rVal.maxPoint.x = neighborMax.x; - rVal.maxPoint.z = targetZ; - } else if(neighborMin.x >= currentMin.x){ - rVal.minPoint.x = neighborMin.x; - rVal.minPoint.z = targetZ; - rVal.maxPoint.x = currentMax.x; - rVal.maxPoint.z = targetZ; - } else { - //they all line up or something - rVal.minPoint.x = currentMin.x; - rVal.minPoint.z = targetZ; - rVal.maxPoint.x = currentMax.x; - rVal.maxPoint.z = targetZ; - } - } - return rVal; - } - -// static float lineDistCalc(SetItem current, SetItem target){ -// float rVal = -1.0f; -// return rVal; -// } - - static Vector3d calculateCenterOfShape(NavShape shape){ - Vector3d rVal = new Vector3d(); - if(shape instanceof NavCube){ - NavCube cube = (NavCube)shape; - rVal.add(cube.getMaxPoint()).add(cube.getMinPoint()); - rVal.mul(0.5); - } - return rVal; - } - - - - static class SetItem implements Comparable { - SetItem parent; - NavShape node; - float cost; - //closest point from parent's parent - Vector3d currentPos; - - public SetItem(SetItem parent, NavShape node, float cost, Vector3d currentPos){ - this.parent = parent; - this.node = node; - this.cost = cost; - this.currentPos = currentPos; - } - - public SetItem getParent() { - return parent; - } - - public NavShape getNode() { - return node; - } - - public float getCost() { - return cost; - } - - public void setCost(float cost) { - this.cost = cost; - } - - @Override - public int compareTo(SetItem target) { - if(this.cost < target.cost){ - return -1; - } - if(this.cost > target.cost){ - return 1; - } - return 0; - } - - public Vector3d getCurrentPos() { - return currentPos; - } - - public void setCurrentPos(Vector3d currentPos) { - this.currentPos = currentPos; - } - - - - - } -} diff --git a/src/main/java/electrosphere/server/pathfinding/NavMeshUtils.java b/src/main/java/electrosphere/server/pathfinding/NavMeshUtils.java deleted file mode 100644 index aa938d81..00000000 --- a/src/main/java/electrosphere/server/pathfinding/NavMeshUtils.java +++ /dev/null @@ -1,361 +0,0 @@ -package electrosphere.server.pathfinding; - -import electrosphere.engine.Globals; -import electrosphere.logger.LoggerInterface; -import electrosphere.server.pathfinding.blocker.NavBlocker; -import electrosphere.server.pathfinding.navmesh.NavCube; -import electrosphere.server.pathfinding.navmesh.NavMesh; -import electrosphere.server.pathfinding.navmesh.NavShape; -import electrosphere.server.physics.terrain.manager.ServerTerrainChunk; - -import java.util.LinkedList; -import java.util.List; - -/** - * - * @author satellite - */ -public class NavMeshUtils { - - static float NAVMESH_PHASE_ONE_DISPARITY_TOLERANCE = 0.5f; - static float NAVMESH_PHASE_TWO_DISPARITY_TOLERANCE = 0.5f; - public static NavMesh createMeshFromChunk(ServerTerrainChunk chunk, NavBlocker navBlocker){ - NavMesh rVal = Globals.navMeshManager.createNavMesh(); - float[][] heightMap = chunk.getWeights()[0]; - boolean[][] navMeshGeneratorMask = navBlocker.getHeightfieldBlocker(); - List firstPassBoxes = new LinkedList(); - int numInCurrent = 0; - float currentMin = 0; - float currentMax = 0; - int startPos = 0; - int endPos = 0; - for(int x = 0; x < ServerTerrainChunk.CHUNK_DIMENSION - 1; x++){ - numInCurrent = 0; - currentMin = 0; - currentMax = 0; - for(int y = 0; y < ServerTerrainChunk.CHUNK_DIMENSION; y++){ - //create node - if(navMeshGeneratorMask[x][y]){ - if(numInCurrent > 0){ - firstPassBoxes.add(new FirstPhaseBox(x,startPos,endPos,currentMin,currentMax)); - } - numInCurrent = 0; - } else { - if(numInCurrent == 0){ - currentMin = heightMap[x][y]; - currentMax = heightMap[x][y]; - startPos = y; - endPos = y+1; - numInCurrent = 1; - } else { - if(currentMin > heightMap[x][y]){ - if(currentMax - heightMap[x][y] < NAVMESH_PHASE_ONE_DISPARITY_TOLERANCE){ - currentMin = heightMap[x][y]; - endPos = y; - numInCurrent++; - } else { - //expel previous rectangle - firstPassBoxes.add(new FirstPhaseBox(x,startPos,endPos,currentMin,currentMax)); - //start new one - currentMin = heightMap[x][y]; - currentMax = heightMap[x][y]; - startPos = y; - endPos = y+1; - numInCurrent = 1; - } - } else if(currentMax < heightMap[x][y]){ - if(heightMap[x][y] - currentMin < NAVMESH_PHASE_ONE_DISPARITY_TOLERANCE){ - currentMin = heightMap[x][y]; - endPos = y; - numInCurrent++; - } else { - //expel previous rectangle - firstPassBoxes.add(new FirstPhaseBox(x,startPos,endPos,currentMin,currentMax)); - //start new one - currentMin = heightMap[x][y]; - currentMax = heightMap[x][y]; - startPos = y; - endPos = y+1; - numInCurrent = 1; - } - } else { - endPos = y; - numInCurrent++; - } - } - } -// if(x > 0){ -// //add back neighbor -// } -// if(y > 0){ -// //add back neighbor -// } - } - - //close off last box on row -// FirstPhaseBox boxy = new FirstPhaseBox(1, 1, 1, 1, 1); - firstPassBoxes.add(new FirstPhaseBox(x,startPos,endPos,currentMin,currentMax)); - - - - } - - //phase two - //??? - List secondPhaseBoxes = new LinkedList(); - List toRemove = new LinkedList(); - for(FirstPhaseBox firstPhaseBox : firstPassBoxes){ - SecondPhaseBox newBox = new SecondPhaseBox( - firstPhaseBox.x,firstPhaseBox.yStart, - firstPhaseBox.x+1,firstPhaseBox.yEnd, - firstPhaseBox.minHeight,firstPhaseBox.maxHeight); -// System.out.println( -// firstPhaseBox.x + " " + -// firstPhaseBox.yStart + " " + -// (firstPhaseBox.x+1) + " " + -// firstPhaseBox.yEnd + " " + -// firstPhaseBox.minHeight + " " + -// firstPhaseBox.maxHeight -// ); -// System.out.println( -// "(" + (newBox.boundMinX + chunk.getWorldX() * Globals.serverTerrainManager.getChunkWidth()) + ", " + -// (newBox.minHeight - 0.5f) + ", " + -// (newBox.boundMinY + chunk.getWorldY() * Globals.serverTerrainManager.getChunkWidth()) + ") (" + -// (newBox.boundMaxX + chunk.getWorldX() * Globals.serverTerrainManager.getChunkWidth()) + ", " + -// (newBox.maxHeight + 0.5f) + ", " + -// (newBox.boundMaxY + chunk.getWorldY() * Globals.serverTerrainManager.getChunkWidth()) + ")" -// ); - toRemove.clear(); - //TODO: iterate this backwards and check for x adjacency, if no adjacency end loop early - List neighborUpdateList = new LinkedList(); - for(SecondPhaseBox interim : secondPhaseBoxes){ - if(firstPhaseBox.yStart == interim.boundMinY && firstPhaseBox.yEnd == interim.boundMaxY && firstPhaseBox.x == interim.boundMaxX){ - for(SecondPhaseBox neighbor : interim.getNeighbors()){ - neighborUpdateList.add(neighbor); -// System.out.println("ADD NEIGHBOR: " + neighbor.boundMaxX + " " + neighbor.boundMaxY + " " + neighbor.boundMinX + " " + neighbor.boundMinY); - } - for(SecondPhaseBox update : neighborUpdateList){ - update.removeNeighbor(interim); - interim.removeNeighbor(update); - update.addNeighbor(newBox); - newBox.addNeighbor(update); - } - toRemove.add(interim); - newBox.setBoundMinX(interim.getBoundMinX()); - //TODO: calculate new min/max height - } else { - //because of the way the rectangles are constructed, we can never have a neighbor along y axis - //only neighbors will be behind us - if(newBox.boundMinX == interim.boundMaxX && !toRemove.contains(interim)){ - if( - (interim.boundMaxY < newBox.boundMaxY && interim.boundMaxY > newBox.boundMinY) || - (interim.boundMinY < newBox.boundMaxY && interim.boundMinY > newBox.boundMinY) || - (newBox.boundMaxY < interim.boundMaxY && newBox.boundMaxY > interim.boundMinY) || - (newBox.boundMinY < interim.boundMaxY && newBox.boundMinY > interim.boundMinY) - ){ -// System.out.println("ADD INTERIM: " + interim.boundMaxX + " " + interim.boundMaxY + " " + interim.boundMinX + " " + interim.boundMinY); - newBox.addNeighbor(interim); - interim.addNeighbor(newBox); - } - } - } - } - secondPhaseBoxes.removeAll(toRemove); - secondPhaseBoxes.add(newBox); - } - - int id = 0; - for(SecondPhaseBox box : secondPhaseBoxes){ - box.setId(id); -// System.out.println("getId:" + box.getId()); - id++; -// System.out.println( -// "(" + (box.boundMinX + chunk.getWorldX() * Globals.serverTerrainManager.getChunkWidth()) + ", " + -// (box.minHeight - 0.5f) + ", " + -// (box.boundMinY + chunk.getWorldY() * Globals.serverTerrainManager.getChunkWidth()) + ") (" + -// (box.boundMaxX + chunk.getWorldX() * Globals.serverTerrainManager.getChunkWidth() - 1) + ", " + -// (box.maxHeight + 0.5f) + ", " + -// (box.boundMaxY + chunk.getWorldY() * Globals.serverTerrainManager.getChunkWidth()) + ")" -// ); -// System.out.println(box.neighbors.size()); - //why the -1? I think the array fiddling above is causing the bounds to be off normally - //this fixes that - NavCube cube = new NavCube( - box.boundMinX + chunk.getWorldX() * ServerTerrainChunk.CHUNK_DIMENSION, - box.minHeight - 0.5f, - box.boundMinY + chunk.getWorldY() * ServerTerrainChunk.CHUNK_DIMENSION, - box.boundMaxX + chunk.getWorldX() * ServerTerrainChunk.CHUNK_DIMENSION, - box.maxHeight + 0.5f, - box.boundMaxY + chunk.getWorldY() * ServerTerrainChunk.CHUNK_DIMENSION - ); - rVal.addNode(cube); - } - - id = 0; - for(NavShape shape : rVal.getNodes()){ - NavCube cube = (NavCube)shape; - - SecondPhaseBox currentBox = secondPhaseBoxes.get(id); -// System.out.println("getId:" + currentBox.getId()); - id++; - for(SecondPhaseBox neighbor : currentBox.getNeighbors()){ - //TODO: solve bug where items are getting picked up from not in second phase boxes - if(!secondPhaseBoxes.contains(neighbor)){ - LoggerInterface.loggerGameLogic.WARNING("Found bad neighbor adjacency in navmesh generation"); - for(SecondPhaseBox newNeighbor : secondPhaseBoxes){ - if(newNeighbor.boundMaxX >= neighbor.boundMaxX && - newNeighbor.boundMaxY >= neighbor.boundMaxY && - newNeighbor.boundMinX <= neighbor.boundMinX && - newNeighbor.boundMinY <= neighbor.boundMinY - ){ - cube.addNodeNeighbor(rVal.getNodes().get(newNeighbor.getId())); - LoggerInterface.loggerGameLogic.WARNING("Managed to replace bad neighbor"); - break; - } - } -// System.out.println("ERR!"); -// System.out.println(neighbor.boundMaxX + " " + neighbor.boundMaxY + " " + neighbor.boundMinX + " " + neighbor.boundMinY); - } else { - cube.addNodeNeighbor(rVal.getNodes().get(neighbor.getId())); - } - } -// System.out.println(cube.getNodeNeighbors().size()); - } -// System.out.println(); -// System.out.println(); -// System.out.println(secondPhaseBoxes.size()); - - return rVal; - } - - static class FirstPhaseBox { - int x; - int yStart; - int yEnd; - float minHeight; - float maxHeight; - - public FirstPhaseBox(int x, int yStart, int yEnd, float minHeight, float maxHeight) { - this.x = x; - this.yStart = yStart; - this.yEnd = yEnd; - this.minHeight = minHeight; - this.maxHeight = maxHeight; - } - - public int getX() { - return x; - } - - public int getyStart() { - return yStart; - } - - public int getyEnd() { - return yEnd; - } - - public float getMinHeight() { - return minHeight; - } - - public float getMaxHeight() { - return maxHeight; - } - - - - } - - static class SecondPhaseBox { - - float minHeight; - float maxHeight; - int boundMinX; - int boundMinY; - int boundMaxX; - int boundMaxY; - List neighbors = new LinkedList(); - int id = -1; - - SecondPhaseBox(int boundMinX, int boundMinY, int boundMaxX, int boundMaxY, float minHeight, float maxHeight){ - this.boundMinX = boundMinX; - this.boundMinY = boundMinY; - - this.boundMaxX = boundMaxX; - this.boundMaxY = boundMaxY; - - this.minHeight = minHeight; - this.maxHeight = maxHeight; - } - - float getMinHeight(){ - return minHeight; - } - float getMaxHeight(){ - return maxHeight; - } - - public int getBoundMinX() { - return boundMinX; - } - - public int getBoundMinY() { - return boundMinY; - } - - public int getBoundMaxX() { - return boundMaxX; - } - - public int getBoundMaxY() { - return boundMaxY; - } - - public void setMinHeight(float minHeight) { - this.minHeight = minHeight; - } - - public void setMaxHeight(float maxHeight) { - this.maxHeight = maxHeight; - } - - public void setBoundMinX(int boundMinX) { - this.boundMinX = boundMinX; - } - - public void setBoundMinY(int boundMinY) { - this.boundMinY = boundMinY; - } - - public void setBoundMaxX(int boundMaxX) { - this.boundMaxX = boundMaxX; - } - - public void setBoundMaxY(int boundMaxY) { - this.boundMaxY = boundMaxY; - } - - public List getNeighbors() { - return neighbors; - } - - public void addNeighbor(SecondPhaseBox neighbor){ - neighbors.add(neighbor); - } - - public void removeNeighbor(SecondPhaseBox neighbor){ - neighbors.remove(neighbor); - } - - public int getId() { - return id; - } - - public void setId(int id) { - this.id = id; - } - - } - -} diff --git a/src/main/java/electrosphere/server/pathfinding/Pathfinder.java b/src/main/java/electrosphere/server/pathfinding/Pathfinder.java new file mode 100644 index 00000000..f766587e --- /dev/null +++ b/src/main/java/electrosphere/server/pathfinding/Pathfinder.java @@ -0,0 +1,92 @@ +package electrosphere.server.pathfinding; + +import java.util.LinkedList; +import java.util.List; + +import org.joml.Vector3d; +import org.recast4j.detour.DefaultQueryFilter; +import org.recast4j.detour.FindNearestPolyResult; +import org.recast4j.detour.MeshData; +import org.recast4j.detour.NavMesh; +import org.recast4j.detour.NavMeshQuery; +import org.recast4j.detour.QueryFilter; +import org.recast4j.detour.Result; +import org.recast4j.detour.StraightPathItem; + +/** + * Performs pathfinding + */ +public class Pathfinder { + + /** + * Maximum points in a straight path + */ + static final int MAX_STRAIGHT_PATH_POINTS = 100; + + /** + * Solves for a path + * @param mesh The navmesh + * @param startPos The start point + * @param endPos The end point + * @return The set of points to path along + */ + public List solve(MeshData mesh, Vector3d startPos, Vector3d endPos){ + List rVal = new LinkedList(); + + //construct objects + NavMesh navMesh = new NavMesh(mesh,6,0); + NavMeshQuery query = new NavMeshQuery(navMesh); + QueryFilter filter = new DefaultQueryFilter(); + + //convert points to correct datatypes + float[] startArr = new float[]{(float)startPos.x, (float)startPos.y, (float)startPos.z}; + float[] endArr = new float[]{(float)endPos.x, (float)endPos.y, (float)endPos.z}; + float[] polySearchBounds = new float[]{10,10,10}; + + //find start poly + Result startPolyResult = query.findNearestPoly(startArr, polySearchBounds, filter); + if(startPolyResult.failed()){ + String message = "Failed to solve for start polygon!\n" + + startPolyResult.message + ; + throw new Error(message); + } + long startRef = startPolyResult.result.getNearestRef(); + + //find end poly + Result endPolyResult = query.findNearestPoly(endArr, polySearchBounds, filter); + if(endPolyResult.failed()){ + String message = "Failed to solve for end polygon!\n" + + endPolyResult.message + ; + throw new Error(message); + } + long endRef = endPolyResult.result.getNearestRef(); + + //solve path + Result> pathResult = query.findPath(startRef, endRef, startArr, endArr, filter); + if(pathResult.failed()){ + String message = "Failed to solve for path!\n" + + pathResult.message + ; + throw new Error(message); + } + + //straighten the path ("string pull") + Result> straightPathResult = query.findStraightPath(startArr, endArr, pathResult.result, MAX_STRAIGHT_PATH_POINTS, 0); + if(straightPathResult.failed()){ + String message = "Failed to straighten path!\n" + + straightPathResult.message + ; + throw new Error(message); + } + + //convert to usable structures + for(StraightPathItem pathItem : straightPathResult.result){ + rVal.add(new Vector3d(pathItem.getPos()[0],pathItem.getPos()[1],pathItem.getPos()[2])); + } + + return rVal; + } + +} diff --git a/src/main/java/electrosphere/server/pathfinding/blocker/NavBlocker.java b/src/main/java/electrosphere/server/pathfinding/blocker/NavBlocker.java deleted file mode 100644 index d213cb24..00000000 --- a/src/main/java/electrosphere/server/pathfinding/blocker/NavBlocker.java +++ /dev/null @@ -1,32 +0,0 @@ -package electrosphere.server.pathfinding.blocker; - -import electrosphere.server.physics.terrain.manager.ServerTerrainChunk; - -/** - * - * Blocks navigation calculations for a defined area - * - * Why it's own class? in case we want to use separate logic for non-heightfield chunks later (dungeons mby) - * - */ -public class NavBlocker { - - boolean[][] heightfieldBlocker; - - public NavBlocker(){ - heightfieldBlocker = new boolean[ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION]; - } - - public NavBlocker(boolean[][] field){ - heightfieldBlocker = field; - } - - public boolean[][] getHeightfieldBlocker(){ - return heightfieldBlocker; - } - - public void setHeightfieldBlockerValue(int x, int y, boolean value){ - heightfieldBlocker[x][y] = value; - } - -} diff --git a/src/main/java/electrosphere/server/pathfinding/blocker/NavTerrainBlockerCache.java b/src/main/java/electrosphere/server/pathfinding/blocker/NavTerrainBlockerCache.java deleted file mode 100644 index 86587933..00000000 --- a/src/main/java/electrosphere/server/pathfinding/blocker/NavTerrainBlockerCache.java +++ /dev/null @@ -1,57 +0,0 @@ -package electrosphere.server.pathfinding.blocker; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * A cache of the blocker fields for terrain meshes - */ -public class NavTerrainBlockerCache { - //Basic idea is we associate string that contains chunk x&y with elevation - //While we incur a penalty with converting ints -> string, think this will - //offset regenerating the array every time we want a new one - int cacheSize = 50; - Map navBlockerMapCache = new HashMap(); - List navBlockerMapCacheContents = new ArrayList(); - - - public String getKey(int x, int y){ - return x + "_" + y; - } - - public NavBlocker getBlocker(int x, int y){ - NavBlocker rVal; - String key = getKey(x,y); - //if in cache - if(navBlockerMapCache.containsKey(key)){ - navBlockerMapCacheContents.remove(key); - navBlockerMapCacheContents.add(0, key); - rVal = navBlockerMapCache.get(key); - return rVal; - } else { - //else fetch from sql if available - - } - //else, create an empty one I guess - rVal = new NavBlocker(); - rVal.setHeightfieldBlockerValue(5,5,true); - rVal.setHeightfieldBlockerValue(6,5,true); - rVal.setHeightfieldBlockerValue(5,6,true); - rVal.setHeightfieldBlockerValue(6,6,true); - rVal.setHeightfieldBlockerValue(7,5,true); - rVal.setHeightfieldBlockerValue(11,5,true); - rVal.setHeightfieldBlockerValue(5,8,true); - rVal.setHeightfieldBlockerValue(5,22,true); - rVal.setHeightfieldBlockerValue(5,50,true); - if(navBlockerMapCache.size() > cacheSize){ - String oldChunk = navBlockerMapCacheContents.remove(navBlockerMapCacheContents.size() - 1); - navBlockerMapCache.remove(oldChunk); - } - navBlockerMapCacheContents.add(0, key); - navBlockerMapCache.put(key, rVal); - return rVal; - } - -} diff --git a/src/main/java/electrosphere/server/pathfinding/navmesh/NavCube.java b/src/main/java/electrosphere/server/pathfinding/navmesh/NavCube.java deleted file mode 100644 index 723a4ac3..00000000 --- a/src/main/java/electrosphere/server/pathfinding/navmesh/NavCube.java +++ /dev/null @@ -1,54 +0,0 @@ -package electrosphere.server.pathfinding.navmesh; - -import java.util.LinkedList; -import java.util.List; -import org.joml.Vector3d; - -/** - * - * @author satellite - */ - -/** - * Axis aligned bounding boxes used as nodes in pathfinding navmeshes - * Inclusive of boundary points on both minimum and maximum - */ - -public class NavCube extends NavShape { - - Vector3d minPoint; - Vector3d maxPoint; - - List neighbors = new LinkedList(); - - - public NavCube(double minX, double minY, double minZ, double maxX, double maxY, double maxZ){ - minPoint = new Vector3d(minX, minY, minZ); - maxPoint = new Vector3d(maxX, maxY, maxZ); - } - - @Override - public void addNodeNeighbor(NavShape neighbor){ - neighbors.add(neighbor); - } - - @Override - public List getNodeNeighbors(){ - return neighbors; - } - - @Override - public boolean containsPoint(double x, double y, double z){ - return x >= minPoint.x && y >= minPoint.y && z >= minPoint.z && x <= maxPoint.x && y <= maxPoint.y && z <= maxPoint.z; - } - - public Vector3d getMinPoint(){ - return minPoint; - } - - public Vector3d getMaxPoint(){ - return maxPoint; - } - - -} diff --git a/src/main/java/electrosphere/server/pathfinding/navmesh/NavMesh.java b/src/main/java/electrosphere/server/pathfinding/navmesh/NavMesh.java deleted file mode 100644 index 605bf30c..00000000 --- a/src/main/java/electrosphere/server/pathfinding/navmesh/NavMesh.java +++ /dev/null @@ -1,43 +0,0 @@ -package electrosphere.server.pathfinding.navmesh; - -import java.util.LinkedList; -import java.util.List; - -/** - * - * @author satellite - */ -public class NavMesh { - - //nav method, ie walking, flying, climbing, swimming, etc - String method; - - List navNodes = new LinkedList(); - List meshNeighbors = new LinkedList(); - - public void addMeshNeighbor(NavMesh neighbor){ - meshNeighbors.add(neighbor); - } - - public List getMeshNeighbors(){ - return meshNeighbors; - } - - public void addNode(NavShape node){ - navNodes.add(node); - } - - public List getNodes(){ - return navNodes; - } - - public boolean containsPoint(double x, double y, double z){ - for(NavShape shape : navNodes){ - if(shape.containsPoint(x, y, z)){ - return true; - } - } - return false; - } - -} diff --git a/src/main/java/electrosphere/server/pathfinding/navmesh/NavShape.java b/src/main/java/electrosphere/server/pathfinding/navmesh/NavShape.java deleted file mode 100644 index 12158897..00000000 --- a/src/main/java/electrosphere/server/pathfinding/navmesh/NavShape.java +++ /dev/null @@ -1,17 +0,0 @@ -package electrosphere.server.pathfinding.navmesh; - -import java.util.List; - -/** - * - * @author satellite - */ -public abstract class NavShape { - - public abstract void addNodeNeighbor(NavShape neighbor); - - public abstract List getNodeNeighbors(); - - public abstract boolean containsPoint(double x, double y, double z); - -} diff --git a/src/main/java/electrosphere/server/pathfinding/path/Waypoint.java b/src/main/java/electrosphere/server/pathfinding/path/Waypoint.java deleted file mode 100644 index 83bf63bd..00000000 --- a/src/main/java/electrosphere/server/pathfinding/path/Waypoint.java +++ /dev/null @@ -1,12 +0,0 @@ -package electrosphere.server.pathfinding.path; - -import org.joml.Vector3d; - -/** - * - * @author satellite - */ -public class Waypoint { - String method; //ie walking, flying, climbing, swimming, etc - Vector3d position; -} diff --git a/src/main/java/electrosphere/server/physics/terrain/manager/ServerTerrainManager.java b/src/main/java/electrosphere/server/physics/terrain/manager/ServerTerrainManager.java index e97c1d7c..a0966975 100644 --- a/src/main/java/electrosphere/server/physics/terrain/manager/ServerTerrainManager.java +++ b/src/main/java/electrosphere/server/physics/terrain/manager/ServerTerrainManager.java @@ -169,8 +169,10 @@ public class ServerTerrainManager { FileUtils.saveBinaryToSavePath(saveName, "./biome.dat", shortBuff.array()); } //for each chunk, save via disk map - for(ServerTerrainChunk chunk : this.chunkCache.getFullRes()){ - chunkDiskMap.saveToDisk(chunk); + if(this.chunkCache != null){ + for(ServerTerrainChunk chunk : this.chunkCache.getFullRes()){ + chunkDiskMap.saveToDisk(chunk); + } } //save disk map itself if(chunkDiskMap != null){