diff --git a/docs/src/progress/renderertodo.md b/docs/src/progress/renderertodo.md index dc04fd6c..7092fb7c 100644 --- a/docs/src/progress/renderertodo.md +++ b/docs/src/progress/renderertodo.md @@ -1915,6 +1915,7 @@ Calculate road-interection nodes for town layout Place roads using line segments instead of splines Town layout tries to connect intersection nodes with roads Macro area objects don't store start/end bounds separate from aabb anymore +Unify functions to fetch/generate chunks on server diff --git a/src/main/java/electrosphere/server/physics/block/manager/ServerBlockChunkGenerationThread.java b/src/main/java/electrosphere/server/physics/block/manager/ServerBlockChunkGenerationThread.java index 3e41ea4e..05809250 100644 --- a/src/main/java/electrosphere/server/physics/block/manager/ServerBlockChunkGenerationThread.java +++ b/src/main/java/electrosphere/server/physics/block/manager/ServerBlockChunkGenerationThread.java @@ -108,27 +108,7 @@ public class ServerBlockChunkGenerationThread implements Runnable { int i = 0; try { while(chunk == null && i < MAX_TIME_TO_WAIT && Globals.engineState.threadManager.shouldKeepRunning()){ - if(chunkCache.containsChunk(worldX, worldY, worldZ, stride)){ - chunk = chunkCache.get(worldX, worldY, worldZ, stride); - } else { - //pull from disk if it exists - if(chunkDiskMap != null){ - if(chunkDiskMap.containsBlocksAtPosition(worldX, worldY, worldZ)){ - chunk = chunkDiskMap.getBlockChunk(worldX, worldY, worldZ); - } - } - //generate if it does not exist - if(chunk == null){ - chunk = new BlockChunkData(); - chunk.setWorldX(worldX); - chunk.setWorldY(worldY); - chunk.setWorldZ(worldZ); - ServerBlockChunkGenerationThread.generate(chunk, macroData, worldX, worldY, worldZ); - } - if(chunk != null){ - chunkCache.add(worldX, worldY, worldZ, stride, chunk); - } - } + chunk = fetchOrGenerate(macroData, worldX, worldY, worldZ, stride, chunkDiskMap, chunkCache); if(chunk == null){ try { TimeUnit.MILLISECONDS.sleep(WAIT_TIME_MS); @@ -149,6 +129,48 @@ public class ServerBlockChunkGenerationThread implements Runnable { } } + /** + * Fetches or generates a block chunk's data + * @param macroData The macro data + * @param worldX The world x coordinate + * @param worldY The world y coordinate + * @param worldZ The world z coordinate + * @param stride The stride + * @param chunkDiskMap The chunk disk map + * @param chunkCache The chunk cache + * @return The block chunk if it fetched/generated successfully, null otherwise + */ + protected static BlockChunkData fetchOrGenerate( + MacroData macroData, + int worldX, int worldY, int worldZ, int stride, + ServerBlockChunkDiskMap chunkDiskMap, + BlockChunkCache chunkCache + ){ + BlockChunkData chunk = null; + if(chunkCache.containsChunk(worldX, worldY, worldZ, stride)){ + chunk = chunkCache.get(worldX, worldY, worldZ, stride); + } else { + //pull from disk if it exists + if(chunkDiskMap != null){ + if(chunkDiskMap.containsBlocksAtPosition(worldX, worldY, worldZ)){ + chunk = chunkDiskMap.getBlockChunk(worldX, worldY, worldZ); + } + } + //generate if it does not exist + if(chunk == null){ + chunk = new BlockChunkData(); + chunk.setWorldX(worldX); + chunk.setWorldY(worldY); + chunk.setWorldZ(worldZ); + ServerBlockChunkGenerationThread.generate(chunk, macroData, worldX, worldY, worldZ); + } + if(chunk != null){ + chunkCache.add(worldX, worldY, worldZ, stride, chunk); + } + } + return chunk; + } + /** * Generates the actual values of the chunk * @param chunk THe chunk diff --git a/src/main/java/electrosphere/server/physics/block/manager/ServerBlockManager.java b/src/main/java/electrosphere/server/physics/block/manager/ServerBlockManager.java index 87f43bfb..07cb78df 100644 --- a/src/main/java/electrosphere/server/physics/block/manager/ServerBlockManager.java +++ b/src/main/java/electrosphere/server/physics/block/manager/ServerBlockManager.java @@ -22,30 +22,30 @@ public class ServerBlockManager { /** * The parent world data */ - ServerWorldData parent; + protected ServerWorldData parent; /** * The cache of chunks */ @Exclude - BlockChunkCache chunkCache; + private BlockChunkCache chunkCache; /** * The map of chunk position <-> file on disk containing chunk data */ - ServerBlockChunkDiskMap chunkDiskMap = null; + private ServerBlockChunkDiskMap chunkDiskMap = null; /** * The macro data for this world */ @Exclude - MacroData macroData; + private MacroData macroData; /** * The threadpool for chunk generation */ @Exclude - ExecutorService chunkExecutorService = Globals.engineState.threadManager.requestFixedThreadPool(ThreadCounts.SERVER_BLOCK_GENERATION_THREADS); + private ExecutorService chunkExecutorService = Globals.engineState.threadManager.requestFixedThreadPool(ThreadCounts.SERVER_BLOCK_GENERATION_THREADS); /** * Constructor @@ -108,26 +108,7 @@ public class ServerBlockManager { public BlockChunkData getChunk(int worldX, int worldY, int worldZ){ Globals.profiler.beginAggregateCpuSample("ServerBlockManager.getChunk"); //THIS FIRES IF THERE IS A MAIN GAME WORLD RUNNING - BlockChunkData returnedChunk = null; - if(chunkCache.containsChunk(worldX,worldY,worldZ,BlockChunkData.LOD_FULL_RES)){ - returnedChunk = chunkCache.get(worldX,worldY,worldZ, BlockChunkData.LOD_FULL_RES); - } else { - //pull from disk if it exists - if(chunkDiskMap != null){ - if(chunkDiskMap.containsBlocksAtPosition(worldX, worldY, worldZ)){ - returnedChunk = chunkDiskMap.getBlockChunk(worldX, worldY, worldZ); - } - } - //generate if it does not exist - if(returnedChunk == null){ - returnedChunk = new BlockChunkData(); - returnedChunk.setWorldX(worldX); - returnedChunk.setWorldY(worldY); - returnedChunk.setWorldZ(worldZ); - ServerBlockChunkGenerationThread.generate(returnedChunk, macroData, worldX, worldY, worldZ); - } - this.chunkCache.add(worldX, worldY, worldZ, BlockChunkData.LOD_FULL_RES, returnedChunk); - } + BlockChunkData returnedChunk = ServerBlockChunkGenerationThread.fetchOrGenerate(macroData, worldX, worldY, worldZ, BlockChunkData.LOD_FULL_RES, chunkDiskMap, chunkCache); Globals.profiler.endCpuSample(); return returnedChunk; } diff --git a/src/main/java/electrosphere/server/physics/terrain/manager/ChunkGenerationThread.java b/src/main/java/electrosphere/server/physics/terrain/manager/ChunkGenerationThread.java index 02933272..5c0454e7 100644 --- a/src/main/java/electrosphere/server/physics/terrain/manager/ChunkGenerationThread.java +++ b/src/main/java/electrosphere/server/physics/terrain/manager/ChunkGenerationThread.java @@ -6,6 +6,8 @@ import java.util.function.Consumer; import electrosphere.engine.Globals; import electrosphere.logger.LoggerInterface; +import electrosphere.server.datacell.ServerWorldData; +import electrosphere.server.macro.MacroData; import electrosphere.server.macro.spatial.MacroObject; import electrosphere.server.physics.terrain.diskmap.ChunkDiskMap; import electrosphere.server.physics.terrain.generation.interfaces.ChunkGenerator; @@ -43,7 +45,7 @@ public class ChunkGenerationThread implements Runnable { /** * The macro data */ - List macroData; + MacroData macroData; /** * The world x coordinate @@ -83,7 +85,7 @@ public class ChunkGenerationThread implements Runnable { * @param onLoad The work to do once the chunk is available */ public ChunkGenerationThread( - List macroData, + MacroData macroData, ChunkDiskMap chunkDiskMap, ServerChunkCache chunkCache, ChunkGenerator chunkGenerator, @@ -108,23 +110,7 @@ public class ChunkGenerationThread implements Runnable { int i = 0; ServerTerrainChunk chunk = null; while(chunk == null && i < MAX_TIME_TO_WAIT && Globals.engineState.threadManager.shouldKeepRunning()){ - if(chunkCache.containsChunk(worldX, worldY, worldZ, stride)){ - chunk = chunkCache.get(worldX, worldY, worldZ, stride); - } else { - //pull from disk if it exists - if(chunkDiskMap != null && stride == ServerChunkCache.STRIDE_FULL_RES){ - if(chunkDiskMap.containsTerrainAtPosition(worldX, worldY, worldZ, stride)){ - chunk = chunkDiskMap.getTerrainChunk(worldX, worldY, worldZ, stride); - } - } - //generate if it does not exist - if(chunk == null){ - chunk = chunkGenerator.generateChunk(this.macroData, worldX, worldY, worldZ, stride); - } - if(chunk != null){ - chunkCache.add(worldX, worldY, worldZ, stride, chunk); - } - } + chunk = ChunkGenerationThread.getChunk(macroData, worldX, worldY, worldZ, stride, chunkDiskMap, chunkCache, chunkGenerator); if(chunk == null){ try { TimeUnit.MILLISECONDS.sleep(WAIT_TIME_MS); @@ -144,5 +130,54 @@ public class ChunkGenerationThread implements Runnable { LoggerInterface.loggerEngine.ERROR(e); } } + + /** + * Gets a chunk + * @param macroData The macro data + * @param worldX The world x coordinate + * @param worldY The world y coordinate + * @param worldZ The world z coordinate + * @param stride The stride + * @param chunkDiskMap The chunk disk map + * @param chunkCache The chunk cache + * @param chunkGenerator The chunk generator to use + * @return The chunk if it was fetched or created, null otherwise + */ + public static ServerTerrainChunk getChunk( + MacroData macroData, + int worldX, int worldY, int worldZ, int stride, + ChunkDiskMap chunkDiskMap, + ServerChunkCache chunkCache, + ChunkGenerator chunkGenerator + ){ + ServerTerrainChunk rVal = null; + + //get the macro data that affects this chunk + List objects = null; + if(macroData != null){ + objects = macroData.getNearbyObjects(ServerWorldData.convertChunkToRealSpace(worldX, worldY, worldZ)); + } + //if any of this macro data isn't ready, return a null chunk + + + if(chunkCache.containsChunk(worldX, worldY, worldZ, stride)){ + rVal = chunkCache.get(worldX, worldY, worldZ, stride); + } else { + //pull from disk if it exists + if(chunkDiskMap != null && stride == ServerChunkCache.STRIDE_FULL_RES){ + if(chunkDiskMap.containsTerrainAtPosition(worldX, worldY, worldZ, stride)){ + rVal = chunkDiskMap.getTerrainChunk(worldX, worldY, worldZ, stride); + } + } + //generate if it does not exist + if(rVal == null){ + rVal = chunkGenerator.generateChunk(objects, worldX, worldY, worldZ, stride); + } + if(rVal != null){ + chunkCache.add(worldX, worldY, worldZ, stride, rVal); + } + } + return rVal; + } } diff --git a/src/main/java/electrosphere/server/physics/terrain/manager/ServerTerrainManager.java b/src/main/java/electrosphere/server/physics/terrain/manager/ServerTerrainManager.java index 8ebb51ce..bcda7867 100644 --- a/src/main/java/electrosphere/server/physics/terrain/manager/ServerTerrainManager.java +++ b/src/main/java/electrosphere/server/physics/terrain/manager/ServerTerrainManager.java @@ -4,9 +4,9 @@ import electrosphere.client.terrain.cache.ChunkData; import electrosphere.engine.Globals; import electrosphere.engine.threads.ThreadCounts; import electrosphere.entity.scene.RealmDescriptor; +import electrosphere.logger.LoggerInterface; import electrosphere.server.datacell.ServerWorldData; import electrosphere.server.macro.MacroData; -import electrosphere.server.macro.spatial.MacroObject; import electrosphere.server.physics.terrain.diskmap.ChunkDiskMap; import electrosphere.server.physics.terrain.generation.ProceduralChunkGenerator; import electrosphere.server.physics.terrain.generation.interfaces.ChunkGenerator; @@ -21,7 +21,6 @@ import electrosphere.util.annotation.Exclude; import java.nio.ByteBuffer; import java.nio.FloatBuffer; import java.nio.ShortBuffer; -import java.util.List; import java.util.concurrent.ExecutorService; import java.util.function.Consumer; @@ -56,46 +55,46 @@ public class ServerTerrainManager { /** * The parent world data */ - ServerWorldData parent; + protected ServerWorldData parent; /** * the seed for terrain generation */ - long seed; + private long seed; /** * The model of the terrain this manager is managing */ - TerrainModel model; + private TerrainModel model; /** * The cache of chunks */ @Exclude - ServerChunkCache chunkCache; + private ServerChunkCache chunkCache; /** * The map of chunk position <-> file on disk containing chunk data */ - ChunkDiskMap chunkDiskMap = null; + private ChunkDiskMap chunkDiskMap = null; /** * The generation algorithm for this terrain manager */ @Exclude - ChunkGenerator chunkGenerator; + private ChunkGenerator chunkGenerator; /** * The macro data for this world */ @Exclude - MacroData macroData; + private MacroData macroData; /** * The threadpool for chunk generation */ @Exclude - ExecutorService chunkExecutorService = Globals.engineState.threadManager.requestFixedThreadPool(ThreadCounts.SERVER_TERRAIN_GENERATION_THREADS); + private ExecutorService chunkExecutorService = Globals.engineState.threadManager.requestFixedThreadPool(ThreadCounts.SERVER_TERRAIN_GENERATION_THREADS); /** * Constructor @@ -110,10 +109,6 @@ public class ServerTerrainManager { this.chunkGenerator = chunkGenerator; } - ServerTerrainManager(){ - - } - /** * Generates a terrain model for the manager */ @@ -294,25 +289,9 @@ public class ServerTerrainManager { public ServerTerrainChunk getChunk(int worldX, int worldY, int worldZ, int stride){ Globals.profiler.beginAggregateCpuSample("ServerTerrainManager.getChunk"); //THIS FIRES IF THERE IS A MAIN GAME WORLD RUNNING - ServerTerrainChunk returnedChunk = null; - if(chunkCache.containsChunk(worldX,worldY,worldZ,ChunkData.NO_STRIDE)){ - returnedChunk = chunkCache.get(worldX,worldY,worldZ, ChunkData.NO_STRIDE); - } else { - //pull from disk if it exists - if(chunkDiskMap != null){ - if(chunkDiskMap.containsTerrainAtPosition(worldX, worldY, worldZ, stride)){ - returnedChunk = chunkDiskMap.getTerrainChunk(worldX, worldY, worldZ, stride); - } - } - //generate if it does not exist - if(returnedChunk == null){ - List objects = null; - if(macroData != null){ - objects = this.macroData.getNearbyObjects(ServerWorldData.convertChunkToRealSpace(worldX, worldY, worldZ)); - } - returnedChunk = chunkGenerator.generateChunk(objects, worldX, worldY, worldZ, ChunkData.NO_STRIDE); - } - this.chunkCache.add(worldX, worldY, worldZ, ChunkData.NO_STRIDE, returnedChunk); + ServerTerrainChunk returnedChunk = ChunkGenerationThread.getChunk(macroData, worldX, worldY, worldZ, stride, chunkDiskMap, chunkCache, chunkGenerator); + if(returnedChunk == null){ + LoggerInterface.loggerEngine.WARNING("Failed to generate chunk at " + worldX + " " + worldY + " " + worldZ + " asynchronously"); } Globals.profiler.endCpuSample(); return returnedChunk; @@ -357,11 +336,7 @@ public class ServerTerrainManager { */ public void getChunkAsync(int worldX, int worldY, int worldZ, int stride, Consumer onLoad){ Globals.profiler.beginAggregateCpuSample("ServerTerrainManager.getChunkAsync"); - List objects = null; - if(this.macroData != null){ - objects = this.macroData.getNearbyObjects(ServerWorldData.convertChunkToRealSpace(worldX, worldY, worldZ)); - } - chunkExecutorService.submit(new ChunkGenerationThread(objects, chunkDiskMap, chunkCache, chunkGenerator, worldX, worldY, worldZ, stride, onLoad)); + chunkExecutorService.submit(new ChunkGenerationThread(this.macroData, chunkDiskMap, chunkCache, chunkGenerator, worldX, worldY, worldZ, stride, onLoad)); Globals.profiler.endCpuSample(); }