diff --git a/src/main/java/electrosphere/client/terrain/cells/ClientDrawCellManager.java b/src/main/java/electrosphere/client/terrain/cells/ClientDrawCellManager.java index 1d9d0fcf..9ee876be 100644 --- a/src/main/java/electrosphere/client/terrain/cells/ClientDrawCellManager.java +++ b/src/main/java/electrosphere/client/terrain/cells/ClientDrawCellManager.java @@ -50,6 +50,26 @@ public class ClientDrawCellManager { */ public static final double EIGHTH_RES_DIST = 28 * ServerTerrainChunk.CHUNK_DIMENSION; + /** + * Lod value for a full res chunk + */ + public static final int FULL_RES_LOD = 0; + + /** + * Lod value for a half res chunk + */ + public static final int HALF_RES_LOD = 1; + + /** + * Lod value for a quarter res chunk + */ + public static final int QUARTER_RES_LOD = 2; + + /** + * Lod value for a eighth res chunk + */ + public static final int EIGHTH_RES_LOD = 3; + /** * The octree holding all the chunks to evaluate */ @@ -95,6 +115,11 @@ public class ClientDrawCellManager { */ int generated = 0; + /** + * Tracks whether the cell manager has initialized or not + */ + boolean initialized = false; + /** * Constructor * @param voxelTextureAtlas The voxel texture atlas @@ -115,12 +140,18 @@ public class ClientDrawCellManager { Vector3d playerPos = EntityUtils.getPosition(Globals.playerEntity); //the sets to iterate through updatedLastFrame = true; - int attempts = 0; validCellCount = 0; - while(updatedLastFrame && attempts < UPDATE_ATTEMPTS_PER_FRAME){ - FloatingChunkTreeNode rootNode = this.chunkTree.getRoot(); - updatedLastFrame = this.recursivelyUpdateCells(rootNode, playerPos); - attempts++; + //update all full res cells + FloatingChunkTreeNode rootNode = this.chunkTree.getRoot(); + updatedLastFrame = this.recursivelyUpdateCells(rootNode, playerPos, HALF_RES_LOD); + if(!updatedLastFrame && !this.initialized){ + this.initialized = true; + } + if(!updatedLastFrame){ + updatedLastFrame = this.recursivelyUpdateCells(rootNode, playerPos, QUARTER_RES_LOD); + } + if(!updatedLastFrame){ + updatedLastFrame = this.recursivelyUpdateCells(rootNode, playerPos, EIGHTH_RES_LOD); } } Globals.profiler.endCpuSample(); @@ -130,9 +161,10 @@ public class ClientDrawCellManager { * Recursively update child nodes * @param node The root node * @param playerPos The player's position + * @param minLeafLod The minimum LOD required to evaluate a leaf * @return true if there is work remaining to be done, false otherwise */ - private boolean recursivelyUpdateCells(FloatingChunkTreeNode node, Vector3d playerPos){ + private boolean recursivelyUpdateCells(FloatingChunkTreeNode node, Vector3d playerPos, int minLeafLod){ Vector3d playerRealPos = EntityUtils.getPosition(Globals.playerEntity); boolean updated = false; if(this.shouldSplit(playerPos, node)){ @@ -176,15 +208,20 @@ public class ClientDrawCellManager { Globals.profiler.endCpuSample(); updated = true; - } else if(shouldRequest(playerPos, node)){ + } else if(shouldRequest(playerPos, node, minLeafLod)){ Globals.profiler.beginCpuSample("ClientDrawCellManager.request"); + + //calculate what to request DrawCell cell = node.getData(); List highResFaces = this.solveHighResFace(node); + + //actually send requests this.requestChunks(node, highResFaces); cell.setHasRequested(true); + Globals.profiler.endCpuSample(); updated = true; - } else if(shouldGenerate(playerPos, node)){ + } else if(shouldGenerate(playerPos, node, minLeafLod)){ Globals.profiler.beginCpuSample("ClientDrawCellManager.generate"); int lodLevel = this.getLODLevel(playerRealPos, node); List highResFaces = this.solveHighResFace(node); @@ -205,7 +242,7 @@ public class ClientDrawCellManager { this.validCellCount++; List> children = new LinkedList>(node.getChildren()); for(FloatingChunkTreeNode child : children){ - boolean childUpdate = recursivelyUpdateCells(child, playerPos); + boolean childUpdate = recursivelyUpdateCells(child, playerPos, minLeafLod); if(childUpdate == true){ updated = true; } @@ -414,13 +451,15 @@ public class ClientDrawCellManager { * Checks if this cell should request chunk data * @param pos the player's position * @param node the node + * @param minLeafLod The minimum LOD required to evaluate a leaf * @return true if should request chunk data, false otherwise */ - public boolean shouldRequest(Vector3d pos, FloatingChunkTreeNode node){ + public boolean shouldRequest(Vector3d pos, FloatingChunkTreeNode node, int minLeafLod){ return node.isLeaf() && node.getData() != null && !node.getData().hasRequested() && + (this.chunkTree.getMaxLevel() - node.getLevel()) < minLeafLod && ( ( node.getLevel() == this.chunkTree.getMaxLevel() @@ -453,13 +492,15 @@ public class ClientDrawCellManager { * Checks if this cell should generate * @param pos the player's position * @param node the node + * @param minLeafLod The minimum LOD required to evaluate a leaf * @return true if should generate, false otherwise */ - public boolean shouldGenerate(Vector3d pos, FloatingChunkTreeNode node){ + public boolean shouldGenerate(Vector3d pos, FloatingChunkTreeNode node, int minLeafLod){ return node.isLeaf() && node.getData() != null && !node.getData().hasGenerated() && + (this.chunkTree.getMaxLevel() - node.getLevel()) < minLeafLod && ( ( node.getLevel() == this.chunkTree.getMaxLevel() @@ -788,6 +829,14 @@ public class ClientDrawCellManager { return generated; } + /** + * Gets whether the client draw cell manager has initialized or not + * @return true if it has initialized, false otherwise + */ + public boolean isInitialized(){ + return this.initialized; + } + } diff --git a/src/main/java/electrosphere/engine/loadingthreads/ClientLoading.java b/src/main/java/electrosphere/engine/loadingthreads/ClientLoading.java index 80fca928..09ad0d56 100644 --- a/src/main/java/electrosphere/engine/loadingthreads/ClientLoading.java +++ b/src/main/java/electrosphere/engine/loadingthreads/ClientLoading.java @@ -297,7 +297,11 @@ public class ClientLoading { Globals.clientSimulation.setLoadingTerrain(true); //wait for all the terrain data to arrive int i = 0; - while(blockForInit && Globals.clientDrawCellManager.updatedLastFrame() && Globals.threadManager.shouldKeepRunning()){ + while( + blockForInit && + !Globals.clientDrawCellManager.isInitialized() && + Globals.threadManager.shouldKeepRunning() + ){ i++; if(i % DRAW_CELL_UPDATE_RATE == 0){ WindowUtils.updateLoadingWindow("WAITING ON SERVER TO SEND TERRAIN (" + Globals.clientTerrainManager.getAllChunks().size() + ")"); diff --git a/src/main/java/electrosphere/server/terrain/generation/TestGenerationChunkGenerator.java b/src/main/java/electrosphere/server/terrain/generation/TestGenerationChunkGenerator.java index 05c5ba93..de7bf5c4 100644 --- a/src/main/java/electrosphere/server/terrain/generation/TestGenerationChunkGenerator.java +++ b/src/main/java/electrosphere/server/terrain/generation/TestGenerationChunkGenerator.java @@ -24,7 +24,7 @@ public class TestGenerationChunkGenerator implements ChunkGenerator { /** * The size of the realm for testing generation */ - public static final int GENERATOR_REALM_SIZE = 32; + public static final int GENERATOR_REALM_SIZE = 64; /** * The default biome index