Networked terrain editing

This commit is contained in:
austin 2023-06-13 18:50:23 -04:00
parent 01fb472585
commit a8941c5de7
42 changed files with 2398 additions and 402 deletions

View File

@ -54,6 +54,19 @@
"type" : "FIXED_INT"
},
{
"name" : "voxelX",
"type" : "FIXED_INT"
},
{
"name" : "voxelY",
"type" : "FIXED_INT"
},
{
"name" : "voxelZ",
"type" : "FIXED_INT"
},
@ -111,11 +124,40 @@
]
},
{
"messageName" : "Update",
"messageName" : "RequestEditVoxel",
"data" : [
"worldX",
"worldY",
"worldZ"
"worldZ",
"voxelX",
"voxelY",
"voxelZ",
"terrainWeight",
"terrainValue"
]
},
{
"messageName" : "UpdateVoxel",
"data" : [
"worldX",
"worldY",
"worldZ",
"voxelX",
"voxelY",
"voxelZ",
"terrainWeight",
"terrainValue"
]
},
{
"messageName" : "RequestUseTerrainPalette",
"data" : [
"realLocationX",
"realLocationY",
"realLocationZ",
"value",
"terrainWeight",
"terrainValue"
]
},
{

View File

@ -141,7 +141,7 @@ public class ClientFoliageManager {
modelMatrix.rotate(new Quaterniond(grassRotation));
modelMatrix.scale(new Vector3d(EntityUtils.getScale(grassEntity)));
instancedActor.setAttribute(modelMatrixAttribute, modelMatrix);
instancedActor.setAttribute(modelMatrixAttribute, new Matrix4f(modelMatrix));
//draw
// instancedActor.draw(Globals.renderingEngine.getRenderPipelineState());

View File

@ -7,8 +7,10 @@ import electrosphere.server.terrain.manager.ServerTerrainChunk;
*/
public class ChunkData {
//The size of a chunk
//The size of a chunk in virtual data
public static final int CHUNK_SIZE = ServerTerrainChunk.CHUNK_DIMENSION;
//The size of the data passed into marching cubes/transvoxel algorithm to get a fully connected and seamless chunk
public static final int CHUNK_DATA_GENERATOR_SIZE = ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE;
//What type of terrain is in this voxel, eg stone vs dirt vs grass, etc
int[][][] voxelType;

View File

@ -72,7 +72,7 @@ public class DrawCell {
if(modelEntity != null){
Globals.clientScene.deregisterEntity(modelEntity);
}
modelEntity = TerrainChunk.clientCreateTerrainChunkEntity(data.getVoxelWeight(), data.getVoxelType());
modelEntity = TerrainChunk.clientCreateTerrainChunkEntity(data.getVoxelWeight(), data.getVoxelType(), 0);
// TerrainChunk.createTerrainChunkEntity();
// Model terrainModel = RenderUtils.createMinimizedTerrainModelPrecomputedShader(heightmap, texturemap, program, stride);
// Mesh terrainMesh = terrainModel.meshes.get(0);
@ -96,10 +96,6 @@ public class DrawCell {
// EntityUtils.getPosition(modelEntity).set(getRealPos());
ClientEntityUtils.initiallyPositionEntity(modelEntity, getRealPos());
}
public void retireCell(){
EntityUtils.cleanUpEntity(modelEntity);
}
protected Vector3d getRealPos(){
return new Vector3d(
@ -122,12 +118,12 @@ public class DrawCell {
// // System.out.println("generate physics");
// }
/**
* Destroys a drawcell including its physics
*/
public void destroy(){
Realm realm = Globals.realmManager.getEntityRealm(modelEntity);
if(realm != null){
CollisionEngine collisionEngine = Globals.realmManager.getEntityRealm(modelEntity).getCollisionEngine();
collisionEngine.destroyEntityThatHasPhysics(modelEntity);
}
CollisionEngine collisionEngine = Globals.clientSceneWrapper.getCollisionEngine();
collisionEngine.destroyEntityThatHasPhysics(modelEntity);
EntityUtils.cleanUpEntity(modelEntity);
}

View File

@ -0,0 +1,71 @@
package electrosphere.client.terrain.editing;
import org.joml.Vector3d;
import org.joml.Vector3i;
import electrosphere.client.terrain.cache.ChunkData;
import electrosphere.engine.Globals;
import electrosphere.net.parser.net.message.TerrainMessage;
/**
* Utilities for editing terrain from client side of things
*/
public class TerrainEditing {
/**
* Performs a terrain chunk edit. Basically has a sphere around the provided position that it attempts to add value to.
* @param position The position to perform the edit
* @param editMagnitude The magnitude of the edit to perform
* @param type The type of block to make all edited blocks
* @param weight The weight of the sphere to apply the edit to
*/
public static void editTerrain(Vector3d position, float editMagnitude, int type, float weight){
if(position != null){
Globals.clientConnection.queueOutgoingMessage(TerrainMessage.constructRequestUseTerrainPaletteMessage(position.x, position.y, position.z, editMagnitude, weight, type));
//calculate kernel size
// int numPlacesToCheck = (int)((editMagnitude * 2 + 1) * (editMagnitude * 2 + 1) * (editMagnitude * 2 + 1));
// //create and fill in kernel of positions to check
// int[] xOffsetSet = new int[numPlacesToCheck];
// int[] yOffsetSet = new int[numPlacesToCheck];
// int[] zOffsetSet = new int[numPlacesToCheck];
// int i = 0;
// for(int x = -(int)editMagnitude; x <= (int)editMagnitude; x++){
// for(int y = -(int)editMagnitude; y <= (int)editMagnitude; y++){
// for(int z = -(int)editMagnitude; z <= (int)editMagnitude; z++){
// xOffsetSet[i] = x;
// yOffsetSet[i] = y;
// zOffsetSet[i] = z;
// i++;
// }
// }
// }
// for(i = 0; i < numPlacesToCheck; i++){
// //calculate position of edit
// Vector3d offsetPos = new Vector3d(position).add(xOffsetSet[i],yOffsetSet[i],zOffsetSet[i]);
// Vector3i chunkPos = Globals.clientWorldData.convertRealToChunkSpace(offsetPos);
// Vector3i voxelPos = Globals.clientWorldData.convertRealToVoxelSpace(offsetPos);
// //get distance from true center point of sphere to current voxel position in world space
// float distance = (float)new Vector3d(Math.floor(offsetPos.x),Math.floor(offsetPos.y),Math.floor(offsetPos.z)).distance(position);
// float currentPositionMagnitude = editMagnitude - distance;
// ChunkData data = Globals.clientTerrainManager.getChunkDataAtWorldPoint(chunkPos.x, chunkPos.y, chunkPos.z);
// if(
// voxelPos.x < ChunkData.CHUNK_SIZE &&
// voxelPos.y < ChunkData.CHUNK_SIZE &&
// voxelPos.z < ChunkData.CHUNK_SIZE &&
// currentPositionMagnitude > 0 &&
// data != null
// ){
// float current = data.getVoxelWeight()[voxelPos.x][voxelPos.y][voxelPos.z];
// //hard clamp so it doesn't go over 1
// float finalValue = Math.max(Math.min(current + weight,1),-1);
// Globals.clientTerrainManager.updateChunk(
// chunkPos.x, chunkPos.y, chunkPos.z,
// voxelPos.x, voxelPos.y, voxelPos.z,
// finalValue, 1
// );
// }
// }
}
}
}

View File

@ -56,22 +56,22 @@ public class ClientTerrainManager {
messageQueue.remove(message);
switch(message.getMessageSubtype()){
case SENDCHUNKDATA: {
int[][][] values = new int[ChunkData.CHUNK_SIZE][ChunkData.CHUNK_SIZE][ChunkData.CHUNK_SIZE];
float[][][] weights = new float[ChunkData.CHUNK_SIZE][ChunkData.CHUNK_SIZE][ChunkData.CHUNK_SIZE];
int[][][] values = new int[ChunkData.CHUNK_DATA_GENERATOR_SIZE][ChunkData.CHUNK_DATA_GENERATOR_SIZE][ChunkData.CHUNK_DATA_GENERATOR_SIZE];
float[][][] weights = new float[ChunkData.CHUNK_DATA_GENERATOR_SIZE][ChunkData.CHUNK_DATA_GENERATOR_SIZE][ChunkData.CHUNK_DATA_GENERATOR_SIZE];
ByteBuffer buffer = ByteBuffer.wrap(message.getchunkData());
FloatBuffer floatBuffer = buffer.asFloatBuffer();
for(int x = 0; x < ChunkData.CHUNK_SIZE; x++){
for(int y = 0; y < ChunkData.CHUNK_SIZE; y++){
for(int z = 0; z < ChunkData.CHUNK_SIZE; z++){
for(int x = 0; x < ChunkData.CHUNK_DATA_GENERATOR_SIZE; x++){
for(int y = 0; y < ChunkData.CHUNK_DATA_GENERATOR_SIZE; y++){
for(int z = 0; z < ChunkData.CHUNK_DATA_GENERATOR_SIZE; z++){
weights[x][y][z] = floatBuffer.get();
}
}
}
IntBuffer intView = buffer.asIntBuffer();
intView.position(floatBuffer.position());
for(int x = 0; x < ChunkData.CHUNK_SIZE; x++){
for(int y = 0; y < ChunkData.CHUNK_SIZE; y++){
for(int z = 0; z < ChunkData.CHUNK_SIZE; z++){
for(int x = 0; x < ChunkData.CHUNK_DATA_GENERATOR_SIZE; x++){
for(int y = 0; y < ChunkData.CHUNK_DATA_GENERATOR_SIZE; y++){
for(int z = 0; z < ChunkData.CHUNK_DATA_GENERATOR_SIZE; z++){
values[x][y][z] = intView.get();
}
}

View File

@ -10,6 +10,8 @@ import static org.ode4j.ode.internal.Common.dRecip;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Semaphore;
@ -468,131 +470,7 @@ public class CollisionEngine {
// double entityHeight = EntityUtils.getPosition(e).y;
// return entityHeight > worldHeight + 0.1f;
// }
public float sweepTest(DBody body, Vector3f startPos, Vector3f endPos){
// space.collide2(body.getFirstGeom(), endPos, nearCallback);
// SphereShape sphere = new SphereShape(0.1f);
// // CollisionObject collider = new CollisionObject();
// // collider.setCollisionShape(sphere);
// ClosestConvexResultCallbackImpl callback = new ClosestConvexResultCallbackImpl(startPos,endPos,object,dispatcher,world.getPairCache());
// callback.collisionFilterGroup = 1;
// callback.collisionFilterMask = 1;
// world.convexSweepTest(sphere, PhysicsUtils.jomlVecToTransform(startPos), PhysicsUtils.jomlVecToTransform(endPos), callback);
// // callback.hasHit()
// if(callback.hasHit()){
// return callback.closestHitFraction;
// } else {
// return -1.0f;
// }
return -1.0f;
}
boolean RaycastQuery(DSpace space, DVector3 start, DVector3 end) {
// Calculate direction
DVector3 direction = new DVector3();
dSubtractVectors3(direction, end, start);
// Get length
double length = dCalcVectorLengthSquare3(direction);
double inverseLength = dRecip(length);
// Normalize
direction.scale(inverseLength);
// Create ray
DRay ray = OdeHelper.createRay(space, length);
ray.set(start.get0(), start.get1(), start.get2(), direction.get0(), direction.get1(), direction.get2());
// Check collisions
DVector4 hitPosition = new DVector4();
hitPosition.set3(dInfinity);
space.collide2(ray, null, nearCallback);
// Cleanup
ray.destroy();
// Check for hit
if(hitPosition.get3() != dInfinity) {
end.set0(hitPosition.get0());
end.set1(hitPosition.get1());
end.set2(hitPosition.get2());
return true;
}
return false;
}
// private static class ClosestConvexResultCallbackImpl extends ClosestConvexResultCallback {
// CollisionObject me;
// private OverlappingPairCache pairCache;
// private Dispatcher dispatcher;
// public ClosestConvexResultCallbackImpl(Vector3f startPos, Vector3f endPos, CollisionObject me, Dispatcher dispatcher, OverlappingPairCache pairCache){
// super(PhysicsUtils.jomlToVecmathVector3f(startPos),PhysicsUtils.jomlToVecmathVector3f(endPos));
// this.me = me;
// this.pairCache = pairCache;
// this.dispatcher = dispatcher;
// }
// @Override
// public float addSingleResult(LocalConvexResult convexResult, boolean normalInWorldSpace) {
// if (convexResult.hitCollisionObject == me) {
// return 1f;
// }
// Vector3f linVelA = new Vector3f(), linVelB = new Vector3f();
// linVelA.sub(PhysicsUtils.vecmathToJomlVector3f(convexToWorld), PhysicsUtils.vecmathToJomlVector3f(convexFromWorld));
// linVelB.set(0f, 0f, 0f);//toB.getOrigin()-fromB.getOrigin();
// Vector3f relativeVelocity = new Vector3f();
// relativeVelocity.sub(linVelA, linVelB);
// // don't report time of impact for motion away from the contact normal (or causes minor penetration)
// if (convexResult.hitNormalLocal.dot(PhysicsUtils.jomlToVecmathVector3f(relativeVelocity)) >= -0f) {
// return 1f;
// }
// return super.addSingleResult(convexResult, normalInWorldSpace);
// }
// @Override
// public boolean needsCollision(BroadphaseProxy proxy0) {
// // don't collide with itself
// if (proxy0.clientObject == me) {
// return false;
// }
// // don't do CCD when the collision filters are not matching
// if (!super.needsCollision(proxy0)) {
// return false;
// }
// CollisionObject otherObj = (CollisionObject)proxy0.clientObject;
// // call needsResponse, see http://code.google.com/p/bullet/issues/detail?id=179
// if (dispatcher.needsResponse(me, otherObj)) {
// // don't do CCD when there are already contact points (touching contact/penetration)
// ObjectArrayList<PersistentManifold> manifoldArray = new ObjectArrayList<PersistentManifold>();
// BroadphasePair collisionPair = pairCache.findPair(me.getBroadphaseHandle(), proxy0);
// if (collisionPair != null) {
// if (collisionPair.algorithm != null) {
// //manifoldArray.resize(0);
// collisionPair.algorithm.getAllContactManifolds(manifoldArray);
// for (int j=0; j<manifoldArray.size(); j++) {
// PersistentManifold manifold = manifoldArray.getQuick(j);
// if (manifold.getNumContacts() > 0) {
// return false;
// }
// }
// }
// }
// }
// return true;
// }
// }
/**
* Casts a ray into the scene and returns the first entity that the ray collides with.
@ -653,6 +531,29 @@ public class CollisionEngine {
spaceLock.release();
return data.collisionPosition;
}
/**
* Ray casts into the scene and gets the position of the closest collision's position in world space.
* @param start The start position of the ray to cast
* @param direction The direction of the ray to cast
* @param length The length of the ray to cast
* @param typeMask The mask of types to collide the ray with
* @return The position, in world coordinates, of the closest collision of the way, or null if it did not collide with anything.
*/
public Vector3d rayCastPositionMasked(Vector3d start, Vector3d direction, double length, List<String> typeMask){
spaceLock.acquireUninterruptibly();
//create the ray
DRay ray = OdeHelper.createRay(space, length);
ray.set(start.x, start.y, start.z, direction.x, direction.y, direction.z);
//collide
RayCastCallbackData data = new RayCastCallbackData(bodyPointerMap, typeMask);
rayCastCallback.setLength(length);
space.collide2(ray, data, rayCastCallback);
//destroy ray
ray.destroy();
spaceLock.release();
return data.collisionPosition;
}
public void registerPhysicsObject(DBody body){
if(!bodies.contains(body)){
@ -661,11 +562,23 @@ public class CollisionEngine {
}
}
/**
* Destroys a body and all geometry under the body
* @param body The DBody to destroy
*/
public void deregisterPhysicsObject(DBody body){
spaceLock.acquireUninterruptibly();
if(bodies.contains(body)){
bodies.remove(body);
}
Iterator<DGeom> geomIterator = body.getGeomIterator();
while(geomIterator.hasNext()){
DGeom geom = geomIterator.next();
space.remove(geom);
geom.destroy();
}
body.destroy();
spaceLock.release();
}
public void deregisterRigidBody(DBody body){
@ -695,7 +608,7 @@ public class CollisionEngine {
public void destroyEntityThatHasPhysics(Entity e){
//make uncollidable
if(e.containsKey(EntityDataStrings.PHYSICS_COLLISION_BODY) && e.containsKey(EntityDataStrings.PHYSICS_COLLIDABLE)){
if(e.containsKey(EntityDataStrings.PHYSICS_COLLISION_BODY)){
DBody rigidBody = (DBody)e.getData(EntityDataStrings.PHYSICS_COLLISION_BODY);
deregisterPhysicsObject(rigidBody);
}

View File

@ -0,0 +1,24 @@
package electrosphere.collision;
import java.util.LinkedList;
import electrosphere.collision.collidable.Collidable;
/**
* Contains masks for different collision engine functions
*/
public class CollisionMasks {
//Only terrain
public static final LinkedList<String> terrainMask = new LinkedList<String>();
/**
* Fills in all the collision engine masks
*/
public static void initMasks(){
//terrain mask
terrainMask.add(Collidable.TYPE_TERRAIN);
}
}

View File

@ -69,12 +69,11 @@ import java.util.List;
import org.joml.Vector2f;
import org.joml.Vector3d;
import org.joml.Vector3f;
import org.joml.Vector3i;
import org.lwjgl.glfw.GLFW;
import electrosphere.audio.AudioUtils;
import electrosphere.client.targeting.crosshair.Crosshair;
import electrosphere.client.terrain.cache.ChunkData;
import electrosphere.client.terrain.editing.TerrainEditing;
import electrosphere.collision.CollisionEngine;
import electrosphere.controls.Control.ControlMethod;
import electrosphere.controls.Control.ControlType;
@ -134,6 +133,7 @@ public class ControlHandler {
public static final String INPUT_CODE_CHARACTER_OPEN = "characterOpen";
public static final String INPUT_CODE_IRON_SIGHT = "ironSight";
public static final String INPUT_CODE_PLACE_TERRAIN = "placeTerrain";
public static final String INPUT_CODE_REMOVE_TERRAIN = "removeTerrain";
public static final String DATA_STRING_INPUT_CODE_MENU_NAVIGATE_FORWARD = "menuNavigateForward";
public static final String DATA_STRING_INPUT_CODE_MENU_NAVIGATE_BACKWARDS = "menuNavigateBackwards";
@ -328,6 +328,7 @@ public class ControlHandler {
Terrain controls
*/
handler.addControl(INPUT_CODE_PLACE_TERRAIN, new Control(ControlType.KEY,GLFW_KEY_T));
handler.addControl(INPUT_CODE_REMOVE_TERRAIN, new Control(ControlType.KEY,GLFW_KEY_Y));
/*
framestep controls
@ -942,50 +943,52 @@ public class ControlHandler {
Vector3d eyePos = new Vector3d(CameraEntityUtils.getCameraEye(camera));
Vector3d centerPos = new Vector3d(CameraEntityUtils.getCameraCenter(camera));
Vector3d cursorPos = collisionEngine.rayCastPosition(new Vector3d(centerPos), new Vector3d(eyePos).mul(-1.0), 5.0);
int[] xOffsetSet = new int[]{
0,1,0,1,0,1,0,1,
};
int[] yOffsetSet = new int[]{
0,0,0,0,1,1,1,1,
};
int[] zOffsetSet = new int[]{
0,0,1,1,0,0,1,1,
};
if(cursorPos != null){
Vector3i chunkPos = Globals.clientWorldData.convertRealToChunkSpace(cursorPos);
Vector3i voxelPos = Globals.clientWorldData.convertRealToVoxelSpace(cursorPos);
for(int i = 0; i < 8; i++){
Vector3i actualPos = new Vector3i(
voxelPos.x + xOffsetSet[i],
voxelPos.y + yOffsetSet[i],
voxelPos.z + zOffsetSet[i]
);
if(
actualPos.x < ChunkData.CHUNK_SIZE &&
actualPos.y < ChunkData.CHUNK_SIZE &&
actualPos.z < ChunkData.CHUNK_SIZE
){
Globals.clientTerrainManager.updateChunk(
chunkPos.x, chunkPos.y, chunkPos.z,
actualPos.x, actualPos.y, actualPos.z,
1.0f, 1
);
}
}
// Globals.clientTerrainManager.getChunkDataAtWorldPoint(chunkPos.x, chunkPos.y, chunkPos.z)
// .updatePosition(voxelPos.x, voxelPos.y, voxelPos.z, 1.0f, 1);
// Globals.clientTerrainManager.updateChunk(
// chunkPos.x, chunkPos.y, chunkPos.z,
// voxelPos.x, voxelPos.y, voxelPos.z,
// 1.0f, 1
// );
// System.out.println("Terrain");
// System.out.println(Globals.clientWorldData.convertRealToChunkSpace(cursorPos));
// System.out.println(Globals.clientWorldData.convertRealToVoxelSpace(cursorPos));
}
TerrainEditing.editTerrain(cursorPos, 1.1f, 1, 0.01f);
}
}});
controls.get(INPUT_CODE_PLACE_TERRAIN).setRepeatTimeout(0.5f * Main.targetFrameRate);
controls.get(INPUT_CODE_PLACE_TERRAIN).setOnRepeat(new ControlMethod(){public void execute(){
CollisionEngine collisionEngine = Globals.clientSceneWrapper.getCollisionEngine();
Entity camera = Globals.playerCamera;
if(
collisionEngine != null &&
camera != null
){
Vector3d eyePos = new Vector3d(CameraEntityUtils.getCameraEye(camera));
Vector3d centerPos = new Vector3d(CameraEntityUtils.getCameraCenter(camera));
Vector3d cursorPos = collisionEngine.rayCastPosition(new Vector3d(centerPos), new Vector3d(eyePos).mul(-1.0), 5.0);
TerrainEditing.editTerrain(cursorPos, 1.1f, 1, 0.01f);
}
}});
controls.get(INPUT_CODE_PLACE_TERRAIN).setRepeatTimeout(0.2f * Main.targetFrameRate);
mainGameControlList.add(controls.get(INPUT_CODE_REMOVE_TERRAIN));
controls.get(INPUT_CODE_REMOVE_TERRAIN).setOnPress(new ControlMethod(){public void execute(){
CollisionEngine collisionEngine = Globals.clientSceneWrapper.getCollisionEngine();
Entity camera = Globals.playerCamera;
if(
collisionEngine != null &&
camera != null
){
Vector3d eyePos = new Vector3d(CameraEntityUtils.getCameraEye(camera));
Vector3d centerPos = new Vector3d(CameraEntityUtils.getCameraCenter(camera));
Vector3d cursorPos = collisionEngine.rayCastPosition(new Vector3d(centerPos), new Vector3d(eyePos).mul(-1.0), 5.0);
TerrainEditing.editTerrain(cursorPos, 1.1f, 1, -0.01f);
}
}});
controls.get(INPUT_CODE_REMOVE_TERRAIN).setOnRepeat(new ControlMethod(){public void execute(){
CollisionEngine collisionEngine = Globals.clientSceneWrapper.getCollisionEngine();
Entity camera = Globals.playerCamera;
if(
collisionEngine != null &&
camera != null
){
Vector3d eyePos = new Vector3d(CameraEntityUtils.getCameraEye(camera));
Vector3d centerPos = new Vector3d(CameraEntityUtils.getCameraCenter(camera));
Vector3d cursorPos = collisionEngine.rayCastPosition(new Vector3d(centerPos), new Vector3d(eyePos).mul(-1.0), 5.0);
TerrainEditing.editTerrain(cursorPos, 1.1f, 1, -0.01f);
}
}});
controls.get(INPUT_CODE_REMOVE_TERRAIN).setRepeatTimeout(0.2f * Main.targetFrameRate);
}

View File

@ -20,6 +20,7 @@ import electrosphere.client.sim.ClientSimulation;
import electrosphere.client.terrain.cells.DrawCellManager;
import electrosphere.client.terrain.manager.ClientTerrainManager;
import electrosphere.collision.CollisionEngine;
import electrosphere.collision.CollisionMasks;
import electrosphere.collision.CollisionWorldData;
import electrosphere.controls.CameraHandler;
import electrosphere.controls.ControlCallback;
@ -396,6 +397,8 @@ public class Globals {
if(Globals.userSettings.getNetRunNetMonitor()){
netMonitor = new NetMonitor();
}
//init collision masks
CollisionMasks.initMasks();
}
public static void initDefaultAudioResources(){

View File

@ -225,6 +225,8 @@ public class ClientLoading {
Vector3d cursorPos = collisionEngine.rayCastPosition(centerPos, new Vector3d(eyePos).mul(-1.0), 5.0);
if(cursorPos != null){
EntityUtils.getPosition(cursorTracker).set(cursorPos);
} else {
EntityUtils.getPosition(cursorTracker).set(new Vector3d(centerPos).add(new Vector3d(eyePos).normalize().mul(-5.0)));
}
}
}

View File

@ -13,6 +13,7 @@ import electrosphere.logger.LoggerInterface;
import electrosphere.menu.MenuGenerators;
import electrosphere.menu.WindowStrings;
import electrosphere.menu.WindowUtils;
import electrosphere.net.parser.net.message.TerrainMessage;
import electrosphere.renderer.ui.Window;
import electrosphere.server.saves.SaveUtils;
import electrosphere.server.terrain.manager.ServerTerrainManager;
@ -53,14 +54,20 @@ public class DebugSPWorldLoading {
LoggerInterface.loggerEngine.INFO("run server: " + Globals.RUN_SERVER + " run client: " + Globals.RUN_CLIENT);
//init the data of the world
// LoadingUtils.initTerrainDataCellManager();
//init authentication
LoadingUtils.initAuthenticationManager();
//initialize the local connection
Globals.clientUsername = "testuser";
Globals.clientPassword = AuthenticationManager.getHashedString("testpass");
LoadingUtils.initLocalConnection();
//wait for player object creation
while(Globals.playerManager.getPlayers().size() < 1){
try {
TimeUnit.MILLISECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//initialize the "real" objects simulation
LoadingUtils.initMicroSimulation();
//init game specific stuff (ie different skybox colors)
@ -77,29 +84,14 @@ public class DebugSPWorldLoading {
} catch (InterruptedException ex) {}
}
//spawn player character
LoadingUtils.spawnLocalPlayerTestEntity();
initWorldBaseGraphicalEntities();
//request terrain data
Globals.clientConnection.queueOutgoingMessage(TerrainMessage.constructRequestMetadataMessage());
// SeekTown.attachToCreature(Globals.playerEntity);
//hide cursor
Globals.controlHandler.hideMouse();
//make loading window disappear
loadingWindow.setVisible(false);
//recapture screen
Globals.controlHandler.setShouldRecapture(true);
//set rendering flags to main game mode
Globals.RENDER_FLAG_RENDER_SHADOW_MAP = true;
Globals.RENDER_FLAG_RENDER_SCREEN_FRAMEBUFFER_CONTENT = true;
Globals.RENDER_FLAG_RENDER_SCREEN_FRAMEBUFFER = true;
Globals.RENDER_FLAG_RENDER_UI = true;
Globals.RENDER_FLAG_RENDER_BLACK_BACKGROUND = false;
Globals.RENDER_FLAG_RENDER_WHITE_BACKGROUND = false;
LoggerInterface.loggerEngine.INFO("[Client]Finished loading main game");
//set controls state
Globals.controlHandler.setHandlerState(ControlHandler.ControlsState.MAIN_GAME);
//Run client startup process
ClientLoading.loadClientWorld();
}

View File

@ -239,6 +239,7 @@ public class LoadingUtils {
}
}
Realm realm = Globals.realmManager.getRealms().iterator().next();
//create player
//spawn entity
Entity newPlayerEntity = CreatureUtils.serverSpawnBasicCreature(realm,Globals.spawnPoint,template.getCreatureType(),template);
Globals.playerEntity = newPlayerEntity;

View File

@ -142,32 +142,32 @@ public class ClientCollidableTree implements BehaviorTree {
// System.out.println(cumulativeTorque);
// }
//friction
if(angularVelocity.lengthSquared() > 0.001){
angularVelocity.slerp(new Quaterniond(0,0,0,1), 0.03);
// angularVelocity.scale((float)(Math.sqrt(angularVelocity.lengthSquared()) * 0.9));
// System.out.println(angularVelocity);
}
// if(cumulativeTorque.w > 0.001){
// Vector4f holder = inverseInertiaTensor.transform(new Vector4f((float)cumulativeTorque.x,(float)cumulativeTorque.y,(float)cumulativeTorque.z,(float)cumulativeTorque.w));
// cumulativeTorque = new Vector4d(holder.x,holder.y,holder.z,holder.w);
// angularVelocity = angularVelocity.add(cumulativeTorque).normalize();
// cumulativeTorque.set(0,0,0,0);
// // Vector3d normalizedTorqueDir = new Vector3d(cumulativeTorque.x,cumulativeTorque.y,cumulativeTorque.z).normalize();
// // double newMag = cumulativeTorque.w * 0.9;
// // cumulativeTorque.set(normalizedTorqueDir.x,normalizedTorqueDir.y,normalizedTorqueDir.z,newMag);
// if(angularVelocity.lengthSquared() > 0.001){
// angularVelocity.slerp(new Quaterniond(0,0,0,1), 0.03);
// // angularVelocity.scale((float)(Math.sqrt(angularVelocity.lengthSquared()) * 0.9));
// // System.out.println(angularVelocity);
// }
// // if(cumulativeTorque.w > 0.001){
// // Vector4f holder = inverseInertiaTensor.transform(new Vector4f((float)cumulativeTorque.x,(float)cumulativeTorque.y,(float)cumulativeTorque.z,(float)cumulativeTorque.w));
// // cumulativeTorque = new Vector4d(holder.x,holder.y,holder.z,holder.w);
// // angularVelocity = angularVelocity.add(cumulativeTorque).normalize();
// // cumulativeTorque.set(0,0,0,0);
// // // Vector3d normalizedTorqueDir = new Vector3d(cumulativeTorque.x,cumulativeTorque.y,cumulativeTorque.z).normalize();
// // // double newMag = cumulativeTorque.w * 0.9;
// // // cumulativeTorque.set(normalizedTorqueDir.x,normalizedTorqueDir.y,normalizedTorqueDir.z,newMag);
// // }
// if(angularVelocity.lengthSquared() > 0.001){
// // System.out.println("-" + rotation);
// Quaterniond newRotation = new Quaterniond(rotation).mul(angularVelocity).normalize();
// // if(new Quaternionf(newRotation).add(new Quaternionf(rotation).conjugate()).lengthSquared() > 0.2){
// // newRotation.w = Math.copySign(newRotation.w, rotation.w);
// // newRotation.x = Math.copySign(newRotation.x, rotation.x);
// // newRotation.y = Math.copySign(newRotation.y, rotation.y);
// // newRotation.z = Math.copySign(newRotation.z, rotation.z);
// // }
// rotation.set(newRotation);
// // System.out.println("=" + rotation);
// }
if(angularVelocity.lengthSquared() > 0.001){
// System.out.println("-" + rotation);
Quaterniond newRotation = new Quaterniond(rotation).mul(angularVelocity).normalize();
// if(new Quaternionf(newRotation).add(new Quaternionf(rotation).conjugate()).lengthSquared() > 0.2){
// newRotation.w = Math.copySign(newRotation.w, rotation.w);
// newRotation.x = Math.copySign(newRotation.x, rotation.x);
// newRotation.y = Math.copySign(newRotation.y, rotation.y);
// newRotation.z = Math.copySign(newRotation.z, rotation.z);
// }
rotation.set(newRotation);
// System.out.println("=" + rotation);
}
// if(inverseInertiaTensor != null && angularVelocity.w > 0.01){
// // Vector4f angularMomentum = inverseInertiaTensor.transform(new Vector4f((float)cumulativeTorque.x,(float)cumulativeTorque.x,(float)cumulativeTorque.x,(float)cumulativeTorque.w));
// // Quaternionf nextRotation = new Quaternionf(rotation).mul(new Quaternionf(angularMomentum.x,angularMomentum.y,angularMomentum.z,angularMomentum.w).scale(0.001f)).normalize();

View File

@ -1,5 +1,6 @@
package electrosphere.entity.state.gravity;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
@ -9,6 +10,7 @@ import org.joml.Vector3d;
import org.joml.Vector3f;
import org.ode4j.ode.DBody;
import electrosphere.collision.CollisionMasks;
import electrosphere.collision.collidable.Collidable;
import electrosphere.engine.Globals;
import electrosphere.entity.Entity;
@ -161,18 +163,24 @@ public class ClientGravityTree implements BehaviorTree {
gravityVelocity = gravityConstant;
}
float gravityDif = gravityVelocity * (float)Math.pow(1.0f - linearDamping,deltaTime * 2);
Vector3d newGravityPos = new Vector3d(position.x,position.y - gravityDif,position.z);
float hitFraction = Globals.clientSceneWrapper.getCollisionEngine().sweepTest(body, new Vector3f((float)position.x,(float)position.y,(float)position.z), new Vector3f((float)newGravityPos.x,(float)newGravityPos.y,(float)newGravityPos.z));
// Vector3d newGravityPos = new Vector3d(position.x,position.y - gravityDif,position.z);
// Entity terrainHit = Globals.clientSceneWrapper.getCollisionEngine().rayCast(
// position,
// new Vector3d(0,-1,0),
// gravityDif,
// CollisionMasks.terrainMask
// );
// float hitFraction = Globals.clientSceneWrapper.getCollisionEngine().sweepTest(body, new Vector3f((float)position.x,(float)position.y,(float)position.z), new Vector3f((float)newGravityPos.x,(float)newGravityPos.y,(float)newGravityPos.z));
// if(hitFraction >= 0){
// collidable.addImpulse(new Impulse(new Vector3d(0,-1,0),gravityDif * hitFraction,"gravity"));
// position.set(new Vector3d(position.x,position.y - gravityDif * hitFraction,position.z));
// } else {
// position.set(new Vector3d(position.x,position.y - gravityDif,position.z));
// }
if(hitFraction < 0){
hitFraction = 1;
}
collidable.addImpulse(new Impulse(new Vector3d(0,-1,0), new Vector3d(0,0,0), new Vector3d(position), gravityDif * hitFraction,"gravity"));
// if(hitFraction < 0){
// hitFraction = 1;
// }
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));

View File

@ -162,19 +162,19 @@ public class ServerGravityTree implements BehaviorTree {
gravityVelocity = gravityConstant;
}
float gravityDif = gravityVelocity * (float)Math.pow(1.0f - linearDamping,deltaTime * 2);
Vector3d newGravityPos = new Vector3d(position.x,position.y - gravityDif,position.z);
Realm parentRealm = Globals.realmManager.getEntityRealm(parent);
float hitFraction = parentRealm.getCollisionEngine().sweepTest(body, new Vector3f((float)position.x,(float)position.y,(float)position.z), new Vector3f((float)newGravityPos.x,(float)newGravityPos.y,(float)newGravityPos.z));
// Vector3d newGravityPos = new Vector3d(position.x,position.y - gravityDif,position.z);
// Realm parentRealm = Globals.realmManager.getEntityRealm(parent);
// float hitFraction = parentRealm.getCollisionEngine().sweepTest(body, new Vector3f((float)position.x,(float)position.y,(float)position.z), new Vector3f((float)newGravityPos.x,(float)newGravityPos.y,(float)newGravityPos.z));
// if(hitFraction >= 0){
// collidable.addImpulse(new Impulse(new Vector3d(0,-1,0),gravityDif * hitFraction,"gravity"));
// position.set(new Vector3d(position.x,position.y - gravityDif * hitFraction,position.z));
// } else {
// position.set(new Vector3d(position.x,position.y - gravityDif,position.z));
// }
if(hitFraction < 0){
hitFraction = 1;
}
collidable.addImpulse(new Impulse(new Vector3d(0,-1,0), new Vector3d(0,0,0), new Vector3d(position), gravityDif * hitFraction,"gravity"));
// if(hitFraction < 0){
// hitFraction = 1;
// }
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));

View File

@ -21,16 +21,17 @@ public class TerrainChunk {
* Creates a client terrain chunk based on weights and values provided
* @param weights The terrain weights
* @param values The values (block types)
* @param levelOfDetail Increasing value that increments level of detail. 0 would be full resolution, 1 would be half resolution and so on. Only generates physics if levelOfDetail is 0
* @return The terrain chunk entity
*/
public static Entity clientCreateTerrainChunkEntity(float[][][] weights, int[][][] values){
public static Entity clientCreateTerrainChunkEntity(float[][][] weights, int[][][] values, int levelOfDetail){
TerrainChunkData data = TerrainChunkModelGeneration.generateTerrainChunkData(weights, values);
String modelPath = ClientTerrainManager.queueTerrainGridGeneration(data);
Entity rVal = EntityCreationUtils.createClientSpatialEntity();
EntityCreationUtils.makeEntityDrawablePreexistingModel(rVal, modelPath);
if(data.vertices.size() > 0){
if(data.vertices.size() > 0 && levelOfDetail < 1){
PhysicsUtils.clientAttachTerrainChunkRigidBody(rVal, data);
}

View File

@ -4,7 +4,10 @@ import electrosphere.server.datacell.ServerDataCell;
import electrosphere.server.terrain.manager.ServerTerrainManager;
import java.util.List;
import org.joml.Vector3d;
import org.joml.Vector3f;
import org.joml.Vector3i;
/**
*
@ -112,6 +115,30 @@ public class ServerWorldData {
return isArena;
}
/**
* Converts a real coordinate to a world space coordinate
* @param position The real coordinate
* @return The world space coordinate
*/
public Vector3i convertRealToWorldSpace(Vector3d position){
return new Vector3i(
convertRealToChunkSpace(position.x),
convertRealToChunkSpace(position.y),
convertRealToChunkSpace(position.z)
);
}
/**
* Converts a real coordinate to a voxel space coordinate, relative to the containing chunk of the real coordinate
* @param position The real coordinate
* @return The voxel space coordinate
*/
public Vector3i convertRealToVoxelSpace(Vector3d position){
return new Vector3i(
(int)Math.floor(position.x - convertChunkToRealSpace(convertRealToChunkSpace(position.x))),
(int)Math.floor(position.y - convertChunkToRealSpace(convertRealToChunkSpace(position.y))),
(int)Math.floor(position.z - convertChunkToRealSpace(convertRealToChunkSpace(position.z)))
);
}
}

View File

@ -34,6 +34,21 @@ public class TerrainProtocol {
case SENDCHUNKDATA:
Globals.clientTerrainManager.attachTerrainMessage(message);
break;
case UPDATEVOXEL: {
if(Globals.clientTerrainManager.containsChunkDataAtWorldPoint(message.getworldX(), message.getworldY(), message.getworldZ())){
ChunkData data = Globals.clientTerrainManager.getChunkDataAtWorldPoint(message.getworldX(), message.getworldY(), message.getworldZ());
if(data != null){
data.updatePosition(
message.getvoxelX(),
message.getvoxelY(),
message.getvoxelZ(),
message.getterrainWeight(),
message.getterrainValue()
);
Globals.drawCellManager.markUpdateable(message.getworldX(), message.getworldY(), message.getworldZ());
}
}
} break;
default:
LoggerInterface.loggerNetworking.WARNING("Client networking: Unhandled message of type: " + message.getMessageSubtype());
break;

View File

@ -200,9 +200,19 @@ INVENTORY_MESSAGE,
rVal = TerrainMessage.parseRequestChunkMessage(byteBuffer);
}
break;
case TypeBytes.TERRAIN_MESSAGE_TYPE_UPDATE:
case TypeBytes.TERRAIN_MESSAGE_TYPE_REQUESTEDITVOXEL:
if(TerrainMessage.canParseMessage(byteBuffer,secondByte)){
rVal = TerrainMessage.parseUpdateMessage(byteBuffer);
rVal = TerrainMessage.parseRequestEditVoxelMessage(byteBuffer);
}
break;
case TypeBytes.TERRAIN_MESSAGE_TYPE_UPDATEVOXEL:
if(TerrainMessage.canParseMessage(byteBuffer,secondByte)){
rVal = TerrainMessage.parseUpdateVoxelMessage(byteBuffer);
}
break;
case TypeBytes.TERRAIN_MESSAGE_TYPE_REQUESTUSETERRAINPALETTE:
if(TerrainMessage.canParseMessage(byteBuffer,secondByte)){
rVal = TerrainMessage.parseRequestUseTerrainPaletteMessage(byteBuffer);
}
break;
case TypeBytes.TERRAIN_MESSAGE_TYPE_SPAWNPOSITION:

View File

@ -11,7 +11,9 @@ public class TerrainMessage extends NetworkMessage {
REQUESTMETADATA,
RESPONSEMETADATA,
REQUESTCHUNK,
UPDATE,
REQUESTEDITVOXEL,
UPDATEVOXEL,
REQUESTUSETERRAINPALETTE,
SPAWNPOSITION,
REQUESTCHUNKDATA,
SENDCHUNKDATA,
@ -29,6 +31,9 @@ public class TerrainMessage extends NetworkMessage {
int worldX;
int worldY;
int worldZ;
int voxelX;
int voxelY;
int voxelZ;
double realLocationX;
double realLocationY;
double realLocationZ;
@ -133,6 +138,30 @@ public class TerrainMessage extends NetworkMessage {
this.worldZ = worldZ;
}
public int getvoxelX() {
return voxelX;
}
public void setvoxelX(int voxelX) {
this.voxelX = voxelX;
}
public int getvoxelY() {
return voxelY;
}
public void setvoxelY(int voxelY) {
this.voxelY = voxelY;
}
public int getvoxelZ() {
return voxelZ;
}
public void setvoxelZ(int voxelZ) {
this.voxelZ = voxelZ;
}
public double getrealLocationX() {
return realLocationX;
}
@ -205,8 +234,20 @@ public class TerrainMessage extends NetworkMessage {
} else {
return false;
}
case TypeBytes.TERRAIN_MESSAGE_TYPE_UPDATE:
if(byteBuffer.getRemaining() >= TypeBytes.TERRAIN_MESSAGE_TYPE_UPDATE_SIZE){
case TypeBytes.TERRAIN_MESSAGE_TYPE_REQUESTEDITVOXEL:
if(byteBuffer.getRemaining() >= TypeBytes.TERRAIN_MESSAGE_TYPE_REQUESTEDITVOXEL_SIZE){
return true;
} else {
return false;
}
case TypeBytes.TERRAIN_MESSAGE_TYPE_UPDATEVOXEL:
if(byteBuffer.getRemaining() >= TypeBytes.TERRAIN_MESSAGE_TYPE_UPDATEVOXEL_SIZE){
return true;
} else {
return false;
}
case TypeBytes.TERRAIN_MESSAGE_TYPE_REQUESTUSETERRAINPALETTE:
if(byteBuffer.getRemaining() >= TypeBytes.TERRAIN_MESSAGE_TYPE_REQUESTUSETERRAINPALETTE_SIZE){
return true;
} else {
return false;
@ -283,20 +324,82 @@ public class TerrainMessage extends NetworkMessage {
return rVal;
}
public static TerrainMessage parseUpdateMessage(CircularByteBuffer byteBuffer){
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.UPDATE);
public static TerrainMessage parseRequestEditVoxelMessage(CircularByteBuffer byteBuffer){
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.REQUESTEDITVOXEL);
stripPacketHeader(byteBuffer);
rVal.setworldX(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.setworldY(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.setworldZ(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.setvoxelX(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.setvoxelY(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.setvoxelZ(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.setterrainWeight(ByteStreamUtils.popFloatFromByteQueue(byteBuffer));
rVal.setterrainValue(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
return rVal;
}
public static TerrainMessage constructUpdateMessage(int worldX,int worldY,int worldZ){
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.UPDATE);
public static TerrainMessage constructRequestEditVoxelMessage(int worldX,int worldY,int worldZ,int voxelX,int voxelY,int voxelZ,float terrainWeight,int terrainValue){
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.REQUESTEDITVOXEL);
rVal.setworldX(worldX);
rVal.setworldY(worldY);
rVal.setworldZ(worldZ);
rVal.setvoxelX(voxelX);
rVal.setvoxelY(voxelY);
rVal.setvoxelZ(voxelZ);
rVal.setterrainWeight(terrainWeight);
rVal.setterrainValue(terrainValue);
rVal.serialize();
return rVal;
}
public static TerrainMessage parseUpdateVoxelMessage(CircularByteBuffer byteBuffer){
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.UPDATEVOXEL);
stripPacketHeader(byteBuffer);
rVal.setworldX(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.setworldY(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.setworldZ(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.setvoxelX(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.setvoxelY(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.setvoxelZ(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.setterrainWeight(ByteStreamUtils.popFloatFromByteQueue(byteBuffer));
rVal.setterrainValue(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
return rVal;
}
public static TerrainMessage constructUpdateVoxelMessage(int worldX,int worldY,int worldZ,int voxelX,int voxelY,int voxelZ,float terrainWeight,int terrainValue){
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.UPDATEVOXEL);
rVal.setworldX(worldX);
rVal.setworldY(worldY);
rVal.setworldZ(worldZ);
rVal.setvoxelX(voxelX);
rVal.setvoxelY(voxelY);
rVal.setvoxelZ(voxelZ);
rVal.setterrainWeight(terrainWeight);
rVal.setterrainValue(terrainValue);
rVal.serialize();
return rVal;
}
public static TerrainMessage parseRequestUseTerrainPaletteMessage(CircularByteBuffer byteBuffer){
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.REQUESTUSETERRAINPALETTE);
stripPacketHeader(byteBuffer);
rVal.setrealLocationX(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
rVal.setrealLocationY(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
rVal.setrealLocationZ(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
rVal.setvalue(ByteStreamUtils.popFloatFromByteQueue(byteBuffer));
rVal.setterrainWeight(ByteStreamUtils.popFloatFromByteQueue(byteBuffer));
rVal.setterrainValue(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
return rVal;
}
public static TerrainMessage constructRequestUseTerrainPaletteMessage(double realLocationX,double realLocationY,double realLocationZ,float value,float terrainWeight,int terrainValue){
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.REQUESTUSETERRAINPALETTE);
rVal.setrealLocationX(realLocationX);
rVal.setrealLocationY(realLocationY);
rVal.setrealLocationZ(realLocationZ);
rVal.setvalue(value);
rVal.setterrainWeight(terrainWeight);
rVal.setterrainValue(terrainValue);
rVal.serialize();
return rVal;
}
@ -446,12 +549,12 @@ public class TerrainMessage extends NetworkMessage {
rawBytes[6+i] = intValues[i];
}
break;
case UPDATE:
rawBytes = new byte[2+4+4+4];
case REQUESTEDITVOXEL:
rawBytes = new byte[2+4+4+4+4+4+4+4+4];
//message header
rawBytes[0] = TypeBytes.MESSAGE_TYPE_TERRAIN;
//entity messaage header
rawBytes[1] = TypeBytes.TERRAIN_MESSAGE_TYPE_UPDATE;
rawBytes[1] = TypeBytes.TERRAIN_MESSAGE_TYPE_REQUESTEDITVOXEL;
intValues = ByteStreamUtils.serializeIntToBytes(worldX);
for(int i = 0; i < 4; i++){
rawBytes[2+i] = intValues[i];
@ -464,6 +567,92 @@ public class TerrainMessage extends NetworkMessage {
for(int i = 0; i < 4; i++){
rawBytes[10+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeIntToBytes(voxelX);
for(int i = 0; i < 4; i++){
rawBytes[14+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeIntToBytes(voxelY);
for(int i = 0; i < 4; i++){
rawBytes[18+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeIntToBytes(voxelZ);
for(int i = 0; i < 4; i++){
rawBytes[22+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeFloatToBytes(terrainWeight);
for(int i = 0; i < 4; i++){
rawBytes[26+i] = intValues[i];
} intValues = ByteStreamUtils.serializeIntToBytes(terrainValue);
for(int i = 0; i < 4; i++){
rawBytes[30+i] = intValues[i];
}
break;
case UPDATEVOXEL:
rawBytes = new byte[2+4+4+4+4+4+4+4+4];
//message header
rawBytes[0] = TypeBytes.MESSAGE_TYPE_TERRAIN;
//entity messaage header
rawBytes[1] = TypeBytes.TERRAIN_MESSAGE_TYPE_UPDATEVOXEL;
intValues = ByteStreamUtils.serializeIntToBytes(worldX);
for(int i = 0; i < 4; i++){
rawBytes[2+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeIntToBytes(worldY);
for(int i = 0; i < 4; i++){
rawBytes[6+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeIntToBytes(worldZ);
for(int i = 0; i < 4; i++){
rawBytes[10+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeIntToBytes(voxelX);
for(int i = 0; i < 4; i++){
rawBytes[14+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeIntToBytes(voxelY);
for(int i = 0; i < 4; i++){
rawBytes[18+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeIntToBytes(voxelZ);
for(int i = 0; i < 4; i++){
rawBytes[22+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeFloatToBytes(terrainWeight);
for(int i = 0; i < 4; i++){
rawBytes[26+i] = intValues[i];
} intValues = ByteStreamUtils.serializeIntToBytes(terrainValue);
for(int i = 0; i < 4; i++){
rawBytes[30+i] = intValues[i];
}
break;
case REQUESTUSETERRAINPALETTE:
rawBytes = new byte[2+8+8+8+4+4+4];
//message header
rawBytes[0] = TypeBytes.MESSAGE_TYPE_TERRAIN;
//entity messaage header
rawBytes[1] = TypeBytes.TERRAIN_MESSAGE_TYPE_REQUESTUSETERRAINPALETTE;
intValues = ByteStreamUtils.serializeDoubleToBytes(realLocationX);
for(int i = 0; i < 8; i++){
rawBytes[2+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeDoubleToBytes(realLocationY);
for(int i = 0; i < 8; i++){
rawBytes[10+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeDoubleToBytes(realLocationZ);
for(int i = 0; i < 8; i++){
rawBytes[18+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeFloatToBytes(value);
for(int i = 0; i < 4; i++){
rawBytes[26+i] = intValues[i];
} intValues = ByteStreamUtils.serializeFloatToBytes(terrainWeight);
for(int i = 0; i < 4; i++){
rawBytes[30+i] = intValues[i];
} intValues = ByteStreamUtils.serializeIntToBytes(terrainValue);
for(int i = 0; i < 4; i++){
rawBytes[34+i] = intValues[i];
}
break;
case SPAWNPOSITION:
rawBytes = new byte[2+8+8+8];

View File

@ -80,17 +80,21 @@ Message categories
public static final byte TERRAIN_MESSAGE_TYPE_REQUESTMETADATA = 0;
public static final byte TERRAIN_MESSAGE_TYPE_RESPONSEMETADATA = 1;
public static final byte TERRAIN_MESSAGE_TYPE_REQUESTCHUNK = 2;
public static final byte TERRAIN_MESSAGE_TYPE_UPDATE = 3;
public static final byte TERRAIN_MESSAGE_TYPE_SPAWNPOSITION = 4;
public static final byte TERRAIN_MESSAGE_TYPE_REQUESTCHUNKDATA = 5;
public static final byte TERRAIN_MESSAGE_TYPE_SENDCHUNKDATA = 6;
public static final byte TERRAIN_MESSAGE_TYPE_REQUESTEDITVOXEL = 3;
public static final byte TERRAIN_MESSAGE_TYPE_UPDATEVOXEL = 4;
public static final byte TERRAIN_MESSAGE_TYPE_REQUESTUSETERRAINPALETTE = 5;
public static final byte TERRAIN_MESSAGE_TYPE_SPAWNPOSITION = 6;
public static final byte TERRAIN_MESSAGE_TYPE_REQUESTCHUNKDATA = 7;
public static final byte TERRAIN_MESSAGE_TYPE_SENDCHUNKDATA = 8;
/*
Terrain packet sizes
*/
public static final byte TERRAIN_MESSAGE_TYPE_REQUESTMETADATA_SIZE = 2;
public static final byte TERRAIN_MESSAGE_TYPE_RESPONSEMETADATA_SIZE = 30;
public static final byte TERRAIN_MESSAGE_TYPE_REQUESTCHUNK_SIZE = 10;
public static final byte TERRAIN_MESSAGE_TYPE_UPDATE_SIZE = 14;
public static final byte TERRAIN_MESSAGE_TYPE_REQUESTEDITVOXEL_SIZE = 34;
public static final byte TERRAIN_MESSAGE_TYPE_UPDATEVOXEL_SIZE = 34;
public static final byte TERRAIN_MESSAGE_TYPE_REQUESTUSETERRAINPALETTE_SIZE = 38;
public static final byte TERRAIN_MESSAGE_TYPE_SPAWNPOSITION_SIZE = 26;
public static final byte TERRAIN_MESSAGE_TYPE_REQUESTCHUNKDATA_SIZE = 14;
/*

View File

@ -4,11 +4,16 @@ import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import org.joml.Vector3d;
import electrosphere.client.terrain.cache.ChunkData;
import electrosphere.engine.Globals;
import electrosphere.net.parser.net.message.TerrainMessage;
import electrosphere.net.server.Server;
import electrosphere.net.server.ServerConnectionHandler;
import electrosphere.net.server.player.Player;
import electrosphere.server.datacell.Realm;
import electrosphere.server.terrain.editing.TerrainEditing;
import electrosphere.server.terrain.manager.ServerTerrainChunk;
import electrosphere.server.terrain.models.TerrainModification;
@ -27,10 +32,16 @@ public class TerrainProtocol {
message.getworldX(), message.getworldY(), message.getworldZ()
);
break;
case REQUESTEDITVOXEL: {
attemptTerrainEdit(connectionHandler, message);
} break;
case REQUESTUSETERRAINPALETTE: {
attemptUseTerrainEditPalette(connectionHandler, message);
} break;
//all ignored message types
case RESPONSEMETADATA:
case SPAWNPOSITION:
case UPDATE:
case UPDATEVOXEL:
case SENDCHUNKDATA:
//silently ignore
break;
@ -69,12 +80,19 @@ public class TerrainProtocol {
// long[][] randomizer = chunk.getRandomizer();//Globals.serverTerrainManager.getRandomizer(message.getworldX(), message.getworldY());
ByteBuffer buffer = ByteBuffer.allocate(ServerTerrainChunk.CHUNK_DIMENSION*ServerTerrainChunk.CHUNK_DIMENSION*ServerTerrainChunk.CHUNK_DIMENSION*(4+4));
//The length along each access of the chunk data. Typically, should be at least 17.
//Because CHUNK_SIZE is 16, 17 adds the necessary extra value. Each chunk needs the value of the immediately following position to generate
//chunk data that connects seamlessly to the next chunk.
int xWidth = chunk.getWeights().length;
int yWidth = chunk.getWeights()[0].length;
int zWidth = chunk.getWeights()[0][0].length;
ByteBuffer buffer = ByteBuffer.allocate(xWidth*yWidth*zWidth*(4+4));
FloatBuffer floatView = buffer.asFloatBuffer();
for(int x = 0; x < ServerTerrainChunk.CHUNK_DIMENSION; x++){
for(int y = 0; y < ServerTerrainChunk.CHUNK_DIMENSION; y++){
for(int z = 0; z < ServerTerrainChunk.CHUNK_DIMENSION; z++){
for(int x = 0; x < xWidth; x++){
for(int y = 0; y < yWidth; y++){
for(int z = 0; z < zWidth; z++){
floatView.put(chunk.getWeights()[x][y][z]);
}
}
@ -83,9 +101,9 @@ public class TerrainProtocol {
IntBuffer intView = buffer.asIntBuffer();
intView.position(floatView.position());
for(int x = 0; x < ServerTerrainChunk.CHUNK_DIMENSION; x++){
for(int y = 0; y < ServerTerrainChunk.CHUNK_DIMENSION; y++){
for(int z = 0; z < ServerTerrainChunk.CHUNK_DIMENSION; z++){
for(int x = 0; x < xWidth; x++){
for(int y = 0; y < yWidth; y++){
for(int z = 0; z < zWidth; z++){
intView.put(chunk.getValues()[x][y][z]);
}
}
@ -190,5 +208,25 @@ public class TerrainProtocol {
)
);
}
/**
* Attempts to perform an edit requested by a client
* @param message The message containing the edit request
*/
static void attemptTerrainEdit(ServerConnectionHandler connectionHandler, TerrainMessage message){
Player player = Globals.playerManager.getPlayerFromId(connectionHandler.getPlayerId());
}
/**
* Attempts to use an edit palette on the terrain
* @param connectionHandler The connection handler
* @param message The message that contains the request to use an edit palette
*/
static void attemptUseTerrainEditPalette(ServerConnectionHandler connectionHandler, TerrainMessage message){
Player player = Globals.playerManager.getPlayerFromId(connectionHandler.getPlayerId());
Realm realm = Globals.realmManager.getPlayerRealm(player);
Vector3d location = new Vector3d(message.getrealLocationX(), message.getrealLocationY(), message.getrealLocationZ());
TerrainEditing.editTerrain(realm, location, message.getvalue(), message.getterrainValue(), message.getterrainWeight());
}
}

View File

@ -582,35 +582,6 @@ public class Mesh {
HomogenousInstancedArray buffer = uniformGlBufferMap.get(attribute);
buffer.updateBuffer(buffers.get(attribute), 0);
buffer.bind(renderPipelineState);
// switch(uniformTypeMap.get(uniformName)){
// case VEC3F: {
// FloatBuffer buffer = (FloatBuffer)buffers.get(key);
// int bufferIndex = GL31.glGetUniformBlockIndex(shaderIndex, "Lights");
// //bind that position to the slot '2'
// GL31.glUniformBlockBinding(shaderIndex, bufferIndex, BIND_POINT);
// //bind our buffer to slot '2' as well
// GL31.glBindBufferBase(GL_UNIFORM_BUFFER, BIND_POINT, uboIndex);
// //alternatively if want to use range, do glBindBufferRange(GL_UNIFORM_BUFFER, 2, uboExampleBlock, 0, 152);
// } break;
// case VEC3D: {
// } break;
// case VEC4F: {
// } break;
// case VEC4D: {
// } break;
// case DOUBLE: {
// } break;
// case FLOAT: {
// } break;
// case INT: {
// } break;
// }
}
}

View File

@ -9,6 +9,7 @@ import java.util.List;
import java.util.Map;
import java.util.PriorityQueue;
import org.joml.Matrix4d;
import org.joml.Matrix4f;
import org.joml.Vector3d;
import org.joml.Vector3f;
@ -93,6 +94,9 @@ public class InstanceData {
case MAT4F: {
attributeCpuBufferMap.put(shaderAttribute, BufferUtils.createFloatBuffer(capacity * 4 * 4));
} break;
case MAT4D: {
attributeCpuBufferMap.put(shaderAttribute, BufferUtils.createFloatBuffer(capacity * 4 * 4));
} break;
}
if(shaderAttribute.isSingleIndex()){
attributeGlBufferMap.put(shaderAttribute,HomogenousInstancedArray.createHomogenousInstancedArray(shaderAttribute.getIndex(), type, capacity));
@ -156,6 +160,10 @@ public class InstanceData {
buffer.limit(buffer.capacity());
// System.out.println(buffer.position() + " " + buffer.limit());
} break;
case MAT4D: {
FloatBuffer buffer = ((FloatBuffer)attributeCpuBufferMap.get(attribute));
buffer.limit(buffer.capacity());
} break;
case DOUBLE: {
DoubleBuffer buffer = ((DoubleBuffer)attributeCpuBufferMap.get(attribute));
buffer.limit(buffer.capacity());
@ -227,27 +235,29 @@ public class InstanceData {
buffer.put(mat.m31());
buffer.put(mat.m32());
buffer.put(mat.m33());
/*
buffer.put(mat.m00());
buffer.put(mat.m10());
buffer.put(mat.m20());
buffer.put(mat.m30());
} break;
case MAT4D: {
FloatBuffer buffer = ((FloatBuffer)attributeCpuBufferMap.get(attribute));
Matrix4d mat = (Matrix4d)actor.getAttributeValue(attribute);
buffer.put((float)mat.m00());
buffer.put((float)mat.m10());
buffer.put((float)mat.m20());
buffer.put((float)mat.m30());
buffer.put(mat.m01());
buffer.put(mat.m11());
buffer.put(mat.m21());
buffer.put(mat.m31());
buffer.put((float)mat.m10());
buffer.put((float)mat.m11());
buffer.put((float)mat.m12());
buffer.put((float)mat.m13());
buffer.put((float)mat.m20());
buffer.put((float)mat.m21());
buffer.put((float)mat.m22());
buffer.put((float)mat.m23());
buffer.put(mat.m02());
buffer.put(mat.m12());
buffer.put(mat.m22());
buffer.put(mat.m32());
buffer.put(mat.m03());
buffer.put(mat.m13());
buffer.put(mat.m23());
buffer.put(mat.m33());
*/
buffer.put((float)mat.m30());
buffer.put((float)mat.m31());
buffer.put((float)mat.m32());
buffer.put((float)mat.m33());
} break;
case DOUBLE: {
DoubleBuffer buffer = ((DoubleBuffer)attributeCpuBufferMap.get(attribute));
@ -293,6 +303,11 @@ public class InstanceData {
buffer.flip();
// System.out.println(buffer.position() + " " + buffer.limit());
} break;
case MAT4D: {
FloatBuffer buffer = ((FloatBuffer)attributeCpuBufferMap.get(attribute));
buffer.flip();
// System.out.println(buffer.position() + " " + buffer.limit());
} break;
case DOUBLE: {
DoubleBuffer buffer = ((DoubleBuffer)attributeCpuBufferMap.get(attribute));
buffer.flip();
@ -333,6 +348,10 @@ public class InstanceData {
FloatBuffer buffer = ((FloatBuffer)attributeCpuBufferMap.get(attribute));
buffer.flip();
} break;
case MAT4D: {
FloatBuffer buffer = ((FloatBuffer)attributeCpuBufferMap.get(attribute));
buffer.flip();
} break;
case DOUBLE: {
DoubleBuffer buffer = ((DoubleBuffer)attributeCpuBufferMap.get(attribute));
buffer.flip();

View File

@ -4,6 +4,7 @@ package electrosphere.renderer.actor.instance;
import java.util.HashMap;
import java.util.Map;
import org.joml.Matrix4d;
import org.joml.Matrix4f;
import electrosphere.engine.Globals;
@ -78,6 +79,13 @@ public class InstancedActor implements Comparable<InstancedActor> {
attributes.put(attribute, new Matrix4f((Matrix4f)value));
}
}
if(value instanceof Matrix4d){
if(attributes.containsKey(attribute)){
((Matrix4d)attributes.get(attribute)).set((Matrix4d)value);
} else {
attributes.put(attribute, new Matrix4d((Matrix4d)value));
}
}
// attributes.put(attribute, value);
}

View File

@ -119,6 +119,9 @@ public class HomogenousInstancedArray {
case MAT4F: {
return capacity * 4 * 4 * 4;
}
case MAT4D: {
return capacity * 4 * 4 * 4;
}
}
return 0;
}
@ -166,6 +169,29 @@ public class HomogenousInstancedArray {
GL45.glVertexAttribDivisor(matrixAttributeIndices[1], 1);
GL45.glVertexAttribDivisor(matrixAttributeIndices[2], 1);
GL45.glVertexAttribDivisor(matrixAttributeIndices[3], 1);
} else if(type == HomogenousBufferTypes.MAT4D){
//https://solhsa.com/instancing.html
//https://stackoverflow.com/questions/17355051/using-a-matrix-as-vertex-attribute-in-opengl3-core-profile
//"opengl matrix attribute"
//https://learnopengl.com/code_viewer_gh.php?code=src/4.advanced_opengl/10.3.asteroids_instanced/asteroids_instanced.cpp
GL45.glBindBuffer(GL45.GL_ARRAY_BUFFER, bufferPointer);
//enable attributes
GL45.glEnableVertexAttribArray(matrixAttributeIndices[0]);
GL45.glEnableVertexAttribArray(matrixAttributeIndices[1]);
GL45.glEnableVertexAttribArray(matrixAttributeIndices[2]);
GL45.glEnableVertexAttribArray(matrixAttributeIndices[3]);
//update attribute to point to buffer at correct offset + stride
GL45.glVertexAttribPointer(matrixAttributeIndices[0], 4, GL45.GL_FLOAT, false, 64, 0 * 4);
GL45.glVertexAttribPointer(matrixAttributeIndices[1], 4, GL45.GL_FLOAT, false, 64, 4 * 4);
GL45.glVertexAttribPointer(matrixAttributeIndices[2], 4, GL45.GL_FLOAT, false, 64, 4 * 8);
GL45.glVertexAttribPointer(matrixAttributeIndices[3], 4, GL45.GL_FLOAT, false, 64, 4 * 12);
//bind buffer
GL45.glBindBuffer(GL45.GL_ARRAY_BUFFER, bufferPointer);
//tell opengl to send a new value from buffer for each instance (instead of whole buffer for every instance)
GL45.glVertexAttribDivisor(matrixAttributeIndices[0], 1);
GL45.glVertexAttribDivisor(matrixAttributeIndices[1], 1);
GL45.glVertexAttribDivisor(matrixAttributeIndices[2], 1);
GL45.glVertexAttribDivisor(matrixAttributeIndices[3], 1);
} else {
LoggerInterface.loggerRenderer.ERROR("Unsupported operation", new Exception());
}
@ -211,7 +237,11 @@ public class HomogenousInstancedArray {
} break;
case MAT4F: {
FloatBuffer buffer = (FloatBuffer)object;
// GL45.glNamedBufferSubData(bufferPointer, startIndex, buffer);
GL45.glNamedBufferSubData(bufferPointer, startIndex, buffer);
} break;
case MAT4D: {
FloatBuffer buffer = (FloatBuffer)object;
GL45.glNamedBufferSubData(bufferPointer, startIndex, buffer);
} break;
}
//unbind the buffer

View File

@ -27,6 +27,7 @@ public class HomogenousUniformBuffer {
VEC4F,
VEC4D,
MAT4F,
MAT4D,
INT,
FLOAT,
DOUBLE,
@ -111,6 +112,9 @@ public class HomogenousUniformBuffer {
case MAT4F: {
return capacity * 4 * 4 * 4;
}
case MAT4D: {
return capacity * 4 * 4 * 4;
}
}
return 0;
}
@ -177,6 +181,10 @@ public class HomogenousUniformBuffer {
FloatBuffer buffer = (FloatBuffer)object;
GL45.glNamedBufferSubData(bufferPointer, startIndex, buffer);
} break;
case MAT4D: {
FloatBuffer buffer = (FloatBuffer)object;
GL45.glNamedBufferSubData(bufferPointer, startIndex, buffer);
} break;
}
//unbind the buffer
// GL45.glBindBuffer(GL45.GL_UNIFORM_BUFFER, 0);

View File

@ -675,7 +675,11 @@ public class TerrainChunkModelGeneration {
return rVal;
}
/**
* Generates a mesh based on a terrainchunkdata object
* @param data The terrain chunk data object
* @return The mesh
*/
protected static Mesh generateTerrainMesh(TerrainChunkData data){
Mesh mesh = new Mesh();
@ -780,7 +784,11 @@ public class TerrainChunkModelGeneration {
}
/**
* Generates a model based on a terrainchunkdata object
* @param data The terrain chunk data object
* @return The model
*/
public static Model generateTerrainModel(TerrainChunkData data){
Model rVal = new Model();
rVal.meshes = new ArrayList<Mesh>();

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,371 @@
package electrosphere.renderer.meshgen;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.joml.Vector3f;
import org.lwjgl.BufferUtils;
import electrosphere.engine.Globals;
import electrosphere.entity.types.terrain.TerrainChunkData;
import electrosphere.renderer.Material;
import electrosphere.renderer.Mesh;
import electrosphere.renderer.Model;
import electrosphere.renderer.meshgen.TerrainChunkModelGeneration.GridCell;
import electrosphere.renderer.meshgen.TerrainChunkModelGeneration.Triangle;
/**
* Utility functions for generating transvoxel based meshes
*/
public class TransvoxelModelGeneration {
// static class Triangle {
// int[] indices = new int[3]; //array of size 3
// public Triangle(int index0, int index1, int index2){
// indices[0] = index0;
// indices[1] = index1;
// indices[2] = index2;
// }
// }
// static class GridCell {
// Vector3f[] points = new Vector3f[8]; //array of size 8
// double[] val = new double[8]; //array of size 8
// public void setValues(
// Vector3f p1, Vector3f p2, Vector3f p3, Vector3f p4,
// Vector3f p5, Vector3f p6, Vector3f p7, Vector3f p8,
// double val1, double val2, double val3, double val4,
// double val5, double val6, double val7, double val8
// ){
// points[0] = p1; points[1] = p2; points[2] = p3; points[3] = p4;
// points[4] = p5; points[5] = p6; points[6] = p7; points[7] = p8;
// val[0] = val1; val[1] = val2; val[2] = val3; val[3] = val4;
// val[4] = val5; val[5] = val6; val[6] = val7; val[7] = val8;
// }
// }
// protected static int polygonize(
// GridCell grid,
// double isolevel,
// List<Triangle> triangles,
// Map<String,Integer> vertMap,
// List<Vector3f> verts,
// List<Vector3f> normals,
// List<Integer> trianglesSharingVert
// ){
// int i;
// int ntriang;
// int cubeIndex = 0;
// Vector3f[] vertList = new Vector3f[12];
// //get lookup key (index) for edge table
// //edge table tells us which vertices are inside of the surface
// if (grid.val[0] < isolevel) cubeIndex |= 1;
// if (grid.val[1] < isolevel) cubeIndex |= 2;
// if (grid.val[2] < isolevel) cubeIndex |= 4;
// if (grid.val[3] < isolevel) cubeIndex |= 8;
// if (grid.val[4] < isolevel) cubeIndex |= 16;
// if (grid.val[5] < isolevel) cubeIndex |= 32;
// if (grid.val[6] < isolevel) cubeIndex |= 64;
// if (grid.val[7] < isolevel) cubeIndex |= 128;
// //Cube is entirely in/out of the surface
// if (edgeTable[cubeIndex] == 0)
// return(0);
// //instead of having all intersections be perfectly at the midpoint,
// //for each edge this code calculates where along the edge to place the vertex
// //this should dramatically smooth the surface
// if ((edgeTable[cubeIndex] & 1) > 0)
// vertList[0] =
// VertexInterp(isolevel,grid.points[0],grid.points[1],grid.val[0],grid.val[1]);
// if ((edgeTable[cubeIndex] & 2) > 0)
// vertList[1] =
// VertexInterp(isolevel,grid.points[1],grid.points[2],grid.val[1],grid.val[2]);
// if ((edgeTable[cubeIndex] & 4) > 0)
// vertList[2] =
// VertexInterp(isolevel,grid.points[2],grid.points[3],grid.val[2],grid.val[3]);
// if ((edgeTable[cubeIndex] & 8) > 0)
// vertList[3] =
// VertexInterp(isolevel,grid.points[3],grid.points[0],grid.val[3],grid.val[0]);
// if ((edgeTable[cubeIndex] & 16) > 0)
// vertList[4] =
// VertexInterp(isolevel,grid.points[4],grid.points[5],grid.val[4],grid.val[5]);
// if ((edgeTable[cubeIndex] & 32) > 0)
// vertList[5] =
// VertexInterp(isolevel,grid.points[5],grid.points[6],grid.val[5],grid.val[6]);
// if ((edgeTable[cubeIndex] & 64) > 0)
// vertList[6] =
// VertexInterp(isolevel,grid.points[6],grid.points[7],grid.val[6],grid.val[7]);
// if ((edgeTable[cubeIndex] & 128) > 0)
// vertList[7] =
// VertexInterp(isolevel,grid.points[7],grid.points[4],grid.val[7],grid.val[4]);
// if ((edgeTable[cubeIndex] & 256) > 0)
// vertList[8] =
// VertexInterp(isolevel,grid.points[0],grid.points[4],grid.val[0],grid.val[4]);
// if ((edgeTable[cubeIndex] & 512) > 0)
// vertList[9] =
// VertexInterp(isolevel,grid.points[1],grid.points[5],grid.val[1],grid.val[5]);
// if ((edgeTable[cubeIndex] & 1024) > 0)
// vertList[10] =
// VertexInterp(isolevel,grid.points[2],grid.points[6],grid.val[2],grid.val[6]);
// if ((edgeTable[cubeIndex] & 2048) > 0)
// vertList[11] =
// VertexInterp(isolevel,grid.points[3],grid.points[7],grid.val[3],grid.val[7]);
// //Create the triangle
// ntriang = 0;
// for (i=0; triTable[cubeIndex][i]!=-1; i+=3) {
// //
// // Triangles calculation
// //
// //get indices
// Vector3f vert0 = vertList[triTable[cubeIndex][i+0]];
// Vector3f vert1 = vertList[triTable[cubeIndex][i+1]];
// Vector3f vert2 = vertList[triTable[cubeIndex][i+2]];
// int index0 = getVertIndex(vert0,vertMap,verts);
// int index1 = getVertIndex(vert1,vertMap,verts);
// int index2 = getVertIndex(vert2,vertMap,verts);
// //add 0's to normals until it matches vert count
// while(trianglesSharingVert.size() < verts.size()){
// trianglesSharingVert.add(0);
// normals.add(new Vector3f());
// }
// //add new triangle
// Triangle newTriangle = new Triangle(index0,index1,index2);
// triangles.add(newTriangle);
// ntriang++;
// //
// // Normals calculation
// //
// //calculate normal for new triangle
// Vector3f u = verts.get(index1).sub(verts.get(index0), new Vector3f());
// Vector3f v = verts.get(index2).sub(verts.get(index1), new Vector3f());
// Vector3f n = new Vector3f(u.y * v.z - u.z * v.y, u.z * v.x - u.x * v.z, u.x * v.y - u.y * v.x).normalize();
// //for each vertex, average the new normal with the normals that are already there
// int trianglesSharingIndex0 = trianglesSharingVert.get(index0);
// //calculate proportion of each normal
// float oldProportion = trianglesSharingIndex0 / (float)(trianglesSharingIndex0 + 1);
// float newProportion = 1.0f / (float)(trianglesSharingIndex0 + 1);
// //increment number of triangles sharing vert
// trianglesSharingVert.set(index0, trianglesSharingIndex0 + 1);
// Vector3f currentNormal = normals.get(index0);
// currentNormal = averageNormals(currentNormal,oldProportion,n,newProportion);
// normals.get(index0).set(currentNormal);
// int trianglesSharingIndex1 = trianglesSharingVert.get(index1);
// //calculate proportion of each normal
// oldProportion = trianglesSharingIndex1 / (float)(trianglesSharingIndex1 + 1);
// newProportion = 1.0f / (float)(trianglesSharingIndex1 + 1);
// //increment number of triangles sharing vert
// trianglesSharingVert.set(index1, trianglesSharingIndex1 + 1);
// currentNormal = normals.get(index1);
// currentNormal = averageNormals(currentNormal,oldProportion,n,newProportion);
// normals.get(index1).set(currentNormal);
// int trianglesSharingIndex2 = trianglesSharingVert.get(index2);
// //calculate proportion of each normal
// oldProportion = trianglesSharingIndex2 / (float)(trianglesSharingIndex2 + 1);
// newProportion = 1.0f / (float)(trianglesSharingIndex2 + 1);
// //increment number of triangles sharing vert
// trianglesSharingVert.set(index2, trianglesSharingIndex2 + 1);
// currentNormal = normals.get(index2);
// currentNormal = averageNormals(currentNormal,oldProportion,n,newProportion);
// normals.get(index2).set(currentNormal);
// }
// return(ntriang);
// }
// //interpolates the location that the edge gets cut based on the magnitudes of the scalars of the vertices at either end of the edge
// static Vector3f VertexInterp(double isolevel, Vector3f p1, Vector3f p2, double valp1, double valp2){
// double mu;
// float x, y, z;
// if (Math.abs(isolevel-valp1) < 0.00001)
// return(p1);
// if (Math.abs(isolevel-valp2) < 0.00001)
// return(p2);
// if (Math.abs(valp1-valp2) < 0.00001)
// return(p1);
// mu = (isolevel - valp1) / (valp2 - valp1);
// x = (float)(p1.x + mu * (p2.x - p1.x));
// y = (float)(p1.y + mu * (p2.y - p1.y));
// z = (float)(p1.z + mu * (p2.z - p1.z));
// return new Vector3f(x,y,z);
// }
// /**
// * Creates terrain chunk data based on data provided
// * @param terrainGrid the grid of weights to generate off of
// * @param textureGrid the grid of texture indices to generate off of
// * @param neighborLODLevels The lod levels of all neighbors and this cell. Should be 3x3x3 array of lod level values.
// */
// public static TerrainChunkData generateTerrainChunkData(float[][][] terrainGrid, int[][][] textureGrid, int[][][] neighborLODLevels){
// // 5 6
// // +-------------+ +-----5-------+ ^ Y
// // / | / | / | /| | _
// // / | / | 4 9 6 10 | /\ Z
// // 4 +-----+-------+ 7 | +-----+7------+ | | /
// // | 1 +-------+-----+ 2 | +-----1-+-----+ | /
// // | / | / 8 0 11 2 | /
// // | / | / | / | / |/
// // 0 +-------------+ 3 +------3------+ +---------------> X
// //the current grid cell
// GridCell currentCell = new GridCell();
// //the list of all triangles
// List<Triangle> triangles = new LinkedList<Triangle>();
// //the map of vertex to index
// Map<String,Integer> vertMap = new HashMap<String,Integer>();
// //the list of all verts
// List<Vector3f> verts = new LinkedList<Vector3f>();
// //the list of all normals
// List<Vector3f> normals = new LinkedList<Vector3f>();
// //the list of number of triangles that share a vert
// List<Integer> trianglesSharingVert = new LinkedList<Integer>();
// //List of elements in order
// List<Integer> faceElements = new LinkedList<Integer>();
// //List of UVs
// List<Float> UVs = new LinkedList<Float>();
// for(int x = 0; x < terrainGrid.length - 1; x++){
// for(int y = 0; y < terrainGrid[0].length - 1; y++){
// for(int z = 0; z < terrainGrid[0][0].length - 1; z++){
// //push the current cell's values into the gridcell
// currentCell.setValues(
// new Vector3f(x+0,y+0,z+0), new Vector3f(x+0,y+0,z+1), new Vector3f(x+1,y+0,z+1), new Vector3f(x+1,y+0,z+0),
// new Vector3f(x+0,y+1,z+0), new Vector3f(x+0,y+1,z+1), new Vector3f(x+1,y+1,z+1), new Vector3f(x+1,y+1,z+0),
// terrainGrid[x+0][y+0][z+0], terrainGrid[x+0][y+0][z+1], terrainGrid[x+1][y+0][z+1], terrainGrid[x+1][y+0][z+0],
// terrainGrid[x+0][y+1][z+0], terrainGrid[x+0][y+1][z+1], terrainGrid[x+1][y+1][z+1], terrainGrid[x+1][y+1][z+0]
// );
// //polygonize the current gridcell
// polygonize(currentCell, 0, triangles, vertMap, verts, normals, trianglesSharingVert);
// }
// }
// }
// //all verts in order, flattened as an array of floats instead of vecs
// List<Float> vertsFlat = new LinkedList<Float>();
// //all normals in order, flattened as an array of floats instead of vecs
// List<Float> normalsFlat = new LinkedList<Float>();
// //all elements of faces in order
// List<Integer> elementsFlat = new LinkedList<Integer>();
// //flatten verts + normals
// for(Vector3f vert : verts){
// vertsFlat.add(vert.x);
// vertsFlat.add(vert.y);
// vertsFlat.add(vert.z);
// }
// for(Vector3f normal : normals){
// normalsFlat.add(normal.x);
// normalsFlat.add(normal.y);
// normalsFlat.add(normal.z);
// }
// for(Triangle triangle : triangles){
// elementsFlat.add(triangle.indices[0]);
// elementsFlat.add(triangle.indices[1]);
// elementsFlat.add(triangle.indices[2]);
// }
// float[] temp = new float[3];
// int i = 0;
// for(Vector3f normal : normals){
// Vector3f vert = verts.get(i);
// float absX = Math.abs(normal.x);
// float absY = Math.abs(normal.y);
// float absZ = Math.abs(normal.z);
// float uvX = vert.z * absX + vert.x * absY + vert.x * absZ;
// float uvY = vert.y * absX + vert.z * absY + vert.y * absZ;
// temp[0] = uvX;
// temp[1] = uvY;
// // if(absX >= absZ && absX >= absY){
// // temp[0] = normal.z / 2.0f + 0.5f + vert.z * (absX / (absX + absZ)) + vert.x * (absZ / (absX + absZ));
// // temp[1] = normal.y / 2.0f + 0.5f + vert.x * (absY / (absX + absY)) + vert.y * (absX / (absX + absY));
// // } else if(absZ >= absX && absZ >= absY){
// // temp[0] = normal.x / 2.0f + 0.5f + vert.z * (absX / (absX + absZ)) + vert.x * (absZ / (absX + absZ));
// // temp[1] = normal.y / 2.0f + 0.5f + vert.z * (absY / (absZ + absY)) + vert.y * (absZ / (absZ + absY));
// // } else if(absY >= absX && absY >= absZ){
// // temp[0] = normal.x / 2.0f + 0.5f + vert.y * (absX / (absX + absY)) + vert.x * (absY / (absX + absY));
// // temp[1] = normal.z / 2.0f + 0.5f + vert.y * (absZ / (absZ + absY)) + vert.z * (absY / (absZ + absY));
// // } else {
// // temp[0] = vert.x / 1.5f + vert.z / 1.5f;
// // temp[1] = vert.y / 1.5f + vert.z / 1.5f;
// // }
// i++;
// UVs.add(temp[0]);
// UVs.add(temp[1]);
// }
// //List<Float> vertices, List<Float> normals, List<Integer> faceElements, List<Float> uvs
// TerrainChunkData rVal = new TerrainChunkData(vertsFlat, normalsFlat, elementsFlat, UVs);
// return rVal;
// }
// private static String getVertKeyFromPoints(float x, float y, float z){
// return x + "_" + y + "_" + z;
// }
// private static int getVertIndex(Vector3f vert, Map<String,Integer> vertMap, List<Vector3f> verts){
// int rVal = -1;
// String vertKey = getVertKeyFromPoints(vert.x,vert.y,vert.z);
// if(vertMap.containsKey(vertKey)){
// return vertMap.get(vertKey);
// } else {
// rVal = verts.size();
// verts.add(vert);
// vertMap.put(vertKey,rVal);
// return rVal;
// }
// }
// private static Vector3f averageNormals(Vector3f normal0, float proportion0, Vector3f normal1, float proportion1){
// Vector3f rVal = new Vector3f(normal0);
// rVal = rVal.mul(proportion0).add(new Vector3f(normal1).mul(proportion1));
// return rVal;
// }
}

View File

@ -27,7 +27,7 @@ public class ScriptEngine {
//create context
context = Context.newBuilder("js").engine(engine).build();
//read scripts into source map
readScriptsDirectory("/Scripts", FileUtils.getAssetFile("/Scripts"));
readScriptsDirectory("/src/main/sql", FileUtils.getAssetFile("/src/main/sql"));
//create bindings
// try {
// String content = FileUtils.getAssetFileAsString("/Scripts/test.js");

View File

@ -2,8 +2,6 @@ package electrosphere.server.datacell;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Semaphore;
@ -14,11 +12,12 @@ import org.joml.Vector3i;
import electrosphere.engine.Globals;
import electrosphere.entity.Entity;
import electrosphere.entity.EntityUtils;
import electrosphere.entity.Scene;
import electrosphere.game.server.world.ServerWorldData;
import electrosphere.logger.LoggerInterface;
import electrosphere.net.parser.net.message.TerrainMessage;
import electrosphere.net.server.player.Player;
import electrosphere.server.datacell.interfaces.DataCellManager;
import electrosphere.server.datacell.interfaces.VoxelCellManager;
import electrosphere.server.datacell.physics.PhysicsDataCell;
import electrosphere.server.terrain.manager.ServerTerrainManager;
import electrosphere.server.terrain.manager.ServerTerrainChunk;
@ -26,7 +25,7 @@ import electrosphere.server.terrain.manager.ServerTerrainChunk;
/**
* Implementation of DataCellManager that lays out cells in a logical grid (array). Useful for eg 3d terrain gridded world.
*/
public class GriddedDataCellManager implements DataCellManager {
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
Map<String,ServerDataCell> groundDataCells = new HashMap<String,ServerDataCell>();
//loaded cells
@ -37,6 +36,8 @@ public class GriddedDataCellManager implements DataCellManager {
Realm parent;
//Manager for terrain for this particular cell manager
ServerTerrainManager serverTerrainManager;
//lock for terrain editing
Semaphore terrainEditLock = new Semaphore(1);
/**
* Constructor
@ -61,6 +62,7 @@ public class GriddedDataCellManager implements DataCellManager {
* @param player The player
*/
public void addPlayerToRealm(Player player){
Globals.realmManager.setPlayerRealm(player, parent);
int playerSimulationRadius = player.getSimulationRadius();
Vector3i worldPos = player.getWorldPos();
for(int x = worldPos.x - playerSimulationRadius; x < worldPos.x + playerSimulationRadius + 1; x++){
@ -342,4 +344,56 @@ public class GriddedDataCellManager implements DataCellManager {
return rVal;
}
@Override
/**
* Gets the weight of a single voxel at a position
* @param worldPosition The position in world coordinates of the chunk to grab data from
* @param voxelPosition The position in voxel coordinates (local/relative to the chunk) to get voxel values from
* @return The weight of the described voxel
*/
public float getVoxelWeightAtLocalPosition(Vector3i worldPosition, Vector3i voxelPosition) {
return serverTerrainManager.getChunk(worldPosition.x, worldPosition.y, worldPosition.z).getWeights()[voxelPosition.x][voxelPosition.y][voxelPosition.z];
}
@Override
/**
* Gets the type of a single voxel at a position
* @param worldPosition The position in world coordinates of the chunk to grab data from
* @param voxelPosition The position in voxel coordinates (local/relative to the chunk) to get voxel values from
* @return The type of the described voxel
*/
public int getVoxelTypeAtLocalPosition(Vector3i worldPosition, Vector3i voxelPosition) {
return serverTerrainManager.getChunk(worldPosition.x, worldPosition.y, worldPosition.z).getValues()[voxelPosition.x][voxelPosition.y][voxelPosition.z];
}
@Override
/**
* Gets the chunk data at a given world position
* @param worldPosition The position in world coordinates
* @return The ServerTerrainChunk of data at that position, or null if it is out of bounds or otherwise doesn't exist
*/
public ServerTerrainChunk getChunkAtPosition(Vector3i worldPosition) {
return serverTerrainManager.getChunk(worldPosition.x, worldPosition.y, worldPosition.z);
}
@Override
/**
* Edits a single voxel
* @param worldPosition The world position of the chunk to edit
* @param voxelPosition The voxel position of the voxel to edit
* @param weight The weight to set the voxel to
* @param type The type to set the voxel to
*/
public void editChunk(Vector3i worldPosition, Vector3i voxelPosition, float weight, int type) {
terrainEditLock.acquireUninterruptibly();
//update terrain
serverTerrainManager.deformTerrainAtLocationToValue(worldPosition, voxelPosition, weight, type);
//broadcast update to terrain
groundDataCells.get(getServerDataCellKey(worldPosition)).broadcastNetworkMessage(TerrainMessage.constructUpdateVoxelMessage(
worldPosition.x, worldPosition.y, worldPosition.z,
voxelPosition.x, voxelPosition.y, voxelPosition.z,
weight, type));
terrainEditLock.release();
}
}

View File

@ -1,33 +1,26 @@
package electrosphere.server.datacell;
import electrosphere.collision.CollisionEngine;
import electrosphere.collision.CollisionWorldData;
import electrosphere.engine.Globals;
import electrosphere.engine.Main;
import electrosphere.entity.Entity;
import electrosphere.entity.EntityUtils;
import electrosphere.entity.Scene;
import electrosphere.entity.types.hitbox.HitboxManager;
import electrosphere.game.server.world.ServerWorldData;
import electrosphere.logger.LoggerInterface;
import electrosphere.net.parser.net.message.NetworkMessage;
import electrosphere.net.server.Server;
import electrosphere.net.server.player.Player;
import electrosphere.server.datacell.interfaces.DataCellManager;
import electrosphere.server.terrain.manager.ServerTerrainManager;
import java.util.LinkedList;
import java.util.List;
import org.joml.Vector3d;
import org.joml.Vector3f;
import org.joml.Vector3i;
import java.util.HashSet;
import java.util.Set;
/**
* Manages data cells on the server side
*/
public class Realm {
List<ServerDataCell> loadedDataCells = new LinkedList<ServerDataCell>();
//The set containing all data cells loaded into this realm
Set<ServerDataCell> loadedDataCells = new HashSet<ServerDataCell>();
//this is the cell that all players loading into the game (via connection startup, death, etc) reside in
ServerDataCell loadingCell = new ServerDataCell(new Scene());
@ -91,11 +84,22 @@ public class Realm {
cell.broadcastNetworkMessage(message);
}
//Used for cleaning server data cells no longer in use from the realm
Set<ServerDataCell> toCleanQueue = new HashSet<ServerDataCell>();
/**
* Unloads all chunks that haven't had players in them for a set amount of time
*/
public void unloadPlayerlessChunks(){
//TODO: implement and actually call it
//TODO: improve to make have less performance impact
for(ServerDataCell cell : loadedDataCells){
if(cell.getPlayers().size() < 1){
toCleanQueue.add(cell);
}
}
for(ServerDataCell cell : toCleanQueue){
deregisterCell(cell);
}
toCleanQueue.clear();
}

View File

@ -1,7 +1,5 @@
package electrosphere.server.datacell;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
@ -13,6 +11,7 @@ import electrosphere.engine.Globals;
import electrosphere.entity.Entity;
import electrosphere.entity.types.hitbox.HitboxManager;
import electrosphere.game.server.world.ServerWorldData;
import electrosphere.net.server.player.Player;
/**
* Manages all realms for the engine. Should be a singleton
@ -23,6 +22,8 @@ public class RealmManager {
Set<Realm> realms = new CopyOnWriteArraySet<Realm>();
//Map of entities to the realm the entity is in
Map<Entity,Realm> entityToRealmMap = new ConcurrentHashMap<Entity,Realm>();
//Map of player to the realm the player is in
Map<Player,Realm> playerToRealmMap = new ConcurrentHashMap<Player,Realm>();
/**
@ -108,5 +109,24 @@ public class RealmManager {
}
}
//TODO: !!URGENT!! come up with some mechanism to enforce this actually being called every time a player is added to a server data cell
/**
* Adds a player to a realm
* @param player The player
* @param realm The realm
*/
public void setPlayerRealm(Player player, Realm realm){
playerToRealmMap.put(player, realm);
}
/**
* Gets the realm of a given player
* @param player The player
* @return The realm
*/
public Realm getPlayerRealm(Player player){
return playerToRealmMap.get(player);
}
}

View File

@ -14,8 +14,8 @@ import electrosphere.server.content.EnvironmentGenerator;
import electrosphere.server.pathfinding.NavMeshUtils;
import electrosphere.server.pathfinding.navmesh.NavMesh;
import java.util.LinkedList;
import java.util.List;
import java.util.HashSet;
import java.util.Set;
/**
* Container for entities loaded into memory. This isn't intended to be in charge
@ -28,9 +28,15 @@ import java.util.List;
*/
public class ServerDataCell {
List<Player> activePlayers = new LinkedList<Player>();
//all players attached to this server data cell
Set<Player> activePlayers = new HashSet<Player>();
//the navmesh for the data cell
NavMesh navMesh;
//the scene backing the server data cell
Scene scene;
//controls whether the server data cell simulates its entities or not
boolean ready = false;
@ -72,6 +78,14 @@ public class ServerDataCell {
public void removePlayer(Player p){
activePlayers.remove(p);
}
/**
* Gets the set of all players in the server data cell
* @return The set of players in the data cell
*/
public Set<Player> getPlayers(){
return activePlayers;
}
/**
* This should be used to translate a character from macrolevel simulation to
@ -84,25 +98,6 @@ public class ServerDataCell {
throw new UnsupportedOperationException("Not implemented yet");
}
// /**
// * This should be used to translate an entity from one data cell to another.
// * @param e
// */
// protected void addEntity(Entity e){
// loadedEntities.add(e);
// }
// /**
// * Intention of this function is to entirely remove the entity from microlevel simulation.
// * This should be conbined with code to convert the entity into a tracked macrolevel character.
// * The previous should not be true if you're tracking something inconsequential like
// * a rabbit or something. Then just delete it.
// * @param e
// */
// public void removeEntity(Entity e){
// loadedEntities.remove(e);
// }
/**
* Broadcast a message to all players within range of this cell.
* @param message

View File

@ -0,0 +1,44 @@
package electrosphere.server.datacell.interfaces;
import org.joml.Vector3i;
import electrosphere.server.terrain.manager.ServerTerrainChunk;
/**
* Extension of a DataCellManager that provides voxel terrain access and editing functions
*/
public interface VoxelCellManager {
/**
* Gets the weight of a single voxel at a position
* @param worldPosition The position in world coordinates of the chunk to grab data from
* @param voxelPosition The position in voxel coordinates (local/relative to the chunk) to get voxel values from
* @return The weight of the described voxel
*/
public float getVoxelWeightAtLocalPosition(Vector3i worldPosition, Vector3i voxelPosition);
/**
* Gets the type of a single voxel at a position
* @param worldPosition The position in world coordinates of the chunk to grab data from
* @param voxelPosition The position in voxel coordinates (local/relative to the chunk) to get voxel values from
* @return The type of the described voxel
*/
public int getVoxelTypeAtLocalPosition(Vector3i worldPosition, Vector3i voxelPosition);
/**
* Gets the chunk data at a given world position
* @param worldPosition The position in world coordinates
* @return The ServerTerrainChunk of data at that position, or null if it is out of bounds or otherwise doesn't exist
*/
public ServerTerrainChunk getChunkAtPosition(Vector3i worldPosition);
/**
* Edits a single voxel
* @param worldPosition The world position of the chunk to edit
* @param voxelPosition The voxel position of the voxel to edit
* @param weight The weight to set the voxel to
* @param type The type to set the voxel to
*/
public void editChunk(Vector3i worldPosition, Vector3i voxelPosition, float weight, int type);
}

View File

@ -0,0 +1,69 @@
package electrosphere.server.terrain.editing;
import org.joml.Vector3d;
import org.joml.Vector3i;
import electrosphere.engine.Globals;
import electrosphere.server.datacell.Realm;
import electrosphere.server.datacell.interfaces.VoxelCellManager;
import electrosphere.server.terrain.manager.ServerTerrainChunk;
/**
* Provides utilities for editing terrain (particularly brushes, etc)
*/
public class TerrainEditing {
/**
* Performs a terrain chunk edit. Basically has a sphere around the provided position that it attempts to add value to.
* @param position The position to perform the edit
* @param editMagnitude The magnitude of the edit to perform
* @param type The type of block to make all edited blocks
* @param weight The weight of the sphere to apply the edit to
*/
public static void editTerrain(Realm realm, Vector3d position, float editMagnitude, int type, float weight){
if(position != null && realm != null && realm.getDataCellManager() instanceof VoxelCellManager){
VoxelCellManager voxelCellManager = (VoxelCellManager) realm.getDataCellManager();
//calculate kernel size
int numPlacesToCheck = (int)((editMagnitude * 2 + 1) * (editMagnitude * 2 + 1) * (editMagnitude * 2 + 1));
//create and fill in kernel of positions to check
int[] xOffsetSet = new int[numPlacesToCheck];
int[] yOffsetSet = new int[numPlacesToCheck];
int[] zOffsetSet = new int[numPlacesToCheck];
int i = 0;
for(int x = -(int)editMagnitude; x <= (int)editMagnitude; x++){
for(int y = -(int)editMagnitude; y <= (int)editMagnitude; y++){
for(int z = -(int)editMagnitude; z <= (int)editMagnitude; z++){
xOffsetSet[i] = x;
yOffsetSet[i] = y;
zOffsetSet[i] = z;
i++;
}
}
}
for(i = 0; i < numPlacesToCheck; i++){
//calculate position of edit
Vector3d offsetPos = new Vector3d(position).add(xOffsetSet[i],yOffsetSet[i],zOffsetSet[i]);
Vector3i chunkPos = Globals.serverWorldData.convertRealToWorldSpace(offsetPos);
Vector3i voxelPos = Globals.serverWorldData.convertRealToVoxelSpace(offsetPos);
//get distance from true center point of sphere to current voxel position in world space
float distance = (float)new Vector3d(Math.floor(offsetPos.x),Math.floor(offsetPos.y),Math.floor(offsetPos.z)).distance(position);
float currentPositionMagnitude = editMagnitude - distance;
ServerTerrainChunk data = voxelCellManager.getChunkAtPosition(chunkPos);
if(
voxelPos.x < ServerTerrainChunk.CHUNK_DIMENSION &&
voxelPos.y < ServerTerrainChunk.CHUNK_DIMENSION &&
voxelPos.z < ServerTerrainChunk.CHUNK_DIMENSION &&
currentPositionMagnitude > 0 &&
data != null
){
float current = data.getWeights()[voxelPos.x][voxelPos.y][voxelPos.z];
//hard clamp so it doesn't go over 1
float finalValue = Math.max(Math.min(current + weight,1),-1);
voxelCellManager.editChunk(chunkPos, voxelPos, finalValue, type);
}
}
}
}
}

View File

@ -12,6 +12,8 @@ public class ServerTerrainChunk {
//all chunks are 16x16x16
public static final int CHUNK_DIMENSION = 16;
//The size of the data passed into marching cubes/transvoxel to generate a fully connected and seamless chunk
public static final int CHUNK_DATA_GENERATOR_SIZE = CHUNK_DIMENSION + 1;
int worldX, worldY, worldZ;
List<TerrainModification> modifications = new LinkedList<TerrainModification>();
@ -26,20 +28,29 @@ public class ServerTerrainChunk {
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){
float[][][] weights = new float[CHUNK_DIMENSION][CHUNK_DIMENSION][CHUNK_DIMENSION];
int[][][] values = new int[CHUNK_DIMENSION][CHUNK_DIMENSION][CHUNK_DIMENSION];
for(int inc = 0; inc < CHUNK_DIMENSION; inc++){
for(int weightX = 0; weightX < CHUNK_DIMENSION; weightX++){
for(int weightZ = 0; weightZ < CHUNK_DIMENSION; weightZ++){
//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_DIMENSION; weightX++){
for(int weightZ = 0; weightZ < CHUNK_DIMENSION; weightZ++){
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] = 1;
}

View File

@ -268,6 +268,13 @@ public class ServerTerrainManager {
return worldX + "_" + worldY + "_" + worldZ;
}
/**
* Gets a server terrain chunk
* @param worldX The world x position
* @param worldY The world y position
* @param worldZ The world z position
* @return The ServerTerrainChunk
*/
public ServerTerrainChunk getChunk(int worldX, int worldY, int worldZ){
if(model != null){
//THIS FIRES IF THERE IS A MAIN GAME WORLD RUNNING
@ -279,13 +286,15 @@ public class ServerTerrainManager {
returnedChunk = chunkCache.get(key);
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_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION];
int[][][] values = new int[ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION];
for(int weightX = 0; weightX < ServerTerrainChunk.CHUNK_DIMENSION; weightX++){
for(int weightY = 0; weightY < ServerTerrainChunk.CHUNK_DIMENSION; weightY++){
for(int weightZ = 0; weightZ < ServerTerrainChunk.CHUNK_DIMENSION; weightZ++){
if(weightY < heightmap[ServerTerrainChunk.CHUNK_DIMENSION * worldX + weightX][ServerTerrainChunk.CHUNK_DIMENSION * worldZ + weightZ]){
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++){
if(weightY < heightmap[ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE * worldX + weightX][ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE * worldZ + weightZ]){
weights[weightX][weightY][weightZ] = 1;
values[weightX][weightY][weightZ] = 1;
} else {
@ -346,14 +355,19 @@ public class ServerTerrainManager {
}
}
public void deformTerrainAtLocationToValue(
Vector3i worldPos,
Vector3i subChunkPos,
Vector3i voxelPos,
float weight, int value){
System.out.println("Add modification at " + worldPos.x + "," + worldPos.z + " subloc " + voxelPos.x + "," + voxelPos.z);
TerrainModification modification = new TerrainModification(worldPos,subChunkPos,voxelPos,weight,value);
model.addModification(modification);
/**
* Applies a deform to terrain at a given location
* @param worldPos The world coordinates of the chunk to modify
* @param voxelPos The voxel coordinates of the voxel to modify
* @param weight The weight to set it to
* @param value The value to set it to
*/
public void deformTerrainAtLocationToValue(Vector3i worldPos, Vector3i voxelPos, float weight, int value){
TerrainModification modification = new TerrainModification(worldPos,voxelPos,weight,value);
//could be null if, for instance, arena mode
if(model != null){
model.addModification(modification);
}
String key = getKey(worldPos.x,worldPos.y,worldPos.z);
if(chunkCache.containsKey(key)){
ServerTerrainChunk chunk = chunkCache.get(key);

View File

@ -10,14 +10,12 @@ import electrosphere.server.terrain.manager.ServerTerrainChunk;
*/
public class TerrainModification {
Vector3i worldPos;
Vector3i subChunkPos;
Vector3i voxelPos;
float weight;
int value;
public TerrainModification(Vector3i worldPos, Vector3i subChunkPos, Vector3i voxelPos, float weight, int value) {
public TerrainModification(Vector3i worldPos, Vector3i voxelPos, float weight, int value) {
this.worldPos = worldPos;
this.subChunkPos = subChunkPos;
this.voxelPos = voxelPos;
this.weight = weight;
this.value = value;
@ -27,10 +25,6 @@ public class TerrainModification {
return worldPos;
}
public Vector3i getSubChunkPos() {
return subChunkPos;
}
public Vector3i getVoxelPos() {
return voxelPos;
}

View File

@ -186,7 +186,7 @@ public class FileUtils {
public static String getSQLScriptFileAsString(String pathName) throws IOException {
String sanitizedFilePath = sanitizeFilePath(pathName);
File targetFile = new File("./Scripts" + sanitizedFilePath);
File targetFile = new File("./src/main/sql" + sanitizedFilePath);
return Files.readString(targetFile.toPath());
}