From 2f05fc06ddc1cf9748c604f7bae18da11eb77c17 Mon Sep 17 00:00:00 2001 From: austin Date: Fri, 23 May 2025 22:36:29 -0400 Subject: [PATCH] work on rotating buildings on placement --- .../checks/spatial/BeginStructureNode.java | 2 +- .../macro/structure/VirtualStructure.java | 82 +++++++++++++++++-- .../server/macro/town/TownLayout.java | 54 ++++++++++-- .../ServerBlockChunkGenerationThread.java | 40 +++++++-- .../simulation/chara/CharaSimulation.java | 2 +- 5 files changed, 156 insertions(+), 24 deletions(-) diff --git a/src/main/java/electrosphere/server/ai/nodes/checks/spatial/BeginStructureNode.java b/src/main/java/electrosphere/server/ai/nodes/checks/spatial/BeginStructureNode.java index d541ecb7..6d781f64 100644 --- a/src/main/java/electrosphere/server/ai/nodes/checks/spatial/BeginStructureNode.java +++ b/src/main/java/electrosphere/server/ai/nodes/checks/spatial/BeginStructureNode.java @@ -49,7 +49,7 @@ public class BeginStructureNode implements AITreeNode { Vector3d placementPos = StructurePlacementUtils.getPlacementPosition(macroData, structureData, position); //add to macro data - VirtualStructure struct = VirtualStructure.createStructure(macroData, structureData, placementPos); + VirtualStructure struct = VirtualStructure.createStructure(macroData, structureData, placementPos, VirtualStructure.ROT_FACE_NORTH); struct.setRepairable(true); struct.setFab(BlockFab.read(FileUtils.getAssetFile(struct.getFabPath()))); // macroData.getStructures().add(struct); diff --git a/src/main/java/electrosphere/server/macro/structure/VirtualStructure.java b/src/main/java/electrosphere/server/macro/structure/VirtualStructure.java index 9f23df90..562b692d 100644 --- a/src/main/java/electrosphere/server/macro/structure/VirtualStructure.java +++ b/src/main/java/electrosphere/server/macro/structure/VirtualStructure.java @@ -1,8 +1,10 @@ package electrosphere.server.macro.structure; import org.joml.AABBd; +import org.joml.Quaterniond; import org.joml.Vector3d; +import electrosphere.controls.cursor.CursorState; import electrosphere.data.block.fab.BlockFab; import electrosphere.data.struct.StructureData; import electrosphere.server.macro.MacroData; @@ -14,56 +16,84 @@ import electrosphere.util.annotation.Exclude; */ public class VirtualStructure implements MacroAreaObject { + /** + * Rotates the structure to face east + */ + public static final int ROT_FACE_EAST = 0; + + /** + * Rotates the structure ot face north + */ + public static final int ROT_FACE_NORTH = 1; + + /** + * Rotates the structure to face west + */ + public static final int ROT_FACE_WEST = 2; + + /** + * Rotates the structure to face south + */ + public static final int ROT_FACE_SOUTH = 3; + /** * The id of the structure */ - int id; + private int id; /** * The position of the structure */ - Vector3d position; + private Vector3d position; + + /** + * The rotation of the fab + */ + private int rotation = 0; /** * The bounding box for the structure */ - AABBd aabb; + private AABBd aabb; /** * The path to the block fab for the structure */ - String fabPath; + private String fabPath; /** * The actual fab */ @Exclude - BlockFab fab; + private BlockFab fab; /** * The type of the structure */ - String type; + private String type; /** * Tracks whether this structure needs repairs or not */ - boolean repairable = false; + private boolean repairable = false; /** * Creates a structure * @param macroData The macro data * @param data The data * @param position The position + * @param rotation The rotation of the structure * @return The structure */ - public static VirtualStructure createStructure(MacroData macroData, StructureData data, Vector3d position){ + public static VirtualStructure createStructure(MacroData macroData, StructureData data, Vector3d position, int rotation){ VirtualStructure rVal = new VirtualStructure(); rVal.fabPath = data.getFabPath(); rVal.fab = data.getFab(); rVal.type = data.getId(); rVal.position = position; - rVal.aabb = new AABBd(new Vector3d(position), new Vector3d(position).add(data.getDimensions())); + rVal.rotation = rotation; + rVal.aabb = new AABBd(); + VirtualStructure.setAABB(rVal.aabb, rVal.position, data.getDimensions(), rotation); macroData.addStructure(rVal); return rVal; } @@ -146,6 +176,40 @@ public class VirtualStructure implements MacroAreaObject { public void setId(int id){ this.id = id; } + + /** + * Sets the rotation of the structure + * @param rotation The rotation + */ + public void setRotation(int rotation){ + this.rotation = rotation; + } + + /** + * Gets the rotation of the structure + * @return The rotation of the structure + */ + public int getRotation(){ + return this.rotation; + } + + /** + * Calculates the aabb of this structure given a rotation, dims, and start position + * @param aabb The aabb to populate + * @param startPos The start position + * @param dims The dimensions of the structure + * @param rotation The rotation + */ + public static void setAABB(AABBd aabb, Vector3d startPos, Vector3d dims, int rotation){ + //construct aabb based on rotation + Quaterniond rotationQuat = CursorState.getBlockRotation(rotation); + Vector3d dimVec = new Vector3d(dims); + rotationQuat.transform(dimVec); + Vector3d startVec = startPos; + Vector3d endVec = new Vector3d(startPos).add(dimVec); + aabb.setMin(Math.min(startVec.x,endVec.x),Math.min(startVec.y,endVec.y),Math.min(startVec.z,endVec.z)); + aabb.setMax(Math.max(startVec.x,endVec.x),Math.max(startVec.y,endVec.y),Math.max(startVec.z,endVec.z)); + } } diff --git a/src/main/java/electrosphere/server/macro/town/TownLayout.java b/src/main/java/electrosphere/server/macro/town/TownLayout.java index f970c37f..5bda7df4 100644 --- a/src/main/java/electrosphere/server/macro/town/TownLayout.java +++ b/src/main/java/electrosphere/server/macro/town/TownLayout.java @@ -5,9 +5,11 @@ import java.util.List; import java.util.stream.Collectors; import org.joml.AABBd; +import org.joml.Quaterniond; import org.joml.Vector3d; import org.joml.Vector3i; +import electrosphere.controls.cursor.CursorState; import electrosphere.data.struct.StructureData; import electrosphere.engine.Globals; import electrosphere.logger.LoggerInterface; @@ -212,6 +214,8 @@ public class TownLayout { closedSet.add(openHash); } + // System.out.println("Structure count: " + town.getStructures(macroData).size()); + town.setResolution(Town.TOWN_RES_MAX); } @@ -252,10 +256,23 @@ public class TownLayout { //offset applied to the scan location to not place it on top of the road Vector3d roadOffset = null; + int rotation1 = VirtualStructure.ROT_FACE_WEST; + int rotation2 = VirtualStructure.ROT_FACE_EAST; + Vector3d rotOffset = new Vector3d(); + Quaterniond rotQuat1 = null; + Quaterniond rotQuat2 = null; if(isNorthSouth){ roadOffset = new Vector3d(roadRadiusOffsetRaw,0,0); + rotation1 = VirtualStructure.ROT_FACE_SOUTH; + rotation2 = VirtualStructure.ROT_FACE_NORTH; + rotQuat1 = CursorState.getBlockRotation(rotation1); + rotQuat2 = CursorState.getBlockRotation(rotation2); } else { roadOffset = new Vector3d(0,0,roadRadiusOffsetRaw); + rotation1 = VirtualStructure.ROT_FACE_WEST; + rotation2 = VirtualStructure.ROT_FACE_EAST; + rotQuat1 = CursorState.getBlockRotation(rotation1); + rotQuat2 = CursorState.getBlockRotation(rotation2); } //the position to try at @@ -267,17 +284,29 @@ public class TownLayout { //scan along the length of the road for(int i = roadRadiusOffsetRaw; i < len; i++){ + //update rotation spatial offset based on current struct + rotOffset.set(structureData.getDimensions()); + rotQuat1.transform(rotOffset); + rotOffset.x = Math.min(rotOffset.x,0); + rotOffset.y = Math.min(rotOffset.y,0); + rotOffset.z = Math.min(rotOffset.z,0); + rotOffset.mul(-1); + + //solve terrain position to place currPos.set(startPoint).lerp(endPoint,i/(double)len).add(roadOffset); // currPos.set(dir).mul(i).add(startPoint).add(roadOffset); currPos.y = realm.getServerWorldData().getServerTerrainManager().getElevation(currPos); //apply structure placement offset currPos.add(structureData.getPlacementOffset()); + //add offset to re-align after rotation + currPos.add(rotOffset); + //update aabb - aabb.setMin(currPos); - aabb.setMax(new Vector3d(currPos).add(structureData.getDimensions())); + VirtualStructure.setAABB(aabb, currPos, structureData.getDimensions(), rotation1); + if(!macroData.intersectsStruct(aabb)){ - VirtualStructure struct = VirtualStructure.createStructure(macroData, structureData, currPos); + VirtualStructure struct = VirtualStructure.createStructure(macroData, structureData, currPos, rotation1); town.addStructure(struct); //TODO: once have successfully placed this structure type, pick a new one to place } @@ -285,16 +314,27 @@ public class TownLayout { //scan along the length of the road for(int i = 0; i < len; i++){ + //update rotation spatial offset based on current struct + rotOffset.set(structureData.getDimensions()); + rotQuat2.transform(rotOffset); + rotOffset.x = Math.max(rotOffset.x,0); + rotOffset.y = Math.max(rotOffset.y,0); + rotOffset.z = Math.max(rotOffset.z,0); + rotOffset.mul(-1); + //solve terrain position to place - currPos.set(dir).mul(i).add(startPoint).sub(roadOffset).sub(structureData.getDimensions().x,0,structureData.getDimensions().z); + currPos.set(dir).mul(i).add(startPoint).sub(roadOffset).sub(structureData.getDimensions()); currPos.y = realm.getServerWorldData().getServerTerrainManager().getElevation(currPos); //apply structure placement offset currPos.add(structureData.getPlacementOffset()); + //add offset to re-align after rotation + // currPos.add(5,0,5); + //update aabb - aabb.setMin(currPos); - aabb.setMax(new Vector3d(currPos).add(structureData.getDimensions())); + VirtualStructure.setAABB(aabb, currPos, structureData.getDimensions(), rotation2); + if(!macroData.intersectsStruct(aabb)){ - VirtualStructure struct = VirtualStructure.createStructure(macroData, structureData, currPos); + VirtualStructure struct = VirtualStructure.createStructure(macroData, structureData, currPos, rotation2); town.addStructure(struct); //TODO: once have successfully placed this structure type, pick a new one to place } 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 5658f420..c97fce93 100644 --- a/src/main/java/electrosphere/server/physics/block/manager/ServerBlockChunkGenerationThread.java +++ b/src/main/java/electrosphere/server/physics/block/manager/ServerBlockChunkGenerationThread.java @@ -7,11 +7,13 @@ import java.util.function.Consumer; import java.util.stream.Collectors; import org.joml.AABBd; +import org.joml.Quaterniond; import org.joml.Vector3d; import org.joml.Vector3i; import electrosphere.client.block.BlockChunkCache; import electrosphere.client.block.BlockChunkData; +import electrosphere.controls.cursor.CursorState; import electrosphere.engine.Globals; import electrosphere.logger.LoggerInterface; import electrosphere.server.datacell.ServerWorldData; @@ -223,8 +225,9 @@ public class ServerBlockChunkGenerationThread implements Runnable { Vector3i chunkPos = new Vector3i(worldX, worldY, worldZ); Vector3i blockPos = new Vector3i(0,0,0); Vector3d chunkRealPos = ServerWorldData.convertChunkToRealSpace(chunkPos); - Vector3i localBlockPos = new Vector3i(); + Vector3d localBlockPos = new Vector3d(); Vector3d currRealPos = new Vector3d(chunkRealPos); + Vector3d dimVec = new Vector3d(); //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++){ @@ -241,13 +244,38 @@ public class ServerBlockChunkGenerationThread implements Runnable { if(struct.getAABB().testPoint(currRealPos.x, currRealPos.y, currRealPos.z)){ AABBd aabb = struct.getAABB(); localBlockPos.set( - (int)((currRealPos.x - aabb.minX) / BlockChunkData.BLOCK_SIZE_MULTIPLIER), - (int)((currRealPos.y - aabb.minY) / BlockChunkData.BLOCK_SIZE_MULTIPLIER), - (int)((currRealPos.z - aabb.minZ) / BlockChunkData.BLOCK_SIZE_MULTIPLIER) + (int)Math.round((currRealPos.x - aabb.minX) / BlockChunkData.BLOCK_SIZE_MULTIPLIER), + (int)Math.round((currRealPos.y - aabb.minY) / BlockChunkData.BLOCK_SIZE_MULTIPLIER), + (int)Math.round((currRealPos.z - aabb.minZ) / BlockChunkData.BLOCK_SIZE_MULTIPLIER) ); + + Quaterniond rotationQuat = CursorState.getBlockRotation(struct.getRotation()); + rotationQuat.transform(localBlockPos); + dimVec.set(struct.getFab().getDimensions()); + rotationQuat.transform(dimVec); + dimVec.absolute(); + if(localBlockPos.x < 0){ + localBlockPos.x = (int)(dimVec.x + localBlockPos.x); + } + if(localBlockPos.y < 0){ + localBlockPos.y = (int)(dimVec.y + localBlockPos.y); + } + if(localBlockPos.z < 0){ + localBlockPos.z = (int)(dimVec.z + localBlockPos.z); + } + localBlockPos.x = Math.round(localBlockPos.x); + localBlockPos.y = Math.round(localBlockPos.y); + localBlockPos.z = Math.round(localBlockPos.z); //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); + if( + (int)localBlockPos.x >= 0 && + (int)localBlockPos.y >= 0 && + (int)localBlockPos.z >= 0 && + (int)localBlockPos.x < struct.getFab().getDimensions().x && + (int)localBlockPos.y < struct.getFab().getDimensions().y && + (int)localBlockPos.z < struct.getFab().getDimensions().z + ){ + short blocktype = struct.getFab().getType((int)localBlockPos.x,(int)localBlockPos.y,(int)localBlockPos.z); chunk.setType(x, y, z, blocktype); placedBlock = true; } diff --git a/src/main/java/electrosphere/server/simulation/chara/CharaSimulation.java b/src/main/java/electrosphere/server/simulation/chara/CharaSimulation.java index f9015397..7ba6a6ce 100644 --- a/src/main/java/electrosphere/server/simulation/chara/CharaSimulation.java +++ b/src/main/java/electrosphere/server/simulation/chara/CharaSimulation.java @@ -75,7 +75,7 @@ public class CharaSimulation { Vector3d placementPos = StructurePlacementUtils.getPlacementPosition(macroData, structureData, position); //add to macro data - VirtualStructure struct = VirtualStructure.createStructure(macroData, structureData, placementPos); + VirtualStructure struct = VirtualStructure.createStructure(macroData, structureData, placementPos, VirtualStructure.ROT_FACE_NORTH); struct.setRepairable(true); struct.setFab(BlockFab.read(FileUtils.getAssetFile(struct.getFabPath()))); CharacterUtils.addShelter(chara, struct);