pathfinding work
Some checks reported errors
studiorailgun/Renderer/pipeline/head Something is wrong with the build of this commit
Some checks reported errors
studiorailgun/Renderer/pipeline/head Something is wrong with the build of this commit
This commit is contained in:
parent
277c9303ca
commit
f64d360d14
4
.vscode/settings.json
vendored
4
.vscode/settings.json
vendored
@ -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"
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,49 +0,0 @@
|
||||
/* DO NOT EDIT THIS FILE - it is machine generated */
|
||||
#include <jni.h>
|
||||
/* 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
|
||||
@ -1,41 +0,0 @@
|
||||
/* DO NOT EDIT THIS FILE - it is machine generated */
|
||||
#include <jni.h>
|
||||
/* 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
|
||||
@ -0,0 +1,49 @@
|
||||
/* DO NOT EDIT THIS FILE - it is machine generated */
|
||||
#include <jni.h>
|
||||
/* 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
|
||||
@ -0,0 +1,41 @@
|
||||
/* DO NOT EDIT THIS FILE - it is machine generated */
|
||||
#include <jni.h>
|
||||
/* 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
|
||||
@ -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;
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
#include <stdint.h>
|
||||
|
||||
//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"
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
#include <sys/time.h>
|
||||
|
||||
//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"
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
#include <jni.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#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
|
||||
){
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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<ServerDataCell> loadedDataCells = new HashSet<ServerDataCell>();
|
||||
|
||||
//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();
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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<Player> activePlayers = new HashSet<Player>();
|
||||
|
||||
/**
|
||||
* The navmesh for the data cell
|
||||
*/
|
||||
NavMesh navMesh;
|
||||
private Set<Player> activePlayers = new HashSet<Player>();
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
||||
@ -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<Long, PhysicsDataCell> posPhysicsMap,
|
||||
Map<Long, ServerDataCell> groundDataCells,
|
||||
Map<ServerDataCell,GriddedDataCellTrackingData> 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<Vector3d> findPath(Vector3d start, Vector3d end) {
|
||||
throw new UnsupportedOperationException("Unimplemented method 'findPath'");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -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<Vector3d> findPath(Vector3d start, Vector3d end);
|
||||
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -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<NavMesh> meshes = new LinkedList<NavMesh>();
|
||||
|
||||
public ChunkMeshList(ServerTerrainChunk parent){
|
||||
chunk = parent;
|
||||
}
|
||||
|
||||
public void addMesh(NavMesh mesh){
|
||||
meshes.add(mesh);
|
||||
}
|
||||
|
||||
public List<NavMesh> getMeshes(){
|
||||
return meshes;
|
||||
}
|
||||
|
||||
public ServerTerrainChunk getChunk(){
|
||||
return chunk;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@ -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<NavMesh> meshes = new LinkedList<NavMesh>();
|
||||
Map<ServerTerrainChunk,ChunkMeshList> chunkToMeshListMap = new HashMap<ServerTerrainChunk,ChunkMeshList>();
|
||||
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<NavMesh> getMeshes(){
|
||||
return meshes;
|
||||
}
|
||||
|
||||
public List<NavMesh> navigateMeshToMesh(NavMesh startMesh, NavMesh endMesh){
|
||||
List<NavMesh> rVal = null;
|
||||
return rVal;
|
||||
}
|
||||
|
||||
public NavBlocker getNavBlockerForChunk(int x, int y){
|
||||
NavBlocker rVal = null;
|
||||
return rVal;
|
||||
}
|
||||
|
||||
public NavTerrainBlockerCache getBlockerCache(){
|
||||
return blockerCache;
|
||||
}
|
||||
|
||||
}
|
||||
@ -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<Waypoint> navigatePointToPointInMesh(NavMesh mesh, Vector3d start, Vector3d end){
|
||||
|
||||
List<Waypoint> rVal = new LinkedList<Waypoint>();
|
||||
|
||||
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<NavShape> openSet = new LinkedList<NavShape>();
|
||||
List<NavShape> closedSet = new LinkedList<NavShape>();
|
||||
PriorityQueue<SetItem> pathItemsQueue = new PriorityQueue<SetItem>();
|
||||
Map<NavShape,SetItem> pathItems = new HashMap<NavShape,SetItem>();
|
||||
|
||||
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<SetItem> 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> {
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@ -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<FirstPhaseBox> firstPassBoxes = new LinkedList<FirstPhaseBox>();
|
||||
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<SecondPhaseBox> secondPhaseBoxes = new LinkedList<SecondPhaseBox>();
|
||||
List<SecondPhaseBox> toRemove = new LinkedList<SecondPhaseBox>();
|
||||
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<SecondPhaseBox> neighborUpdateList = new LinkedList<SecondPhaseBox>();
|
||||
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<SecondPhaseBox> neighbors = new LinkedList<SecondPhaseBox>();
|
||||
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<SecondPhaseBox> 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -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<Vector3d> solve(MeshData mesh, Vector3d startPos, Vector3d endPos){
|
||||
List<Vector3d> rVal = new LinkedList<Vector3d>();
|
||||
|
||||
//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<FindNearestPolyResult> 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<FindNearestPolyResult> 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<List<Long>> 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<List<StraightPathItem>> 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;
|
||||
}
|
||||
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@ -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<String, NavBlocker> navBlockerMapCache = new HashMap<String, NavBlocker>();
|
||||
List<String> navBlockerMapCacheContents = new ArrayList<String>();
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
@ -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<NavShape> neighbors = new LinkedList<NavShape>();
|
||||
|
||||
|
||||
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<NavShape> 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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -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<NavShape> navNodes = new LinkedList<NavShape>();
|
||||
List<NavMesh> meshNeighbors = new LinkedList<NavMesh>();
|
||||
|
||||
public void addMeshNeighbor(NavMesh neighbor){
|
||||
meshNeighbors.add(neighbor);
|
||||
}
|
||||
|
||||
public List<NavMesh> getMeshNeighbors(){
|
||||
return meshNeighbors;
|
||||
}
|
||||
|
||||
public void addNode(NavShape node){
|
||||
navNodes.add(node);
|
||||
}
|
||||
|
||||
public List<NavShape> 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;
|
||||
}
|
||||
|
||||
}
|
||||
@ -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<NavShape> getNodeNeighbors();
|
||||
|
||||
public abstract boolean containsPoint(double x, double y, double z);
|
||||
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
@ -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){
|
||||
|
||||
Loading…
Reference in New Issue
Block a user