Physics fixes
This commit is contained in:
parent
ceb5a5aaf8
commit
c71f4fecad
3
buildNumber.properties
Normal file
3
buildNumber.properties
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
#maven.buildNumber.plugin properties file
|
||||||
|
#Fri Jul 14 20:48:01 EDT 2023
|
||||||
|
buildNumber=4
|
||||||
8
pom.xml
8
pom.xml
@ -13,6 +13,14 @@
|
|||||||
<joml.version>1.9.19</joml.version>
|
<joml.version>1.9.19</joml.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
|
<!-- Used for build number plugin because it LITERALLY WONT LET YOU NOT HAVE SCM-->
|
||||||
|
<scm>
|
||||||
|
<connection>scm:svn:http://127.0.0.1/dummy</connection>
|
||||||
|
<developerConnection>scm:svn:https://127.0.0.1/dummy</developerConnection>
|
||||||
|
<tag>HEAD</tag>
|
||||||
|
<url>http://127.0.0.1/dummy</url>
|
||||||
|
</scm>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<!-- generic LWJGL runtimes -->
|
<!-- generic LWJGL runtimes -->
|
||||||
<!--License: BSD-->
|
<!--License: BSD-->
|
||||||
|
|||||||
1
saves/default/chunk.map
Normal file
1
saves/default/chunk.map
Normal file
@ -0,0 +1 @@
|
|||||||
|
{}
|
||||||
@ -49,10 +49,10 @@ import electrosphere.entity.EntityDataStrings;
|
|||||||
import electrosphere.entity.EntityUtils;
|
import electrosphere.entity.EntityUtils;
|
||||||
import electrosphere.entity.state.collidable.Impulse;
|
import electrosphere.entity.state.collidable.Impulse;
|
||||||
import electrosphere.entity.types.hitbox.HitboxData;
|
import electrosphere.entity.types.hitbox.HitboxData;
|
||||||
|
import electrosphere.logger.LoggerInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* TODO: https://stackoverflow.com/questions/32445679/3d-java-collision-detection-with-jbullet
|
|
||||||
*/
|
*/
|
||||||
public class CollisionEngine {
|
public class CollisionEngine {
|
||||||
|
|
||||||
@ -85,58 +85,6 @@ public class CollisionEngine {
|
|||||||
world = OdeHelper.createWorld();
|
world = OdeHelper.createWorld();
|
||||||
space = OdeHelper.createHashSpace();
|
space = OdeHelper.createHashSpace();
|
||||||
contactgroup = OdeHelper.createJointGroup();
|
contactgroup = OdeHelper.createJointGroup();
|
||||||
|
|
||||||
|
|
||||||
// callback = new InternalTickCallback(){
|
|
||||||
// @Override
|
|
||||||
// public void internalTick(DynamicsWorld dw, float f) {
|
|
||||||
// Dispatcher dispatcher = dw.getDispatcher();
|
|
||||||
// int manifoldCount = dispatcher.getNumManifolds();
|
|
||||||
// for (int i = 0; i < manifoldCount; i++) {
|
|
||||||
// PersistentManifold manifold = dispatcher.getManifoldByIndexInternal(i);
|
|
||||||
// // The following two lines are optional.
|
|
||||||
// CollisionObject object1 = (CollisionObject)manifold.getBody0();
|
|
||||||
// CollisionObject object2 = (CollisionObject)manifold.getBody1();
|
|
||||||
// Collidable physicsObject1 = (Collidable)object1.getUserPointer();
|
|
||||||
// Collidable physicsObject2 = (Collidable)object2.getUserPointer();
|
|
||||||
// boolean hit = false;
|
|
||||||
// Vector3d normal = null;
|
|
||||||
// Vector3d localPosition1 = null;
|
|
||||||
// Vector3d localPosition2 = null;
|
|
||||||
// Vector3d worldPosA = null;
|
|
||||||
// Vector3d worldPosB = null;
|
|
||||||
// float magnitude = 0.0f;
|
|
||||||
// for (int j = 0; j < manifold.getNumContacts(); j++) {
|
|
||||||
// ManifoldPoint contactPoint = manifold.getContactPoint(j);
|
|
||||||
// if (contactPoint.getDistance() < 0.0f) {
|
|
||||||
// magnitude = -contactPoint.getDistance();
|
|
||||||
// //linear dampen
|
|
||||||
// // magnitude = magnitude;// * (float)Math.pow(1.0f - linearDamping,deltaTime * 2);
|
|
||||||
// hit = true;
|
|
||||||
// // System.out.println(contactPoint.positionWorldOnA + " " + contactPoint.positionWorldOnB);
|
|
||||||
// normal = new Vector3d(contactPoint.normalWorldOnB.x,contactPoint.normalWorldOnB.y,contactPoint.normalWorldOnB.z);
|
|
||||||
// localPosition1 = new Vector3d(contactPoint.localPointA.x,contactPoint.localPointA.y,contactPoint.localPointA.z);
|
|
||||||
// localPosition2 = new Vector3d(contactPoint.localPointB.x,contactPoint.localPointB.y,contactPoint.localPointB.z);
|
|
||||||
// worldPosA = new Vector3d(contactPoint.positionWorldOnA.x,contactPoint.positionWorldOnA.y,contactPoint.positionWorldOnA.z);
|
|
||||||
// worldPosB = new Vector3d(contactPoint.positionWorldOnB.x,contactPoint.positionWorldOnB.y,contactPoint.positionWorldOnB.z);
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// if (hit) {
|
|
||||||
// resolveCollision(physicsObject1,physicsObject2, new Vector3d(normal).mul(-1.0), localPosition1, worldPosA, magnitude);
|
|
||||||
// resolveCollision(physicsObject2,physicsObject1, normal, localPosition2, worldPosB, magnitude);
|
|
||||||
// // System.out.println("HIT + " + normal);
|
|
||||||
// // Collision happened between physicsObject1 and physicsObject2. Collision normal is in variable 'normal'.
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
// world.setInternalTickCallback(callback, world);
|
|
||||||
|
|
||||||
//https://pybullet.org/Bullet/phpBB3/viewtopic.php?t=11507
|
|
||||||
//https://www.google.com/search?client=firefox-b-1-d&q=bullet+set+position+and+check+if+collision
|
|
||||||
//https://pybullet.org/Bullet/phpBB3/viewtopic.php?t=11399
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -457,8 +405,8 @@ public class CollisionEngine {
|
|||||||
|
|
||||||
public void listBodyPositions(){
|
public void listBodyPositions(){
|
||||||
for(DBody body : bodies){
|
for(DBody body : bodies){
|
||||||
System.out.println(body);
|
LoggerInterface.loggerEngine.INFO("" + body);
|
||||||
System.out.println(PhysicsUtils.getRigidBodyPosition(body));
|
LoggerInterface.loggerEngine.INFO("" + PhysicsUtils.getRigidBodyPosition(body));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -740,5 +688,31 @@ public class CollisionEngine {
|
|||||||
body.setQuaternion(PhysicsUtils.jomlQuatToOdeQuat(rotation));
|
body.setQuaternion(PhysicsUtils.jomlQuatToOdeQuat(rotation));
|
||||||
spaceLock.release();
|
spaceLock.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the position of the body in a thread-safe way
|
||||||
|
* @param body The body to get the position of
|
||||||
|
* @return The position
|
||||||
|
*/
|
||||||
|
protected Vector3d getBodyPosition(DBody body){
|
||||||
|
Vector3d rVal = null;
|
||||||
|
spaceLock.acquireUninterruptibly();
|
||||||
|
rVal = PhysicsUtils.odeVecToJomlVec(body.getPosition());
|
||||||
|
spaceLock.release();
|
||||||
|
return rVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the rotation of the body in a thread-safe way
|
||||||
|
* @param body The body to get the rotation of
|
||||||
|
* @return The rotation
|
||||||
|
*/
|
||||||
|
protected Quaterniond getBodyRotation(DBody body){
|
||||||
|
Quaterniond rVal = null;
|
||||||
|
spaceLock.acquireUninterruptibly();
|
||||||
|
rVal = PhysicsUtils.odeQuatToJomlQuat(body.getQuaternion());
|
||||||
|
spaceLock.release();
|
||||||
|
return rVal;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,7 +18,6 @@ import org.ode4j.ode.DMass;
|
|||||||
import org.ode4j.ode.DPlane;
|
import org.ode4j.ode.DPlane;
|
||||||
import org.ode4j.ode.DSphere;
|
import org.ode4j.ode.DSphere;
|
||||||
import org.ode4j.ode.DTriMesh;
|
import org.ode4j.ode.DTriMesh;
|
||||||
import org.ode4j.ode.OdeHelper;
|
|
||||||
|
|
||||||
import electrosphere.collision.collidable.Collidable;
|
import electrosphere.collision.collidable.Collidable;
|
||||||
import electrosphere.engine.Globals;
|
import electrosphere.engine.Globals;
|
||||||
@ -105,20 +104,13 @@ public class PhysicsUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
DBody body = OdeHelper.createBody(null);
|
|
||||||
|
|
||||||
DTriMesh triMesh = collisionEngine.createTrimeshGeom(vertices,indices);
|
DTriMesh triMesh = collisionEngine.createTrimeshGeom(vertices,indices);
|
||||||
triMesh.setBody(body);
|
|
||||||
|
DBody body = collisionEngine.createDBody(triMesh);
|
||||||
// terrainRigidBody.setFriction(1f);
|
|
||||||
|
|
||||||
Globals.clientSceneWrapper.getCollisionEngine().registerCollisionObject(body, new Collidable(terrain,Collidable.TYPE_TERRAIN));
|
Globals.clientSceneWrapper.getCollisionEngine().registerCollisionObject(body, new Collidable(terrain,Collidable.TYPE_TERRAIN));
|
||||||
|
|
||||||
// terrainRigidBody.getAabb(aabbMin, aabbMax);
|
|
||||||
//
|
|
||||||
// System.out.println("aabbMin: " + aabbMin + " aabbMax: " + aabbMax);
|
|
||||||
|
|
||||||
|
|
||||||
terrain.putData(EntityDataStrings.PHYSICS_COLLISION_BODY, body);
|
terrain.putData(EntityDataStrings.PHYSICS_COLLISION_BODY, body);
|
||||||
|
|
||||||
return body;
|
return body;
|
||||||
@ -200,7 +192,7 @@ public class PhysicsUtils {
|
|||||||
*/
|
*/
|
||||||
public static DBody generateRigidBodyFromAIScene(CollisionEngine collisionEngine, AIScene scene){
|
public static DBody generateRigidBodyFromAIScene(CollisionEngine collisionEngine, AIScene scene){
|
||||||
|
|
||||||
DBody body = OdeHelper.createBody(collisionEngine.getDWorld());
|
DBody body = collisionEngine.createDBody(null);
|
||||||
|
|
||||||
PointerBuffer meshesBuffer = scene.mMeshes();
|
PointerBuffer meshesBuffer = scene.mMeshes();
|
||||||
while(meshesBuffer.hasRemaining()){
|
while(meshesBuffer.hasRemaining()){
|
||||||
@ -244,14 +236,6 @@ public class PhysicsUtils {
|
|||||||
return body;
|
return body;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a test plane body to the engine scene
|
|
||||||
* @param engine The engine
|
|
||||||
*/
|
|
||||||
public static void addTestPlaneRigidBody(CollisionEngine engine){
|
|
||||||
DPlane plane = OdeHelper.createPlane(engine.getSpace(), 0, 1, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the current position of a rigid body as a joml vector
|
* Gets the current position of a rigid body as a joml vector
|
||||||
* @param body The dbody
|
* @param body The dbody
|
||||||
@ -308,17 +292,6 @@ public class PhysicsUtils {
|
|||||||
collisionEngine.setBodyTransform(body, position, rotation);
|
collisionEngine.setBodyTransform(body, position, rotation);
|
||||||
}
|
}
|
||||||
|
|
||||||
// public static RigidBody getUnitCylinderRigidBody(float mass){
|
|
||||||
// CylinderShape cylinderShape = new CylinderShape(jomlToVecmathVector3f(new Vector3f(1.0f,1.0f,1.0f)));
|
|
||||||
// DefaultMotionState defaultMotionState = new DefaultMotionState(new Transform(new javax.vecmath.Matrix4f(new javax.vecmath.Quat4f(0,1,0,1),new javax.vecmath.Vector3f(0,0,0),1.0f)));
|
|
||||||
// RigidBodyConstructionInfo cylinderRigidBodyCI = new RigidBodyConstructionInfo(mass, defaultMotionState, cylinderShape);
|
|
||||||
// RigidBody cylinderRigidBody = new RigidBody(cylinderRigidBodyCI);
|
|
||||||
//// cylinderRigidBody.setMassProps(mass, PhysicsUtils.jomlToVecmathVector3f(new Vector3f(1.0f,1.0f,1.0f)));
|
|
||||||
// cylinderRigidBody.clearForces();
|
|
||||||
// return cylinderRigidBody;
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
//The width of a plane rigid body
|
//The width of a plane rigid body
|
||||||
//It's really a box under the hood
|
//It's really a box under the hood
|
||||||
static final double PLANE_WIDTH = 0.3;
|
static final double PLANE_WIDTH = 0.3;
|
||||||
|
|||||||
@ -1011,7 +1011,7 @@ public class ControlHandler {
|
|||||||
void setAlwaysOnDebugControls(){
|
void setAlwaysOnDebugControls(){
|
||||||
alwaysOnDebugControlList.add(controls.get(DEBUG_OPEN_DEBUG_MENU));
|
alwaysOnDebugControlList.add(controls.get(DEBUG_OPEN_DEBUG_MENU));
|
||||||
controls.get(DEBUG_OPEN_DEBUG_MENU).setOnPress(new ControlMethod(){public void execute(){
|
controls.get(DEBUG_OPEN_DEBUG_MENU).setOnPress(new ControlMethod(){public void execute(){
|
||||||
System.out.println("open debug menu");
|
LoggerInterface.loggerEngine.INFO("open debug menu");
|
||||||
// Window mainMenuWindow = new Window(0, 0, Globals.WINDOW_WIDTH, Globals.WINDOW_HEIGHT);
|
// Window mainMenuWindow = new Window(0, 0, Globals.WINDOW_WIDTH, Globals.WINDOW_HEIGHT);
|
||||||
Window mainMenuInGame = MenuGeneratorsDebug.createTopLevelDebugMenu();
|
Window mainMenuInGame = MenuGeneratorsDebug.createTopLevelDebugMenu();
|
||||||
// mainMenuWindow.addChild(mainMenuInGame);
|
// mainMenuWindow.addChild(mainMenuInGame);
|
||||||
|
|||||||
@ -17,6 +17,7 @@ import electrosphere.net.parser.net.message.TerrainMessage;
|
|||||||
import electrosphere.net.server.ServerConnectionHandler;
|
import electrosphere.net.server.ServerConnectionHandler;
|
||||||
import electrosphere.renderer.ui.Window;
|
import electrosphere.renderer.ui.Window;
|
||||||
import electrosphere.server.saves.SaveUtils;
|
import electrosphere.server.saves.SaveUtils;
|
||||||
|
import electrosphere.server.terrain.generation.OverworldChunkGenerator;
|
||||||
import electrosphere.server.terrain.manager.ServerTerrainManager;
|
import electrosphere.server.terrain.manager.ServerTerrainManager;
|
||||||
import electrosphere.util.FileUtils;
|
import electrosphere.util.FileUtils;
|
||||||
import electrosphere.controls.ControlHandler;
|
import electrosphere.controls.ControlHandler;
|
||||||
@ -31,7 +32,7 @@ public class DebugSPWorldLoading {
|
|||||||
WindowUtils.replaceMainMenuContents(MenuGenerators.createEmptyMainMenu());
|
WindowUtils.replaceMainMenuContents(MenuGenerators.createEmptyMainMenu());
|
||||||
loadingWindow.setVisible(true);
|
loadingWindow.setVisible(true);
|
||||||
|
|
||||||
Globals.serverTerrainManager = new ServerTerrainManager(2000,50,0.0f,0);
|
Globals.serverTerrainManager = new ServerTerrainManager(2000,50,0.0f,0, new OverworldChunkGenerator());
|
||||||
if(!SaveUtils.getSaves().contains("random_sp_world")){
|
if(!SaveUtils.getSaves().contains("random_sp_world")){
|
||||||
//
|
//
|
||||||
//the juicy server GENERATION part
|
//the juicy server GENERATION part
|
||||||
@ -95,32 +96,4 @@ public class DebugSPWorldLoading {
|
|||||||
ClientLoading.loadClientWorld();
|
ClientLoading.loadClientWorld();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static void initWorldBaseGraphicalEntities(){
|
|
||||||
/*
|
|
||||||
|
|
||||||
Skybox
|
|
||||||
|
|
||||||
*/
|
|
||||||
// Model skyboxModel = Globals.assetManager.fetchModel(AssetDataStrings.ASSET_STRING_SKYBOX_BASIC);
|
|
||||||
// Globals.skybox = EntityUtils.spawnDrawableEntity(AssetDataStrings.ASSET_STRING_SKYBOX_BASIC);
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
Player Camera
|
|
||||||
|
|
||||||
*/
|
|
||||||
Globals.playerCamera = CameraEntityUtils.spawnPlayerEntityTrackingCameraEntity(new Vector3f(1,0,1), new Vector3f(0,0,1));
|
|
||||||
// Globals.playerCamera = CameraEntityUtils.spawnPlayerEntityAirplaneTrackingCameraEntity(new Vector3f(1,0,1), new Vector3f(0,0,1));
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
Targeting crosshair
|
|
||||||
*/
|
|
||||||
Crosshair.initCrossHairEntity();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -41,6 +41,7 @@ import electrosphere.server.datacell.Realm;
|
|||||||
import electrosphere.server.saves.SaveUtils;
|
import electrosphere.server.saves.SaveUtils;
|
||||||
import electrosphere.server.simulation.MacroSimulation;
|
import electrosphere.server.simulation.MacroSimulation;
|
||||||
import electrosphere.server.simulation.MicroSimulation;
|
import electrosphere.server.simulation.MicroSimulation;
|
||||||
|
import electrosphere.server.terrain.generation.OverworldChunkGenerator;
|
||||||
import electrosphere.server.terrain.manager.ServerTerrainManager;
|
import electrosphere.server.terrain.manager.ServerTerrainManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -60,7 +61,7 @@ public class LoadingUtils {
|
|||||||
Actually initialize the terrain manager
|
Actually initialize the terrain manager
|
||||||
*/
|
*/
|
||||||
float randomDampener = 0.0f; //0.25f;
|
float randomDampener = 0.0f; //0.25f;
|
||||||
Globals.serverTerrainManager = new ServerTerrainManager(2000,50,randomDampener,0);
|
Globals.serverTerrainManager = new ServerTerrainManager(2000,50,randomDampener,0,new OverworldChunkGenerator());
|
||||||
if(Globals.RUN_SERVER){
|
if(Globals.RUN_SERVER){
|
||||||
if(Globals.userSettings.gameplayGenerateWorld()){
|
if(Globals.userSettings.gameplayGenerateWorld()){
|
||||||
Globals.serverTerrainManager.generate();
|
Globals.serverTerrainManager.generate();
|
||||||
|
|||||||
@ -3,6 +3,7 @@ package electrosphere.engine.loadingthreads;
|
|||||||
import electrosphere.engine.Globals;
|
import electrosphere.engine.Globals;
|
||||||
import electrosphere.logger.LoggerInterface;
|
import electrosphere.logger.LoggerInterface;
|
||||||
import electrosphere.server.saves.SaveUtils;
|
import electrosphere.server.saves.SaveUtils;
|
||||||
|
import electrosphere.server.terrain.generation.OverworldChunkGenerator;
|
||||||
import electrosphere.server.terrain.manager.ServerTerrainManager;
|
import electrosphere.server.terrain.manager.ServerTerrainManager;
|
||||||
|
|
||||||
public class ServerLoading {
|
public class ServerLoading {
|
||||||
@ -15,7 +16,7 @@ public class ServerLoading {
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
//TODO: Globals.serverTerrainManager = new ServerTerrainManager(2000,50,100,randomDampener,0);
|
//TODO: Globals.serverTerrainManager = new ServerTerrainManager(2000,50,100,randomDampener,0);
|
||||||
Globals.serverTerrainManager = new ServerTerrainManager(2000,50,0.0f,0);
|
Globals.serverTerrainManager = new ServerTerrainManager(2000,50,0.0f,0, new OverworldChunkGenerator());
|
||||||
SaveUtils.loadSave(Globals.currentSaveName);
|
SaveUtils.loadSave(Globals.currentSaveName);
|
||||||
// LoadingUtils.initTerrainDataCellManager();
|
// LoadingUtils.initTerrainDataCellManager();
|
||||||
//TODO: set spawnpoint
|
//TODO: set spawnpoint
|
||||||
|
|||||||
@ -201,8 +201,12 @@ public class ClientCollidableTree implements BehaviorTree {
|
|||||||
|
|
||||||
//update collision engine of this thing's position
|
//update collision engine of this thing's position
|
||||||
CollidableTemplate template = (CollidableTemplate)parent.getData(EntityDataStrings.PHYSICS_MODEL_TEMPLATE);
|
CollidableTemplate template = (CollidableTemplate)parent.getData(EntityDataStrings.PHYSICS_MODEL_TEMPLATE);
|
||||||
body.setPosition(position.x + template.getOffsetX(),position.y + template.getOffsetY(),position.z + template.getOffsetZ());
|
PhysicsUtils.setRigidBodyTransform(
|
||||||
body.setQuaternion(PhysicsUtils.jomlQuatToOdeQuat(rotation));
|
Globals.clientSceneWrapper.getCollisionEngine(),
|
||||||
|
new Vector3d(position.x + template.getOffsetX(),position.y + template.getOffsetY(),position.z + template.getOffsetZ()),
|
||||||
|
rotation,
|
||||||
|
body
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -207,9 +207,12 @@ public class ServerCollidableTree implements BehaviorTree {
|
|||||||
|
|
||||||
//update collision engine of this thing's position
|
//update collision engine of this thing's position
|
||||||
CollidableTemplate template = (CollidableTemplate)parent.getData(EntityDataStrings.PHYSICS_MODEL_TEMPLATE);
|
CollidableTemplate template = (CollidableTemplate)parent.getData(EntityDataStrings.PHYSICS_MODEL_TEMPLATE);
|
||||||
body.setPosition(position.x + template.getOffsetX(),position.y + template.getOffsetY(),position.z + template.getOffsetZ());
|
PhysicsUtils.setRigidBodyTransform(
|
||||||
body.setQuaternion(PhysicsUtils.jomlQuatToOdeQuat(rotation));
|
parentRealm.getCollisionEngine(),
|
||||||
|
new Vector3d(position.x + template.getOffsetX(),position.y + template.getOffsetY(),position.z + template.getOffsetZ()),
|
||||||
|
rotation,
|
||||||
|
body
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -181,9 +181,6 @@ public class ClientGravityTree implements BehaviorTree {
|
|||||||
// hitFraction = 1;
|
// hitFraction = 1;
|
||||||
// }
|
// }
|
||||||
collidable.addImpulse(new Impulse(new Vector3d(0,-1,0), new Vector3d(0,0,0), new Vector3d(position), gravityDif,"gravity"));
|
collidable.addImpulse(new Impulse(new Vector3d(0,-1,0), new Vector3d(0,0,0), new Vector3d(position), gravityDif,"gravity"));
|
||||||
// System.out.println(hitFraction);
|
|
||||||
// bodyTransformMatrix = new javax.vecmath.Matrix4f(PhysicsUtils.jomlToVecmathQuaternionf(rotation),PhysicsUtils.jomlToVecmathVector3f(new Vector3f((float)position.x,(float)position.y,(float)position.z)),1.0f);
|
|
||||||
// body.setWorldTransform(new electrosphere.linearmath.Transform(bodyTransformMatrix));
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case NOT_ACTIVE:
|
case NOT_ACTIVE:
|
||||||
|
|||||||
@ -175,9 +175,6 @@ public class ServerGravityTree implements BehaviorTree {
|
|||||||
// hitFraction = 1;
|
// hitFraction = 1;
|
||||||
// }
|
// }
|
||||||
collidable.addImpulse(new Impulse(new Vector3d(0,-1,0), new Vector3d(0,0,0), new Vector3d(position), gravityDif,"gravity"));
|
collidable.addImpulse(new Impulse(new Vector3d(0,-1,0), new Vector3d(0,0,0), new Vector3d(position), gravityDif,"gravity"));
|
||||||
// System.out.println(hitFraction);
|
|
||||||
// bodyTransformMatrix = new javax.vecmath.Matrix4f(PhysicsUtils.jomlToVecmathQuaternionf(rotation),PhysicsUtils.jomlToVecmathVector3f(new Vector3f((float)position.x,(float)position.y,(float)position.z)),1.0f);
|
|
||||||
// body.setWorldTransform(new electrosphere.linearmath.Transform(bodyTransformMatrix));
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case NOT_ACTIVE:
|
case NOT_ACTIVE:
|
||||||
|
|||||||
@ -99,27 +99,25 @@ public class GroundMovementTree implements BehaviorTree {
|
|||||||
this.facing = facing;
|
this.facing = facing;
|
||||||
state = MovementTreeState.STARTUP;
|
state = MovementTreeState.STARTUP;
|
||||||
//if we aren't the server, alert the server we intend to walk forward
|
//if we aren't the server, alert the server we intend to walk forward
|
||||||
if(!Globals.RUN_SERVER){
|
Vector3d position = EntityUtils.getPosition(parent);
|
||||||
Vector3d position = EntityUtils.getPosition(parent);
|
Quaterniond rotation = EntityUtils.getRotation(parent);
|
||||||
Quaterniond rotation = EntityUtils.getRotation(parent);
|
Vector3d facingVector = CreatureUtils.getFacingVector(parent);
|
||||||
Vector3d facingVector = CreatureUtils.getFacingVector(parent);
|
float velocity = CreatureUtils.getVelocity(parent);
|
||||||
float velocity = CreatureUtils.getVelocity(parent);
|
Globals.clientConnection.queueOutgoingMessage(
|
||||||
Globals.clientConnection.queueOutgoingMessage(
|
EntityMessage.constructmoveUpdateMessage(
|
||||||
EntityMessage.constructmoveUpdateMessage(
|
Globals.clientSceneWrapper.mapClientToServerId(parent.getId()),
|
||||||
parent.getId(),
|
Main.getCurrentFrame(),
|
||||||
Main.getCurrentFrame(),
|
position.x,
|
||||||
position.x,
|
position.y,
|
||||||
position.y,
|
position.z,
|
||||||
position.z,
|
rotation.x,
|
||||||
rotation.x,
|
rotation.y,
|
||||||
rotation.y,
|
rotation.z,
|
||||||
rotation.z,
|
rotation.w,
|
||||||
rotation.w,
|
velocity,
|
||||||
velocity,
|
0 //magic number corresponding to state startup
|
||||||
0 //magic number corresponding to state startup
|
)
|
||||||
)
|
);
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,27 +129,25 @@ public class GroundMovementTree implements BehaviorTree {
|
|||||||
public void slowdown(){
|
public void slowdown(){
|
||||||
state = MovementTreeState.SLOWDOWN;
|
state = MovementTreeState.SLOWDOWN;
|
||||||
//if we aren't the server, alert the server we intend to slow down
|
//if we aren't the server, alert the server we intend to slow down
|
||||||
if(!Globals.RUN_SERVER){
|
Vector3d position = EntityUtils.getPosition(parent);
|
||||||
Vector3d position = EntityUtils.getPosition(parent);
|
Quaterniond rotation = EntityUtils.getRotation(parent);
|
||||||
Quaterniond rotation = EntityUtils.getRotation(parent);
|
Vector3d facingVector = CreatureUtils.getFacingVector(parent);
|
||||||
Vector3d facingVector = CreatureUtils.getFacingVector(parent);
|
float velocity = CreatureUtils.getVelocity(parent);
|
||||||
float velocity = CreatureUtils.getVelocity(parent);
|
Globals.clientConnection.queueOutgoingMessage(
|
||||||
Globals.clientConnection.queueOutgoingMessage(
|
EntityMessage.constructmoveUpdateMessage(
|
||||||
EntityMessage.constructmoveUpdateMessage(
|
Globals.clientSceneWrapper.mapClientToServerId(parent.getId()),
|
||||||
parent.getId(),
|
Main.getCurrentFrame(),
|
||||||
Main.getCurrentFrame(),
|
position.x,
|
||||||
position.x,
|
position.y,
|
||||||
position.y,
|
position.z,
|
||||||
position.z,
|
rotation.x,
|
||||||
rotation.x,
|
rotation.y,
|
||||||
rotation.y,
|
rotation.z,
|
||||||
rotation.z,
|
rotation.w,
|
||||||
rotation.w,
|
velocity,
|
||||||
velocity,
|
2 //magic number corresponding to state slowdown
|
||||||
2 //magic number corresponding to state slowdown
|
)
|
||||||
)
|
);
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void simulate(float deltaTime){
|
public void simulate(float deltaTime){
|
||||||
@ -233,15 +229,14 @@ public class GroundMovementTree implements BehaviorTree {
|
|||||||
// System.out.println(EntityUtils.getEntityPosition(parent));
|
// System.out.println(EntityUtils.getEntityPosition(parent));
|
||||||
// System.out.println(message.getpositionX() + " " + message.getpositionY() + " " + message.getpositionZ());
|
// System.out.println(message.getpositionX() + " " + message.getpositionY() + " " + message.getpositionZ());
|
||||||
//this should only fire on the client, we don't want the server snap updating due to client position reporting
|
//this should only fire on the client, we don't want the server snap updating due to client position reporting
|
||||||
if(!Globals.RUN_SERVER){
|
if(position.distance(message.getpositionX(),message.getpositionY(),message.getpositionZ()) > STATE_DIFFERENCE_HARD_UPDATE_THRESHOLD){
|
||||||
if(position.distance(message.getpositionX(),message.getpositionY(),message.getpositionZ()) > STATE_DIFFERENCE_HARD_UPDATE_THRESHOLD){
|
EntityUtils.getPosition(parent).set(message.getpositionX(),message.getpositionY(),message.getpositionZ());
|
||||||
EntityUtils.getPosition(parent).set(message.getpositionX(),message.getpositionY(),message.getpositionZ());
|
} else if(position.distance(message.getpositionX(),message.getpositionY(),message.getpositionZ()) > STATE_DIFFERENCE_SOFT_UPDATE_THRESHOLD){
|
||||||
} else if(position.distance(message.getpositionX(),message.getpositionY(),message.getpositionZ()) > STATE_DIFFERENCE_SOFT_UPDATE_THRESHOLD){
|
EntityUtils.getPosition(parent).add(new Vector3d(message.getpositionX(),message.getpositionY(),message.getpositionZ()).mul(SOFT_UPDATE_MULTIPLIER));
|
||||||
EntityUtils.getPosition(parent).add(new Vector3d(message.getpositionX(),message.getpositionY(),message.getpositionZ()).mul(SOFT_UPDATE_MULTIPLIER));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
//we want to always update the server facing vector with where the client says they're facing
|
//we want to always update the server facing vector with where the client says they're facing
|
||||||
CreatureUtils.setFacingVector(parent, new Vector3d(message.getrotationX(),message.getrotationY(),message.getrotationZ()));
|
EntityUtils.getRotation(parent).set(message.getrotationX(),message.getrotationY(),message.getrotationZ(),message.getrotationW());
|
||||||
|
// CreatureUtils.setFacingVector(parent, new Vector3d(message.getrotationX(),message.getrotationY(),message.getrotationZ()));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -274,14 +269,6 @@ public class GroundMovementTree implements BehaviorTree {
|
|||||||
state = MovementTreeState.MOVE;
|
state = MovementTreeState.MOVE;
|
||||||
}
|
}
|
||||||
CreatureUtils.setVelocity(parent, velocity);
|
CreatureUtils.setVelocity(parent, velocity);
|
||||||
// body.applyCentralForce(PhysicsUtils.jomlToVecmathVector3f(new Vector3f(movementVector.x,0,movementVector.z).normalize().mul(velocity)));
|
|
||||||
// EntityUtils.getRotation(parent).set(movementQuaternion);
|
|
||||||
// //move the entity
|
|
||||||
// newPosition = new Vector3d(position).add(new Vector3d(movementVector).mul(velocity).mul(Main.deltaTime));
|
|
||||||
// //check/update if collision
|
|
||||||
// if(!Globals.collisionEngine.checkCanOccupyPosition(Globals.commonWorldData, parent, newPosition)){
|
|
||||||
// newPosition = Globals.collisionEngine.suggestMovementPosition(Globals.commonWorldData, parent, newPosition);
|
|
||||||
// }
|
|
||||||
// //actually update
|
// //actually update
|
||||||
collidable.addImpulse(new Impulse(new Vector3d(movementVector), new Vector3d(0,0,0), new Vector3d(0,0,0), velocity * Main.deltaFrames, "movement"));
|
collidable.addImpulse(new Impulse(new Vector3d(movementVector), new Vector3d(0,0,0), new Vector3d(0,0,0), velocity * Main.deltaFrames, "movement"));
|
||||||
// position.set(newPosition);
|
// position.set(newPosition);
|
||||||
@ -308,14 +295,6 @@ public class GroundMovementTree implements BehaviorTree {
|
|||||||
velocity = maxNaturalVelocity;
|
velocity = maxNaturalVelocity;
|
||||||
CreatureUtils.setVelocity(parent, velocity);
|
CreatureUtils.setVelocity(parent, velocity);
|
||||||
}
|
}
|
||||||
// body.applyCentralForce(PhysicsUtils.jomlToVecmathVector3f(force));
|
|
||||||
// EntityUtils.getRotation(parent).set(movementQuaternion);
|
|
||||||
//check if can move forward (collision engine)
|
|
||||||
//if can, move forward by entity movement stats
|
|
||||||
// newPosition = new Vector3d(position).add(new Vector3d(movementVector).mul(velocity).mul(Main.deltaTime));
|
|
||||||
// if(!Globals.collisionEngine.checkCanOccupyPosition(Globals.commonWorldData, parent, newPosition)){
|
|
||||||
// newPosition = Globals.collisionEngine.suggestMovementPosition(Globals.commonWorldData, parent, newPosition);
|
|
||||||
// }
|
|
||||||
collidable.addImpulse(new Impulse(new Vector3d(movementVector), new Vector3d(0,0,0), new Vector3d(0,0,0), velocity * Main.deltaFrames, "movement"));
|
collidable.addImpulse(new Impulse(new Vector3d(movementVector), new Vector3d(0,0,0), new Vector3d(0,0,0), velocity * Main.deltaFrames, "movement"));
|
||||||
// position.set(newPosition);
|
// position.set(newPosition);
|
||||||
rotation.set(movementQuaternion);
|
rotation.set(movementQuaternion);
|
||||||
@ -350,13 +329,6 @@ public class GroundMovementTree implements BehaviorTree {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
CreatureUtils.setVelocity(parent, velocity);
|
CreatureUtils.setVelocity(parent, velocity);
|
||||||
// body.applyCentralForce(PhysicsUtils.jomlToVecmathVector3f(new Vector3f(movementVector).mul(-1.0f).normalize().mul(velocity)));
|
|
||||||
// EntityUtils.getRotation(parent).rotationTo(new Vector3f(0,0,1), new Vector3f((float)movementVector.x,(float)movementVector.y,(float)movementVector.z));
|
|
||||||
//move the entity
|
|
||||||
// newPosition = new Vector3d(position).add(new Vector3d(movementVector).mul(velocity).mul(Main.deltaTime));
|
|
||||||
// if(!Globals.collisionEngine.checkCanOccupyPosition(Globals.commonWorldData, parent, newPosition)){
|
|
||||||
// newPosition = Globals.collisionEngine.suggestMovementPosition(Globals.commonWorldData, parent, newPosition);
|
|
||||||
// }
|
|
||||||
collidable.addImpulse(new Impulse(new Vector3d(movementVector), new Vector3d(0,0,0), new Vector3d(0,0,0), velocity * Main.deltaFrames, "movement"));
|
collidable.addImpulse(new Impulse(new Vector3d(movementVector), new Vector3d(0,0,0), new Vector3d(0,0,0), velocity * Main.deltaFrames, "movement"));
|
||||||
// position.set(newPosition);
|
// position.set(newPosition);
|
||||||
rotation.set(movementQuaternion);
|
rotation.set(movementQuaternion);
|
||||||
@ -365,14 +337,6 @@ public class GroundMovementTree implements BehaviorTree {
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
case IDLE:
|
case IDLE:
|
||||||
// body.clearForces();
|
|
||||||
|
|
||||||
// if(Globals.collisionEngine.gravityCheck(Globals.commonWorldData, parent)){
|
|
||||||
// position.set(Globals.collisionEngine.suggestMovementPosition(Globals.commonWorldData,parent,new Vector3f(position.x,position.y - 9.8f,position.z)));
|
|
||||||
// }
|
|
||||||
// position.set(new Vector3f(position.x,position.y - 0.08f,position.z));
|
|
||||||
// bodyTransformMatrix = new javax.vecmath.Matrix4f(PhysicsUtils.jomlToVecmathQuaternionf(rotation),PhysicsUtils.jomlToVecmathVector3f(position),1.0f);
|
|
||||||
// body.setWorldTransform(new com.bulletphysics.linearmath.Transform(bodyTransformMatrix));
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -99,44 +99,11 @@ public class ServerGroundMovementTree implements BehaviorTree {
|
|||||||
this.facing = facing;
|
this.facing = facing;
|
||||||
state = MovementTreeState.STARTUP;
|
state = MovementTreeState.STARTUP;
|
||||||
//if we aren't the server, alert the server we intend to walk forward
|
//if we aren't the server, alert the server we intend to walk forward
|
||||||
if(!Globals.RUN_SERVER){
|
|
||||||
Vector3d position = EntityUtils.getPosition(parent);
|
|
||||||
Quaterniond rotation = EntityUtils.getRotation(parent);
|
|
||||||
Vector3d facingVector = CreatureUtils.getFacingVector(parent);
|
|
||||||
float velocity = CreatureUtils.getVelocity(parent);
|
|
||||||
Globals.clientConnection.queueOutgoingMessage(
|
|
||||||
EntityMessage.constructmoveUpdateMessage(
|
|
||||||
parent.getId(),
|
|
||||||
Main.getCurrentFrame(),
|
|
||||||
position.x,
|
|
||||||
position.y,
|
|
||||||
position.z,
|
|
||||||
rotation.x,
|
|
||||||
rotation.y,
|
|
||||||
rotation.z,
|
|
||||||
rotation.w,
|
|
||||||
velocity,
|
|
||||||
0 //magic number corresponding to state startup
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void interrupt(){
|
|
||||||
state = MovementTreeState.IDLE;
|
|
||||||
CreatureUtils.setVelocity(parent, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void slowdown(){
|
|
||||||
state = MovementTreeState.SLOWDOWN;
|
|
||||||
//if we aren't the server, alert the server we intend to slow down
|
|
||||||
if(!Globals.RUN_SERVER){
|
|
||||||
Vector3d position = EntityUtils.getPosition(parent);
|
Vector3d position = EntityUtils.getPosition(parent);
|
||||||
Quaterniond rotation = EntityUtils.getRotation(parent);
|
Quaterniond rotation = EntityUtils.getRotation(parent);
|
||||||
Vector3d facingVector = CreatureUtils.getFacingVector(parent);
|
Vector3d facingVector = CreatureUtils.getFacingVector(parent);
|
||||||
float velocity = CreatureUtils.getVelocity(parent);
|
float velocity = CreatureUtils.getVelocity(parent);
|
||||||
Globals.clientConnection.queueOutgoingMessage(
|
DataCellSearchUtils.getEntityDataCell(parent).broadcastNetworkMessage(
|
||||||
EntityMessage.constructmoveUpdateMessage(
|
EntityMessage.constructmoveUpdateMessage(
|
||||||
parent.getId(),
|
parent.getId(),
|
||||||
Main.getCurrentFrame(),
|
Main.getCurrentFrame(),
|
||||||
@ -148,12 +115,41 @@ public class ServerGroundMovementTree implements BehaviorTree {
|
|||||||
rotation.z,
|
rotation.z,
|
||||||
rotation.w,
|
rotation.w,
|
||||||
velocity,
|
velocity,
|
||||||
2 //magic number corresponding to state slowdown
|
0 //magic number corresponding to state startup
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void interrupt(){
|
||||||
|
state = MovementTreeState.IDLE;
|
||||||
|
CreatureUtils.setVelocity(parent, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void slowdown(){
|
||||||
|
state = MovementTreeState.SLOWDOWN;
|
||||||
|
//if we aren't the server, alert the server we intend to slow down
|
||||||
|
Vector3d position = EntityUtils.getPosition(parent);
|
||||||
|
Quaterniond rotation = EntityUtils.getRotation(parent);
|
||||||
|
Vector3d facingVector = CreatureUtils.getFacingVector(parent);
|
||||||
|
float velocity = CreatureUtils.getVelocity(parent);
|
||||||
|
DataCellSearchUtils.getEntityDataCell(parent).broadcastNetworkMessage(
|
||||||
|
EntityMessage.constructmoveUpdateMessage(
|
||||||
|
parent.getId(),
|
||||||
|
Main.getCurrentFrame(),
|
||||||
|
position.x,
|
||||||
|
position.y,
|
||||||
|
position.z,
|
||||||
|
rotation.x,
|
||||||
|
rotation.y,
|
||||||
|
rotation.z,
|
||||||
|
rotation.w,
|
||||||
|
velocity,
|
||||||
|
2 //magic number corresponding to state slowdown
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public void simulate(float deltaTime){
|
public void simulate(float deltaTime){
|
||||||
float velocity = CreatureUtils.getVelocity(parent);
|
float velocity = CreatureUtils.getVelocity(parent);
|
||||||
float acceleration = CreatureUtils.getAcceleration(parent);
|
float acceleration = CreatureUtils.getAcceleration(parent);
|
||||||
@ -201,11 +197,11 @@ public class ServerGroundMovementTree implements BehaviorTree {
|
|||||||
long updateTime = message.gettime();
|
long updateTime = message.gettime();
|
||||||
// System.out.println("MOVE to " + message.getX() + " " + message.getY() + " " + message.getZ());
|
// System.out.println("MOVE to " + message.getX() + " " + message.getY() + " " + message.getZ());
|
||||||
switch(message.getMessageSubtype()){
|
switch(message.getMessageSubtype()){
|
||||||
case MOVE:
|
case MOVE: {
|
||||||
break;
|
} break;
|
||||||
case SETFACING:
|
case SETFACING:
|
||||||
break;
|
break;
|
||||||
case MOVEUPDATE:
|
case MOVEUPDATE: {
|
||||||
if(updateTime > lastUpdateTime){
|
if(updateTime > lastUpdateTime){
|
||||||
lastUpdateTime = updateTime;
|
lastUpdateTime = updateTime;
|
||||||
switch(message.gettreeState()){
|
switch(message.gettreeState()){
|
||||||
@ -230,10 +226,11 @@ public class ServerGroundMovementTree implements BehaviorTree {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
//we want to always update the server facing vector with where the client says they're facing
|
//we want to always update the server facing vector with where the client says they're facing
|
||||||
CreatureUtils.setFacingVector(parent, new Vector3d(message.getrotationX(),message.getrotationY(),message.getrotationZ()));
|
EntityUtils.getRotation(parent).set(message.getrotationX(),message.getrotationY(),message.getrotationZ(),message.getrotationW());
|
||||||
|
CreatureUtils.setFacingVector(parent, new Vector3d(0,0,1).rotate(EntityUtils.getRotation(parent)));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
} break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -263,14 +260,6 @@ public class ServerGroundMovementTree implements BehaviorTree {
|
|||||||
state = MovementTreeState.MOVE;
|
state = MovementTreeState.MOVE;
|
||||||
}
|
}
|
||||||
CreatureUtils.setVelocity(parent, velocity);
|
CreatureUtils.setVelocity(parent, velocity);
|
||||||
// body.applyCentralForce(PhysicsUtils.jomlToVecmathVector3f(new Vector3f(movementVector.x,0,movementVector.z).normalize().mul(velocity)));
|
|
||||||
// EntityUtils.getRotation(parent).set(movementQuaternion);
|
|
||||||
// //move the entity
|
|
||||||
// newPosition = new Vector3d(position).add(new Vector3d(movementVector).mul(velocity).mul(Main.deltaTime));
|
|
||||||
// //check/update if collision
|
|
||||||
// if(!Globals.collisionEngine.checkCanOccupyPosition(Globals.commonWorldData, parent, newPosition)){
|
|
||||||
// newPosition = Globals.collisionEngine.suggestMovementPosition(Globals.commonWorldData, parent, newPosition);
|
|
||||||
// }
|
|
||||||
// //actually update
|
// //actually update
|
||||||
collidable.addImpulse(new Impulse(new Vector3d(movementVector), new Vector3d(0,0,0), new Vector3d(0,0,0), velocity * Main.deltaFrames, "movement"));
|
collidable.addImpulse(new Impulse(new Vector3d(movementVector), new Vector3d(0,0,0), new Vector3d(0,0,0), velocity * Main.deltaFrames, "movement"));
|
||||||
// position.set(newPosition);
|
// position.set(newPosition);
|
||||||
@ -312,14 +301,6 @@ public class ServerGroundMovementTree implements BehaviorTree {
|
|||||||
velocity = maxNaturalVelocity;
|
velocity = maxNaturalVelocity;
|
||||||
CreatureUtils.setVelocity(parent, velocity);
|
CreatureUtils.setVelocity(parent, velocity);
|
||||||
}
|
}
|
||||||
// body.applyCentralForce(PhysicsUtils.jomlToVecmathVector3f(force));
|
|
||||||
// EntityUtils.getRotation(parent).set(movementQuaternion);
|
|
||||||
//check if can move forward (collision engine)
|
|
||||||
//if can, move forward by entity movement stats
|
|
||||||
// newPosition = new Vector3d(position).add(new Vector3d(movementVector).mul(velocity).mul(Main.deltaTime));
|
|
||||||
// if(!Globals.collisionEngine.checkCanOccupyPosition(Globals.commonWorldData, parent, newPosition)){
|
|
||||||
// newPosition = Globals.collisionEngine.suggestMovementPosition(Globals.commonWorldData, parent, newPosition);
|
|
||||||
// }
|
|
||||||
collidable.addImpulse(new Impulse(new Vector3d(movementVector), new Vector3d(0,0,0), new Vector3d(0,0,0), velocity * Main.deltaFrames, "movement"));
|
collidable.addImpulse(new Impulse(new Vector3d(movementVector), new Vector3d(0,0,0), new Vector3d(0,0,0), velocity * Main.deltaFrames, "movement"));
|
||||||
// position.set(newPosition);
|
// position.set(newPosition);
|
||||||
rotation.set(movementQuaternion);
|
rotation.set(movementQuaternion);
|
||||||
@ -369,13 +350,6 @@ public class ServerGroundMovementTree implements BehaviorTree {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
CreatureUtils.setVelocity(parent, velocity);
|
CreatureUtils.setVelocity(parent, velocity);
|
||||||
// body.applyCentralForce(PhysicsUtils.jomlToVecmathVector3f(new Vector3f(movementVector).mul(-1.0f).normalize().mul(velocity)));
|
|
||||||
// EntityUtils.getRotation(parent).rotationTo(new Vector3f(0,0,1), new Vector3f((float)movementVector.x,(float)movementVector.y,(float)movementVector.z));
|
|
||||||
//move the entity
|
|
||||||
// newPosition = new Vector3d(position).add(new Vector3d(movementVector).mul(velocity).mul(Main.deltaTime));
|
|
||||||
// if(!Globals.collisionEngine.checkCanOccupyPosition(Globals.commonWorldData, parent, newPosition)){
|
|
||||||
// newPosition = Globals.collisionEngine.suggestMovementPosition(Globals.commonWorldData, parent, newPosition);
|
|
||||||
// }
|
|
||||||
collidable.addImpulse(new Impulse(new Vector3d(movementVector), new Vector3d(0,0,0), new Vector3d(0,0,0), velocity * Main.deltaFrames, "movement"));
|
collidable.addImpulse(new Impulse(new Vector3d(movementVector), new Vector3d(0,0,0), new Vector3d(0,0,0), velocity * Main.deltaFrames, "movement"));
|
||||||
// position.set(newPosition);
|
// position.set(newPosition);
|
||||||
rotation.set(movementQuaternion);
|
rotation.set(movementQuaternion);
|
||||||
@ -399,14 +373,6 @@ public class ServerGroundMovementTree implements BehaviorTree {
|
|||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case IDLE:
|
case IDLE:
|
||||||
// body.clearForces();
|
|
||||||
|
|
||||||
// if(Globals.collisionEngine.gravityCheck(Globals.commonWorldData, parent)){
|
|
||||||
// position.set(Globals.collisionEngine.suggestMovementPosition(Globals.commonWorldData,parent,new Vector3f(position.x,position.y - 9.8f,position.z)));
|
|
||||||
// }
|
|
||||||
// position.set(new Vector3f(position.x,position.y - 0.08f,position.z));
|
|
||||||
// bodyTransformMatrix = new javax.vecmath.Matrix4f(PhysicsUtils.jomlToVecmathQuaternionf(rotation),PhysicsUtils.jomlToVecmathVector3f(position),1.0f);
|
|
||||||
// body.setWorldTransform(new com.bulletphysics.linearmath.Transform(bodyTransformMatrix));
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -40,6 +40,7 @@ import electrosphere.renderer.ui.events.NavigationEvent;
|
|||||||
import electrosphere.renderer.ui.events.ValueChangeEvent;
|
import electrosphere.renderer.ui.events.ValueChangeEvent;
|
||||||
import electrosphere.renderer.ui.form.FormElement;
|
import electrosphere.renderer.ui.form.FormElement;
|
||||||
import electrosphere.server.saves.SaveUtils;
|
import electrosphere.server.saves.SaveUtils;
|
||||||
|
import electrosphere.server.terrain.generation.OverworldChunkGenerator;
|
||||||
import electrosphere.server.terrain.manager.ServerTerrainManager;
|
import electrosphere.server.terrain.manager.ServerTerrainManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -130,7 +131,7 @@ public class MenuGenerators {
|
|||||||
//create save dir
|
//create save dir
|
||||||
SaveUtils.createOrOverwriteSave(saveName);
|
SaveUtils.createOrOverwriteSave(saveName);
|
||||||
//create and save terrain
|
//create and save terrain
|
||||||
ServerTerrainManager terrainManager = new ServerTerrainManager(2000,50,0.0f,0);
|
ServerTerrainManager terrainManager = new ServerTerrainManager(2000,50,0.0f,0,new OverworldChunkGenerator());
|
||||||
terrainManager.generate();
|
terrainManager.generate();
|
||||||
terrainManager.save(SaveUtils.deriveSaveDirectoryPath(saveName));
|
terrainManager.save(SaveUtils.deriveSaveDirectoryPath(saveName));
|
||||||
WindowUtils.replaceMainMenuContents(MenuGenerators.createWorldSelectMenu());
|
WindowUtils.replaceMainMenuContents(MenuGenerators.createWorldSelectMenu());
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import java.util.HashMap;
|
|||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.CopyOnWriteArraySet;
|
||||||
import java.util.concurrent.Semaphore;
|
import java.util.concurrent.Semaphore;
|
||||||
|
|
||||||
import org.joml.Vector3d;
|
import org.joml.Vector3d;
|
||||||
@ -29,6 +30,10 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
|
|||||||
//these are going to be the natural ground grid of data cells, but we're going to have more than this
|
//these are going to be the natural ground grid of data cells, but we're going to have more than this
|
||||||
Map<String,ServerDataCell> groundDataCells = new HashMap<String,ServerDataCell>();
|
Map<String,ServerDataCell> groundDataCells = new HashMap<String,ServerDataCell>();
|
||||||
Map<ServerDataCell,Vector3i> cellPositionMap = new HashMap<ServerDataCell,Vector3i>();
|
Map<ServerDataCell,Vector3i> cellPositionMap = new HashMap<ServerDataCell,Vector3i>();
|
||||||
|
//Map of server data cell to the number of frames said cell has had no players
|
||||||
|
Map<ServerDataCell,Integer> cellPlayerlessFrameMap = new HashMap<ServerDataCell,Integer>();
|
||||||
|
//The number of frames without players that must pass before a server data cell is unloaded
|
||||||
|
static final int UNLOAD_FRAME_THRESHOLD = 100;
|
||||||
//loaded cells
|
//loaded cells
|
||||||
Semaphore loadedCellsLock = new Semaphore(1);
|
Semaphore loadedCellsLock = new Semaphore(1);
|
||||||
Set<ServerDataCell> loadedCells;
|
Set<ServerDataCell> loadedCells;
|
||||||
@ -55,7 +60,7 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
|
|||||||
*/
|
*/
|
||||||
public void init(ServerWorldData data){
|
public void init(ServerWorldData data){
|
||||||
discreteWorldSize = data.getWorldSizeDiscrete();
|
discreteWorldSize = data.getWorldSizeDiscrete();
|
||||||
loadedCells = new HashSet<ServerDataCell>();
|
loadedCells = new CopyOnWriteArraySet<ServerDataCell>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -87,6 +92,7 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
|
|||||||
//add to loaded cells
|
//add to loaded cells
|
||||||
loadedCellsLock.acquireUninterruptibly();
|
loadedCellsLock.acquireUninterruptibly();
|
||||||
loadedCells.add(groundDataCells.get(getServerDataCellKey(targetPos)));
|
loadedCells.add(groundDataCells.get(getServerDataCellKey(targetPos)));
|
||||||
|
cellPlayerlessFrameMap.put(groundDataCells.get(getServerDataCellKey(targetPos)),0);
|
||||||
loadedCellsLock.release();
|
loadedCellsLock.release();
|
||||||
//generate/handle content for new server data cell
|
//generate/handle content for new server data cell
|
||||||
|
|
||||||
@ -108,9 +114,9 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
|
|||||||
int playerSimulationRadius = player.getSimulationRadius();
|
int playerSimulationRadius = player.getSimulationRadius();
|
||||||
Vector3i oldPosition = player.getWorldPos();
|
Vector3i oldPosition = player.getWorldPos();
|
||||||
player.setWorldPos(newPosition);
|
player.setWorldPos(newPosition);
|
||||||
// System.out.println("=======" + "SET" + newX + " " + newY + " FROM " + oldX + " " + oldY + "========");
|
// System.out.println("=======" + "SET" + newX + " " + newY + " FROM " + oldX + " " + oldY + "========");
|
||||||
// int removals = 0;
|
int removals = 0;
|
||||||
// int additions = 0;
|
int additions = 0;
|
||||||
for(int x = oldPosition.x - playerSimulationRadius; x < oldPosition.x + playerSimulationRadius + 1; x++){
|
for(int x = oldPosition.x - playerSimulationRadius; x < oldPosition.x + playerSimulationRadius + 1; x++){
|
||||||
for(int y = oldPosition.y - playerSimulationRadius; y < oldPosition.y + playerSimulationRadius + 1; y++){
|
for(int y = oldPosition.y - playerSimulationRadius; y < oldPosition.y + playerSimulationRadius + 1; y++){
|
||||||
for(int z = oldPosition.z - playerSimulationRadius; z < oldPosition.z + playerSimulationRadius + 1; z++){
|
for(int z = oldPosition.z - playerSimulationRadius; z < oldPosition.z + playerSimulationRadius + 1; z++){
|
||||||
@ -166,6 +172,7 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
|
|||||||
//add to loaded cells
|
//add to loaded cells
|
||||||
loadedCellsLock.acquireUninterruptibly();
|
loadedCellsLock.acquireUninterruptibly();
|
||||||
loadedCells.add(groundDataCells.get(getServerDataCellKey(targetPos)));
|
loadedCells.add(groundDataCells.get(getServerDataCellKey(targetPos)));
|
||||||
|
cellPlayerlessFrameMap.put(groundDataCells.get(getServerDataCellKey(targetPos)),0);
|
||||||
loadedCellsLock.release();
|
loadedCellsLock.release();
|
||||||
//add player
|
//add player
|
||||||
groundDataCells.get(getServerDataCellKey(targetPos)).addPlayer(player);
|
groundDataCells.get(getServerDataCellKey(targetPos)).addPlayer(player);
|
||||||
@ -178,7 +185,7 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// System.out.println("removals: " + removals + "\tadditions: " + additions);
|
// System.out.println("removals: " + removals + "\tadditions: " + additions);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -221,12 +228,23 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
|
|||||||
//TODO: improve to make have less performance impact
|
//TODO: improve to make have less performance impact
|
||||||
for(ServerDataCell cell : loadedCells){
|
for(ServerDataCell cell : loadedCells){
|
||||||
if(cell.getPlayers().size() < 1){
|
if(cell.getPlayers().size() < 1){
|
||||||
System.out.println("Unload cell");
|
int frameCount = cellPlayerlessFrameMap.get(cell) + 1;
|
||||||
toCleanQueue.add(cell);
|
cellPlayerlessFrameMap.put(cell,frameCount);
|
||||||
|
if(frameCount > UNLOAD_FRAME_THRESHOLD){
|
||||||
|
System.out.println("Unload cell " + getCellWorldPosition(cell));
|
||||||
|
toCleanQueue.add(cell);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(cellPlayerlessFrameMap.get(cell) > 0){
|
||||||
|
cellPlayerlessFrameMap.put(cell, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for(ServerDataCell cell : toCleanQueue){
|
for(ServerDataCell cell : toCleanQueue){
|
||||||
parent.deregisterCell(cell);
|
parent.deregisterCell(cell);
|
||||||
|
loadedCells.remove(cell);
|
||||||
|
String key = getServerDataCellKey(getCellWorldPosition(cell));
|
||||||
|
groundDataCells.remove(key);
|
||||||
}
|
}
|
||||||
toCleanQueue.clear();
|
toCleanQueue.clear();
|
||||||
}
|
}
|
||||||
@ -280,6 +298,7 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
|
|||||||
//add to loaded cells
|
//add to loaded cells
|
||||||
loadedCellsLock.acquireUninterruptibly();
|
loadedCellsLock.acquireUninterruptibly();
|
||||||
loadedCells.add(groundDataCells.get(getServerDataCellKey(worldPos)));
|
loadedCells.add(groundDataCells.get(getServerDataCellKey(worldPos)));
|
||||||
|
cellPlayerlessFrameMap.put(groundDataCells.get(getServerDataCellKey(worldPos)),0);
|
||||||
loadedCellsLock.release();
|
loadedCellsLock.release();
|
||||||
}
|
}
|
||||||
return groundDataCells.get(getServerDataCellKey(worldPos));
|
return groundDataCells.get(getServerDataCellKey(worldPos));
|
||||||
@ -314,6 +333,7 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
|
|||||||
Globals.microSimulation.simulate(cell, parent.getHitboxManager());
|
Globals.microSimulation.simulate(cell, parent.getHitboxManager());
|
||||||
}
|
}
|
||||||
loadedCellsLock.release();
|
loadedCellsLock.release();
|
||||||
|
updatePlayerPositions();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -6,6 +6,8 @@ import electrosphere.engine.Globals;
|
|||||||
import electrosphere.game.server.world.ServerWorldData;
|
import electrosphere.game.server.world.ServerWorldData;
|
||||||
import electrosphere.logger.LoggerInterface;
|
import electrosphere.logger.LoggerInterface;
|
||||||
import electrosphere.server.db.DatabaseUtils;
|
import electrosphere.server.db.DatabaseUtils;
|
||||||
|
import electrosphere.server.terrain.generation.OverworldChunkGenerator;
|
||||||
|
import electrosphere.server.terrain.generation.interfaces.ChunkGenerator;
|
||||||
import electrosphere.server.terrain.manager.ServerTerrainManager;
|
import electrosphere.server.terrain.manager.ServerTerrainManager;
|
||||||
import electrosphere.util.FileUtils;
|
import electrosphere.util.FileUtils;
|
||||||
|
|
||||||
@ -106,7 +108,7 @@ public class SaveUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static boolean loadTerrainAndCreateWorldData(String currentSaveName){
|
public static boolean loadTerrainAndCreateWorldData(String currentSaveName){
|
||||||
Globals.serverTerrainManager = new ServerTerrainManager(2000,50,0.0f,0);
|
Globals.serverTerrainManager = new ServerTerrainManager(2000,50,0.0f,0,new OverworldChunkGenerator());
|
||||||
SaveUtils.loadTerrainAndDB(currentSaveName);
|
SaveUtils.loadTerrainAndDB(currentSaveName);
|
||||||
Globals.serverWorldData = ServerWorldData.createGameWorld(Globals.serverTerrainManager);
|
Globals.serverWorldData = ServerWorldData.createGameWorld(Globals.serverTerrainManager);
|
||||||
Globals.realmManager.createGriddedRealm(Globals.serverWorldData);
|
Globals.realmManager.createGriddedRealm(Globals.serverWorldData);
|
||||||
|
|||||||
@ -89,21 +89,12 @@ public class MicroSimulation {
|
|||||||
// CollidableTree tree = CollidableTree.getCollidableTree(currentCollidable);
|
// CollidableTree tree = CollidableTree.getCollidableTree(currentCollidable);
|
||||||
// tree.simulate(Main.deltaFrames);
|
// tree.simulate(Main.deltaFrames);
|
||||||
// }
|
// }
|
||||||
//targeting crosshair
|
|
||||||
if(Globals.RUN_CLIENT){
|
|
||||||
Crosshair.checkTargetable();
|
|
||||||
Crosshair.updateTargetCrosshairPosition();
|
|
||||||
}
|
|
||||||
//simulate behavior trees
|
//simulate behavior trees
|
||||||
dataCell.getScene().simulateBehaviorTrees(Main.deltaFrames);
|
dataCell.getScene().simulateBehaviorTrees(Main.deltaFrames);
|
||||||
//sum collidable impulses
|
//sum collidable impulses
|
||||||
for(Entity collidable : dataCell.getScene().getEntitiesWithTag(EntityTags.COLLIDABLE)){
|
for(Entity collidable : dataCell.getScene().getEntitiesWithTag(EntityTags.COLLIDABLE)){
|
||||||
ServerCollidableTree.getServerCollidableTree(collidable).simulate(Main.deltaFrames);
|
ServerCollidableTree.getServerCollidableTree(collidable).simulate(Main.deltaFrames);
|
||||||
}
|
}
|
||||||
//delete all client side entities that aren't in visible chunks
|
|
||||||
if(Globals.clientEntityCullingManager != null){
|
|
||||||
Globals.clientEntityCullingManager.clearOutOfBoundsEntities();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,92 +0,0 @@
|
|||||||
package electrosphere.server.terrain.diskcache;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import electrosphere.net.server.Server;
|
|
||||||
import electrosphere.server.terrain.manager.ServerTerrainChunk;
|
|
||||||
import electrosphere.util.FileUtils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An interface for accessing the disk cache of chunk information
|
|
||||||
*/
|
|
||||||
public class ChunkDiskCache {
|
|
||||||
|
|
||||||
//The map of world position+chunk type to the file that actually houses that information
|
|
||||||
Map<String,String> worldPosFileMap;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*/
|
|
||||||
public ChunkDiskCache(){
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a key for a given chunk file based on a world coordinate
|
|
||||||
* @param worldX The x component
|
|
||||||
* @param worldY The y component
|
|
||||||
* @param worldZ The z component
|
|
||||||
* @return The key
|
|
||||||
*/
|
|
||||||
private static String getTerrainChunkKey(int worldX, int worldY, int worldZ){
|
|
||||||
return worldX + "_" + worldY + "_" + worldZ + "t";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a key for a given chunk file based on a world coordinate
|
|
||||||
* @param worldX The x component
|
|
||||||
* @param worldY The y component
|
|
||||||
* @param worldZ The z component
|
|
||||||
* @return The key
|
|
||||||
*/
|
|
||||||
private static String getFluidChunkKey(int worldX, int worldY, int worldZ){
|
|
||||||
return worldX + "_" + worldY + "_" + worldZ + "f";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initializes a diskcache based on a given save name
|
|
||||||
* @param saveName The save name
|
|
||||||
*/
|
|
||||||
public void init(String saveName){
|
|
||||||
worldPosFileMap = FileUtils.loadObjectFromSavePath(saveName, "ChunkCache.map", Map.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the cache contains a given chunk position
|
|
||||||
* @param worldX The x component
|
|
||||||
* @param worldY The y component
|
|
||||||
* @param worldZ The z component
|
|
||||||
* @return True if the cache contains the chunk, false otherwise
|
|
||||||
*/
|
|
||||||
public boolean containsTerrainAtPosition(int worldX, int worldY, int worldZ){
|
|
||||||
return worldPosFileMap.containsKey(getTerrainChunkKey(worldX, worldY, worldZ));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the cache contains a given chunk position
|
|
||||||
* @param worldX The x component
|
|
||||||
* @param worldY The y component
|
|
||||||
* @param worldZ The z component
|
|
||||||
* @return True if the cache contains the chunk, false otherwise
|
|
||||||
*/
|
|
||||||
public boolean containsFluidAtPosition(int worldX, int worldY, int worldZ){
|
|
||||||
return worldPosFileMap.containsKey(getFluidChunkKey(worldX, worldY, worldZ));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the server terrain chunk from disk if it exists, otherwise returns null
|
|
||||||
* @param worldX The x coordinate
|
|
||||||
* @param worldY The y coordinate
|
|
||||||
* @param worldZ The z coordinate
|
|
||||||
* @return The server terrain chunk if it exists, null otherwise
|
|
||||||
*/
|
|
||||||
public ServerTerrainChunk getTerrainChunk(int worldX, int worldY, int worldZ){
|
|
||||||
ServerTerrainChunk rVal = null;
|
|
||||||
if(containsTerrainAtPosition(worldX, worldY, worldZ)){
|
|
||||||
String fileName = worldPosFileMap.get(getTerrainChunkKey(worldX, worldY, worldZ));
|
|
||||||
//TODO: implement
|
|
||||||
}
|
|
||||||
return rVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -0,0 +1,205 @@
|
|||||||
|
package electrosphere.server.terrain.diskmap;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.FloatBuffer;
|
||||||
|
import java.nio.IntBuffer;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.zip.DeflaterInputStream;
|
||||||
|
import java.util.zip.DeflaterOutputStream;
|
||||||
|
import java.util.zip.InflaterOutputStream;
|
||||||
|
|
||||||
|
import electrosphere.engine.Globals;
|
||||||
|
import electrosphere.net.server.Server;
|
||||||
|
import electrosphere.server.terrain.manager.ServerTerrainChunk;
|
||||||
|
import electrosphere.util.FileUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An interface for accessing the disk map of chunk information
|
||||||
|
*/
|
||||||
|
public class ChunkDiskMap {
|
||||||
|
|
||||||
|
//The map of world position+chunk type to the file that actually houses that information
|
||||||
|
Map<String,String> worldPosFileMap = new HashMap<String,String>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*/
|
||||||
|
public ChunkDiskMap(){
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a key for a given chunk file based on a world coordinate
|
||||||
|
* @param worldX The x component
|
||||||
|
* @param worldY The y component
|
||||||
|
* @param worldZ The z component
|
||||||
|
* @return The key
|
||||||
|
*/
|
||||||
|
private static String getTerrainChunkKey(int worldX, int worldY, int worldZ){
|
||||||
|
return worldX + "_" + worldY + "_" + worldZ + "t";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a key for a given chunk file based on a world coordinate
|
||||||
|
* @param worldX The x component
|
||||||
|
* @param worldY The y component
|
||||||
|
* @param worldZ The z component
|
||||||
|
* @return The key
|
||||||
|
*/
|
||||||
|
private static String getFluidChunkKey(int worldX, int worldY, int worldZ){
|
||||||
|
return worldX + "_" + worldY + "_" + worldZ + "f";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes a diskmap based on a given save name
|
||||||
|
* @param saveName The save name
|
||||||
|
*/
|
||||||
|
public void init(String saveName){
|
||||||
|
if(FileUtils.getSaveFile(saveName, "chunk.map").exists()){
|
||||||
|
worldPosFileMap = FileUtils.loadObjectFromSavePath(saveName, "chunk.map", Map.class);
|
||||||
|
} else {
|
||||||
|
worldPosFileMap = new HashMap<String,String>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves the disk map to disk
|
||||||
|
*/
|
||||||
|
public void save(){
|
||||||
|
FileUtils.serializeObjectToSavePath(Globals.currentSaveName, "chunk.map", this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the map contains a given chunk position
|
||||||
|
* @param worldX The x component
|
||||||
|
* @param worldY The y component
|
||||||
|
* @param worldZ The z component
|
||||||
|
* @return True if the map contains the chunk, false otherwise
|
||||||
|
*/
|
||||||
|
public boolean containsTerrainAtPosition(int worldX, int worldY, int worldZ){
|
||||||
|
return worldPosFileMap.containsKey(getTerrainChunkKey(worldX, worldY, worldZ));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the map contains a given chunk position
|
||||||
|
* @param worldX The x component
|
||||||
|
* @param worldY The y component
|
||||||
|
* @param worldZ The z component
|
||||||
|
* @return True if the map contains the chunk, false otherwise
|
||||||
|
*/
|
||||||
|
public boolean containsFluidAtPosition(int worldX, int worldY, int worldZ){
|
||||||
|
return worldPosFileMap.containsKey(getFluidChunkKey(worldX, worldY, worldZ));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the server terrain chunk from disk if it exists, otherwise returns null
|
||||||
|
* @param worldX The x coordinate
|
||||||
|
* @param worldY The y coordinate
|
||||||
|
* @param worldZ The z coordinate
|
||||||
|
* @return The server terrain chunk if it exists, null otherwise
|
||||||
|
*/
|
||||||
|
public ServerTerrainChunk getTerrainChunk(int worldX, int worldY, int worldZ){
|
||||||
|
ServerTerrainChunk rVal = null;
|
||||||
|
if(containsTerrainAtPosition(worldX, worldY, worldZ)){
|
||||||
|
//read file
|
||||||
|
String fileName = worldPosFileMap.get(getTerrainChunkKey(worldX, worldY, worldZ));
|
||||||
|
byte[] rawDataCompressed = FileUtils.loadBinaryFromSavePath(Globals.currentSaveName, fileName);
|
||||||
|
//decompress
|
||||||
|
byte[] rawData = null;
|
||||||
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
|
InflaterOutputStream inflaterInputStream = new InflaterOutputStream(out);
|
||||||
|
try {
|
||||||
|
inflaterInputStream.write(rawData);
|
||||||
|
inflaterInputStream.flush();
|
||||||
|
inflaterInputStream.close();
|
||||||
|
rawData = out.toByteArray();
|
||||||
|
} catch (IOException e) {
|
||||||
|
// TODO Auto-generated catch block
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
//parse
|
||||||
|
if(rawData != null){
|
||||||
|
ByteBuffer buffer = ByteBuffer.wrap(rawData);
|
||||||
|
FloatBuffer floatView = buffer.asFloatBuffer();
|
||||||
|
int DIM = ServerTerrainChunk.CHUNK_DIMENSION;
|
||||||
|
float[][][] weights = new float[DIM][DIM][DIM];
|
||||||
|
int[][][] values = new int[DIM][DIM][DIM];
|
||||||
|
for(int x = 0; x < DIM; x++){
|
||||||
|
for(int y = 0; y < DIM; y++){
|
||||||
|
for(int z = 0; z < DIM; z++){
|
||||||
|
weights[x][y][z] = floatView.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IntBuffer intView = buffer.asIntBuffer();
|
||||||
|
intView.position(DIM * DIM * DIM * 4);
|
||||||
|
for(int x = 0; x < DIM; x++){
|
||||||
|
for(int y = 0; y < DIM; y++){
|
||||||
|
for(int z = 0; z < DIM; z++){
|
||||||
|
values[x][y][z] = intView.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rVal = new ServerTerrainChunk(worldX, worldY, worldZ, weights, values);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves a terrain chunk to disk
|
||||||
|
* @param terrainChunk The terrain chunk
|
||||||
|
*/
|
||||||
|
public void saveToDisk(ServerTerrainChunk terrainChunk){
|
||||||
|
//get the file name for this chunk
|
||||||
|
String fileName = null;
|
||||||
|
String chunkKey = getTerrainChunkKey(terrainChunk.getWorldX(),terrainChunk.getWorldY(),terrainChunk.getWorldZ());
|
||||||
|
if(worldPosFileMap.containsKey(chunkKey)){
|
||||||
|
fileName = worldPosFileMap.get(chunkKey);
|
||||||
|
} else {
|
||||||
|
fileName = chunkKey + ".dat";
|
||||||
|
}
|
||||||
|
//generate binary for the file
|
||||||
|
float[][][] weights = terrainChunk.getWeights();
|
||||||
|
int[][][] values = terrainChunk.getValues();
|
||||||
|
int DIM = ServerTerrainChunk.CHUNK_DIMENSION;
|
||||||
|
ByteBuffer buffer = ByteBuffer.allocate(DIM * DIM * DIM * 4 + DIM * DIM * DIM * 4);
|
||||||
|
FloatBuffer floatView = buffer.asFloatBuffer();
|
||||||
|
for(int x = 0; x < DIM; x++){
|
||||||
|
for(int y = 0; y < DIM; y++){
|
||||||
|
for(int z = 0; z < DIM; z++){
|
||||||
|
floatView.put(weights[x][y][z]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buffer.position(DIM * DIM * DIM * 4);
|
||||||
|
IntBuffer intView = buffer.asIntBuffer();
|
||||||
|
for(int x = 0; x < DIM; x++){
|
||||||
|
for(int y = 0; y < DIM; y++){
|
||||||
|
for(int z = 0; z < DIM; z++){
|
||||||
|
intView.put(values[x][y][z]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//compress
|
||||||
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
|
DeflaterOutputStream deflaterInputStream = new DeflaterOutputStream(out);
|
||||||
|
try {
|
||||||
|
deflaterInputStream.write(buffer.array());
|
||||||
|
deflaterInputStream.flush();
|
||||||
|
deflaterInputStream.close();
|
||||||
|
//write to disk
|
||||||
|
FileUtils.saveBinaryToSavePath(Globals.currentSaveName, fileName, out.toByteArray());
|
||||||
|
//save to the map of filenames
|
||||||
|
worldPosFileMap.put(chunkKey,fileName);
|
||||||
|
} catch (IOException e) {
|
||||||
|
// TODO Auto-generated catch block
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,43 @@
|
|||||||
|
package electrosphere.server.terrain.generation;
|
||||||
|
|
||||||
|
import electrosphere.server.terrain.generation.interfaces.ChunkGenerator;
|
||||||
|
import electrosphere.server.terrain.manager.ServerTerrainChunk;
|
||||||
|
import electrosphere.server.terrain.models.TerrainModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An arena terrain chunk generator
|
||||||
|
*/
|
||||||
|
public class ArenaChunkGenerator implements ChunkGenerator {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ServerTerrainChunk generateChunk(int worldX, int worldY, int worldZ) {
|
||||||
|
//Each chunk also needs custody of the next chunk's first values so that they can perfectly overlap.
|
||||||
|
//Hence, width should actually be chunk dimension + 1
|
||||||
|
float[][][] weights = new float[ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE][ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE][ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE];
|
||||||
|
int[][][] values = new int[ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE][ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE][ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE];
|
||||||
|
for(int inc = 0; inc < ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE; inc++){
|
||||||
|
for(int weightX = 0; weightX < ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE; weightX++){
|
||||||
|
for(int weightZ = 0; weightZ < ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE; weightZ++){
|
||||||
|
weights[weightX][inc][weightZ] = -1;
|
||||||
|
values[weightX][inc][weightZ] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(worldY < 1){
|
||||||
|
for(int weightX = 0; weightX < ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE; weightX++){
|
||||||
|
for(int weightZ = 0; weightZ < ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE; weightZ++){
|
||||||
|
weights[weightX][0][weightZ] = 0.1f;
|
||||||
|
values[weightX][0][weightZ] = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ServerTerrainChunk rVal = new ServerTerrainChunk(worldX, worldY, worldZ, weights, values);
|
||||||
|
return rVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setModel(TerrainModel model) {
|
||||||
|
//Does nothing as the arena is not based on a terrain model
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,88 @@
|
|||||||
|
package electrosphere.server.terrain.generation;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
import electrosphere.game.terrain.processing.TerrainInterpolator;
|
||||||
|
import electrosphere.server.terrain.generation.interfaces.ChunkGenerator;
|
||||||
|
import electrosphere.server.terrain.manager.ServerTerrainChunk;
|
||||||
|
import electrosphere.server.terrain.models.TerrainModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Chunk generator for overworld chunks
|
||||||
|
*/
|
||||||
|
public class OverworldChunkGenerator implements ChunkGenerator {
|
||||||
|
|
||||||
|
//The model of terrain for the overworld
|
||||||
|
TerrainModel model;
|
||||||
|
|
||||||
|
//cache for the bicubic interpolated chunks
|
||||||
|
//don't need to interpolate each time a new chunk is created
|
||||||
|
//This should eventually be removed as terrain generation becomes more complicated than a heightmap
|
||||||
|
Map<String, float[][]> heightmapCache = new ConcurrentHashMap<String, float[][]>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*/
|
||||||
|
public OverworldChunkGenerator(){
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ServerTerrainChunk generateChunk(int worldX, int worldY, int worldZ) {
|
||||||
|
ServerTerrainChunk returnedChunk;
|
||||||
|
//Each chunk also needs custody of the next chunk's first values so that they can perfectly overlap.
|
||||||
|
//Hence, width should actually be chunk dimension + 1
|
||||||
|
float[][] heightmap = getHeightmap(worldX, worldZ);
|
||||||
|
float[][][] weights = new float[ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE][ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE][ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE];
|
||||||
|
int[][][] values = new int[ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE][ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE][ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE];
|
||||||
|
for(int weightX = 0; weightX < ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE; weightX++){
|
||||||
|
for(int weightY = 0; weightY < ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE; weightY++){
|
||||||
|
for(int weightZ = 0; weightZ < ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE; weightZ++){
|
||||||
|
float height = heightmap[ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE * worldX + weightX][ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE * worldZ + weightZ];
|
||||||
|
if(weightY < height){
|
||||||
|
weights[weightX][weightY][weightZ] = 1;
|
||||||
|
values[weightX][weightY][weightZ] = 1;
|
||||||
|
} else if(height == 0 && weightY == 0 && worldY == 0) {
|
||||||
|
weights[weightX][weightY][weightZ] = 0.1f;
|
||||||
|
values[weightX][weightY][weightZ] = 1;
|
||||||
|
} else {
|
||||||
|
weights[weightX][weightY][weightZ] = -1;
|
||||||
|
values[weightX][weightY][weightZ] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
returnedChunk = new ServerTerrainChunk(worldX, worldY, worldZ, weights, values);
|
||||||
|
return returnedChunk;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
/**
|
||||||
|
* Sets the terrain model for the overworld algo
|
||||||
|
*/
|
||||||
|
public void setModel(TerrainModel model){
|
||||||
|
this.model = model;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a heightmap array. Either pulls it from cache if it exists or does the logic to generate it
|
||||||
|
* @param worldX The x position in world coordinates of the chunk
|
||||||
|
* @param worldZ THe z position in world coordinates of the chunk
|
||||||
|
* @return The heightmap array
|
||||||
|
*/
|
||||||
|
private float[][] getHeightmap(int worldX, int worldZ){
|
||||||
|
String key = worldX + "_" + worldZ;
|
||||||
|
if(heightmapCache.containsKey(key)){
|
||||||
|
return heightmapCache.get(key);
|
||||||
|
} else {
|
||||||
|
float[][] macroValues = model.getRad5MacroValuesAtPosition(worldX, worldZ);
|
||||||
|
float[][] heightmap = TerrainInterpolator.getBicubicInterpolatedChunk(
|
||||||
|
macroValues,
|
||||||
|
model.getDynamicInterpolationRatio()
|
||||||
|
);
|
||||||
|
heightmapCache.put(key,heightmap);
|
||||||
|
return heightmap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,26 @@
|
|||||||
|
package electrosphere.server.terrain.generation.interfaces;
|
||||||
|
|
||||||
|
import electrosphere.server.terrain.manager.ServerTerrainChunk;
|
||||||
|
import electrosphere.server.terrain.models.TerrainModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An interface for generating chunks. Used to isolate different algorithms for getting chunks from one another.
|
||||||
|
*/
|
||||||
|
public interface ChunkGenerator {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a chunk given an x, y, and z
|
||||||
|
* @param worldX The x component
|
||||||
|
* @param worldY The y component
|
||||||
|
* @param worldZ The z component
|
||||||
|
* @return The chunk
|
||||||
|
*/
|
||||||
|
public ServerTerrainChunk generateChunk(int worldX, int worldY, int worldZ);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the terrain model for the generation algorithm
|
||||||
|
* @param model The terrain model
|
||||||
|
*/
|
||||||
|
public void setModel(TerrainModel model);
|
||||||
|
|
||||||
|
}
|
||||||
@ -29,38 +29,6 @@ public class ServerTerrainChunk {
|
|||||||
this.weights = weights;
|
this.weights = weights;
|
||||||
this.values = values;
|
this.values = values;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an arena chunk. Should be flat land if worldY=0, otherwise all air
|
|
||||||
* @param worldX The world x position
|
|
||||||
* @param worldY The world y position
|
|
||||||
* @param worldZ The world z position
|
|
||||||
* @return The ServerTerrainChunk
|
|
||||||
*/
|
|
||||||
public static ServerTerrainChunk getArenaChunk(int worldX, int worldY, int worldZ){
|
|
||||||
//Each chunk also needs custody of the next chunk's first values so that they can perfectly overlap.
|
|
||||||
//Hence, width should actually be chunk dimension + 1
|
|
||||||
float[][][] weights = new float[CHUNK_DATA_GENERATOR_SIZE][CHUNK_DATA_GENERATOR_SIZE][CHUNK_DATA_GENERATOR_SIZE];
|
|
||||||
int[][][] values = new int[CHUNK_DATA_GENERATOR_SIZE][CHUNK_DATA_GENERATOR_SIZE][CHUNK_DATA_GENERATOR_SIZE];
|
|
||||||
for(int inc = 0; inc < CHUNK_DATA_GENERATOR_SIZE; inc++){
|
|
||||||
for(int weightX = 0; weightX < CHUNK_DATA_GENERATOR_SIZE; weightX++){
|
|
||||||
for(int weightZ = 0; weightZ < CHUNK_DATA_GENERATOR_SIZE; weightZ++){
|
|
||||||
weights[weightX][inc][weightZ] = -1;
|
|
||||||
values[weightX][inc][weightZ] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(worldY < 1){
|
|
||||||
for(int weightX = 0; weightX < CHUNK_DATA_GENERATOR_SIZE; weightX++){
|
|
||||||
for(int weightZ = 0; weightZ < CHUNK_DATA_GENERATOR_SIZE; weightZ++){
|
|
||||||
weights[weightX][0][weightZ] = 0.1f;
|
|
||||||
values[weightX][0][weightZ] = 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ServerTerrainChunk rVal = new ServerTerrainChunk(worldX, worldY, worldZ, weights, values);
|
|
||||||
return rVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getWorldX() {
|
public int getWorldX() {
|
||||||
return worldX;
|
return worldX;
|
||||||
|
|||||||
@ -4,7 +4,10 @@ import com.google.gson.Gson;
|
|||||||
|
|
||||||
import electrosphere.engine.Globals;
|
import electrosphere.engine.Globals;
|
||||||
import electrosphere.game.terrain.processing.TerrainInterpolator;
|
import electrosphere.game.terrain.processing.TerrainInterpolator;
|
||||||
|
import electrosphere.server.terrain.diskmap.ChunkDiskMap;
|
||||||
|
import electrosphere.server.terrain.generation.ArenaChunkGenerator;
|
||||||
import electrosphere.server.terrain.generation.continentphase.TerrainGenerator;
|
import electrosphere.server.terrain.generation.continentphase.TerrainGenerator;
|
||||||
|
import electrosphere.server.terrain.generation.interfaces.ChunkGenerator;
|
||||||
import electrosphere.server.terrain.models.TerrainModel;
|
import electrosphere.server.terrain.models.TerrainModel;
|
||||||
import electrosphere.server.terrain.models.TerrainModification;
|
import electrosphere.server.terrain.models.TerrainModification;
|
||||||
import electrosphere.util.FileUtils;
|
import electrosphere.util.FileUtils;
|
||||||
@ -38,36 +41,52 @@ public class ServerTerrainManager {
|
|||||||
|
|
||||||
long seed;
|
long seed;
|
||||||
|
|
||||||
|
//The model of the terrain this manager is managing
|
||||||
TerrainModel model;
|
TerrainModel model;
|
||||||
|
|
||||||
|
|
||||||
//Basic idea is we associate string that contains chunk x&y with elevation
|
//In memory cache of chunk data
|
||||||
|
//Basic idea is we associate string that contains chunk x&y&z with elevation
|
||||||
//While we incur a penalty with converting ints -> string, think this will
|
//While we incur a penalty with converting ints -> string, think this will
|
||||||
//offset regenerating the array every time we want a new one
|
//offset regenerating the array every time we want a new one
|
||||||
int cacheSize = 500;
|
int cacheSize = 500;
|
||||||
Map<String, ServerTerrainChunk> chunkCache;
|
Map<String, ServerTerrainChunk> chunkCache;
|
||||||
List<String> chunkCacheContents;
|
List<String> chunkCacheContents;
|
||||||
|
|
||||||
//cache for the bicubic interpolated chunks
|
//The map of chunk position <-> file on disk containing chunk data
|
||||||
//don't need to interpolate each time a new chunk is created
|
ChunkDiskMap chunkDiskMap = null;
|
||||||
//This should eventually be removed as terrain generation becomes more complicated than a heightmap
|
|
||||||
Map<String, float[][]> heightmapCache = new ConcurrentHashMap<>();
|
//The generation algorithm for this terrain manager
|
||||||
|
ChunkGenerator chunkGenerator;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
public ServerTerrainManager(int worldSizeDiscrete, int verticalInterpolationRatio, float interpolationRandomDampener, long seed){
|
* Constructor
|
||||||
|
*/
|
||||||
|
public ServerTerrainManager(
|
||||||
|
int worldSizeDiscrete,
|
||||||
|
int verticalInterpolationRatio,
|
||||||
|
float interpolationRandomDampener,
|
||||||
|
long seed,
|
||||||
|
ChunkGenerator chunkGenerator
|
||||||
|
){
|
||||||
this.worldSizeDiscrete = worldSizeDiscrete;
|
this.worldSizeDiscrete = worldSizeDiscrete;
|
||||||
this.verticalInterpolationRatio = verticalInterpolationRatio;
|
this.verticalInterpolationRatio = verticalInterpolationRatio;
|
||||||
this.chunkCache = new ConcurrentHashMap<String, ServerTerrainChunk>();
|
this.chunkCache = new ConcurrentHashMap<String, ServerTerrainChunk>();
|
||||||
this.chunkCacheContents = new CopyOnWriteArrayList<String>();
|
this.chunkCacheContents = new CopyOnWriteArrayList<String>();
|
||||||
this.interpolationRandomDampener = interpolationRandomDampener;
|
this.interpolationRandomDampener = interpolationRandomDampener;
|
||||||
this.seed = seed;
|
this.seed = seed;
|
||||||
|
this.chunkGenerator = chunkGenerator;
|
||||||
}
|
}
|
||||||
|
|
||||||
ServerTerrainManager(){
|
ServerTerrainManager(){
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an arena terrain manager
|
||||||
|
* @return The arena terrain manager
|
||||||
|
*/
|
||||||
public static ServerTerrainManager constructArenaTerrainManager(){
|
public static ServerTerrainManager constructArenaTerrainManager(){
|
||||||
ServerTerrainManager rVal = new ServerTerrainManager();
|
ServerTerrainManager rVal = new ServerTerrainManager();
|
||||||
rVal.worldSizeDiscrete = 2;
|
rVal.worldSizeDiscrete = 2;
|
||||||
@ -75,16 +94,22 @@ public class ServerTerrainManager {
|
|||||||
rVal.chunkCache = new ConcurrentHashMap<String, ServerTerrainChunk>();
|
rVal.chunkCache = new ConcurrentHashMap<String, ServerTerrainChunk>();
|
||||||
rVal.chunkCacheContents = new CopyOnWriteArrayList<String>();
|
rVal.chunkCacheContents = new CopyOnWriteArrayList<String>();
|
||||||
rVal.interpolationRandomDampener = 0.0f;
|
rVal.interpolationRandomDampener = 0.0f;
|
||||||
|
rVal.chunkGenerator = new ArenaChunkGenerator();
|
||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a terrain model for the manager
|
||||||
|
*/
|
||||||
public void generate(){
|
public void generate(){
|
||||||
TerrainGenerator terrainGen = new TerrainGenerator();
|
TerrainGenerator terrainGen = new TerrainGenerator();
|
||||||
terrainGen.setInterpolationRatio(worldSizeDiscrete/200);
|
terrainGen.setInterpolationRatio(worldSizeDiscrete/200);
|
||||||
terrainGen.setVerticalInterpolationRatio(verticalInterpolationRatio);
|
terrainGen.setVerticalInterpolationRatio(verticalInterpolationRatio);
|
||||||
terrainGen.setRandomSeed(seed);
|
terrainGen.setRandomSeed(seed);
|
||||||
model = terrainGen.generateModel();
|
model = terrainGen.generateModel();
|
||||||
|
this.chunkGenerator.setModel(model);
|
||||||
model.setInterpolationRandomDampener(interpolationRandomDampener);
|
model.setInterpolationRandomDampener(interpolationRandomDampener);
|
||||||
|
this.chunkDiskMap = new ChunkDiskMap();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -100,10 +125,19 @@ public class ServerTerrainManager {
|
|||||||
floatView.flip();
|
floatView.flip();
|
||||||
FileUtils.saveBinaryToSavePath(saveName, "./terrain.dat", buffer.array());
|
FileUtils.saveBinaryToSavePath(saveName, "./terrain.dat", buffer.array());
|
||||||
FileUtils.serializeObjectToSavePath(saveName, "./terrain.json", model);
|
FileUtils.serializeObjectToSavePath(saveName, "./terrain.json", model);
|
||||||
|
if(chunkDiskMap != null){
|
||||||
|
chunkDiskMap.save();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads a terrain manager from a save file
|
||||||
|
* @param saveName The name of the save
|
||||||
|
*/
|
||||||
public void load(String saveName){
|
public void load(String saveName){
|
||||||
|
//load terrain model
|
||||||
model = FileUtils.loadObjectFromSavePath(saveName, "./terrain.json", TerrainModel.class);
|
model = FileUtils.loadObjectFromSavePath(saveName, "./terrain.json", TerrainModel.class);
|
||||||
|
chunkGenerator.setModel(model);
|
||||||
byte[] data = FileUtils.loadBinaryFromSavePath(saveName, "./terrain.dat");
|
byte[] data = FileUtils.loadBinaryFromSavePath(saveName, "./terrain.dat");
|
||||||
ByteBuffer buffer = ByteBuffer.wrap(data);
|
ByteBuffer buffer = ByteBuffer.wrap(data);
|
||||||
FloatBuffer floatView = buffer.asFloatBuffer();
|
FloatBuffer floatView = buffer.asFloatBuffer();
|
||||||
@ -114,6 +148,9 @@ public class ServerTerrainManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
model.setElevationArray(elevation);
|
model.setElevationArray(elevation);
|
||||||
|
//load chunk disk map
|
||||||
|
chunkDiskMap = new ChunkDiskMap();
|
||||||
|
chunkDiskMap.init(saveName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public float[][] getTerrainAtChunk(int x, int y){
|
public float[][] getTerrainAtChunk(int x, int y){
|
||||||
@ -156,10 +193,21 @@ public class ServerTerrainManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the terrain model backing this terrain manager
|
||||||
|
* @return The terrain model
|
||||||
|
*/
|
||||||
public TerrainModel getModel() {
|
public TerrainModel getModel() {
|
||||||
return model;
|
return model;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the key for a given world position
|
||||||
|
* @param worldX The x component
|
||||||
|
* @param worldY The y component
|
||||||
|
* @param worldZ The z component
|
||||||
|
* @return The key
|
||||||
|
*/
|
||||||
public String getKey(int worldX, int worldY, int worldZ){
|
public String getKey(int worldX, int worldY, int worldZ){
|
||||||
return worldX + "_" + worldY + "_" + worldZ;
|
return worldX + "_" + worldY + "_" + worldZ;
|
||||||
}
|
}
|
||||||
@ -172,77 +220,32 @@ public class ServerTerrainManager {
|
|||||||
* @return The ServerTerrainChunk
|
* @return The ServerTerrainChunk
|
||||||
*/
|
*/
|
||||||
public ServerTerrainChunk getChunk(int worldX, int worldY, int worldZ){
|
public ServerTerrainChunk getChunk(int worldX, int worldY, int worldZ){
|
||||||
if(model != null){
|
//THIS FIRES IF THERE IS A MAIN GAME WORLD RUNNING
|
||||||
//THIS FIRES IF THERE IS A MAIN GAME WORLD RUNNING
|
String key = getKey(worldX,worldY,worldZ);
|
||||||
String key = getKey(worldX,worldY,worldZ);
|
ServerTerrainChunk returnedChunk = null;
|
||||||
ServerTerrainChunk returnedChunk;
|
if(chunkCache.containsKey(key)){
|
||||||
if(chunkCache.containsKey(key)){
|
chunkCacheContents.remove(key);
|
||||||
chunkCacheContents.remove(key);
|
chunkCacheContents.add(0, key);
|
||||||
chunkCacheContents.add(0, key);
|
returnedChunk = chunkCache.get(key);
|
||||||
returnedChunk = chunkCache.get(key);
|
return returnedChunk;
|
||||||
return returnedChunk;
|
|
||||||
} else {
|
|
||||||
//Each chunk also needs custody of the next chunk's first values so that they can perfectly overlap.
|
|
||||||
//Hence, width should actually be chunk dimension + 1
|
|
||||||
float[][] heightmap = getHeightmap(worldX, worldZ);
|
|
||||||
float[][][] weights = new float[ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE][ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE][ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE];
|
|
||||||
int[][][] values = new int[ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE][ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE][ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE];
|
|
||||||
for(int weightX = 0; weightX < ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE; weightX++){
|
|
||||||
for(int weightY = 0; weightY < ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE; weightY++){
|
|
||||||
for(int weightZ = 0; weightZ < ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE; weightZ++){
|
|
||||||
float height = heightmap[ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE * worldX + weightX][ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE * worldZ + weightZ];
|
|
||||||
if(weightY < height){
|
|
||||||
weights[weightX][weightY][weightZ] = 1;
|
|
||||||
values[weightX][weightY][weightZ] = 1;
|
|
||||||
} else if(height == 0 && weightY == 0 && worldY == 0) {
|
|
||||||
weights[weightX][weightY][weightZ] = 0.1f;
|
|
||||||
values[weightX][weightY][weightZ] = 1;
|
|
||||||
} else {
|
|
||||||
weights[weightX][weightY][weightZ] = -1;
|
|
||||||
values[weightX][weightY][weightZ] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(chunkCacheContents.size() > cacheSize){
|
|
||||||
String oldChunk = chunkCacheContents.remove(chunkCacheContents.size() - 1);
|
|
||||||
chunkCache.remove(oldChunk);
|
|
||||||
}
|
|
||||||
returnedChunk = new ServerTerrainChunk(worldX, worldY, worldZ, weights, values);
|
|
||||||
chunkCache.put(key, returnedChunk);
|
|
||||||
chunkCacheContents.add(key);
|
|
||||||
return returnedChunk;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
//THIS FIRES IF THERE IS AN ARENA WORLD RUNNING
|
if(chunkCacheContents.size() > cacheSize){
|
||||||
String key = getKey(worldX, worldY, worldZ);
|
String oldChunk = chunkCacheContents.remove(chunkCacheContents.size() - 1);
|
||||||
ServerTerrainChunk returnedChunk;
|
chunkCache.remove(oldChunk);
|
||||||
if(chunkCache.containsKey(key)){
|
|
||||||
chunkCacheContents.remove("" + key);
|
|
||||||
chunkCacheContents.add(0, key);
|
|
||||||
returnedChunk = chunkCache.get(key);
|
|
||||||
return returnedChunk;
|
|
||||||
} else {
|
|
||||||
returnedChunk = ServerTerrainChunk.getArenaChunk(worldX, worldY, worldZ);
|
|
||||||
chunkCache.put(key, returnedChunk);
|
|
||||||
chunkCacheContents.add(key);
|
|
||||||
return returnedChunk;
|
|
||||||
}
|
}
|
||||||
}
|
//pull from disk if it exists
|
||||||
}
|
if(chunkDiskMap != null){
|
||||||
|
if(chunkDiskMap.containsTerrainAtPosition(worldX, worldY, worldZ)){
|
||||||
private float[][] getHeightmap(int worldX, int worldZ){
|
returnedChunk = chunkDiskMap.getTerrainChunk(worldX, worldY, worldZ);
|
||||||
String key = worldX + "_" + worldZ;
|
}
|
||||||
if(heightmapCache.containsKey(key)){
|
}
|
||||||
return heightmapCache.get(key);
|
//generate if it does not exist
|
||||||
} else {
|
if(returnedChunk == null){
|
||||||
float[][] macroValues = model.getRad5MacroValuesAtPosition(worldX, worldZ);
|
returnedChunk = chunkGenerator.generateChunk(worldX, worldY, worldZ);
|
||||||
float[][] heightmap = TerrainInterpolator.getBicubicInterpolatedChunk(
|
}
|
||||||
macroValues,
|
chunkCache.put(key, returnedChunk);
|
||||||
model.getDynamicInterpolationRatio()
|
chunkCacheContents.add(key);
|
||||||
);
|
return returnedChunk;
|
||||||
heightmapCache.put(key,heightmap);
|
|
||||||
return heightmap;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -193,6 +193,14 @@ public class FileUtils {
|
|||||||
return Files.readString(targetFile.toPath());
|
return Files.readString(targetFile.toPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads an object from a save folder
|
||||||
|
* @param <T> The type of the object
|
||||||
|
* @param saveName The name of the save
|
||||||
|
* @param pathName The path of the file containing the object json
|
||||||
|
* @param className The class of the object
|
||||||
|
* @return The object
|
||||||
|
*/
|
||||||
public static <T>T loadObjectFromSavePath(String saveName, String pathName, Class<T> className){
|
public static <T>T loadObjectFromSavePath(String saveName, String pathName, Class<T> className){
|
||||||
T rVal = null;
|
T rVal = null;
|
||||||
String sanitizedFilePath = sanitizeFilePath(pathName);
|
String sanitizedFilePath = sanitizeFilePath(pathName);
|
||||||
@ -204,6 +212,12 @@ public class FileUtils {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serializes an object to a save folder
|
||||||
|
* @param saveName The name of the save
|
||||||
|
* @param pathName The path within the save folder to the file
|
||||||
|
* @param object The object to save
|
||||||
|
*/
|
||||||
public static void serializeObjectToSavePath(String saveName, String pathName, Object object){
|
public static void serializeObjectToSavePath(String saveName, String pathName, Object object){
|
||||||
String sanitizedFilePath = sanitizeFilePath(pathName);
|
String sanitizedFilePath = sanitizeFilePath(pathName);
|
||||||
try {
|
try {
|
||||||
@ -248,11 +262,11 @@ public class FileUtils {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if a directory exists
|
* Checks if a directory exists
|
||||||
* @param directoryName
|
* @param fileName
|
||||||
* @return true if directory exists, false otherwise
|
* @return true if directory exists, false otherwise
|
||||||
*/
|
*/
|
||||||
public static boolean checkFileExists(String directoryName){
|
public static boolean checkFileExists(String fileName){
|
||||||
File targetDir = new File(sanitizeFilePath(directoryName));
|
File targetDir = new File(sanitizeFilePath(fileName));
|
||||||
if(targetDir.exists()){
|
if(targetDir.exists()){
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
package electrosphere.util.worldviewer;
|
package electrosphere.util.worldviewer;
|
||||||
|
|
||||||
import electrosphere.server.simulation.MacroSimulation;
|
import electrosphere.server.simulation.MacroSimulation;
|
||||||
|
import electrosphere.server.terrain.generation.OverworldChunkGenerator;
|
||||||
import electrosphere.server.terrain.manager.ServerTerrainManager;
|
import electrosphere.server.terrain.manager.ServerTerrainManager;
|
||||||
import electrosphere.server.terrain.models.TerrainModel;
|
import electrosphere.server.terrain.models.TerrainModel;
|
||||||
|
|
||||||
@ -19,7 +20,7 @@ public class TerrainViewer {
|
|||||||
|
|
||||||
TerrainModel terrainModel;
|
TerrainModel terrainModel;
|
||||||
|
|
||||||
ServerTerrainManager terrainManager = new ServerTerrainManager(2000, 1000, 0.05f, new Random().nextLong());
|
ServerTerrainManager terrainManager = new ServerTerrainManager(2000, 1000, 0.05f, new Random().nextLong(), new OverworldChunkGenerator());
|
||||||
terrainManager.generate();
|
terrainManager.generate();
|
||||||
terrainModel = terrainManager.getModel();
|
terrainModel = terrainManager.getModel();
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user