diff --git a/docs/src/progress/renderertodo.md b/docs/src/progress/renderertodo.md index e9cc4b3b..8cf86f76 100644 --- a/docs/src/progress/renderertodo.md +++ b/docs/src/progress/renderertodo.md @@ -999,6 +999,10 @@ Lower client cache size (to fight memory stalling) Manual free button on memory debug window +passing chunk data between nodes +storing min lod of children at every level of tree + + # TODO diff --git a/src/main/java/electrosphere/client/terrain/cells/ClientDrawCellManager.java b/src/main/java/electrosphere/client/terrain/cells/ClientDrawCellManager.java index 83e51686..21b982cc 100644 --- a/src/main/java/electrosphere/client/terrain/cells/ClientDrawCellManager.java +++ b/src/main/java/electrosphere/client/terrain/cells/ClientDrawCellManager.java @@ -235,6 +235,7 @@ public class ClientDrawCellManager { //perform op WorldOctTreeNode container = chunkTree.split(node); container.setData(DrawCell.generateTerrainCell(container.getMinBound(), this.chunkTree.getMaxLevel() - container.getLevel())); + container.getData().transferChunkData(node.getData()); //do creations container.getChildren().forEach(child -> { @@ -617,6 +618,7 @@ public class ClientDrawCellManager { Globals.profiler.beginCpuSample("ClientDrawCellManager.join"); //perform op WorldOctTreeNode newLeaf = chunkTree.join(node, DrawCell.generateTerrainCell(node.getMinBound(),node.getData().lod)); + newLeaf.getData().transferChunkData(node.getData()); //do deletions this.twoLayerDestroy(node); @@ -757,11 +759,9 @@ public class ClientDrawCellManager { * @param node The top node */ private void twoLayerDestroy(WorldOctTreeNode node){ - if(node.getData() == null){ + if(!node.getData().hasGenerated()){ for(WorldOctTreeNode child : node.getChildren()){ - if(child.getData() != null){ - child.getData().destroy(); - } + child.getData().destroy(); } } else { node.getData().destroy(); diff --git a/src/main/java/electrosphere/client/terrain/cells/DrawCell.java b/src/main/java/electrosphere/client/terrain/cells/DrawCell.java index 7dd6c4d6..a7906ab1 100644 --- a/src/main/java/electrosphere/client/terrain/cells/DrawCell.java +++ b/src/main/java/electrosphere/client/terrain/cells/DrawCell.java @@ -47,9 +47,10 @@ public class DrawCell { //the main entity for the cell Entity modelEntity; - //Allocated once instead of continuously, used to generate the visual/physics models - float[][][] weights = new float[ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE][ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE][ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE]; - int[][][] types = new int[ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE][ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE][ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE]; + /** + * The data for generating the visuals + */ + TransvoxelChunkData chunkData; /** * Tracks whether the draw cell has requested its chunk data or not @@ -62,16 +63,6 @@ public class DrawCell { boolean hasGenerated = false; - /** - * The initial voxel type encountered - */ - int initialVoxelType = -1; - - /** - * True if there are multiple types of voxels in this chunk - */ - boolean multiVoxelType = false; - /** * Tracks whether this draw cell is flagged as homogenous from the server or not */ @@ -91,7 +82,7 @@ public class DrawCell { * The cached minimum distance */ double cachedMinDistance = -1; - + /** * Private constructor @@ -133,21 +124,30 @@ public class DrawCell { * Generates a drawable entity based on this chunk */ public void generateDrawableEntity(VoxelTextureAtlas atlas, int lod, List higherLODFaces){ - Globals.profiler.beginAggregateCpuSample("DrawCell.fillInData"); - boolean success = this.fillInData(lod); - Globals.profiler.endCpuSample(); - if(!success){ - this.setFailedGenerationAttempts(this.getFailedGenerationAttempts() + 1); - return; + boolean success = true; + if(chunkData == null){ + ChunkData currentChunk = Globals.clientTerrainManager.getChunkDataAtWorldPoint( + worldPos.x, + worldPos.y, + worldPos.z, + lod + ); + if(currentChunk == null){ + success = false; + } else { + this.homogenous = currentChunk.getHomogenousValue() != ChunkData.NOT_HOMOGENOUS; + success = true; + } + if(!success){ + this.setFailedGenerationAttempts(this.getFailedGenerationAttempts() + 1); + return; + } + this.chunkData = new TransvoxelChunkData(currentChunk.getVoxelWeight(), currentChunk.getVoxelType(), lod); } - if(modelEntity != null){ - Globals.clientScene.deregisterEntity(modelEntity); - } - TransvoxelChunkData chunkData = new TransvoxelChunkData(weights, types, lod); if(higherLODFaces != null){ for(DrawCellFace face : higherLODFaces){ Globals.profiler.beginCpuSample("DrawCell.fillInFaceData"); - success = this.fillInFaceData(chunkData,face,lod); + success = this.fillInFaceData(this.chunkData,face,lod); Globals.profiler.endCpuSample(); if(!success){ this.setFailedGenerationAttempts(this.getFailedGenerationAttempts() + 1); @@ -155,10 +155,11 @@ public class DrawCell { } } } - modelEntity = TerrainChunk.clientCreateTerrainChunkEntity(chunkData, lod, atlas, this.hasPolygons()); + if(modelEntity != null){ + ClientEntityUtils.destroyEntity(modelEntity); + } + modelEntity = TerrainChunk.clientCreateTerrainChunkEntity(this.chunkData, lod, atlas, this.hasPolygons()); ClientEntityUtils.initiallyPositionEntity(modelEntity, this.getRealPos(), new Quaterniond()); - // this.weights = null; - // this.types = null; this.setHasGenerated(true); } @@ -201,57 +202,17 @@ public class DrawCell { return modelEntity; } - /** - * Fills in the internal arrays of data for generate terrain models - * @return true if the data was successfully filled, false otherwise + * Transfers chunk data from the source to this draw cell + * @param source The source draw cell */ - private boolean fillInData(int lod){ - // if(lod == ClientDrawCellManager.FULL_RES_LOD){ - ChunkData currentChunk = Globals.clientTerrainManager.getChunkDataAtWorldPoint( - worldPos.x, - worldPos.y, - worldPos.z, - lod - ); - if(currentChunk == null){ - return false; - } - if(currentChunk.getHomogenousValue() != ChunkData.NOT_HOMOGENOUS){ - return true; - } - for(int x = 0; x < ChunkData.CHUNK_DATA_SIZE; x++){ - for(int y = 0; y < ChunkData.CHUNK_DATA_SIZE; y++){ - for(int z = 0; z < ChunkData.CHUNK_DATA_SIZE; z++){ - weights[x][y][z] = currentChunk.getWeight( - x, - y, - z - ); - types[x][y][z] = currentChunk.getType( - x, - y, - z - ); - if(currentChunk.getHomogenousValue() == ChunkData.NOT_HOMOGENOUS){ - this.homogenous = false; - } - - - //checks to see if there is only one type of voxel in this chunk - if(!this.multiVoxelType){ - if(this.initialVoxelType == -1){ - this.initialVoxelType = types[x][y][z]; - } else if(this.initialVoxelType != types[x][y][z]){ - this.multiVoxelType = true; - } - } - } - } - } - return true; + public void transferChunkData(DrawCell source){ + this.chunkData = source.chunkData; + this.homogenous = source.homogenous; + this.hasRequested = source.hasRequested; } + /** * Fills in the data for the higher resolution face * @param chunkData The data for the chunk to generate @@ -517,7 +478,7 @@ public class DrawCell { * @return true if it has polygons, false otherwise */ private boolean hasPolygons(){ - return this.multiVoxelType; + return !this.homogenous; } /** diff --git a/src/main/java/electrosphere/client/terrain/manager/ClientTerrainManager.java b/src/main/java/electrosphere/client/terrain/manager/ClientTerrainManager.java index 7e68ba21..035a81ff 100644 --- a/src/main/java/electrosphere/client/terrain/manager/ClientTerrainManager.java +++ b/src/main/java/electrosphere/client/terrain/manager/ClientTerrainManager.java @@ -55,7 +55,7 @@ public class ClientTerrainManager { public static final int INTERPOLATION_RATIO = ServerTerrainManager.SERVER_TERRAIN_MANAGER_INTERPOLATION_RATIO; //caches chunks from server - static final int CACHE_SIZE = 1000 + (int)(ClientDrawCellManager.FULL_RES_DIST * 10) + (int)(ClientDrawCellManager.HALF_RES_DIST * 10); + static final int CACHE_SIZE = 2500 + (int)(ClientDrawCellManager.FULL_RES_DIST * 10) + (int)(ClientDrawCellManager.HALF_RES_DIST * 10); /** * Size of the cache in bytes diff --git a/src/main/java/electrosphere/entity/ClientEntityUtils.java b/src/main/java/electrosphere/entity/ClientEntityUtils.java index cf465f4b..54fc1c38 100644 --- a/src/main/java/electrosphere/entity/ClientEntityUtils.java +++ b/src/main/java/electrosphere/entity/ClientEntityUtils.java @@ -53,6 +53,14 @@ public class ClientEntityUtils { //deregister all behavior trees EntityUtils.cleanUpEntity(entity); + + if(Globals.clientSceneWrapper != null){ + Globals.clientSceneWrapper.getScene().deregisterEntity(entity); + Globals.clientSceneWrapper.deregisterTranslationMapping(entity); + } + if(Globals.clientScene != null){ + Globals.clientScene.deregisterEntity(entity); + } } } diff --git a/src/main/java/electrosphere/entity/types/terrain/TerrainChunk.java b/src/main/java/electrosphere/entity/types/terrain/TerrainChunk.java index ec3c2bda..a8920194 100644 --- a/src/main/java/electrosphere/entity/types/terrain/TerrainChunk.java +++ b/src/main/java/electrosphere/entity/types/terrain/TerrainChunk.java @@ -31,7 +31,7 @@ public class TerrainChunk { /** * Used for generating terrain chunks */ - static final ExecutorService generationService = Executors.newFixedThreadPool(2); + static final ExecutorService generationService = Executors.newFixedThreadPool(4); /** * Creates a client terrain chunk based on weights and values provided diff --git a/src/main/java/electrosphere/server/content/ServerContentGenerator.java b/src/main/java/electrosphere/server/content/ServerContentGenerator.java index 149f7877..df7bdbcf 100644 --- a/src/main/java/electrosphere/server/content/ServerContentGenerator.java +++ b/src/main/java/electrosphere/server/content/ServerContentGenerator.java @@ -53,43 +53,43 @@ public class ServerContentGenerator { //generate foliage - BiomeData biome = null; - if(realm.getServerWorldData() != null && realm.getServerWorldData().getServerTerrainManager() != null && realm.getServerWorldData().getServerTerrainManager().getModel() != null){ - biome = realm.getServerWorldData().getServerTerrainManager().getModel().getSurfaceBiome(worldPos.x, worldPos.z); - } - List foliageDescriptions = biome.getSurfaceGenerationParams().getFoliageDescriptions(); - if(foliageDescriptions != null){ - for(int x = 0; x < ServerTerrainChunk.CHUNK_DIMENSION; x++){ - for(int z = 0; z < ServerTerrainChunk.CHUNK_DIMENSION; z++){ - double height = realm.getServerWorldData().getServerTerrainManager().getElevation(worldPos.x, worldPos.z, x, z) + HEIGHT_MANUAL_ADJUSTMENT; - if( - realm.getServerWorldData().convertVoxelToRealSpace(0, worldPos.y) <= height && - realm.getServerWorldData().convertVoxelToRealSpace(ServerTerrainChunk.CHUNK_DIMENSION, worldPos.y) > height - ){ - for(BiomeFoliageDescription foliageDescription : foliageDescriptions){ - double scale = foliageDescription.getScale(); - double regularity = foliageDescription.getRegularity(); - double threshold = foliageDescription.getThreshold(); - double realX = realm.getServerWorldData().convertVoxelToRealSpace(x, worldPos.x); - double realZ = realm.getServerWorldData().convertVoxelToRealSpace(z, worldPos.z); - if(NoiseUtils.relaxedPointGen(realX * scale, realZ * scale, regularity, threshold) > 0){ - String type = foliageDescription.getEntityIDs().get(random.nextInt(0,foliageDescription.getEntityIDs().size())); - FoliageUtils.serverSpawnTreeFoliage( - realm, - new Vector3d( - realX, - height, - realZ - ), - type, - random.nextLong() - ); - } - } - } - } - } - } + // BiomeData biome = null; + // if(realm.getServerWorldData() != null && realm.getServerWorldData().getServerTerrainManager() != null && realm.getServerWorldData().getServerTerrainManager().getModel() != null){ + // biome = realm.getServerWorldData().getServerTerrainManager().getModel().getSurfaceBiome(worldPos.x, worldPos.z); + // } + // List foliageDescriptions = biome.getSurfaceGenerationParams().getFoliageDescriptions(); + // if(foliageDescriptions != null){ + // for(int x = 0; x < ServerTerrainChunk.CHUNK_DIMENSION; x++){ + // for(int z = 0; z < ServerTerrainChunk.CHUNK_DIMENSION; z++){ + // double height = realm.getServerWorldData().getServerTerrainManager().getElevation(worldPos.x, worldPos.z, x, z) + HEIGHT_MANUAL_ADJUSTMENT; + // if( + // realm.getServerWorldData().convertVoxelToRealSpace(0, worldPos.y) <= height && + // realm.getServerWorldData().convertVoxelToRealSpace(ServerTerrainChunk.CHUNK_DIMENSION, worldPos.y) > height + // ){ + // for(BiomeFoliageDescription foliageDescription : foliageDescriptions){ + // double scale = foliageDescription.getScale(); + // double regularity = foliageDescription.getRegularity(); + // double threshold = foliageDescription.getThreshold(); + // double realX = realm.getServerWorldData().convertVoxelToRealSpace(x, worldPos.x); + // double realZ = realm.getServerWorldData().convertVoxelToRealSpace(z, worldPos.z); + // if(NoiseUtils.relaxedPointGen(realX * scale, realZ * scale, regularity, threshold) > 0){ + // String type = foliageDescription.getEntityIDs().get(random.nextInt(0,foliageDescription.getEntityIDs().size())); + // FoliageUtils.serverSpawnTreeFoliage( + // realm, + // new Vector3d( + // realX, + // height, + // realZ + // ), + // type, + // random.nextLong() + // ); + // } + // } + // } + // } + // } + // } } diff --git a/src/main/java/electrosphere/server/datacell/Realm.java b/src/main/java/electrosphere/server/datacell/Realm.java index fbc9219f..cb893f24 100644 --- a/src/main/java/electrosphere/server/datacell/Realm.java +++ b/src/main/java/electrosphere/server/datacell/Realm.java @@ -204,7 +204,7 @@ public class Realm { // //data cell manager update misc variables (player positions, unload not-in-use cells) if(dataCellManager != null){ - dataCellManager.unloadPlayerlessChunks(); + // dataCellManager.unloadPlayerlessChunks(); } // //clear collidable impulse lists diff --git a/src/main/java/electrosphere/server/fluid/manager/ServerFluidManager.java b/src/main/java/electrosphere/server/fluid/manager/ServerFluidManager.java index 74315e0c..403b6448 100644 --- a/src/main/java/electrosphere/server/fluid/manager/ServerFluidManager.java +++ b/src/main/java/electrosphere/server/fluid/manager/ServerFluidManager.java @@ -273,13 +273,13 @@ public class ServerFluidManager { public boolean simulate(int worldX, int worldY, int worldZ){ boolean rVal = false; Globals.profiler.beginAggregateCpuSample("ServerFluidManager.simulate"); - if(simulate){ - ServerFluidChunk fluidChunk = this.getChunk(worldX, worldY, worldZ); - ServerTerrainChunk terrainChunk = this.serverTerrainManager.getChunk(worldX, worldY, worldZ); - if(fluidChunk != null && terrainChunk != null && this.serverFluidSimulator != null){ - rVal = this.serverFluidSimulator.simulate(fluidChunk,terrainChunk,worldX,worldY,worldZ); - } - } + // if(simulate){ + // ServerFluidChunk fluidChunk = this.getChunk(worldX, worldY, worldZ); + // ServerTerrainChunk terrainChunk = this.serverTerrainManager.getChunk(worldX, worldY, worldZ); + // if(fluidChunk != null && terrainChunk != null && this.serverFluidSimulator != null){ + // rVal = this.serverFluidSimulator.simulate(fluidChunk,terrainChunk,worldX,worldY,worldZ); + // } + // } Globals.profiler.endCpuSample(); return rVal; } diff --git a/src/main/java/electrosphere/server/terrain/generation/TestGenerationChunkGenerator.java b/src/main/java/electrosphere/server/terrain/generation/TestGenerationChunkGenerator.java index 2d5b2bd0..a9d10b3b 100644 --- a/src/main/java/electrosphere/server/terrain/generation/TestGenerationChunkGenerator.java +++ b/src/main/java/electrosphere/server/terrain/generation/TestGenerationChunkGenerator.java @@ -159,6 +159,7 @@ public class TestGenerationChunkGenerator implements ChunkGenerator { // } // }); } else { + GeneratedVoxel voxel = new GeneratedVoxel(); for(int x = 0; x < ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE; x++){ Globals.profiler.beginAggregateCpuSample("TestGenerationChunkGenerator - Generate slice"); for(int y = 0; y < ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE; y++){ @@ -169,7 +170,8 @@ public class TestGenerationChunkGenerator implements ChunkGenerator { int finalChunkX = (x * strideValue) % ServerTerrainChunk.CHUNK_DIMENSION; int finalChunkY = (y * strideValue) % ServerTerrainChunk.CHUNK_DIMENSION; int finalChunkZ = (z * strideValue) % ServerTerrainChunk.CHUNK_DIMENSION; - GeneratedVoxel voxel = this.getVoxel( + this.getVoxel( + voxel, finalWorldX, finalWorldY, finalWorldZ, finalChunkX, finalChunkY, finalChunkZ, stride, @@ -182,7 +184,7 @@ public class TestGenerationChunkGenerator implements ChunkGenerator { } if(firstType == -1){ firstType = values[x][y][z]; - } else if(homogenous && firstType == values[x][y][z]){ + } else if(homogenous && firstType != values[x][y][z]){ homogenous = false; } } @@ -222,6 +224,7 @@ public class TestGenerationChunkGenerator implements ChunkGenerator { /** * Gets the value for a chunk + * @param voxel The voxel to fill * @param worldX The world x pos * @param worldY The world y pos * @param worldZ The world z pos @@ -231,9 +234,9 @@ public class TestGenerationChunkGenerator implements ChunkGenerator { * @param stride The stride of the data * @param surfaceHeight The height of the surface at x,z * @param surfaceBiome The surface biome of the chunk - * @return The value of the chunk */ - private GeneratedVoxel getVoxel( + private void getVoxel( + GeneratedVoxel voxel, int worldX, int worldY, int worldZ, int chunkX, int chunkY, int chunkZ, int stride, @@ -256,7 +259,8 @@ public class TestGenerationChunkGenerator implements ChunkGenerator { double surfacePercent = TestGenerationChunkGenerator.getSurfaceWeight(surfaceHeight,realY,strideMultiplier); Globals.profiler.endCpuSample(); if(heightDiff < -strideMultiplier * SURFACE_VOXEL_WIDTH){ - return getSubsurfaceVoxel( + getSubsurfaceVoxel( + voxel, worldX, worldY, worldZ, chunkX, chunkY, chunkZ, realX, realY, realZ, @@ -265,7 +269,8 @@ public class TestGenerationChunkGenerator implements ChunkGenerator { surfaceBiome ); } else if(heightDiff > 0) { - return getOverSurfaceVoxel( + getOverSurfaceVoxel( + voxel, worldX, worldY, worldZ, chunkX, chunkY, chunkZ, realX, realY, realZ,- @@ -274,7 +279,8 @@ public class TestGenerationChunkGenerator implements ChunkGenerator { surfaceBiome ); } else { - return getSurfaceVoxel( + getSurfaceVoxel( + voxel, worldX, worldY, worldZ, chunkX, chunkY, chunkZ, realX, realY, realZ, @@ -289,7 +295,8 @@ public class TestGenerationChunkGenerator implements ChunkGenerator { * Gets the voxel on the surface * @return The voxel */ - private GeneratedVoxel getSurfaceVoxel( + private void getSurfaceVoxel( + GeneratedVoxel voxel, int worldX, int worldY, int worldZ, int chunkX, int chunkY, int chunkZ, double realX, double realY, double realZ, @@ -297,17 +304,16 @@ public class TestGenerationChunkGenerator implements ChunkGenerator { float surfaceHeight, BiomeData surfaceBiome ){ - GeneratedVoxel voxel = new GeneratedVoxel(); voxel.weight = (float)surfacePercent * 2 - 1; voxel.type = 2; - return voxel; } /** * Gets the voxel below the surface * @return The voxel */ - private GeneratedVoxel getSubsurfaceVoxel( + private void getSubsurfaceVoxel( + GeneratedVoxel voxel, int worldX, int worldY, int worldZ, int chunkX, int chunkY, int chunkZ, double realX, double realY, double realZ, @@ -315,7 +321,6 @@ public class TestGenerationChunkGenerator implements ChunkGenerator { float surfaceHeight, BiomeData surfaceBiome ){ - GeneratedVoxel voxel = new GeneratedVoxel(); if(realY < surfaceHeight - 5){ voxel.weight = 1; voxel.type = 6; @@ -323,14 +328,14 @@ public class TestGenerationChunkGenerator implements ChunkGenerator { voxel.weight = 1; voxel.type = 1; } - return voxel; } /** * Gets the voxel above the service * @return The voxel */ - private GeneratedVoxel getOverSurfaceVoxel( + private void getOverSurfaceVoxel( + GeneratedVoxel voxel, int worldX, int worldY, int worldZ, int chunkX, int chunkY, int chunkZ, double realX, double realY, double realZ, @@ -338,10 +343,8 @@ public class TestGenerationChunkGenerator implements ChunkGenerator { float surfaceHeight, BiomeData surfaceBiome ){ - GeneratedVoxel voxel = new GeneratedVoxel(); voxel.weight = -1; voxel.type = 0; - return voxel; } /** diff --git a/src/main/java/electrosphere/util/ds/octree/WorldOctTree.java b/src/main/java/electrosphere/util/ds/octree/WorldOctTree.java index c755f31d..48058bb0 100644 --- a/src/main/java/electrosphere/util/ds/octree/WorldOctTree.java +++ b/src/main/java/electrosphere/util/ds/octree/WorldOctTree.java @@ -1,7 +1,6 @@ package electrosphere.util.ds.octree; import java.util.ArrayList; -import java.util.Collections; import java.util.LinkedList; import java.util.List; @@ -381,7 +380,7 @@ public class WorldOctTree { * Gets the children of this node */ public List> getChildren() { - return Collections.unmodifiableList(this.children); + return this.children; } /**