solve for entry points

This commit is contained in:
austin 2025-05-16 18:45:26 -04:00
parent 5def6da2de
commit e964bceac4

View File

@ -12,6 +12,7 @@ import electrosphere.client.interact.select.AreaSelection.AreaSelectionType;
import electrosphere.client.scene.ClientWorldData;
import electrosphere.data.block.fab.RoomMetadata;
import electrosphere.data.block.fab.StructureMetadata;
import electrosphere.engine.Globals;
/**
* Solves for the rooms in a structure
@ -22,6 +23,16 @@ public class RoomSolver {
* Maximum radius of room in blocks
*/
public static final int MAX_ROOM_SIZE = 20;
/**
* Minimum height of a doorway
*/
public static final int DOORWAY_MIN_HEIGHT = 8;
/**
* Minimum width of a doorway
*/
public static final int DOORWAY_MIN_WIDTH = 4;
/**
* 6-connected neighbors (orthogonal)
@ -67,9 +78,12 @@ public class RoomSolver {
}
}
//vectors used across scanning
Vector3d selectionStart = new Vector3d();
while(localMaximums.size() > 0){
Vector3i toConsider = localMaximums.poll();
Vector3d selectionStart = new Vector3d(boundingArea.getRectStart()).add(
selectionStart.set(boundingArea.getRectStart()).add(
toConsider.x * BlockChunkData.BLOCK_SIZE_MULTIPLIER,
toConsider.y * BlockChunkData.BLOCK_SIZE_MULTIPLIER,
toConsider.z * BlockChunkData.BLOCK_SIZE_MULTIPLIER
@ -87,14 +101,301 @@ public class RoomSolver {
continue;
}
//create the new room
//don't consider edge points
if(
toConsider.x == 0 || toConsider.y == 0 || toConsider.z == 0 ||
toConsider.x == dimX || toConsider.y == dimY || toConsider.z == dimZ
){
continue;
}
//Calculate the cavity
Vector3i roomCenterChunkPos = ClientWorldData.convertRealToChunkSpace(selectionStart);
Vector3i roomCenterBlockPos = ClientWorldData.convertRealToLocalBlockSpace(selectionStart);
AreaSelection roomArea = AreaSelection.selectRectangularBlockCavity(roomCenterChunkPos, roomCenterBlockPos, MAX_ROOM_SIZE);
structureMetadata.getRooms().add(new RoomMetadata(roomArea));
//check if outside bounds of map
if(roomArea.getRectStart().y <= 0){
continue;
}
//scan along the floor and make sure we have voxels underneath each position
boolean floorIsValid = true;
int floorDimX = (int)((roomArea.getRectEnd().x - roomArea.getRectStart().x) * BlockChunkData.BLOCKS_PER_UNIT_DISTANCE);
int floorDimZ = (int)((roomArea.getRectEnd().z - roomArea.getRectStart().z) * BlockChunkData.BLOCKS_PER_UNIT_DISTANCE);
for(int x = 0; x < floorDimX; x++){
for(int z = 0; z < floorDimZ; z++){
selectionStart.set(roomArea.getRectStart()).add(
floorDimX * BlockChunkData.BLOCK_SIZE_MULTIPLIER,
-1 * BlockChunkData.BLOCK_SIZE_MULTIPLIER,
floorDimZ * BlockChunkData.BLOCK_SIZE_MULTIPLIER
);
Vector3i floorChunkPos = ClientWorldData.convertRealToChunkSpace(selectionStart);
Vector3i floorBlockPos = ClientWorldData.convertRealToLocalBlockSpace(selectionStart);
BlockChunkData chunkData = Globals.clientState.clientBlockManager.getChunkDataAtWorldPoint(floorChunkPos, BlockChunkData.LOD_FULL_RES);
short type = chunkData.getType(floorBlockPos.x, floorBlockPos.y, floorBlockPos.z);
if(!RoomSolver.isFloor(type)){
floorIsValid = false;
break;
}
}
if(!floorIsValid){
break;
}
}
if(!floorIsValid){
continue;
}
//scan for entrances to the room
LinkedList<Vector3d> entryPoints = RoomSolver.scanForEntrances(roomArea.getRectStart(), floorDimX, floorDimZ);
if(entryPoints.size() < 1){
continue;
}
RoomMetadata data = new RoomMetadata(roomArea);
data.setEntryPoints(entryPoints);
structureMetadata.getRooms().add(data);
}
}
/**
* Scans the room for entrances
* @param roomStart The start point of the room
* @param floorDimX The x dimension of the floor
* @param floorDimZ The z dimension of the floor
*/
private static LinkedList<Vector3d> scanForEntrances(Vector3d roomStart, int floorDimX, int floorDimZ){
LinkedList<Vector3d> rVal = new LinkedList<Vector3d>();
Vector3d tempVec = new Vector3d();
//scan for entrances to the room
int lastSolidBlock = 0;
//scan negative z dir
for(int x = 0; x < floorDimX; x++){
tempVec.set(roomStart).add(
x * BlockChunkData.BLOCK_SIZE_MULTIPLIER,
0,
-1 * BlockChunkData.BLOCK_SIZE_MULTIPLIER
);
Vector3i floorChunkPos = ClientWorldData.convertRealToChunkSpace(tempVec);
Vector3i floorBlockPos = ClientWorldData.convertRealToLocalBlockSpace(tempVec);
BlockChunkData chunkData = Globals.clientState.clientBlockManager.getChunkDataAtWorldPoint(floorChunkPos, BlockChunkData.LOD_FULL_RES);
short type = chunkData.getType(floorBlockPos.x, floorBlockPos.y, floorBlockPos.z);
if(RoomSolver.isWall(type)){
int dist = (x - lastSolidBlock);
if(dist >= DOORWAY_MIN_WIDTH){
//scan for doorway from here
boolean foundDoor = true;
for(int z = lastSolidBlock + 1; z < x; z++){
for(int y = 0; y < DOORWAY_MIN_HEIGHT; y++){
tempVec.set(roomStart).add(
z * BlockChunkData.BLOCK_SIZE_MULTIPLIER,
y * BlockChunkData.BLOCK_SIZE_MULTIPLIER,
-1 * BlockChunkData.BLOCK_SIZE_MULTIPLIER
);
floorChunkPos = ClientWorldData.convertRealToChunkSpace(tempVec);
floorBlockPos = ClientWorldData.convertRealToLocalBlockSpace(tempVec);
chunkData = Globals.clientState.clientBlockManager.getChunkDataAtWorldPoint(floorChunkPos, BlockChunkData.LOD_FULL_RES);
type = chunkData.getType(floorBlockPos.x, floorBlockPos.y, floorBlockPos.z);
if(!RoomSolver.isDoorway(type)){
foundDoor = false;
break;
}
}
if(!foundDoor){
break;
}
}
if(foundDoor){
rVal.add(new Vector3d(roomStart).add(
(lastSolidBlock + dist / 2.0) * BlockChunkData.BLOCK_SIZE_MULTIPLIER,
0,
0
));
}
}
lastSolidBlock = x;
}
}
//scan positive z dir
for(int x = 0; x < floorDimX; x++){
tempVec.set(roomStart).add(
x * BlockChunkData.BLOCK_SIZE_MULTIPLIER,
0,
floorDimZ * BlockChunkData.BLOCK_SIZE_MULTIPLIER
);
Vector3i floorChunkPos = ClientWorldData.convertRealToChunkSpace(tempVec);
Vector3i floorBlockPos = ClientWorldData.convertRealToLocalBlockSpace(tempVec);
BlockChunkData chunkData = Globals.clientState.clientBlockManager.getChunkDataAtWorldPoint(floorChunkPos, BlockChunkData.LOD_FULL_RES);
short type = chunkData.getType(floorBlockPos.x, floorBlockPos.y, floorBlockPos.z);
if(RoomSolver.isWall(type)){
int dist = (x - lastSolidBlock);
if(dist >= DOORWAY_MIN_WIDTH){
//scan for doorway from here
boolean foundDoor = true;
for(int z = lastSolidBlock + 1; z < x; z++){
for(int y = 0; y < DOORWAY_MIN_HEIGHT; y++){
tempVec.set(roomStart).add(
z * BlockChunkData.BLOCK_SIZE_MULTIPLIER,
y * BlockChunkData.BLOCK_SIZE_MULTIPLIER,
floorDimZ * BlockChunkData.BLOCK_SIZE_MULTIPLIER
);
floorChunkPos = ClientWorldData.convertRealToChunkSpace(tempVec);
floorBlockPos = ClientWorldData.convertRealToLocalBlockSpace(tempVec);
chunkData = Globals.clientState.clientBlockManager.getChunkDataAtWorldPoint(floorChunkPos, BlockChunkData.LOD_FULL_RES);
type = chunkData.getType(floorBlockPos.x, floorBlockPos.y, floorBlockPos.z);
if(!RoomSolver.isDoorway(type)){
foundDoor = false;
break;
}
}
if(!foundDoor){
break;
}
}
if(foundDoor){
rVal.add(new Vector3d(roomStart).add(
(lastSolidBlock + dist / 2.0) * BlockChunkData.BLOCK_SIZE_MULTIPLIER,
0,
(floorDimZ - 1) * BlockChunkData.BLOCK_SIZE_MULTIPLIER
));
}
}
lastSolidBlock = x;
}
}
//scan negative x dir
lastSolidBlock = 0;
for(int x = 0; x < floorDimZ; x++){
tempVec.set(roomStart).add(
-1 * BlockChunkData.BLOCK_SIZE_MULTIPLIER,
0,
x * BlockChunkData.BLOCK_SIZE_MULTIPLIER
);
Vector3i floorChunkPos = ClientWorldData.convertRealToChunkSpace(tempVec);
Vector3i floorBlockPos = ClientWorldData.convertRealToLocalBlockSpace(tempVec);
BlockChunkData chunkData = Globals.clientState.clientBlockManager.getChunkDataAtWorldPoint(floorChunkPos, BlockChunkData.LOD_FULL_RES);
short type = chunkData.getType(floorBlockPos.x, floorBlockPos.y, floorBlockPos.z);
if(RoomSolver.isWall(type)){
int dist = (x - lastSolidBlock);
if(dist >= DOORWAY_MIN_WIDTH){
//scan for doorway from here
boolean foundDoor = true;
for(int z = lastSolidBlock + 1; z < x; z++){
for(int y = 0; y < DOORWAY_MIN_HEIGHT; y++){
tempVec.set(roomStart).add(
-1 * BlockChunkData.BLOCK_SIZE_MULTIPLIER,
y * BlockChunkData.BLOCK_SIZE_MULTIPLIER,
z * BlockChunkData.BLOCK_SIZE_MULTIPLIER
);
floorChunkPos = ClientWorldData.convertRealToChunkSpace(tempVec);
floorBlockPos = ClientWorldData.convertRealToLocalBlockSpace(tempVec);
chunkData = Globals.clientState.clientBlockManager.getChunkDataAtWorldPoint(floorChunkPos, BlockChunkData.LOD_FULL_RES);
type = chunkData.getType(floorBlockPos.x, floorBlockPos.y, floorBlockPos.z);
if(!RoomSolver.isDoorway(type)){
foundDoor = false;
break;
}
}
if(!foundDoor){
break;
}
}
if(foundDoor){
rVal.add(new Vector3d(roomStart).add(
0,
0,
(lastSolidBlock + dist / 2.0) * BlockChunkData.BLOCK_SIZE_MULTIPLIER
));
}
}
lastSolidBlock = x;
}
}
//scan negative x dir
lastSolidBlock = 0;
for(int x = 0; x < floorDimZ; x++){
tempVec.set(roomStart).add(
floorDimX * BlockChunkData.BLOCK_SIZE_MULTIPLIER,
0,
x * BlockChunkData.BLOCK_SIZE_MULTIPLIER
);
Vector3i floorChunkPos = ClientWorldData.convertRealToChunkSpace(tempVec);
Vector3i floorBlockPos = ClientWorldData.convertRealToLocalBlockSpace(tempVec);
BlockChunkData chunkData = Globals.clientState.clientBlockManager.getChunkDataAtWorldPoint(floorChunkPos, BlockChunkData.LOD_FULL_RES);
short type = chunkData.getType(floorBlockPos.x, floorBlockPos.y, floorBlockPos.z);
if(RoomSolver.isWall(type)){
int dist = (x - lastSolidBlock);
if(dist >= DOORWAY_MIN_WIDTH){
//scan for doorway from here
boolean foundDoor = true;
for(int z = lastSolidBlock + 1; z < x; z++){
for(int y = 0; y < DOORWAY_MIN_HEIGHT; y++){
tempVec.set(roomStart).add(
floorDimX * BlockChunkData.BLOCK_SIZE_MULTIPLIER,
y * BlockChunkData.BLOCK_SIZE_MULTIPLIER,
z * BlockChunkData.BLOCK_SIZE_MULTIPLIER
);
floorChunkPos = ClientWorldData.convertRealToChunkSpace(tempVec);
floorBlockPos = ClientWorldData.convertRealToLocalBlockSpace(tempVec);
chunkData = Globals.clientState.clientBlockManager.getChunkDataAtWorldPoint(floorChunkPos, BlockChunkData.LOD_FULL_RES);
type = chunkData.getType(floorBlockPos.x, floorBlockPos.y, floorBlockPos.z);
if(!RoomSolver.isDoorway(type)){
foundDoor = false;
break;
}
}
if(!foundDoor){
break;
}
}
if(foundDoor){
rVal.add(new Vector3d(roomStart).add(
(floorDimX - 1) * BlockChunkData.BLOCK_SIZE_MULTIPLIER,
0,
(lastSolidBlock + dist / 2.0) * BlockChunkData.BLOCK_SIZE_MULTIPLIER
));
}
}
lastSolidBlock = x;
}
}
return rVal;
}
/**
* Checks if a block is a valid floor block
* @param type The type of block
* @return true if it is a valid floor block, false otherwise
*/
private static boolean isFloor(short type){
return type != BlockChunkData.BLOCK_TYPE_EMPTY;
}
/**
* Checks if a block is a valid wall block
* @param type The type of block
* @return true if it is a valid wall block, false otherwise
*/
private static boolean isWall(short type){
return type != BlockChunkData.BLOCK_TYPE_EMPTY;
}
/**
* Checks if a block is a valid dooway block
* @param type The type of block
* @return true if is a valid doorway block, false otherwise
*/
private static boolean isDoorway(short type){
return type == BlockChunkData.BLOCK_TYPE_EMPTY;
}
}