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
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

View File

@ -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

View File

@ -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;
}

View File

@ -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<MacroObject> 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<MacroObject> 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<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.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<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);
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<ServerTerrainChunk> onLoad){
Globals.profiler.beginAggregateCpuSample("ServerTerrainManager.getChunkAsync");
List<MacroObject> 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();
}