From 5fee2d06af93d1dfbc061e85ae0d9a7c626f5da9 Mon Sep 17 00:00:00 2001 From: austin Date: Sat, 23 Nov 2024 16:47:33 -0500 Subject: [PATCH] Fix terrain editing --- docs/src/progress/renderertodo.md | 3 + .../client/scene/ClientWorldData.java | 25 ++++++++ .../client/script/ScriptClientVoxelUtils.java | 7 +- .../client/terrain/cache/ChunkData.java | 2 +- .../terrain/cells/ClientDrawCellManager.java | 7 +- .../client/terrain/cells/DrawCell.java | 10 ++- .../client/terrain/foliage/FoliageCell.java | 19 ++++-- .../terrain/foliage/FoliageCellManager.java | 13 +++- .../client/terrain/foliage/FoliageModel.java | 15 +++-- .../entity/ClientEntityUtils.java | 7 ++ .../net/client/protocol/TerrainProtocol.java | 64 +++++++++++++++++-- .../net/server/protocol/TerrainProtocol.java | 14 ++-- .../actor/instance/TextureInstancedActor.java | 9 +++ .../datacell/GriddedDataCellManager.java | 57 ++++++++++------- .../util/ds/octree/WorldOctTree.java | 2 +- 15 files changed, 199 insertions(+), 55 deletions(-) diff --git a/docs/src/progress/renderertodo.md b/docs/src/progress/renderertodo.md index 787a0a23..a15412df 100644 --- a/docs/src/progress/renderertodo.md +++ b/docs/src/progress/renderertodo.md @@ -1132,6 +1132,8 @@ Disable tunnel noise to align foliage better + adjust manual value for foliage p (11/23/2024) Clean up top level folder Break out dependency documentation into a dedicated file +Fix terrain editing +Fix foliage not updating at edited chunk # TODO @@ -1168,6 +1170,7 @@ Bug Fixes - Fix particles not spawning in correct positions - Fix flickering when applying yoga signal (may need to rethink arch here) - Fix virtual scrollables not working + - Fix foliage flickering on edit Startup Performance - Allow texture map to bind multiple model paths to a single set of mesh->textures diff --git a/src/main/java/electrosphere/client/scene/ClientWorldData.java b/src/main/java/electrosphere/client/scene/ClientWorldData.java index 11b5656e..0fb3d8dd 100644 --- a/src/main/java/electrosphere/client/scene/ClientWorldData.java +++ b/src/main/java/electrosphere/client/scene/ClientWorldData.java @@ -154,6 +154,31 @@ public class ClientWorldData { ); } + + /** + * Converts a relative voxel position to its absolute voxel equivalent + * @param voxelPos The relative voxel position + * @param worldPos The position of the chunk + * @return The absolute voxel position ie the voxel-aligned position not clamped to the current chunk + */ + public Vector3i convertRelativeVoxelToAbsoluteVoxelSpace(Vector3i voxelPos, Vector3i worldPos){ + return new Vector3i( + worldPos.x * ServerTerrainChunk.CHUNK_DIMENSION + voxelPos.x, + worldPos.y * ServerTerrainChunk.CHUNK_DIMENSION + voxelPos.y, + worldPos.z * ServerTerrainChunk.CHUNK_DIMENSION + voxelPos.z + ); + } + + /** + * Converts a relative voxel position to its absolute voxel equivalent + * @param voxelPos The relative voxel position + * @param worldPos The position of the chunk + * @return The absolute voxel position ie the voxel-aligned position not clamped to the current chunk + */ + public int convertRelativeVoxelToAbsoluteVoxelSpace(int voxelPos, int worldPos){ + return worldPos * ServerTerrainChunk.CHUNK_DIMENSION + voxelPos; + } + /** * Converts a world space vector to a real space vector * @param position The world space vector diff --git a/src/main/java/electrosphere/client/script/ScriptClientVoxelUtils.java b/src/main/java/electrosphere/client/script/ScriptClientVoxelUtils.java index 0b10173e..7754b4b4 100644 --- a/src/main/java/electrosphere/client/script/ScriptClientVoxelUtils.java +++ b/src/main/java/electrosphere/client/script/ScriptClientVoxelUtils.java @@ -14,6 +14,11 @@ import electrosphere.entity.Entity; */ public class ScriptClientVoxelUtils { + /** + * Increment to edit terrain by + */ + static final float EDIT_INCREMENT = 0.1f; + /** * Applies the current voxel palette where the player's cursor is looking */ @@ -29,7 +34,7 @@ public class ScriptClientVoxelUtils { Vector3d centerPos = new Vector3d(CameraEntityUtils.getCameraCenter(camera)); Vector3d cursorPos = collisionEngine.rayCastPosition(new Vector3d(centerPos), new Vector3d(eyePos).mul(-1.0), CollisionEngine.DEFAULT_INTERACT_DISTANCE); if(Globals.clientSelectedVoxelType != null){ - TerrainEditing.editTerrain(cursorPos, 1.1f, Globals.clientSelectedVoxelType.getId(), 0.1f); + TerrainEditing.editTerrain(cursorPos, 1.1f, Globals.clientSelectedVoxelType.getId(), EDIT_INCREMENT); } } } diff --git a/src/main/java/electrosphere/client/terrain/cache/ChunkData.java b/src/main/java/electrosphere/client/terrain/cache/ChunkData.java index e208823b..b1ed4dd6 100644 --- a/src/main/java/electrosphere/client/terrain/cache/ChunkData.java +++ b/src/main/java/electrosphere/client/terrain/cache/ChunkData.java @@ -159,7 +159,7 @@ public class ChunkData { voxelWeight[localX][localY][localZ] = weight; voxelType[localX][localY][localZ] = type; //store as modified in cache - String key = getVoxelPositionKey(new Vector3i(localX,localY,localZ)); + String key = this.getVoxelPositionKey(new Vector3i(localX,localY,localZ)); if(!modifiedSinceLastGeneration.contains(key)){ modifiedSinceLastGeneration.add(key); } diff --git a/src/main/java/electrosphere/client/terrain/cells/ClientDrawCellManager.java b/src/main/java/electrosphere/client/terrain/cells/ClientDrawCellManager.java index e2bc2079..0778039c 100644 --- a/src/main/java/electrosphere/client/terrain/cells/ClientDrawCellManager.java +++ b/src/main/java/electrosphere/client/terrain/cells/ClientDrawCellManager.java @@ -799,8 +799,11 @@ public class ClientDrawCellManager { * @param worldY The world y position * @param worldZ The world z position */ - public void markUpdateable(float worldX, float worldY, float worldZ){ - throw new Error("Unimplemented"); + public void markUpdateable(int worldX, int worldY, int worldZ){ + DrawCell drawCell = this.getDrawCell(worldX, worldY, worldZ); + drawCell.ejectChunkData(); + drawCell.setHasGenerated(false); + drawCell.setHasRequested(false); } /** diff --git a/src/main/java/electrosphere/client/terrain/cells/DrawCell.java b/src/main/java/electrosphere/client/terrain/cells/DrawCell.java index 59bd988e..e512b291 100644 --- a/src/main/java/electrosphere/client/terrain/cells/DrawCell.java +++ b/src/main/java/electrosphere/client/terrain/cells/DrawCell.java @@ -175,10 +175,11 @@ public class DrawCell { } } } + Entity toDelete = this.modelEntity; modelEntity = TerrainChunk.clientCreateTerrainChunkEntity( this.chunkData, this.notifyTarget, - this.modelEntity, + toDelete, lod, atlas, this.hasPolygons() @@ -555,6 +556,13 @@ public class DrawCell { this.failedGenerationAttempts = this.failedGenerationAttempts + attempts; } + /** + * Ejects the chunk data + */ + public void ejectChunkData(){ + this.chunkData = null; + } + /** * Gets whether this draw cell is homogenous or not * @return true if it is homogenous, false otherwise diff --git a/src/main/java/electrosphere/client/terrain/foliage/FoliageCell.java b/src/main/java/electrosphere/client/terrain/foliage/FoliageCell.java index b945bbdb..9a22cea0 100644 --- a/src/main/java/electrosphere/client/terrain/foliage/FoliageCell.java +++ b/src/main/java/electrosphere/client/terrain/foliage/FoliageCell.java @@ -19,7 +19,6 @@ import electrosphere.client.terrain.cache.ChunkData; import electrosphere.engine.Globals; import electrosphere.entity.ClientEntityUtils; import electrosphere.entity.Entity; -import electrosphere.entity.EntityCreationUtils; import electrosphere.entity.EntityUtils; import electrosphere.entity.btree.BehaviorTree; import electrosphere.renderer.OpenGLState; @@ -267,7 +266,6 @@ public class FoliageCell { this.chunkData = new TransvoxelChunkData(currentChunk.getVoxelWeight(), currentChunk.getVoxelType(), 0); } this.generate(); - this.setHasGenerated(true); } @@ -276,9 +274,6 @@ public class FoliageCell { */ protected void generate(){ boolean shouldGenerate = false; - if(!Globals.clientDrawCellManager.hasGeneratedPhysics(worldPos.x, worldPos.y, worldPos.z)){ - return; - } ChunkData data = Globals.clientTerrainManager.getChunkDataAtWorldPoint(worldPos,ChunkData.NO_STRIDE); if(data == null){ return; @@ -315,9 +310,12 @@ public class FoliageCell { if(shouldGenerate){ Entity oldEntity = this.modelEntity; //create entity - this.modelEntity = EntityCreationUtils.createClientSpatialEntity(); - FoliageModel.clientCreateFoliageChunkEntity(foliageTypesSupported,scale,this.modelEntity,this.getRealPos(),worldPos,voxelPos,notifyTarget,oldEntity); + this.modelEntity = FoliageModel.clientCreateFoliageChunkEntity(foliageTypesSupported,scale,this.getRealPos(),worldPos,voxelPos,notifyTarget,oldEntity); } else { + if(this.modelEntity != null){ + ClientEntityUtils.destroyEntity(this.modelEntity); + this.modelEntity = null; + } this.homogenous = true; } this.hasGenerated = true; @@ -650,6 +648,13 @@ public class FoliageCell { this.failedGenerationAttempts = this.failedGenerationAttempts + attempts; } + /** + * Ejects the chunk data + */ + public void ejectChunkData(){ + this.chunkData = null; + } + /** * Gets whether this foliage cell is homogenous or not * @return true if it is homogenous, false otherwise diff --git a/src/main/java/electrosphere/client/terrain/foliage/FoliageCellManager.java b/src/main/java/electrosphere/client/terrain/foliage/FoliageCellManager.java index 8612e5c7..9166a74c 100644 --- a/src/main/java/electrosphere/client/terrain/foliage/FoliageCellManager.java +++ b/src/main/java/electrosphere/client/terrain/foliage/FoliageCellManager.java @@ -723,9 +723,18 @@ public class FoliageCellManager { * @param worldX The world x position * @param worldY The world y position * @param worldZ The world z position + * @param voxelX The voxel x position + * @param voxelY The voxel y position + * @param voxelZ The voxel z position */ - public void markUpdateable(float worldX, float worldY, float worldZ){ - throw new Error("Unimplemented"); + public void markUpdateable(int worldX, int worldY, int worldZ, int voxelX, int voxelY, int voxelZ){ + int absVoxelX = Globals.clientWorldData.convertRelativeVoxelToAbsoluteVoxelSpace(voxelX,worldX); + int absVoxelY = Globals.clientWorldData.convertRelativeVoxelToAbsoluteVoxelSpace(voxelY,worldY); + int absVoxelZ = Globals.clientWorldData.convertRelativeVoxelToAbsoluteVoxelSpace(voxelZ,worldZ); + FoliageCell foliageCell = this.getFoliageCell(absVoxelX, absVoxelY, absVoxelZ); + foliageCell.ejectChunkData(); + foliageCell.setHasGenerated(false); + foliageCell.setHasRequested(false); } /** diff --git a/src/main/java/electrosphere/client/terrain/foliage/FoliageModel.java b/src/main/java/electrosphere/client/terrain/foliage/FoliageModel.java index 0e754144..63b0b4d3 100644 --- a/src/main/java/electrosphere/client/terrain/foliage/FoliageModel.java +++ b/src/main/java/electrosphere/client/terrain/foliage/FoliageModel.java @@ -137,7 +137,6 @@ public class FoliageModel { public static Entity clientCreateFoliageChunkEntity( List foliageTypesSupported, int scale, - Entity modelEntity, Vector3d realPos, Vector3i worldPos, Vector3i voxelPos, @@ -218,11 +217,17 @@ public class FoliageModel { QueuedTexture queuedAsset = new QueuedTexture(buffer,textureWidth,textureHeight); Globals.assetManager.queuedAsset(queuedAsset); - TextureInstancedActor.attachTextureInstancedActor(modelEntity, foliageType.getGraphicsTemplate().getModel().getPath(), vertexPath, fragmentPath, queuedAsset, drawCount, textureHeight); - ClientEntityUtils.initiallyPositionEntity(modelEntity, realPos, new Quaterniond()); - EntityUtils.getScale(modelEntity).set(1,1,1); + TextureInstancedActor.attachTextureInstancedActor(rVal, foliageType.getGraphicsTemplate().getModel().getPath(), vertexPath, fragmentPath, queuedAsset, drawCount, textureHeight); + ClientEntityUtils.initiallyPositionEntity(rVal, realPos, new Quaterniond()); + EntityUtils.getScale(rVal).set(1,1,1); //add ambient foliage behavior tree - AmbientFoliage.attachAmbientFoliageTree(modelEntity, 1.0f, foliageType.getGrowthModel().getGrowthRate()); + AmbientFoliage.attachAmbientFoliageTree(rVal, 1.0f, foliageType.getGrowthModel().getGrowthRate()); + } + if(toDelete != null){ + ClientEntityUtils.destroyEntity(toDelete); + } + if(notifyTarget != null){ + notifyTarget.alertToGeneration(); } } catch (Error e){ LoggerInterface.loggerEngine.ERROR(e); diff --git a/src/main/java/electrosphere/entity/ClientEntityUtils.java b/src/main/java/electrosphere/entity/ClientEntityUtils.java index 5ea4773e..3e045672 100644 --- a/src/main/java/electrosphere/entity/ClientEntityUtils.java +++ b/src/main/java/electrosphere/entity/ClientEntityUtils.java @@ -10,6 +10,7 @@ import electrosphere.entity.state.attach.AttachUtils; import electrosphere.entity.state.hitbox.HitboxCollectionState; import electrosphere.entity.types.collision.CollisionObjUtils; import electrosphere.renderer.actor.ActorUtils; +import electrosphere.renderer.actor.instance.TextureInstancedActor; /** * Client only entity utility functions @@ -55,6 +56,12 @@ public class ClientEntityUtils { //deregister all behavior trees EntityUtils.cleanUpEntity(entity); + //instanced actor + if(TextureInstancedActor.getTextureInstancedActor(entity) != null){ + TextureInstancedActor actor = TextureInstancedActor.getTextureInstancedActor(entity); + actor.free(); + } + if(Globals.clientSceneWrapper != null){ Globals.clientSceneWrapper.getScene().deregisterEntity(entity); Globals.clientSceneWrapper.deregisterTranslationMapping(entity); diff --git a/src/main/java/electrosphere/net/client/protocol/TerrainProtocol.java b/src/main/java/electrosphere/net/client/protocol/TerrainProtocol.java index 4466dc40..f0414a80 100644 --- a/src/main/java/electrosphere/net/client/protocol/TerrainProtocol.java +++ b/src/main/java/electrosphere/net/client/protocol/TerrainProtocol.java @@ -107,13 +107,67 @@ public class TerrainProtocol implements ClientProtocolTemplate { // //mark all relevant drawcells as updateable for(Vector3i worldPosToUpdate : positionsToUpdate){ - if(Globals.clientTerrainManager.containsChunkDataAtWorldPoint(worldPosToUpdate.x, worldPosToUpdate.y, worldPosToUpdate.z, ChunkData.NO_STRIDE)){ - ChunkData data = Globals.clientTerrainManager.getChunkDataAtWorldPoint(worldPosToUpdate.x, worldPosToUpdate.y, worldPosToUpdate.z, ChunkData.NO_STRIDE); - if(data != null){ - Globals.clientDrawCellManager.markUpdateable(worldPosToUpdate.x, worldPosToUpdate.y, worldPosToUpdate.z); + if( + worldPosToUpdate.x >= 0 && worldPosToUpdate.x < Globals.clientWorldData.getWorldDiscreteSize() && + worldPosToUpdate.y >= 0 && worldPosToUpdate.y < Globals.clientWorldData.getWorldDiscreteSize() && + worldPosToUpdate.z >= 0 && worldPosToUpdate.z < Globals.clientWorldData.getWorldDiscreteSize() + ){ + // + //mark terrain chunk for update + Globals.clientDrawCellManager.markUpdateable(worldPosToUpdate.x, worldPosToUpdate.y, worldPosToUpdate.z); + + // + //update foliage manager + Globals.foliageCellManager.markUpdateable( + worldPosToUpdate.x, worldPosToUpdate.y, worldPosToUpdate.z, + message.getvoxelX(), message.getvoxelY(), message.getvoxelZ() + ); + if(message.getvoxelX() > 0){ + Globals.foliageCellManager.markUpdateable( + worldPosToUpdate.x, worldPosToUpdate.y, worldPosToUpdate.z, + message.getvoxelX() - 1, message.getvoxelY(), message.getvoxelZ() + ); + if(message.getvoxelY() > 0){ + Globals.foliageCellManager.markUpdateable( + worldPosToUpdate.x, worldPosToUpdate.y, worldPosToUpdate.z, + message.getvoxelX() - 1, message.getvoxelY() - 1, message.getvoxelZ() + ); + if(message.getvoxelZ() > 0){ + Globals.foliageCellManager.markUpdateable( + worldPosToUpdate.x, worldPosToUpdate.y, worldPosToUpdate.z, + message.getvoxelX() - 1, message.getvoxelY() - 1, message.getvoxelZ() - 1 + ); + } + } else { + if(message.getvoxelZ() > 0){ + Globals.foliageCellManager.markUpdateable( + worldPosToUpdate.x, worldPosToUpdate.y, worldPosToUpdate.z, + message.getvoxelX() - 1, message.getvoxelY(), message.getvoxelZ() - 1 + ); + } + } + } else { + if(message.getvoxelY() > 0){ + Globals.foliageCellManager.markUpdateable( + worldPosToUpdate.x, worldPosToUpdate.y, worldPosToUpdate.z, + message.getvoxelX(), message.getvoxelY() - 1, message.getvoxelZ() + ); + if(message.getvoxelZ() > 0){ + Globals.foliageCellManager.markUpdateable( + worldPosToUpdate.x, worldPosToUpdate.y, worldPosToUpdate.z, + message.getvoxelX(), message.getvoxelY() - 1, message.getvoxelZ() - 1 + ); + } + } else { + if(message.getvoxelZ() > 0){ + Globals.foliageCellManager.markUpdateable( + worldPosToUpdate.x, worldPosToUpdate.y, worldPosToUpdate.z, + message.getvoxelX(), message.getvoxelY(), message.getvoxelZ() - 1 + ); + } + } } } - // Globals.clientFoliageManager.evaluateChunk(worldPos); } } break; case SENDFLUIDDATA: { diff --git a/src/main/java/electrosphere/net/server/protocol/TerrainProtocol.java b/src/main/java/electrosphere/net/server/protocol/TerrainProtocol.java index 5ca2430e..51b8531d 100644 --- a/src/main/java/electrosphere/net/server/protocol/TerrainProtocol.java +++ b/src/main/java/electrosphere/net/server/protocol/TerrainProtocol.java @@ -28,13 +28,13 @@ public class TerrainProtocol implements ServerProtocolTemplate { public TerrainMessage handleAsyncMessage(ServerConnectionHandler connectionHandler, TerrainMessage message) { switch(message.getMessageSubtype()){ case REQUESTCHUNKDATA: { - sendWorldSubChunkAsync(connectionHandler, + TerrainProtocol.sendWorldSubChunkAsync(connectionHandler, message.getworldX(), message.getworldY(), message.getworldZ() ); return null; } case REQUESTREDUCEDCHUNKDATA: { - sendWorldSubChunkAsyncStrided(connectionHandler, + TerrainProtocol.sendWorldSubChunkAsyncStrided(connectionHandler, message.getworldX(), message.getworldY(), message.getworldZ(), message.getchunkResolution() ); return null; @@ -49,25 +49,25 @@ public class TerrainProtocol implements ServerProtocolTemplate { public void handleSyncMessage(ServerConnectionHandler connectionHandler, TerrainMessage message) { switch(message.getMessageSubtype()){ case REQUESTMETADATA: { - sendWorldMetadata(connectionHandler); + TerrainProtocol.sendWorldMetadata(connectionHandler); } break; case REQUESTCHUNKDATA: { LoggerInterface.loggerNetworking.DEBUG("(Server) Received request for terrain " + message.getworldX() + " " + message.getworldY() + " " + message.getworldZ()); // System.out.println("Received request for terrain " + message.getworldX() + " " + message.getworldY() + " " + message.getworldZ()); - sendWorldSubChunk(connectionHandler, + TerrainProtocol.sendWorldSubChunk(connectionHandler, message.getworldX(), message.getworldY(), message.getworldZ() ); } break; case REQUESTEDITVOXEL: { - attemptTerrainEdit(connectionHandler, message); + TerrainProtocol.attemptTerrainEdit(connectionHandler, message); } break; case REQUESTUSETERRAINPALETTE: { - attemptUseTerrainEditPalette(connectionHandler, message); + TerrainProtocol.attemptUseTerrainEditPalette(connectionHandler, message); } break; case REQUESTFLUIDDATA: { LoggerInterface.loggerNetworking.DEBUG("(Server) Received request for fluid " + message.getworldX() + " " + message.getworldY() + " " + message.getworldZ()); // System.out.println("Received request for fluid " + message.getworldX() + " " + message.getworldY() + " " + message.getworldZ()); - sendWorldFluidSubChunk(connectionHandler, + TerrainProtocol.sendWorldFluidSubChunk(connectionHandler, message.getworldX(), message.getworldY(), message.getworldZ() ); } break; diff --git a/src/main/java/electrosphere/renderer/actor/instance/TextureInstancedActor.java b/src/main/java/electrosphere/renderer/actor/instance/TextureInstancedActor.java index 970fffb9..0bc1f67a 100644 --- a/src/main/java/electrosphere/renderer/actor/instance/TextureInstancedActor.java +++ b/src/main/java/electrosphere/renderer/actor/instance/TextureInstancedActor.java @@ -185,4 +185,13 @@ public class TextureInstancedActor { model.setWorldPos(worldPos); } } + + /** + * Frees the texture instanced actor + */ + public void free(){ + if(this.queuedTexture != null && this.queuedTexture.getTexture() != null){ + Globals.assetManager.queueTextureForDeletion(this.queuedTexture.getTexture().getPath()); + } + } } diff --git a/src/main/java/electrosphere/server/datacell/GriddedDataCellManager.java b/src/main/java/electrosphere/server/datacell/GriddedDataCellManager.java index 4d71be48..a9a7b4ce 100644 --- a/src/main/java/electrosphere/server/datacell/GriddedDataCellManager.java +++ b/src/main/java/electrosphere/server/datacell/GriddedDataCellManager.java @@ -653,8 +653,6 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager */ public void editChunk(Vector3i worldPosition, Vector3i voxelPosition, float weight, int type) { terrainEditLock.acquireUninterruptibly(); - //update terrain - serverTerrainManager.deformTerrainAtLocationToValue(worldPosition, voxelPosition, weight, type); List worldPositionsToUpdate = new LinkedList(); worldPositionsToUpdate.add(worldPosition); if(voxelPosition.x < 1){ @@ -664,32 +662,45 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager if(voxelPosition.z < 1){ worldPositionsToUpdate.add(new Vector3i(worldPosition).sub(1,1,1)); } - } else { - if(voxelPosition.z < 1){ - worldPositionsToUpdate.add(new Vector3i(worldPosition).sub(1,0,1)); - } } - } else { - if(voxelPosition.y < 1){ - worldPositionsToUpdate.add(new Vector3i(worldPosition).sub(0,1,0)); - if(voxelPosition.z < 1){ - worldPositionsToUpdate.add(new Vector3i(worldPosition).sub(0,1,1)); - } - } else { - if(voxelPosition.z < 1){ - worldPositionsToUpdate.add(new Vector3i(worldPosition).sub(0,0,1)); - } + if(voxelPosition.z < 1){ + worldPositionsToUpdate.add(new Vector3i(worldPosition).sub(1,0,1)); } } + if(voxelPosition.y < 1){ + worldPositionsToUpdate.add(new Vector3i(worldPosition).sub(0,1,0)); + if(voxelPosition.z < 1){ + worldPositionsToUpdate.add(new Vector3i(worldPosition).sub(0,1,1)); + } + } + if(voxelPosition.z < 1){ + worldPositionsToUpdate.add(new Vector3i(worldPosition).sub(0,0,1)); + } //update all loaded cells for(Vector3i toUpdate : worldPositionsToUpdate){ - ServerDataCell cell = groundDataCells.get(getServerDataCellKey(toUpdate)); - if(cell != null){ - this.createTerrainPhysicsEntities(toUpdate); - cell.broadcastNetworkMessage(TerrainMessage.constructUpdateVoxelMessage( - worldPosition.x, worldPosition.y, worldPosition.z, - voxelPosition.x, voxelPosition.y, voxelPosition.z, - weight, type)); + if( + toUpdate.x >= 0 && toUpdate.x < this.serverWorldData.getWorldSizeDiscrete() && + toUpdate.y >= 0 && toUpdate.y < this.serverWorldData.getWorldSizeDiscrete() && + toUpdate.z >= 0 && toUpdate.z < this.serverWorldData.getWorldSizeDiscrete() + ){ + //update terrain + int localVoxelX = voxelPosition.x + (ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE - 1) * (worldPosition.x - toUpdate.x); + int localVoxelY = voxelPosition.y + (ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE - 1) * (worldPosition.y - toUpdate.y); + int localVoxelZ = voxelPosition.z + (ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE - 1) * (worldPosition.z - toUpdate.z); + serverTerrainManager.deformTerrainAtLocationToValue(toUpdate, new Vector3i(localVoxelX, localVoxelY, localVoxelZ), weight, type); + + //update anything loaded + ServerDataCell cell = groundDataCells.get(this.getServerDataCellKey(toUpdate)); + if(cell != null){ + //update physics + this.createTerrainPhysicsEntities(toUpdate); + + //broadcast update + cell.broadcastNetworkMessage(TerrainMessage.constructUpdateVoxelMessage( + toUpdate.x, toUpdate.y, toUpdate.z, + localVoxelX, localVoxelY, localVoxelZ, + weight, type)); + } } } terrainEditLock.release(); diff --git a/src/main/java/electrosphere/util/ds/octree/WorldOctTree.java b/src/main/java/electrosphere/util/ds/octree/WorldOctTree.java index 48058bb0..df755564 100644 --- a/src/main/java/electrosphere/util/ds/octree/WorldOctTree.java +++ b/src/main/java/electrosphere/util/ds/octree/WorldOctTree.java @@ -223,7 +223,7 @@ public class WorldOctTree { ){ throw new Error("Trying to search for node outside tree range!"); } - WorldOctTreeNode searchResult = recursiveSearchUnsafe(root,position,maxLevel); + WorldOctTreeNode searchResult = this.recursiveSearchUnsafe(root,position,maxLevel); if(!returnNonLeaf && !searchResult.isLeaf()){ return null; }