From 27330797e9c41c0a0d7e22fb5117d27ac10a4a56 Mon Sep 17 00:00:00 2001 From: austin Date: Tue, 20 May 2025 12:50:51 -0400 Subject: [PATCH] macro data blocks terrain and block gen --- docs/src/progress/renderertodo.md | 1 + .../gridded/GriddedDataCellManager.java | 9 ++++++++ .../datacell/physics/PhysicsDataCell.java | 22 ++++++++++++------- .../electrosphere/server/macro/MacroData.java | 1 + .../server/macro/spatial/MacroLODObject.java | 14 ++++++++++++ .../electrosphere/server/macro/town/Town.java | 8 ++++++- .../ServerBlockChunkGenerationThread.java | 13 +++++++++++ .../generation/ProceduralChunkGenerator.java | 2 ++ .../manager/ChunkGenerationThread.java | 6 ++++- .../terrain/manager/ServerTerrainManager.java | 2 +- 10 files changed, 67 insertions(+), 11 deletions(-) create mode 100644 src/main/java/electrosphere/server/macro/spatial/MacroLODObject.java diff --git a/docs/src/progress/renderertodo.md b/docs/src/progress/renderertodo.md index 7092fb7c..2fcb2114 100644 --- a/docs/src/progress/renderertodo.md +++ b/docs/src/progress/renderertodo.md @@ -1916,6 +1916,7 @@ 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 +Macro data blocks terrain and block generation until it is ready diff --git a/src/main/java/electrosphere/server/datacell/gridded/GriddedDataCellManager.java b/src/main/java/electrosphere/server/datacell/gridded/GriddedDataCellManager.java index 3c72040d..0c72b838 100644 --- a/src/main/java/electrosphere/server/datacell/gridded/GriddedDataCellManager.java +++ b/src/main/java/electrosphere/server/datacell/gridded/GriddedDataCellManager.java @@ -10,6 +10,7 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.ExecutorService; import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.ReentrantLock; import org.joml.Vector3d; @@ -816,6 +817,14 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager try { BlockChunkData blockChunkData = realm.getServerWorldData().getServerBlockManager().getChunk(worldPos.x, worldPos.y, worldPos.z); ServerTerrainChunk terrainChunk = realm.getServerWorldData().getServerTerrainManager().getChunk(worldPos.x, worldPos.y, worldPos.z, ServerChunkCache.STRIDE_FULL_RES); + while(terrainChunk == null){ + TimeUnit.MILLISECONDS.sleep(1); + terrainChunk = realm.getServerWorldData().getServerTerrainManager().getChunk(worldPos.x, worldPos.y, worldPos.z, ServerChunkCache.STRIDE_FULL_RES); + } + while(blockChunkData == null){ + TimeUnit.MILLISECONDS.sleep(1); + blockChunkData = realm.getServerWorldData().getServerBlockManager().getChunk(worldPos.x, worldPos.y, worldPos.z); + } targetCell.setTerrainChunk(terrainChunk); targetCell.setBlockChunk(blockChunkData); diff --git a/src/main/java/electrosphere/server/datacell/physics/PhysicsDataCell.java b/src/main/java/electrosphere/server/datacell/physics/PhysicsDataCell.java index 1315d2d2..cb9a2a77 100644 --- a/src/main/java/electrosphere/server/datacell/physics/PhysicsDataCell.java +++ b/src/main/java/electrosphere/server/datacell/physics/PhysicsDataCell.java @@ -85,16 +85,22 @@ public class PhysicsDataCell { // this.fillInData(); + //grab local reference to this cell's entities + Entity localPhysicsEnt = this.physicsEntity; + Entity localBlockPhysicsEntity = this.blockPhysicsEntity; + + //check if cell has already been retired + if(localBlockPhysicsEntity == null || localPhysicsEnt == null){ + return; + } + + //generate this.terrainChunkData = TerrainChunk.serverGenerateTerrainChunkData(weights, types); - TerrainChunk.serverCreateTerrainChunkEntity(this.physicsEntity, this.terrainChunkData); - this.physicsEntity.putData(EntityDataStrings.TERRAIN_IS_TERRAIN, true); + TerrainChunk.serverCreateTerrainChunkEntity(localPhysicsEnt, this.terrainChunkData); + localPhysicsEnt.putData(EntityDataStrings.TERRAIN_IS_TERRAIN, true); this.blockData = BlockMeshgen.rasterize(this.blockChunk); - BlockChunkEntity.serverCreateBlockChunkEntity(this.blockPhysicsEntity, this.blockData); - this.blockPhysicsEntity.putData(EntityDataStrings.TERRAIN_IS_TERRAIN, true); - // //then actually perform the attach - // physicsObject = PhysicsUtils.attachTerrainRigidBody(physicsEntity,heightmap,true); - // Realm realm = Globals.serverState.realmManager.getEntityRealm(physicsEntity); - // realm.getCollisionEngine().registerPhysicsEntity(physicsEntity); + BlockChunkEntity.serverCreateBlockChunkEntity(localBlockPhysicsEntity, this.blockData); + localBlockPhysicsEntity.putData(EntityDataStrings.TERRAIN_IS_TERRAIN, true); } /** diff --git a/src/main/java/electrosphere/server/macro/MacroData.java b/src/main/java/electrosphere/server/macro/MacroData.java index 161447bc..49d5ab43 100644 --- a/src/main/java/electrosphere/server/macro/MacroData.java +++ b/src/main/java/electrosphere/server/macro/MacroData.java @@ -298,6 +298,7 @@ public class MacroData { public List getNearbyObjects(Vector3d position){ List rVal = new LinkedList(); rVal.addAll(this.roads); + rVal.addAll(this.towns); return rVal; } diff --git a/src/main/java/electrosphere/server/macro/spatial/MacroLODObject.java b/src/main/java/electrosphere/server/macro/spatial/MacroLODObject.java new file mode 100644 index 00000000..98567362 --- /dev/null +++ b/src/main/java/electrosphere/server/macro/spatial/MacroLODObject.java @@ -0,0 +1,14 @@ +package electrosphere.server.macro.spatial; + +/** + * A macro object that can be simulated at different resolutions + */ +public interface MacroLODObject { + + /** + * Checks if this macro object is full resolution or not + * @return true if it is full resolution, false otherwise + */ + public boolean isFullRes(); + +} diff --git a/src/main/java/electrosphere/server/macro/town/Town.java b/src/main/java/electrosphere/server/macro/town/Town.java index 0d4d03cc..1aac1e85 100644 --- a/src/main/java/electrosphere/server/macro/town/Town.java +++ b/src/main/java/electrosphere/server/macro/town/Town.java @@ -5,6 +5,7 @@ import electrosphere.server.macro.MacroData; import electrosphere.server.macro.character.Character; import electrosphere.server.macro.civilization.Civilization; import electrosphere.server.macro.spatial.MacroAreaObject; +import electrosphere.server.macro.spatial.MacroLODObject; import electrosphere.server.macro.structure.VirtualStructure; import java.util.LinkedList; @@ -17,7 +18,7 @@ import org.joml.Vector3d; /** * Server representation of a town */ -public class Town implements MacroAreaObject { +public class Town implements MacroAreaObject, MacroLODObject { /** * Minimum data resolution town (ie hasn't generated structures or residents) @@ -209,5 +210,10 @@ public class Town implements MacroAreaObject { public Civilization getParent(MacroData macroData){ return macroData.getCivilization(this.parentCivId); } + + @Override + public boolean isFullRes() { + return this.resolution == TOWN_RES_MAX; + } } 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 05809250..bbd4808a 100644 --- a/src/main/java/electrosphere/server/physics/block/manager/ServerBlockChunkGenerationThread.java +++ b/src/main/java/electrosphere/server/physics/block/manager/ServerBlockChunkGenerationThread.java @@ -15,6 +15,8 @@ import electrosphere.engine.Globals; import electrosphere.logger.LoggerInterface; import electrosphere.server.datacell.ServerWorldData; import electrosphere.server.macro.MacroData; +import electrosphere.server.macro.spatial.MacroLODObject; +import electrosphere.server.macro.spatial.MacroObject; import electrosphere.server.macro.structure.VirtualStructure; import electrosphere.server.physics.block.diskmap.ServerBlockChunkDiskMap; @@ -146,6 +148,17 @@ public class ServerBlockChunkGenerationThread implements Runnable { ServerBlockChunkDiskMap chunkDiskMap, BlockChunkCache chunkCache ){ + //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 + long notFullResCount = objects.stream().filter((MacroObject macroObj) -> macroObj instanceof MacroLODObject).map((MacroObject oldView) -> (MacroLODObject)oldView).filter((MacroLODObject lodObj) -> !lodObj.isFullRes()).count(); + if(notFullResCount > 0){ + return null; + } + BlockChunkData chunk = null; if(chunkCache.containsChunk(worldX, worldY, worldZ, stride)){ chunk = chunkCache.get(worldX, worldY, worldZ, stride); diff --git a/src/main/java/electrosphere/server/physics/terrain/generation/ProceduralChunkGenerator.java b/src/main/java/electrosphere/server/physics/terrain/generation/ProceduralChunkGenerator.java index 49464e43..59e41d42 100644 --- a/src/main/java/electrosphere/server/physics/terrain/generation/ProceduralChunkGenerator.java +++ b/src/main/java/electrosphere/server/physics/terrain/generation/ProceduralChunkGenerator.java @@ -14,6 +14,7 @@ import electrosphere.engine.Globals; import electrosphere.server.datacell.ServerWorldData; import electrosphere.server.macro.civilization.road.Road; import electrosphere.server.macro.spatial.MacroObject; +import electrosphere.server.macro.town.Town; import electrosphere.server.physics.terrain.generation.heightmap.EmptySkyGen; import electrosphere.server.physics.terrain.generation.heightmap.HeightmapGenerator; import electrosphere.server.physics.terrain.generation.heightmap.HeightmapNoiseGen; @@ -281,6 +282,7 @@ public class ProceduralChunkGenerator implements ChunkGenerator { } } } + } else if(object instanceof Town){ } else { throw new Error("Unsupported object type " + object); } 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 5c0454e7..635c48ec 100644 --- a/src/main/java/electrosphere/server/physics/terrain/manager/ChunkGenerationThread.java +++ b/src/main/java/electrosphere/server/physics/terrain/manager/ChunkGenerationThread.java @@ -8,6 +8,7 @@ import electrosphere.engine.Globals; import electrosphere.logger.LoggerInterface; import electrosphere.server.datacell.ServerWorldData; import electrosphere.server.macro.MacroData; +import electrosphere.server.macro.spatial.MacroLODObject; import electrosphere.server.macro.spatial.MacroObject; import electrosphere.server.physics.terrain.diskmap.ChunkDiskMap; import electrosphere.server.physics.terrain.generation.interfaces.ChunkGenerator; @@ -158,7 +159,10 @@ public class ChunkGenerationThread implements Runnable { objects = macroData.getNearbyObjects(ServerWorldData.convertChunkToRealSpace(worldX, worldY, worldZ)); } //if any of this macro data isn't ready, return a null chunk - + long notFullResCount = objects.stream().filter((MacroObject macroObj) -> macroObj instanceof MacroLODObject).map((MacroObject oldView) -> (MacroLODObject)oldView).filter((MacroLODObject lodObj) -> !lodObj.isFullRes()).count(); + if(notFullResCount > 0){ + return null; + } if(chunkCache.containsChunk(worldX, worldY, worldZ, stride)){ rVal = chunkCache.get(worldX, worldY, worldZ, stride); 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 bcda7867..198a242d 100644 --- a/src/main/java/electrosphere/server/physics/terrain/manager/ServerTerrainManager.java +++ b/src/main/java/electrosphere/server/physics/terrain/manager/ServerTerrainManager.java @@ -291,7 +291,7 @@ public class ServerTerrainManager { //THIS FIRES IF THERE IS A MAIN GAME WORLD RUNNING 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"); + LoggerInterface.loggerEngine.WARNING("Failed to generate chunk at " + worldX + " " + worldY + " " + worldZ + " synchronously"); } Globals.profiler.endCpuSample(); return returnedChunk;