ServerBlockManager places structures
All checks were successful
studiorailgun/Renderer/pipeline/head This commit looks good

This commit is contained in:
austin 2025-04-29 15:41:18 -04:00
parent 69b7fe2f77
commit 12e95dc2b8
8 changed files with 193 additions and 26 deletions

View File

@ -1588,6 +1588,7 @@ Fab selection doesn't overflow anymore
Cleaning up parts of Main class Cleaning up parts of Main class
Spawn test structure in macro data on creation Spawn test structure in macro data on creation
Macro data structures block regular foliage generation Macro data structures block regular foliage generation
ServerBlockManager places macro data structures when generating chunks that contain them

View File

@ -149,6 +149,10 @@ public class SceneLoader {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
} }
//hook up macro data if relevant
if(macroData != null){
realm.getServerWorldData().getServerBlockManager().setMacroData(macroData);
}
//load scripts //load scripts
if(!isLevelEditor && file.getInitScriptPath() != null){ if(!isLevelEditor && file.getInitScriptPath() != null){
Realm finalRealm = realm; Realm finalRealm = realm;

View File

@ -211,6 +211,12 @@ public class BlockFab implements BlockMeshgenData {
@Override @Override
public short getType(int x, int y, int z) { public short getType(int x, int y, int z) {
if(x < 0 || y < 0 || z < 0){
throw new Error("Negative bounds! " + x + " " + y + " " + z);
}
if(x >= dimensions.x || y >= dimensions.y || z >= dimensions.z){
throw new Error("Out of bounds! " + x + " " + y + " " + z);
}
return this.types[x * dimensions.y * dimensions.z + y * dimensions.z + z]; return this.types[x * dimensions.y * dimensions.z + y * dimensions.z + z];
} }

View File

@ -228,6 +228,21 @@ public class ServerWorldData {
); );
} }
/**
* Converts a chunk space position to a real space position
* @param x the x coordinate
* @param y the y coordinate
* @param z the z coordinate
* @return The real space position
*/
public static Vector3d convertChunkToRealSpace(int x, int y, int z){
return new Vector3d(
ServerWorldData.convertChunkToRealSpace(x),
ServerWorldData.convertChunkToRealSpace(y),
ServerWorldData.convertChunkToRealSpace(z)
);
}
/** /**
* Converts a real position to a local block grid position * Converts a real position to a local block grid position
* @param real The real position * @param real The real position
@ -237,6 +252,30 @@ public class ServerWorldData {
return (int)Math.floor(real * BlockChunkData.BLOCKS_PER_UNIT_DISTANCE % BlockChunkData.CHUNK_DATA_WIDTH); return (int)Math.floor(real * BlockChunkData.BLOCKS_PER_UNIT_DISTANCE % BlockChunkData.CHUNK_DATA_WIDTH);
} }
/**
* Converts a local block grid position to a real position
* @param chunk The chunk pos
* @param blockPos The block's local pos
* @return The real position
*/
public static double convertLocalBlockToRealSpace(int chunk, int blockPos){
return ServerWorldData.convertChunkToRealSpace(chunk + blockPos / BlockChunkData.CHUNK_DATA_WIDTH) + (blockPos % BlockChunkData.CHUNK_DATA_WIDTH) * BlockChunkData.BLOCK_SIZE_MULTIPLIER;
}
/**
* Converts a local block grid position to a real position
* @param chunk The chunk pos
* @param blockPos The block's local pos
* @return The real position
*/
public static Vector3d convertLocalBlockToRealSpace(Vector3i chunk, Vector3i blockPos){
return new Vector3d(
ServerWorldData.convertLocalBlockToRealSpace(chunk.x, blockPos.x),
ServerWorldData.convertLocalBlockToRealSpace(chunk.y, blockPos.y),
ServerWorldData.convertLocalBlockToRealSpace(chunk.z, blockPos.z)
);
}
/** /**
* Converts a chunk space coordinate to a real space coordinate * Converts a chunk space coordinate to a real space coordinate
* @param chunk The position within the chunk * @param chunk The position within the chunk

View File

@ -1,5 +1,9 @@
package electrosphere.server.macro; package electrosphere.server.macro;
import java.io.File;
import electrosphere.game.data.block.BlockFab;
import electrosphere.server.macro.structure.Structure;
import electrosphere.util.FileUtils; import electrosphere.util.FileUtils;
/** /**
@ -14,6 +18,18 @@ public class MacroDataLoader {
*/ */
public static MacroData loadFromSave(String saveName){ public static MacroData loadFromSave(String saveName){
MacroData rVal = FileUtils.loadObjectFromSavePath(saveName, "macro.json", MacroData.class); MacroData rVal = FileUtils.loadObjectFromSavePath(saveName, "macro.json", MacroData.class);
//preload and assign structure fabs
for(Structure structure : rVal.getStructures()){
File fabFile = FileUtils.getAssetFile(structure.getFabPath());
if(!fabFile.exists()){
throw new Error("Failed to locate structure that does not exist! " + fabFile.getAbsolutePath());
}
BlockFab fab = BlockFab.read(fabFile);
if(fab == null){
throw new Error("Failed to read fab!");
}
structure.setFab(fab);
}
return rVal; return rVal;
} }

View File

@ -7,10 +7,12 @@ import java.util.List;
import org.joml.AABBd; import org.joml.AABBd;
import org.joml.Vector3d; import org.joml.Vector3d;
import electrosphere.game.data.block.BlockFab;
import electrosphere.game.data.struct.StructureData; import electrosphere.game.data.struct.StructureData;
import electrosphere.server.macro.character.CharacterData; import electrosphere.server.macro.character.CharacterData;
import electrosphere.server.macro.character.CharacterDataStrings; import electrosphere.server.macro.character.CharacterDataStrings;
import electrosphere.server.macro.spatial.MacroAreaObject; import electrosphere.server.macro.spatial.MacroAreaObject;
import electrosphere.util.annotation.Exclude;
/** /**
* Server representation of a structure * Server representation of a structure
@ -32,6 +34,12 @@ public class Structure extends CharacterData implements MacroAreaObject {
*/ */
String fabPath; String fabPath;
/**
* The actual fab
*/
@Exclude
BlockFab fab;
/** /**
* The type of the structure * The type of the structure
*/ */
@ -135,6 +143,29 @@ public class Structure extends CharacterData implements MacroAreaObject {
return this.aabb; return this.aabb;
} }
/**
* Gets the path to the corresponding fab
* @return The path
*/
public String getFabPath(){
return fabPath;
}
/**
* Gets the fab object
* @return The fab object
*/
public BlockFab getFab() {
return fab;
}
/**
* Sets the fab object
* @param fab The fab object
*/
public void setFab(BlockFab fab) {
this.fab = fab;
}
} }

View File

@ -1,12 +1,21 @@
package electrosphere.server.physics.block.manager; package electrosphere.server.physics.block.manager;
import java.util.List;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.stream.Collectors;
import org.joml.AABBd;
import org.joml.Vector3d;
import org.joml.Vector3i;
import electrosphere.client.block.BlockChunkCache; import electrosphere.client.block.BlockChunkCache;
import electrosphere.client.block.BlockChunkData; import electrosphere.client.block.BlockChunkData;
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.structure.Structure;
import electrosphere.server.physics.block.diskmap.ServerBlockChunkDiskMap; import electrosphere.server.physics.block.diskmap.ServerBlockChunkDiskMap;
/** /**
@ -34,6 +43,11 @@ public class ServerBlockChunkGenerationThread implements Runnable {
*/ */
BlockChunkCache chunkCache; BlockChunkCache chunkCache;
/**
* The macro data
*/
MacroData macroData;
/** /**
* The world x coordinate * The world x coordinate
*/ */
@ -61,6 +75,7 @@ public class ServerBlockChunkGenerationThread implements Runnable {
/** /**
* Creates the chunk generation job * Creates the chunk generation job
* @param macroData The macro data
* @param chunkDiskMap The chunk disk map * @param chunkDiskMap The chunk disk map
* @param chunkCache The chunk cache on the server * @param chunkCache The chunk cache on the server
* @param worldX The world x coordinate * @param worldX The world x coordinate
@ -70,6 +85,7 @@ public class ServerBlockChunkGenerationThread 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 ServerBlockChunkGenerationThread( public ServerBlockChunkGenerationThread(
MacroData macroData,
ServerBlockChunkDiskMap chunkDiskMap, ServerBlockChunkDiskMap chunkDiskMap,
BlockChunkCache chunkCache, BlockChunkCache chunkCache,
int worldX, int worldY, int worldZ, int worldX, int worldY, int worldZ,
@ -83,6 +99,7 @@ public class ServerBlockChunkGenerationThread implements Runnable {
this.worldZ = worldZ; this.worldZ = worldZ;
this.stride = stride; this.stride = stride;
this.onLoad = onLoad; this.onLoad = onLoad;
this.macroData = macroData;
} }
@Override @Override
@ -102,19 +119,12 @@ public class ServerBlockChunkGenerationThread implements Runnable {
} }
//generate if it does not exist //generate if it does not exist
if(chunk == null){ if(chunk == null){
//TODO: generate from macro-level data
chunk = BlockChunkData.allocate(); chunk = BlockChunkData.allocate();
chunk.setHomogenousValue(0); chunk.setWorldX(worldX);
// if(worldX == 0 && worldY == 0 && worldZ == 0){ chunk.setWorldY(worldY);
// chunk.setHomogenousValue(BlockChunkData.NOT_HOMOGENOUS); chunk.setWorldZ(worldZ);
// for(int x = 0; x < 16; x++){
// for(int y = 0; y < 16; y++){ ServerBlockChunkGenerationThread.generate(chunk, macroData, worldX, worldY, worldZ);
// for(int z = 0; z < 16; z++){
// chunk.setType(x, y, z, 1);
// }
// }
// }
// }
} }
if(chunk != null){ if(chunk != null){
chunkCache.add(worldX, worldY, worldZ, stride, chunk); chunkCache.add(worldX, worldY, worldZ, stride, chunk);
@ -140,4 +150,59 @@ public class ServerBlockChunkGenerationThread implements Runnable {
} }
} }
/**
* Generates the actual values of the chunk
* @param chunk THe chunk
* @param macroData The macro data
* @param worldX THe world x coordinate
* @param worldY The world y coordinate
* @param worldZ The world z coordinate
*/
protected static void generate(BlockChunkData chunk, MacroData macroData, int worldX, int worldY, int worldZ){
//check if this chunk intersects any macro data
AABBd localAABB = new AABBd(ServerWorldData.convertChunkToRealSpace(worldX,worldY,worldZ),ServerWorldData.convertChunkToRealSpace(worldX+1,worldY+1,worldZ+1));
List<Structure> filtered = macroData.getStructures().stream().filter((Structure struct) -> {return struct.getAABB().testAABB(localAABB);}).collect(Collectors.toList());
if(filtered.size() > 0){
Vector3i chunkPos = new Vector3i(worldX, worldY, worldZ);
Vector3i blockPos = new Vector3i(0,0,0);
Vector3d chunkRealPos = ServerWorldData.convertChunkToRealSpace(chunkPos);
Vector3i localBlockPos = new Vector3i();
//contains at least one structure
for(int x = 0; x < BlockChunkData.CHUNK_DATA_WIDTH; x++){
for(int y = 0; y < BlockChunkData.CHUNK_DATA_WIDTH; y++){
for(int z = 0; z < BlockChunkData.CHUNK_DATA_WIDTH; z++){
boolean placedBlock = false;
//try placing a structure block
blockPos.set(x,y,z);
Vector3d currRealPoint = ServerWorldData.convertLocalBlockToRealSpace(chunkPos, blockPos);
for(Structure struct : filtered){
if(struct.getAABB().testPoint(currRealPoint.x, currRealPoint.y, currRealPoint.z)){
localBlockPos.set(
(int)((chunkRealPos.x + (x * BlockChunkData.BLOCK_SIZE_MULTIPLIER) - struct.getStartPos().x) / BlockChunkData.BLOCK_SIZE_MULTIPLIER),
(int)((chunkRealPos.y + (y * BlockChunkData.BLOCK_SIZE_MULTIPLIER) - struct.getStartPos().y) / BlockChunkData.BLOCK_SIZE_MULTIPLIER),
(int)((chunkRealPos.z + (z * BlockChunkData.BLOCK_SIZE_MULTIPLIER) - struct.getStartPos().z) / BlockChunkData.BLOCK_SIZE_MULTIPLIER)
);
//structure file might have dimensions larger than fab, so need to make sure we're inbounds on fab file to draw data from fab file
if(localBlockPos.x < struct.getFab().getDimensions().x && localBlockPos.y < struct.getFab().getDimensions().y && localBlockPos.z < struct.getFab().getDimensions().z){
short blocktype = struct.getFab().getType(localBlockPos.x,localBlockPos.y,localBlockPos.z);
chunk.setType(x, y, z, blocktype);
placedBlock = true;
}
}
}
//if failed to place structure block, place an empty block
if(!placedBlock){
chunk.setType(x, y, z, BlockChunkData.BLOCK_TYPE_EMPTY);
}
}
}
}
} else {
//an empty chunk (no structures inside)
chunk.setHomogenousValue(0);
}
}
} }

View File

@ -4,6 +4,7 @@ import electrosphere.client.block.BlockChunkCache;
import electrosphere.client.block.BlockChunkData; import electrosphere.client.block.BlockChunkData;
import electrosphere.engine.Globals; import electrosphere.engine.Globals;
import electrosphere.server.datacell.ServerWorldData; import electrosphere.server.datacell.ServerWorldData;
import electrosphere.server.macro.MacroData;
import electrosphere.server.physics.block.diskmap.ServerBlockChunkDiskMap; import electrosphere.server.physics.block.diskmap.ServerBlockChunkDiskMap;
import electrosphere.util.annotation.Exclude; import electrosphere.util.annotation.Exclude;
@ -39,6 +40,12 @@ public class ServerBlockManager {
*/ */
ServerBlockChunkDiskMap chunkDiskMap = null; ServerBlockChunkDiskMap chunkDiskMap = null;
/**
* The macro data for this world
*/
@Exclude
MacroData macroData;
/** /**
* The threadpool for chunk generation * The threadpool for chunk generation
*/ */
@ -120,17 +127,7 @@ public class ServerBlockManager {
returnedChunk.setWorldX(worldX); returnedChunk.setWorldX(worldX);
returnedChunk.setWorldY(worldY); returnedChunk.setWorldY(worldY);
returnedChunk.setWorldZ(worldZ); returnedChunk.setWorldZ(worldZ);
returnedChunk.setHomogenousValue(0); ServerBlockChunkGenerationThread.generate(returnedChunk, macroData, worldX, worldY, worldZ);
// if(worldX == 0 && worldY == 0 && worldZ == 0){
// returnedChunk.setHomogenousValue(BlockChunkData.NOT_HOMOGENOUS);
// for(int x = 3; x < 16; x++){
// for(int y = 8; y < 16; y++){
// for(int z = 3; z < 16; z++){
// returnedChunk.setType(x, y, z, 1);
// }
// }
// }
// }
} }
this.chunkCache.add(worldX, worldY, worldZ, BlockChunkData.LOD_FULL_RES, returnedChunk); this.chunkCache.add(worldX, worldY, worldZ, BlockChunkData.LOD_FULL_RES, returnedChunk);
} }
@ -148,7 +145,7 @@ public class ServerBlockManager {
*/ */
public void getChunkAsync(int worldX, int worldY, int worldZ, int stride, Consumer<BlockChunkData> onLoad){ public void getChunkAsync(int worldX, int worldY, int worldZ, int stride, Consumer<BlockChunkData> onLoad){
Globals.profiler.beginAggregateCpuSample("ServerBlockManager.getChunkAsync"); Globals.profiler.beginAggregateCpuSample("ServerBlockManager.getChunkAsync");
chunkExecutorService.submit(new ServerBlockChunkGenerationThread(chunkDiskMap, chunkCache, worldX, worldY, worldZ, stride, onLoad)); chunkExecutorService.submit(new ServerBlockChunkGenerationThread(this.macroData, chunkDiskMap, chunkCache, worldX, worldY, worldZ, stride, onLoad));
Globals.profiler.endCpuSample(); Globals.profiler.endCpuSample();
} }
@ -194,4 +191,12 @@ public class ServerBlockManager {
chunkExecutorService.shutdownNow(); chunkExecutorService.shutdownNow();
} }
/**
* Sets the macro data for the block manager
* @param macroData The macro data
*/
public void setMacroData(MacroData macroData){
this.macroData = macroData;
}
} }