unify chunk fetch/gen funcs
All checks were successful
studiorailgun/Renderer/pipeline/head This commit looks good

This commit is contained in:
austin 2025-05-20 12:28:22 -04:00
parent 36f5d67241
commit 3685eb1c92
5 changed files with 117 additions and 103 deletions

View File

@ -1915,6 +1915,7 @@ Calculate road-interection nodes for town layout
Place roads using line segments instead of splines Place roads using line segments instead of splines
Town layout tries to connect intersection nodes with roads Town layout tries to connect intersection nodes with roads
Macro area objects don't store start/end bounds separate from aabb anymore Macro area objects don't store start/end bounds separate from aabb anymore
Unify functions to fetch/generate chunks on server

View File

@ -108,27 +108,7 @@ public class ServerBlockChunkGenerationThread implements Runnable {
int i = 0; int i = 0;
try { try {
while(chunk == null && i < MAX_TIME_TO_WAIT && Globals.engineState.threadManager.shouldKeepRunning()){ while(chunk == null && i < MAX_TIME_TO_WAIT && Globals.engineState.threadManager.shouldKeepRunning()){
if(chunkCache.containsChunk(worldX, worldY, worldZ, stride)){ chunk = fetchOrGenerate(macroData, worldX, worldY, worldZ, stride, chunkDiskMap, chunkCache);
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);
}
}
if(chunk == null){ if(chunk == null){
try { try {
TimeUnit.MILLISECONDS.sleep(WAIT_TIME_MS); 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 * Generates the actual values of the chunk
* @param chunk THe chunk * @param chunk THe chunk

View File

@ -22,30 +22,30 @@ public class ServerBlockManager {
/** /**
* The parent world data * The parent world data
*/ */
ServerWorldData parent; protected ServerWorldData parent;
/** /**
* The cache of chunks * The cache of chunks
*/ */
@Exclude @Exclude
BlockChunkCache chunkCache; private BlockChunkCache chunkCache;
/** /**
* The map of chunk position <-> file on disk containing chunk data * The map of chunk position <-> file on disk containing chunk data
*/ */
ServerBlockChunkDiskMap chunkDiskMap = null; private ServerBlockChunkDiskMap chunkDiskMap = null;
/** /**
* The macro data for this world * The macro data for this world
*/ */
@Exclude @Exclude
MacroData macroData; private MacroData macroData;
/** /**
* The threadpool for chunk generation * The threadpool for chunk generation
*/ */
@Exclude @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 * Constructor
@ -108,26 +108,7 @@ public class ServerBlockManager {
public BlockChunkData getChunk(int worldX, int worldY, int worldZ){ public BlockChunkData getChunk(int worldX, int worldY, int worldZ){
Globals.profiler.beginAggregateCpuSample("ServerBlockManager.getChunk"); Globals.profiler.beginAggregateCpuSample("ServerBlockManager.getChunk");
//THIS FIRES IF THERE IS A MAIN GAME WORLD RUNNING //THIS FIRES IF THERE IS A MAIN GAME WORLD RUNNING
BlockChunkData returnedChunk = null; BlockChunkData returnedChunk = ServerBlockChunkGenerationThread.fetchOrGenerate(macroData, worldX, worldY, worldZ, BlockChunkData.LOD_FULL_RES, chunkDiskMap, chunkCache);
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);
}
Globals.profiler.endCpuSample(); Globals.profiler.endCpuSample();
return returnedChunk; return returnedChunk;
} }

View File

@ -6,6 +6,8 @@ import java.util.function.Consumer;
import electrosphere.engine.Globals; import electrosphere.engine.Globals;
import electrosphere.logger.LoggerInterface; import electrosphere.logger.LoggerInterface;
import electrosphere.server.datacell.ServerWorldData;
import electrosphere.server.macro.MacroData;
import electrosphere.server.macro.spatial.MacroObject; import electrosphere.server.macro.spatial.MacroObject;
import electrosphere.server.physics.terrain.diskmap.ChunkDiskMap; import electrosphere.server.physics.terrain.diskmap.ChunkDiskMap;
import electrosphere.server.physics.terrain.generation.interfaces.ChunkGenerator; import electrosphere.server.physics.terrain.generation.interfaces.ChunkGenerator;
@ -43,7 +45,7 @@ public class ChunkGenerationThread implements Runnable {
/** /**
* The macro data * The macro data
*/ */
List<MacroObject> macroData; MacroData macroData;
/** /**
* The world x coordinate * The world x coordinate
@ -83,7 +85,7 @@ public class ChunkGenerationThread implements Runnable {
* @param onLoad The work to do once the chunk is available * @param onLoad The work to do once the chunk is available
*/ */
public ChunkGenerationThread( public ChunkGenerationThread(
List<MacroObject> macroData, MacroData macroData,
ChunkDiskMap chunkDiskMap, ChunkDiskMap chunkDiskMap,
ServerChunkCache chunkCache, ServerChunkCache chunkCache,
ChunkGenerator chunkGenerator, ChunkGenerator chunkGenerator,
@ -108,23 +110,7 @@ public class ChunkGenerationThread implements Runnable {
int i = 0; int i = 0;
ServerTerrainChunk chunk = null; ServerTerrainChunk chunk = null;
while(chunk == null && i < MAX_TIME_TO_WAIT && Globals.engineState.threadManager.shouldKeepRunning()){ while(chunk == null && i < MAX_TIME_TO_WAIT && Globals.engineState.threadManager.shouldKeepRunning()){
if(chunkCache.containsChunk(worldX, worldY, worldZ, stride)){ chunk = ChunkGenerationThread.getChunk(macroData, worldX, worldY, worldZ, stride, chunkDiskMap, chunkCache, chunkGenerator);
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);
}
}
if(chunk == null){ if(chunk == null){
try { try {
TimeUnit.MILLISECONDS.sleep(WAIT_TIME_MS); TimeUnit.MILLISECONDS.sleep(WAIT_TIME_MS);
@ -144,5 +130,54 @@ public class ChunkGenerationThread implements Runnable {
LoggerInterface.loggerEngine.ERROR(e); 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<MacroObject> 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;
}
} }

View File

@ -4,9 +4,9 @@ import electrosphere.client.terrain.cache.ChunkData;
import electrosphere.engine.Globals; import electrosphere.engine.Globals;
import electrosphere.engine.threads.ThreadCounts; import electrosphere.engine.threads.ThreadCounts;
import electrosphere.entity.scene.RealmDescriptor; import electrosphere.entity.scene.RealmDescriptor;
import electrosphere.logger.LoggerInterface;
import electrosphere.server.datacell.ServerWorldData; import electrosphere.server.datacell.ServerWorldData;
import electrosphere.server.macro.MacroData; import electrosphere.server.macro.MacroData;
import electrosphere.server.macro.spatial.MacroObject;
import electrosphere.server.physics.terrain.diskmap.ChunkDiskMap; import electrosphere.server.physics.terrain.diskmap.ChunkDiskMap;
import electrosphere.server.physics.terrain.generation.ProceduralChunkGenerator; import electrosphere.server.physics.terrain.generation.ProceduralChunkGenerator;
import electrosphere.server.physics.terrain.generation.interfaces.ChunkGenerator; import electrosphere.server.physics.terrain.generation.interfaces.ChunkGenerator;
@ -21,7 +21,6 @@ import electrosphere.util.annotation.Exclude;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.FloatBuffer; import java.nio.FloatBuffer;
import java.nio.ShortBuffer; import java.nio.ShortBuffer;
import java.util.List;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.function.Consumer; import java.util.function.Consumer;
@ -56,46 +55,46 @@ public class ServerTerrainManager {
/** /**
* The parent world data * The parent world data
*/ */
ServerWorldData parent; protected ServerWorldData parent;
/** /**
* the seed for terrain generation * the seed for terrain generation
*/ */
long seed; private long seed;
/** /**
* The model of the terrain this manager is managing * The model of the terrain this manager is managing
*/ */
TerrainModel model; private TerrainModel model;
/** /**
* The cache of chunks * The cache of chunks
*/ */
@Exclude @Exclude
ServerChunkCache chunkCache; private ServerChunkCache chunkCache;
/** /**
* The map of chunk position <-> file on disk containing chunk data * 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 * The generation algorithm for this terrain manager
*/ */
@Exclude @Exclude
ChunkGenerator chunkGenerator; private ChunkGenerator chunkGenerator;
/** /**
* The macro data for this world * The macro data for this world
*/ */
@Exclude @Exclude
MacroData macroData; private MacroData macroData;
/** /**
* The threadpool for chunk generation * The threadpool for chunk generation
*/ */
@Exclude @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 * Constructor
@ -110,10 +109,6 @@ public class ServerTerrainManager {
this.chunkGenerator = chunkGenerator; this.chunkGenerator = chunkGenerator;
} }
ServerTerrainManager(){
}
/** /**
* Generates a terrain model for the manager * 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){ public ServerTerrainChunk getChunk(int worldX, int worldY, int worldZ, int stride){
Globals.profiler.beginAggregateCpuSample("ServerTerrainManager.getChunk"); Globals.profiler.beginAggregateCpuSample("ServerTerrainManager.getChunk");
//THIS FIRES IF THERE IS A MAIN GAME WORLD RUNNING //THIS FIRES IF THERE IS A MAIN GAME WORLD RUNNING
ServerTerrainChunk returnedChunk = null; ServerTerrainChunk returnedChunk = ChunkGenerationThread.getChunk(macroData, worldX, worldY, worldZ, stride, chunkDiskMap, chunkCache, chunkGenerator);
if(chunkCache.containsChunk(worldX,worldY,worldZ,ChunkData.NO_STRIDE)){ if(returnedChunk == null){
returnedChunk = chunkCache.get(worldX,worldY,worldZ, ChunkData.NO_STRIDE); LoggerInterface.loggerEngine.WARNING("Failed to generate chunk at " + worldX + " " + worldY + " " + worldZ + " asynchronously");
} 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<MacroObject> 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);
} }
Globals.profiler.endCpuSample(); Globals.profiler.endCpuSample();
return returnedChunk; return returnedChunk;
@ -357,11 +336,7 @@ public class ServerTerrainManager {
*/ */
public void getChunkAsync(int worldX, int worldY, int worldZ, int stride, Consumer<ServerTerrainChunk> onLoad){ public void getChunkAsync(int worldX, int worldY, int worldZ, int stride, Consumer<ServerTerrainChunk> onLoad){
Globals.profiler.beginAggregateCpuSample("ServerTerrainManager.getChunkAsync"); Globals.profiler.beginAggregateCpuSample("ServerTerrainManager.getChunkAsync");
List<MacroObject> objects = null; chunkExecutorService.submit(new ChunkGenerationThread(this.macroData, chunkDiskMap, chunkCache, chunkGenerator, worldX, worldY, worldZ, stride, onLoad));
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));
Globals.profiler.endCpuSample(); Globals.profiler.endCpuSample();
} }