From 488ce9fd21c119988fab693da2ea418471461103 Mon Sep 17 00:00:00 2001 From: austin Date: Tue, 20 May 2025 16:21:04 -0400 Subject: [PATCH] place buildings along roads --- assets/Data/game/structure.json | 6 +- docs/src/progress/renderertodo.md | 1 + .../gridded/GriddedDataCellManager.java | 3 + .../electrosphere/server/macro/MacroData.java | 1 + .../macro/structure/VirtualStructure.java | 8 ++ .../server/macro/town/TownLayout.java | 102 +++++++++++++++--- .../generation/ProceduralChunkGenerator.java | 7 +- 7 files changed, 108 insertions(+), 20 deletions(-) diff --git a/assets/Data/game/structure.json b/assets/Data/game/structure.json index d7987140..3f9444be 100644 --- a/assets/Data/game/structure.json +++ b/assets/Data/game/structure.json @@ -5,9 +5,9 @@ "displayName" : "Default House", "fabPath" : "Data/fab/defaultHouse.fab", "dimensions" : { - "x" : 100, - "y" : 100, - "z" : 100 + "x" : 5, + "y" : 5, + "z" : 5 }, "placementOffset" : { "x" : 0, diff --git a/docs/src/progress/renderertodo.md b/docs/src/progress/renderertodo.md index 4068defa..df727956 100644 --- a/docs/src/progress/renderertodo.md +++ b/docs/src/progress/renderertodo.md @@ -1922,6 +1922,7 @@ Roads block content generation Properly layout roads along town points in TownLayout Town generates a structure -- scaffolding for doing it across roads Structures create foundations in terrain voxels +Place buildings along roads diff --git a/src/main/java/electrosphere/server/datacell/gridded/GriddedDataCellManager.java b/src/main/java/electrosphere/server/datacell/gridded/GriddedDataCellManager.java index 0c72b838..b9e01538 100644 --- a/src/main/java/electrosphere/server/datacell/gridded/GriddedDataCellManager.java +++ b/src/main/java/electrosphere/server/datacell/gridded/GriddedDataCellManager.java @@ -40,6 +40,7 @@ import electrosphere.server.datacell.interfaces.VoxelCellManager; import electrosphere.server.datacell.physics.PhysicsDataCell; import electrosphere.server.entity.ServerContentManager; import electrosphere.server.entity.serialization.ContentSerialization; +import electrosphere.server.macro.MacroDataUpdater; import electrosphere.server.macro.spatial.MacroObject; import electrosphere.server.pathfinding.recast.PathingProgressiveData; import electrosphere.server.pathfinding.voxel.VoxelPathfinder; @@ -362,6 +363,7 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager worldPos.z * ServerTerrainChunk.CHUNK_PLACEMENT_OFFSET ); + MacroDataUpdater.update(parent, parent.getMacroData(), realPos); BlockChunkData blockChunkData = parent.getServerWorldData().getServerBlockManager().getChunk(worldPos.x, worldPos.y, worldPos.z); ServerTerrainChunk terrainChunk = parent.getServerWorldData().getServerTerrainManager().getChunk(worldPos.x, worldPos.y, worldPos.z, ServerChunkCache.STRIDE_FULL_RES); @@ -813,6 +815,7 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager ServerEntityUtils.destroyEntity(blockEntity); } + MacroDataUpdater.update(parent, parent.getMacroData(), realPos); this.generationService.submit(() -> { try { BlockChunkData blockChunkData = realm.getServerWorldData().getServerBlockManager().getChunk(worldPos.x, worldPos.y, worldPos.z); diff --git a/src/main/java/electrosphere/server/macro/MacroData.java b/src/main/java/electrosphere/server/macro/MacroData.java index 0706a4e0..a04adefa 100644 --- a/src/main/java/electrosphere/server/macro/MacroData.java +++ b/src/main/java/electrosphere/server/macro/MacroData.java @@ -288,6 +288,7 @@ public class MacroData { * @param structure The structure */ public void addStructure(VirtualStructure structure){ + structure.setId(structures.size()); structures.add(structure); } diff --git a/src/main/java/electrosphere/server/macro/structure/VirtualStructure.java b/src/main/java/electrosphere/server/macro/structure/VirtualStructure.java index 50603b4c..9f23df90 100644 --- a/src/main/java/electrosphere/server/macro/structure/VirtualStructure.java +++ b/src/main/java/electrosphere/server/macro/structure/VirtualStructure.java @@ -138,6 +138,14 @@ public class VirtualStructure implements MacroAreaObject { public int getId(){ return id; } + + /** + * Sets the id of this structure + * @param id The id + */ + public void setId(int id){ + this.id = id; + } } diff --git a/src/main/java/electrosphere/server/macro/town/TownLayout.java b/src/main/java/electrosphere/server/macro/town/TownLayout.java index e5994b85..701e9a19 100644 --- a/src/main/java/electrosphere/server/macro/town/TownLayout.java +++ b/src/main/java/electrosphere/server/macro/town/TownLayout.java @@ -88,33 +88,103 @@ public class TownLayout { scanPoint.set(townCenter).add(0,0,-TOWN_LAYOUT_SCALER); Vector3d downNodeLoc = TownLayout.getTownCenter(realm, scanPoint); + // + //generate roads + Road newRoad; + //up-facing road - Road.createRoad(macroData, upNodeLoc, centerNodeLoc); - //generate structures along the road - StructureData structureData = allowedStructures.get(0); - Vector3d pos = new Vector3d(centerNodeLoc).add(10,0,10); - pos.y = realm.getServerWorldData().getServerTerrainManager().getElevation(pos); - AABBd aabb = new AABBd(); - aabb.setMin(pos); - aabb.setMax(new Vector3d(pos).add(structureData.getDimensions())); - if(!macroData.intersectsStruct(aabb)){ - VirtualStructure struct = VirtualStructure.createStructure(macroData, structureData, pos); - town.addStructure(struct); - } + newRoad = Road.createRoad(macroData, upNodeLoc, centerNodeLoc); + TownLayout.generateStructuresAlongRoad(realm, town, newRoad, allowedStructures); //right-facing road - Road.createRoad(macroData, rightNodeLoc, centerNodeLoc); + newRoad = Road.createRoad(macroData, rightNodeLoc, centerNodeLoc); + TownLayout.generateStructuresAlongRoad(realm, town, newRoad, allowedStructures); //left-facing road - Road.createRoad(macroData, leftNodeLoc, centerNodeLoc); + newRoad = Road.createRoad(macroData, leftNodeLoc, centerNodeLoc); + TownLayout.generateStructuresAlongRoad(realm, town, newRoad, allowedStructures); //down-facing road - Road.createRoad(macroData, downNodeLoc, centerNodeLoc); - + newRoad = Road.createRoad(macroData, downNodeLoc, centerNodeLoc); + TownLayout.generateStructuresAlongRoad(realm, town, newRoad, allowedStructures); town.setResolution(Town.TOWN_RES_MAX); } + /** + * Generates structures along a road + * @param realm The realm + * @param town The town + * @param road The road + * @param allowedStructures The list of allowed structure types + */ + private static void generateStructuresAlongRoad(Realm realm, Town town, Road road, List allowedStructures){ + MacroData macroData = realm.getMacroData(); + + //get values to scan along + Vector3d startPoint = road.getPoint1(); + Vector3d endPoint = road.getPoint2(); + Vector3d dir = new Vector3d(endPoint).sub(startPoint).normalize(); + int len = (int)startPoint.distance(endPoint); + + //determine if it's primarily north-south or east-west + boolean isNorthSouth = true; + if(Math.abs(endPoint.x - startPoint.x) > Math.abs(endPoint.z - startPoint.z)){ + isNorthSouth = false; + } else { + isNorthSouth = true; + } + + //offset applied to the scan location to not place it on top of the road + Vector3d placementOffset = null; + if(isNorthSouth){ + placementOffset = new Vector3d(road.getRadius() + 10,0,0); + } else { + placementOffset = new Vector3d(0,0,road.getRadius() + 10); + } + + //the position to try at + Vector3d currPos = new Vector3d(); + AABBd aabb = new AABBd(); + + //the type of structure to place + StructureData structureData = allowedStructures.get(0); + + //scan along the length of the road + for(int i = 0; i < len; i++){ + //solve terrain position to place + currPos.set(dir).mul(i).add(startPoint).add(placementOffset); + currPos.y = realm.getServerWorldData().getServerTerrainManager().getElevation(currPos); + //apply structure placement offset + currPos.add(structureData.getPlacementOffset()); + //update aabb + aabb.setMin(currPos); + aabb.setMax(new Vector3d(currPos).add(structureData.getDimensions())); + if(!macroData.intersectsStruct(aabb)){ + VirtualStructure struct = VirtualStructure.createStructure(macroData, structureData, currPos); + town.addStructure(struct); + //TODO: once have successfully placed this structure type, pick a new one to place + } + } + + //scan along the length of the road + for(int i = 0; i < len; i++){ + //solve terrain position to place + currPos.set(dir).mul(i).add(startPoint).sub(placementOffset).sub(structureData.getDimensions().x,0,structureData.getDimensions().z); + currPos.y = realm.getServerWorldData().getServerTerrainManager().getElevation(currPos); + //apply structure placement offset + currPos.add(structureData.getPlacementOffset()); + //update aabb + aabb.setMin(currPos); + aabb.setMax(new Vector3d(currPos).add(structureData.getDimensions())); + if(!macroData.intersectsStruct(aabb)){ + VirtualStructure struct = VirtualStructure.createStructure(macroData, structureData, currPos); + town.addStructure(struct); + //TODO: once have successfully placed this structure type, pick a new one to place + } + } + } + /** * Clamps the scan point to the closest town center point * @param realm The realm 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 1d2222f9..8bb97868 100644 --- a/src/main/java/electrosphere/server/physics/terrain/generation/ProceduralChunkGenerator.java +++ b/src/main/java/electrosphere/server/physics/terrain/generation/ProceduralChunkGenerator.java @@ -57,6 +57,11 @@ public class ProceduralChunkGenerator implements ChunkGenerator { */ public static final int SURFACE_VOXEL_WIDTH = 2; + /** + * The width of the foundation generated underneath structures + */ + public static final int VIRTUAL_STRUCTURE_FOUNDATION_WIDTH = 2; + /** * Tag for the test generator */ @@ -291,7 +296,7 @@ public class ProceduralChunkGenerator implements ChunkGenerator { if(realX >= aabb.minX && realX <= aabb.maxX && realZ >= aabb.minZ && realZ <= aabb.maxZ){ //check if within foundation range double vertDist = aabb.minY - realY; - if(vertDist > 0 && vertDist < 2){ + if(vertDist > 0 && vertDist < VIRTUAL_STRUCTURE_FOUNDATION_WIDTH){ voxel.type = 1; voxel.weight = 1; rVal = true;