/*
This is very amazing and definitely most efficient generation system. I recommend not copying it because it is definitely not efficient lol (too much work went into this)
But feel free to take a look ;)
*/
let facilityType 
world.afterEvents.worldLoad.subscribe(() => {
  facilityType = world.getDynamicProperty('facilityType')
})

import { world, system, Player, BlockVolume } from "@minecraft/server";
import { MAPS, MOON_LOOT_TABLE, ITEM_LIST, ENTITIES } from "../data";
import { OVERWORLD, worldPlayers, shipEntity, spawnDoor, shotgunWieldedMisfire, getDistance } from "../main";
import { TILES, FIRE_ALLOWED_TILES, ONE_TIME_TILES, SPAWNABLE_BLOCKS, SCRAP_SPAWNERS } from "./tileSets";
import { Vector3 } from "../VectorMath/index";

system.afterEvents.scriptEventReceive.subscribe((ev) => {
  if (ev.id !== "js:resetGen") return;
  world.setDynamicProperty("rooms");
});

function clearGenerate(restartGeneration = false) {
  world.setDynamicProperty("currentPowerLevel", 0);
  world.setDynamicProperty("currentOutdoorPowerLevel", 0);
  world.setDynamicProperty("generationPercentage", 0);
  world.setDynamicProperty("minSpawnOverride", 0);
  world.setDynamicProperty("totalScrapPossible", 0);

  let roomsMap = new Map(world.getDynamicProperty("rooms") ? JSON.parse(world.getDynamicProperty("rooms")) : []);
  let fireExitsMap = new Map(
    world.getDynamicProperty("fireExits") ? JSON.parse(world.getDynamicProperty("fireExits")) : []
  );
  let doorsMap = new Map(
    world.getDynamicProperty("doors") ? JSON.parse(world.getDynamicProperty("doors")) : []
  );
  let ventMap = new Map(world.getDynamicProperty("vents") ? JSON.parse(world.getDynamicProperty("vents")) : []);
  let lightMap = new Map(world.getDynamicProperty("lights") ? JSON.parse(world.getDynamicProperty("lights")) : []);
  let turretIdMap = new Map(world.getDynamicProperty("turretIds") ? JSON.parse(world.getDynamicProperty("turretIds")) : []);

  if (roomsMap) {
    for (const [key, { min, max }] of roomsMap.entries()) {
      console.warn(`Tile: ${key}`);
      console.warn(`"Min:", ${JSON.stringify(min)}`);
      console.warn(`"Max:", ${JSON.stringify(max)}`);

      const fillVol = new BlockVolume(min, max);
      OVERWORLD.fillBlocks(fillVol, "air");
      roomsMap.delete(key);
      world.setDynamicProperty("rooms", JSON.stringify([...roomsMap]));
    }

    const moonId = world.getDynamicProperty("moon");
    let shipLocation = { x: 0, y: -60, z: 0 };

    for (const key of Object.keys(MAPS)) {
      if (MAPS[key].id === moonId) {
        shipLocation = MAPS[key].shipLocation;
        break;
      }
    }

    let entities = [...OVERWORLD.getEntities({ location: shipLocation, maxDistance: 500 })];

    for (const entity of OVERWORLD.getEntities()) {
        const familyComponent = entity.getComponent("minecraft:type_family");
        if (familyComponent && (familyComponent.hasTypeFamily("scrap") || familyComponent.hasTypeFamily("monster") || familyComponent.hasTypeFamily("daytime"))) {
          entities.push(entity);
        }
        if (entity.typeId.includes("_dead")) {
          entities.push(entity);
        }
    }

    for (let entity of entities) {
      if (!(entity instanceof Player) && entity.typeId !== "js:ship" && entity.typeId !== "js:artifice_world_ticker") {
        //   console.warn(`Removed ${entity.typeId}`)
        if (entity.typeId == "js:tree" || entity.typeId == "js:alive_tree") {
          const pos1 = {
            x: entity.location.x,
            y: entity.location.y + 1,
            z: entity.location.z
          }
          const pos2 = {
            x: entity.location.x,
            y: entity.location.y + 15,
            z: entity.location.z
          }
          const fillArea = new BlockVolume(pos1, pos2)
          entity.dimension.fillBlocks(fillArea, 'minecraft:air', {blockFilter: {includeTypes: ["ding:tree_collision"]}})
        }
        try {
          entity.remove();
        } catch(e) {
          console.error(e)
        }
      }
    }
  } else {
    console.warn("No rooms found.");
  }

  if (doorsMap) {
    for (const [key, { fireExitLocation, rotation }] of doorsMap.entries()) {
      doorsMap.delete(key);
      world.setDynamicProperty("doors", JSON.stringify([...doorsMap]));
    }
  }
  if (fireExitsMap) {
    for (const [key, { fireExitLocation, rotation }] of fireExitsMap.entries()) {
      fireExitsMap.delete(key);
      world.setDynamicProperty("fireExits", JSON.stringify([...fireExitsMap]));
    }
  }
  if (ventMap) {
    for (const [key, { ventLocation, active }] of ventMap.entries()) {
      ventMap.delete(key);
      world.setDynamicProperty("vents", JSON.stringify([...ventMap]));
    }
  }
  if (lightMap) {
    for (const [key, { lightLocation }] of lightMap.entries()) {
      lightMap.delete(key);
      world.setDynamicProperty("lights", JSON.stringify([...lightMap]));
    }
  }
  if (turretIdMap) {
    world.setDynamicProperty("turretIds", JSON.stringify([]));
  }

  const entities = Object.keys(ENTITIES)
  for (const ent of entities) {
    if (ent.typeId == "minecraft:player" || ent.typeId == "minecraft:iron_golem" || ent.typeId == "js:mine" || ent.typeId == "js:turret" || ent.typeId == "js:wandering_locusts") continue;
    
    world.setDynamicProperty(`entCount_${ent.split('js:')[1]}`, 0);

    console.warn(`entCount_${ent.split('js:')[1]} ${world.getDynamicProperty(`entCount_${ent.split('js:')[1]}`)}`)
  }

  for (let player of worldPlayers) {
    player.wasCriticallyInjured = false
  }

  if (restartGeneration == true) {
    system.runTimeout(() => {
      console.warn(`Restarting Generation`)
      generate()
    }, 3 * 20)
  }
}

function selectRandomLayout(mapName) {
  const mapLayout = MAPS[mapName]?.layout;
  if (!mapLayout) {
    throw new Error(`Map ${mapName} not found or layout not defined.`);
  }

  const randomChance = Math.random() * 100; // Generate a random number between 0 and 100
  let cumulativeChance = 0;

  for (const [layout, chance] of Object.entries(mapLayout)) {
    cumulativeChance += chance;
    if (randomChance <= cumulativeChance) {
      return layout; // Return the selected layout
    }
  }

  throw new Error("Failed to select a layout. Check the MAPS configuration.");
}



function generate() {
  const moonId = world.getDynamicProperty("moon");
  let mapName;
  let shipLocation = { x: 0, y: -60, z: 0 };

  for (const key of Object.keys(MAPS)) {
    if (MAPS[key].id === moonId) {
      mapName = key;
      shipLocation = MAPS[key].shipLocation;
      break;
    }
  }
  
  const selectedLayout = selectRandomLayout(mapName);
  // world.sendMessage(`Selected layout: ${selectedLayout}`);
  world.setDynamicProperty('facilityType', selectedLayout)
  
  facilityType = world.getDynamicProperty('facilityType')

  world.setDynamicProperty("currentPowerLevel", 0);
  world.setDynamicProperty("currentOutdoorPowerLevel", 0);
  world.setDynamicProperty("generationPercentage", 0);
  world.setDynamicProperty("minSpawnOverride", 0);
  world.setDynamicProperty("totalScrapPossible", 0);
  processedExits.clear();
  system.runJob(generator(mapName, shipLocation));
}



function testIfRoomInFront(location) {
  const blockInFront = OVERWORLD.getBlock(location);

  const roomsMap = new Map(
    world.getDynamicProperty("rooms") ? JSON.parse(world.getDynamicProperty("rooms")) : []
  );

  let blockInsideRoom = false; 
  let blockInsideRoomName;

  for (const [key, { min, max }] of roomsMap.entries()) {
    const intersects =
      blockInFront.x >= min.x && blockInFront.x <= max.x &&
      blockInFront.y >= min.y && blockInFront.y <= max.y &&
      blockInFront.z >= min.z && blockInFront.z <= max.z;

    if (intersects) {
      blockInsideRoom = true;
      blockInsideRoomName = key.split('_')[0]
      console.warn(blockInsideRoom, blockInsideRoomName)
      break; 
    }
  }
  return blockInsideRoom;
}

system.afterEvents.scriptEventReceive.subscribe((ev) => {
  const entity = ev.sourceEntity;
  const message = ev.id;

  if (message == "js:clearGenerate") {
    clearGenerate()
  };

  if (message == "js:generate") {
    generate()
  };

  if (message == "js:test") {
    const blockInFront = OVERWORLD.getBlock(entity.location);

    const roomsMap = new Map(
      world.getDynamicProperty("rooms") ? JSON.parse(world.getDynamicProperty("rooms")) : []
    );

    let blockInsideRoom = false; 
    let blockInsideRoomName;

    for (const [key, { min, max }] of roomsMap.entries()) {
      const intersects =
        blockInFront.x >= min.x && blockInFront.x <= max.x &&
        blockInFront.y >= min.y && blockInFront.y <= max.y &&
        blockInFront.z >= min.z && blockInFront.z <= max.z;

      if (intersects) {
        blockInsideRoom = true;
        blockInsideRoomName = key.split('_')[0]
        console.warn(blockInsideRoom, blockInsideRoomName)
        break; 
      }
    }
  }
});

let roomsToGenerate

function* generator(mapName, shipLocation) {
  const mainLocation = {
    x: shipLocation.x,
    y: shipLocation.y - 75 - 30,
    z: shipLocation.z,
  };

  let main = world.structureManager.get("mystructure:main");
  if (facilityType == "mansion") {
    let mainRand = Math.random() * 100
    if (mainRand <= 25) {
      main = world.structureManager.get("mystructure:m_main");
    } else if (mainRand > 25 && mainRand <= 50) {
      main = world.structureManager.get("mystructure:m_main1");
    } else if (mainRand > 50 && mainRand <= 75) {
      main = world.structureManager.get("mystructure:m_main2");
    } else if (mainRand > 75 && mainRand <= 100) {
      main = world.structureManager.get("mystructure:m_main3");
    }
  }

  if (!main) throw `Failed to get main structure`;
  world.structureManager.place(main, OVERWORLD, mainLocation);

  const min = mainLocation;
  let max = {
    x: mainLocation.x + 9,
    y: mainLocation.y + 37,
    z: mainLocation.z + 9,
  };
  if (facilityType == "mansion") {
    max = {
      x: mainLocation.x + 25,
      y: mainLocation.y + 19,
      z: mainLocation.z + 33,
    };
  }

  const roomsMap = new Map(world.getDynamicProperty("rooms") ? JSON.parse(world.getDynamicProperty("rooms")) : []);
  const mainKey = `main_${Date.now()}`;

  roomsMap.set(mainKey, { min, max });

  world.setDynamicProperty("rooms", JSON.stringify([...roomsMap]));

  const mapSizeMultiplier = MAPS[mapName].mapMultiplier;
  const maxFireExits = MAPS[mapName].fireExits;

  world.setDynamicProperty("currentFireExits", 0);

  roomsToGenerate = (Math.floor(Math.random() * 9) + 21) * mapSizeMultiplier;
  if (mapName == "march") {
    roomsToGenerate += 4;
  } else {
    roomsToGenerate += 1;
  }

  world.setDynamicProperty("currentRooms", 1);
  world.setDynamicProperty("apparatus", 0);
  world.setDynamicProperty("minSpawnOverride", 0);

  let currentRooms = world.getDynamicProperty("currentRooms");

  let generationPercentage = Math.round((currentRooms / roomsToGenerate) * 100);

  let tileSet = {
    "2x1catwalk": 23,
    "2x1jump1": 23,
    hallway: 14,
    stair1: 40,
    blocked: 12,
  };
  
  if (facilityType == "mansion") {
    tileSet = {
      "m_hallway_1": 45,
      "m_hallway_l": 0,
      "m_3x2bigroom1": 0,
      "m_2x2bigroom2": 0,
      "m_hallway_3": 10,
      blocked: 12,
    };
  }

  let branches = OVERWORLD.getEntities({
    type: "minecraft:armor_stand",
    name: "main",
    location: shipLocation,
    maxDistance: 500,
  });

  let numberOfBranches = Math.floor(Math.random() * (4 - 3 + 1)) + 3

  let branchesProcessed = 0
  
  if (facilityType == "mansion") {
    function shuffleArray(array) {
      for (let i = array.length - 1; i > 0; i--) {
        const j = Math.floor(Math.random() * (i + 1));
        [array[i], array[j]] = [array[j], array[i]];
      }
      return array;
    }

    branches = shuffleArray(branches);
  }

  for (let branch of branches) { 
    const branchLocation = branch.location;
    const rotation = branch.getRotation().y;
    let branchDirection = "north";
    if (rotation === -180) {
      branchDirection = "north";
    }
    if (rotation === 90) {
      branchDirection = "west";
    }
    if (rotation === -90) {
      branchDirection = "east";
    }
    if (rotation === 0) {
      branchDirection = "south";
    }


    let initialTile = selectRandomTile(tileSet);
    

    if (facilityType == "mansion") {
      branchesProcessed++
      if (branchesProcessed > numberOfBranches) {
        initialTile = "blocked"
      }
    }

    console.warn(`Chose ${initialTile}`);

    if (initialTile !== "blocked") {
      system.runJob(placeTile(branchLocation, initialTile, branchDirection));
      yield;
      
      let fillBlock = "ding:concrete_brick_wall"
      let fillAreaNS = `~-1 ~ ~ ~1 ~3 ~`
      let fillAreaEW = `~ ~ ~-1 ~ ~3 ~1`
      if (facilityType == "mansion") {
        fillBlock = "ding:mansion_wall"
        fillAreaNS = `~-3 ~ ~ ~3 ~5 ~`
        fillAreaEW = `~ ~ ~-3 ~ ~5 ~3`
      }

      let doorChance = Math.random() * 100;
      if (doorChance <= 80) {
        if (branchDirection == "north" || branchDirection == "south") {
          branch.runCommand(`fill ${fillAreaNS} ${fillBlock} replace air`); 
          branch.runCommand(`fill ${fillAreaNS} ${fillBlock} replace ding:tiny_pipe`);
          branch.runCommand(`fill ${fillAreaNS} ${fillBlock} replace ding:tiny_pipe_curve`);
          branch.runCommand(`fill ${fillAreaNS} ${fillBlock} replace ding:tiny_pipe_curve2`);
          branch.runCommand(`fill ${fillAreaNS} ${fillBlock} replace ding:tiny_pipe_curve3`);
          branch.runCommand(`fill ${fillAreaNS} ${fillBlock} replace ding:tiny_pipe_curve4`);
        }
        if (branchDirection == "east" || branchDirection == "west") {
          branch.runCommand(`fill ${fillAreaEW} ${fillBlock} replace air`);
          branch.runCommand(`fill ${fillAreaEW} ${fillBlock} replace ding:tiny_pipe`);
          branch.runCommand(`fill ${fillAreaEW} ${fillBlock} replace ding:tiny_pipe_curve`);
          branch.runCommand(`fill ${fillAreaEW} ${fillBlock} replace ding:tiny_pipe_curve2`);
          branch.runCommand(`fill ${fillAreaEW} ${fillBlock} replace ding:tiny_pipe_curve3`);
          branch.runCommand(`fill ${fillAreaEW} ${fillBlock} replace ding:tiny_pipe_curve4`);
        }
        let lockChance = Math.random() * 100;
        let locked = false
        if (lockChance <= 15) {
          locked = true
          system.runJob(spawnKey(branchLocation));
        }

        const doorsMap = new Map(
          world.getDynamicProperty("doors") ? JSON.parse(world.getDynamicProperty("doors")) : []
        );
        const key = `Door_${Date.now()}`;
        let roomLocation = branchLocation
        let roomDirection = branchDirection

        doorsMap.set(key, { roomLocation, roomDirection, locked });
        world.setDynamicProperty("doors", JSON.stringify([...doorsMap]));

        //world.sendMessage(`Main Door ${JSON.stringify(roomLocation)}`)
      }

    } else {
      const fillVol = new BlockVolume(branchLocation, {
        x: branchLocation.x,
        y: branchLocation.y + 1,
        z: branchLocation.z,
      });

      if (facilityType == "mansion") {
        OVERWORLD.fillBlocks(fillVol, "ding:mansion_wall");
      } else {
        OVERWORLD.fillBlocks(fillVol, "ding:sheet_wall");
      }

      delete tileSet[initialTile];
    }

    currentRooms = world.getDynamicProperty("currentRooms");
    world.setDynamicProperty("currentRooms", currentRooms + 1);
    currentRooms = world.getDynamicProperty("currentRooms");

    generationPercentage = (currentRooms / roomsToGenerate) * 100;
    world.setDynamicProperty("generationPercentage", generationPercentage);
    // //world.sendMessage(`Generation ${generationPercentage}% complete out of ${roomsToGenerate}`)

    worldPlayers.forEach((player) => {
      const scaledScore = world.getDynamicProperty("generationPercentage");
      player.uiManager.updateGenerationPercent(scaledScore)
    });

    branch.remove();
  }

  if (facilityType == "facility") {
    tileSet = {
      "2x1catwalk": 20,
      "2x1jump1": 20,
      hallway: 25,
      hallway_t: 15,
      hallway_lt: 15,
      hallway_rt: 15,
      hallway_x: 15,
      hallway_doorway: 7,
      hallway_maze: 1,
      hallway_big_x: 3,
      stair1: 30,
      stair2: 30,
      "2x1storage": 15,
      "2x2bigroom": 10,
      "2x2server": 15,
      "2x2storage": 15,
      "3x2apparatus": 5,
      "3x3apparatus": 5,
      backrooms: 5,
    };
  } else {
    tileSet = {
      "m_stair2": 1,
      "m_stair1": 1,
      "m_hallway_2": 10,
      "m_hallway_1": 10,
      "m_hallway_x": 5,
      "m_3x2window": 1,
      "m_hallway_l": 5,
      "m_3x2fireplace": 1,
      "m_3x2bigroom1": 1,
      "m_2x3stair3": 1,
      "m_hallway_t": 5,
      "m_2x2kitchen": 1,
      "m_2x2bigroom2": 1,
      "m_hallway_3": 5
    }
  }
    //  system.runJob(
    //     mainBranchIterationGeneration(mapName, shipLocation, maxFireExits, roomsToGenerate, mainBranchIteration)
    //   );

  // const mainBranchIteration = system.runInterval(() => {
  //   system.runJob(
  //     mainBranchIterationGeneration(mapName, shipLocation, maxFireExits, roomsToGenerate, mainBranchIteration)
  //   );
  // }, 2);

  function mainBranchIterationGenerator(
    mapName,
    shipLocation,
    maxFireExits,
    roomsToGenerate,
    mainBranchIteration
  ) {
    return new Promise((resolve, reject) => {
      const generator = mainBranchIterationGeneration(
        mapName,
        shipLocation,
        maxFireExits,
        roomsToGenerate,
        mainBranchIteration
      );
  
      function step() {
        try {
          const { value, done } = generator.next();
          if (done) {
            resolve(); // Resolve the Promise when the generator is done
          } else {
            system.runTimeout(() => step(), 1); // Step through the generator asynchronously
          }
        } catch (error) {
          reject(error); // Reject the Promise on errors
        }
      }
  
      step(); // Start the generator execution
    });
  }
  let isMainBranchIterationRunning = false; // Flag to track if the function is running

  const mainBranchIteration = system.runInterval(() => {
    if (!isMainBranchIterationRunning) {
      isMainBranchIterationRunning = true; // Set the flag to true
      mainBranchIterationGenerator(
        mapName,
        shipLocation,
        maxFireExits,
        roomsToGenerate,
        mainBranchIteration
      )
        .then(() => {
          isMainBranchIterationRunning = false; // Reset the flag after completion
        })
        .catch((error) => {
          console.error("Error during mainBranchIterationGenerator:", error);
          isMainBranchIterationRunning = false; // Reset the flag even if there's an error
        });
    } else {
      console.warn(
        "mainBranchIterationGenerator is still running, skipping this iteration."
      );
    }
  }, 2);

}

system.afterEvents.scriptEventReceive.subscribe((ev) => {
  const entity = ev.sourceEntity;
  const message = ev.id;

  if (!entity || message !== "js:next") return;

  const moonId = world.getDynamicProperty("moon");
  let mapName;
  let shipLocation = { x: 0, y: -60, z: 0 };

  for (const key of Object.keys(MAPS)) {
    if (MAPS[key].id === moonId) {
      mapName = key;
      shipLocation = MAPS[key].shipLocation;
      break;
    }
  }
  const mapSizeMultiplier = MAPS[mapName].mapMultiplier;
  const maxFireExits = MAPS[mapName].fireExits;

  // let roomsToGenerate = Math.floor(Math.random() * 41) * mapSizeMultiplier
  let roomsToGenerate = 30;

  if (mapName == "march") {
    roomsToGenerate = 34;
  } else {
    roomsToGenerate = 31;
  }
  let mainBranchIteration;
  let currentRooms = /** @type {number} */ (world.getDynamicProperty("currentRooms"));
  let generationPercentage = Math.round((currentRooms / roomsToGenerate) * 100);
  if (generationPercentage >= 100) {
    endGeneration(shipLocation);
  } else {
    system.runJob(
      mainBranchIterationGeneration(mapName, shipLocation, maxFireExits, roomsToGenerate, mainBranchIteration)
    );
  }
});


function selectRandomTile(tileSet) {
  let totalWeight = 0;
  for (let tile in tileSet) {
    totalWeight += tileSet[tile];
  }

  let randomNum = Math.random() * totalWeight;

  let accumulatedWeight = 0;
  for (let tile in tileSet) {
    accumulatedWeight += tileSet[tile];
    if (randomNum < accumulatedWeight) {
      return tile;
    }
  }
}


let tileSet = {}
if (facilityType == "facility") {
 tileSet = {
    "2x1catwalk": 20,
    "2x1jump1": 20,
    hallway: 25,
    hallway_t: 15,
    hallway_lt: 15,
    hallway_rt: 15,
    hallway_x: 15,
    hallway_doorway: 7,
    hallway_big_x: 3,
    stair1: 30,
    stair2: 30,
    hallway_maze: 1,
    "2x1storage": 15,
    "2x2bigroom": 10,
    "2x2server": 15,
    "2x2storage": 15,
    "3x2apparatus": 5,
    "3x3apparatus": 5,
    "3x6hugeroom": 2,
    backrooms: 5,
  };
} else {
  tileSet = {
    "m_stair2": 1,
    "m_stair1": 1,
    "m_hallway_2": 10,
    "m_hallway_1": 10,
    "m_hallway_x": 5,
    "m_3x2window": 1,
    "m_hallway_l": 5,
    "m_3x2fireplace": 1,
    "m_3x2bigroom1": 1,
    "m_2x3stair3": 1,
    "m_hallway_t": 5,
    "m_2x2kitchen": 1,
    "m_2x2bigroom2": 1,
    "m_hallway_3": 5
  }
}



const processedExits = new Set();

function* mainBranchIterationGeneration(mapName, shipLocation, maxFireExits, roomsToGenerate, mainBranchIteration) {
  let currentRooms = world.getDynamicProperty("currentRooms");
  let generationPercentage = Math.round((currentRooms / roomsToGenerate) * 100);

  let currentFireExits = world.getDynamicProperty("currentFireExits");

  const possibleRooms = OVERWORLD.getEntities({
    type: "minecraft:armor_stand",
    location: shipLocation,
    maxDistance: 500,
  });
  ;

  let room = possibleRooms[0];
  //for (let room of possibleRooms) {
  if (generationPercentage >= 100) {

    const mainLocation = {
      x: shipLocation.x,
      y: shipLocation.y - 75 - 30,
      z: shipLocation.z,
    };

    const doorsMap = new Map(
      world.getDynamicProperty("doors") ? JSON.parse(world.getDynamicProperty("doors")) : []
    );

    for (const [key, { roomLocation, roomDirection, locked }] of doorsMap.entries()) {
      let inFrontLocation = roomLocation
      if (roomDirection == "north") {
        inFrontLocation = {
          x: roomLocation.x,
          y: roomLocation.y,
          z: roomLocation.z - 1,
        };
      } else if (roomDirection == "south") {
        inFrontLocation = {
          x: roomLocation.x,
          y: roomLocation.y,
          z: roomLocation.z + 1,
        };
      } else if (roomDirection == "east") {
        inFrontLocation = {
          x: roomLocation.x + 1,
          y: roomLocation.y,
          z: roomLocation.z,
        };
      } else if (roomDirection == "west") {
        inFrontLocation = {
          x: roomLocation.x - 1,
          y: roomLocation.y,
          z: roomLocation.z,
        };
      }
      const blockInFrontInsideRoom = testIfRoomInFront(inFrontLocation)
      if (blockInFrontInsideRoom == true) {
        spawnDoor(roomLocation, "js:facility_door", roomDirection, locked, null, null);
      } else {  
        let fillBlock = "ding:concrete_brick_wall"
        if (facilityType == "mansion") {
          fillBlock = "ding:mansion_wallpaper"
        }
        const fillVol = new BlockVolume(roomLocation, {
          x: roomLocation.x,
          y: roomLocation.y + 1,
          z: roomLocation.z,
        });
      
        OVERWORLD.fillBlocks(fillVol, fillBlock);
      }
    }

    const waterPuddles = OVERWORLD.getEntities({
      type: "js:water_puddle_marker",
      location: shipLocation,
      maxDistance: 500,
    });

    for (let puddle of waterPuddles) {
      let random = Math.random()
      if (random < 0.1) {
        OVERWORLD.setBlockType(puddle.location, 'ding:water_puddle')
      }
      puddle.remove()
    }



    const lights = [
      ...OVERWORLD.getEntities({ type: "js:facility_light_marker", location: shipLocation, maxDistance: 500}),
      ...OVERWORLD.getEntities({ type: "js:facility_light_marker2", location: shipLocation, maxDistance: 500}),
    ];
    
    const lightMap = new Map(world.getDynamicProperty("lights") ? JSON.parse(world.getDynamicProperty("lights")) : []);

    for (let light of lights) {
      const key = `Light_${Date.now()}`;
      let lightLocation = light.location;

      lightMap.set(key, { lightLocation });

      // console.warn(`${JSON.stringify([...lightMap])}`);

      world.setDynamicProperty("lights", JSON.stringify([...lightMap]));
    }

    let facilityBlackout = false;

    let facilityLightChance = Math.random() * 100;
    if (facilityLightChance <= 30) {
      facilityBlackout = true;
    }
    //"hallway_maze": 100,sage(`Facility Blackout: ${facilityBlackout}`)

    if (facilityBlackout == true) {
      for (let light of lights) {
        if (light.typeId == "js:facility_light_marker") {
          let randomLight = Math.random() * 100;
          if (randomLight <= 7) {

            OVERWORLD.setBlockType(light.location, "ding:ceiling_lamp");
            const lightSpawned = OVERWORLD.getBlock(light.location);
            lightSpawned.setPermutation(lightSpawned.permutation.withState("js:on", false));
            
            light.remove();
          } else {

            OVERWORLD.setBlockType(light.location, "ding:ceiling_lamp");
            const lightSpawned = OVERWORLD.getBlock(light.location);
            lightSpawned.setPermutation(lightSpawned.permutation.withState("js:on", true));

            light.remove();
          }
        } else {
          let lightLocation = light.location;
          const lightRot = light.getRotation().y;
          let lightDirection = "north";
          if (lightRot === -180) {
            lightDirection = "north";
          }
          if (lightRot === 90) {
            lightDirection = "west";
          }
          if (lightRot === -90) {
            lightDirection = "east";
          }
          if (lightRot === 0) {
            lightDirection = "south";
          }

          OVERWORLD.setBlockType(lightLocation, "ding:wall_lamp");
          const lightSpawned = OVERWORLD.getBlock(lightLocation);
          lightSpawned.setPermutation(lightSpawned.permutation.withState("js:on", false));
          lightSpawned.setPermutation(lightSpawned.permutation.withState("minecraft:cardinal_direction", lightDirection));
          light.remove();
        }
      }
    } else {
      
      for (let light of lights) {
        if (light.typeId == "js:facility_light_marker") {
          let randomLight = Math.random() * 100;
          if (randomLight <= 75) {

            OVERWORLD.setBlockType(light.location, "ding:ceiling_lamp");
            const lightSpawned = OVERWORLD.getBlock(light.location);
            lightSpawned.setPermutation(lightSpawned.permutation.withState("js:on", false));
            
            light.remove();
          } else {

            OVERWORLD.setBlockType(light.location, "ding:ceiling_lamp");
            const lightSpawned = OVERWORLD.getBlock(light.location);
            lightSpawned.setPermutation(lightSpawned.permutation.withState("js:on", true));

            light.remove();
          }
        } else {
          let lightLocation = light.location;
          const lightRot = light.getRotation().y;
          let lightDirection = "north";
          if (lightRot === -180) {
            lightDirection = "north";
          }
          if (lightRot === 90) {
            lightDirection = "west";
          }
          if (lightRot === -90) {
            lightDirection = "east";
          }
          if (lightRot === 0) {
            lightDirection = "south";
          }

          OVERWORLD.setBlockType(lightLocation, "ding:wall_lamp");
          const lightSpawned = OVERWORLD.getBlock(lightLocation);
          lightSpawned.setPermutation(lightSpawned.permutation.withState("js:on", false));
          lightSpawned.setPermutation(lightSpawned.permutation.withState("minecraft:cardinal_direction", lightDirection));
          light.remove();
        }
      }
    }

    const vents = OVERWORLD.getEntities({ type: "js:vent_marker", location: shipLocation, maxDistance: 500 });

    for (let vent of vents) {
      let ventChance = Math.random() * 100;
      if (ventChance <= 35) {
        vent.remove();
        continue;
      }

      let ventLocation = vent.location;
      const ventRot = vent.getRotation().y;
      let ventDirection = "north";
      if (ventRot === -180) {
        ventDirection = "north";
      }
      if (ventRot === 90) {
        ventDirection = "west";
      }
      if (ventRot === -90) {
        ventDirection = "east";
      }
      if (ventRot === 0) {
        ventDirection = "south";
      }

      OVERWORLD.setBlockType(ventLocation, "js:vent");
      const ventSpawned = OVERWORLD.getBlock(ventLocation);
      ventSpawned.setPermutation(ventSpawned.permutation.withState("js:open", false));
      ventSpawned.setPermutation(ventSpawned.permutation.withState("minecraft:cardinal_direction", ventDirection));

      const ventMap = new Map(world.getDynamicProperty("vents") ? JSON.parse(world.getDynamicProperty("vents")) : []);
      const key = `Vent_${Date.now()}`;

      ventLocation = ventSpawned.location;
      let active = false;

      ventMap.set(key, { ventLocation, active });

      // console.warn(`${JSON.stringify([...ventMap])}`);

      world.setDynamicProperty("vents", JSON.stringify([...ventMap]));

      vent.remove();
    }


    const mansionFurniture = OVERWORLD.getEntities({ type: "js:furniture_marker", location: shipLocation, maxDistance: 500 });

    for (let furniture of mansionFurniture) {
      let direction = "north"
      let randDir = Math.floor(Math.random() * (4 - 1 + 1)) + 1
      if (randDir = 2) {
        direction = "south"
      } else if (randDir = 3) {
        direction = "east"
      } else if (randDir = 4) {
        direction = "west"
      }

      let random = Math.random() * 100
      if (random < 25) {
        OVERWORLD.setBlockType(furniture.location, "ding:stool");
        const furnitureSpawned = OVERWORLD.getBlock(furniture.location);
        furnitureSpawned.setPermutation(furnitureSpawned.permutation.withState("minecraft:cardinal_direction", direction));
      }
      if (random >= 25 && random < 50) {
        OVERWORLD.setBlockType(furniture.location, "ding:mansion_table");
        const furnitureSpawned = OVERWORLD.getBlock(furniture.location);
        furnitureSpawned.setPermutation(furnitureSpawned.permutation.withState("minecraft:cardinal_direction", direction));
      }

      furniture.remove()

    }

    const mansionBookshelves = OVERWORLD.getEntities({ type: "js:mansion_bookshelf_marker", location: shipLocation, maxDistance: 500 });

    for (let shelf of mansionBookshelves) {
      let shelfLocation = shelf.location;
      const shelfRot = shelf.getRotation().y;
      let shelfDirection = "north";
      if (shelfRot === -180) {
        shelfDirection = "north";
      }
      if (shelfRot === 90) {
        shelfDirection = "west";
      }
      if (shelfRot === -90) {
        shelfDirection = "east";
      }
      if (shelfRot === 0) {
        shelfDirection = "south";
      }

      let shelfChance = Math.random() * 100;
      if (shelfChance <= 25) {

        if (shelfDirection == "north" || shelfDirection == "south") {
          shelf.runCommand(`fill ~-2 ~ ~ ~2 ~3 ~ ding:mansion_bookshelf replace air`)
        } 
        if (shelfDirection == "east" || shelfDirection == "west") {
          shelf.runCommand(`fill ~ ~ ~-2 ~ ~3 ~2 ding:mansion_bookshelf replace air`)
        } 
        shelf.remove();
        continue;
      } else if (shelfChance > 25 && shelfChance < 50) {
        let lanternLocation = {
          x: shelfLocation.x,
          y: shelfLocation.y + 2,
          z: shelfLocation.z
        }
        OVERWORLD.setBlockType(lanternLocation, "ding:wall_lantern");
        const lanternSpawned = OVERWORLD.getBlock(lanternLocation);
        lanternSpawned.setPermutation(lanternSpawned.permutation.withState("js:on", true));

        let lanternDirection = "north"
        if (shelfDirection == "north") {
          lanternDirection = "south"
        }
        if (shelfDirection == "south") {
          lanternDirection = "north"
        }
        if (shelfDirection == "east") {
          lanternDirection = "west"
        }
        if (shelfDirection == "west") {
          lanternDirection = "east"
        }
        lanternSpawned.setPermutation(lanternSpawned.permutation.withState("minecraft:cardinal_direction", lanternDirection));

        shelf.remove();
        continue;
      } else if (shelfChance >= 50 && shelfChance < 60) {
        OVERWORLD.setBlockType(shelfLocation, "js:vent");
        const ventSpawned = OVERWORLD.getBlock(shelfLocation);
        ventSpawned.setPermutation(ventSpawned.permutation.withState("js:open", false));
        ventSpawned.setPermutation(ventSpawned.permutation.withState("minecraft:cardinal_direction", shelfDirection));

        const ventMap = new Map(world.getDynamicProperty("vents") ? JSON.parse(world.getDynamicProperty("vents")) : []);
        const key = `Vent_${Date.now()}`;

        let ventLocation = ventSpawned.location;
        let active = false;

        ventMap.set(key, { ventLocation, active });

        // console.warn(`${JSON.stringify([...ventMap])}`);

        world.setDynamicProperty("vents", JSON.stringify([...ventMap]));

        shelf.remove();
        continue;
      }

      shelf.remove();
    }
    

    // const mansionWindows = OVERWORLD.getEntities({ type: "js:mansion_window_marker", location: shipLocation, maxDistance: 500 });

    // for (let window of mansionWindows) {
    //   const windowEnt = OVERWORLD.spawnEntity('js:mansion_window', window.location, {initialRotation: -window.getRotation().y })
    //   window.remove()
    // }

    const fireExitsMap = new Map(
      world.getDynamicProperty("fireExits") ? JSON.parse(world.getDynamicProperty("fireExits")) : []
    );

    for (const [key, { location, inFrontLocation, originalDir, inverseDir, fireExitNum }] of fireExitsMap.entries()) {
      spawnDoor(location, "js:fire_exit_door", originalDir, null, null, fireExitNum);

      OVERWORLD.setBlockType(
        { x: inFrontLocation.x, y: inFrontLocation.y + 2, z: inFrontLocation.z },
        "ding:fire_exit_lamp"
      );

      const fireExitLamp = OVERWORLD.getBlock({ x: inFrontLocation.x, y: inFrontLocation.y + 2, z: inFrontLocation.z });

      fireExitLamp.setPermutation(fireExitLamp.permutation.withState("minecraft:cardinal_direction", inverseDir));
    }

    
    endGeneration(shipLocation);
    system.clearRun(mainBranchIteration);
    system.runJob(spawnScrap(mapName, mainLocation));
    
  }

  if (!room) {
    console.warn(`NO ROOMS`)
    if (generationPercentage < 100) {
      console.warn(`GENERATION INCOMPLETE. Clearing and queuing restart`)
      clearGenerate(true)
      endGeneration(shipLocation);
      system.clearRun(mainBranchIteration);
    }
    return;
  };

  const rotation = room.getRotation().y;
  let roomDirection = "north";
  if (rotation === -180) {
    roomDirection = "north";
  }
  if (rotation === 90) {
    roomDirection = "west";
  }
  if (rotation === -90) {
    roomDirection = "east";
  }
  if (rotation === 0) {
    roomDirection = "south";
  }

  //"hallway_maze": 100,sage(`Room ${rotation}, ${JSON.stringify(room.location)}, ${room.nameTag}`)

  const roomName = room.nameTag;
  const roomLocation = room.location;

  if (room.nameTag == "hallway_doorway") {
    console.warn(`Hallway doorway targetted, skipping`);
    return;
  }

  if (room.nameTag == "3x2apparatus") {
    let doorChance = Math.random() * 100;
    if (doorChance <= 80) {
      spawnDoor(roomLocation, "js:facility_door", roomDirection, true, null, null);
      system.runJob(spawnKey(roomLocation));
    } else {
      spawnDoor(roomLocation, "js:facility_door", roomDirection, false, null, null);
    }
    room.remove();
    return;
  }

  const isOverlapping = overlappingDoorwayCheck(room, roomLocation, roomDirection);
  if (isOverlapping == true) return;

  let tolerance = mapName === "march" ? 3 : 10; // Set tolerance based on mapName
  const exitPoints = mapName === "march" ? [33, 66, 85] : [60, 75, 90]; // Define exit points
  let fireExitRoom = false;

  // Helper function to check if a value is near a target with tolerance
  function isAroundMultipleOf(value, target, tolerance) {
    return Math.abs(value - target) <= tolerance;
  }

  // Check for the next exit index
  let nextExitIndex = exitPoints.findIndex(exit =>
    isAroundMultipleOf(generationPercentage, exit, tolerance) && !processedExits.has(exit)
  );

  if (nextExitIndex !== -1 && currentFireExits < maxFireExits) {
    // world.sendMessage(`Attempt fire exit`)
    let fireExitPlaced = false; // Track if a fire exit was placed

    for (let subRoom of possibleRooms) {
      if (
        FIRE_ALLOWED_TILES.includes(subRoom.nameTag) &&
        subRoom.nameTag !== "hallway"
      ) {
        //world.sendMessage(`Fireable room`)
        // Check for overlapping doorway entities
        const overlappingDoorways = OVERWORLD.getEntities({
          type: "minecraft:armor_stand",
          location: subRoom.location,
          maxDistance: 2,
        });
        if (overlappingDoorways.length > 1) {
           //world.sendMessage(`FIRE: Overlapping doorway, skipping this selection at ${JSON.stringify(subRoom.location)}`);
          continue;
        }

        // Check if there is a room 10 blocks ahead
        const block10BlocksInFront = subRoom.getBlockFromViewDirection({ maxDistance: 10 });
        if (block10BlocksInFront) {
          //world.sendMessage(`FIRE: Room ahead, skipping this selection at ${JSON.stringify(subRoom.location)}`);
          continue;
        }

        // Stop if max fire exits are already reached
        if (currentFireExits >= maxFireExits) break;

        // Determine direction and fire exit placement details
        const subRotation = subRoom.getRotation().y;
        let originalDir = "north";
        if (subRotation === -180) originalDir = "north";
        else if (subRotation === 90) originalDir = "west";
        else if (subRotation === -90) originalDir = "east";
        else if (subRotation === 0) originalDir = "south";

        let inverseDir = {
          north: "south",
          south: "north",
          west: "east",
          east: "west",
        }[originalDir];

        const location = subRoom.location;
        const fireExitNum = currentFireExits;

        let inFrontLocation = {
          north: { x: location.x, y: location.y, z: location.z + 1 },
          south: { x: location.x, y: location.y, z: location.z - 1 },
          west: { x: location.x + 1, y: location.y, z: location.z },
          east: { x: location.x - 1, y: location.y, z: location.z },
        }[originalDir];

        const fireExitsMap = new Map(
          world.getDynamicProperty("fireExits") ? JSON.parse(world.getDynamicProperty("fireExits")) : []
        );
        const key = `FireExit_${fireExitNum}`;

        fireExitsMap.set(key, { location, inFrontLocation, originalDir, inverseDir, fireExitNum });
        world.setDynamicProperty("fireExits", JSON.stringify([...fireExitsMap]));

        // //world.sendMessage(`${generationPercentage} Fire Exit placed at ${JSON.stringify(location)}`);
        subRoom.remove();

        world.setDynamicProperty("currentFireExits", currentFireExits + 1);
        currentRooms = world.getDynamicProperty("currentRooms");
        world.setDynamicProperty("currentRooms", currentRooms + 1);

        generationPercentage = Math.round((currentRooms / roomsToGenerate) * 100);
        // world.sendMessage(`Fire exit queud ${JSON.stringify(location)}`)
        fireExitRoom = true;
        fireExitPlaced = true;

        // Mark this exit point as processed
        processedExits.add(exitPoints[nextExitIndex]);
        break;
      }
    }

    // Log message if fire exit placement failed
    if (!fireExitPlaced) {
      // world.sendMessage("Failed to place a fire exit, skipping to the next threshold.");
      // Mark this exit point as processed even if placement failed
      processedExits.add(exitPoints[nextExitIndex]);
    }
  }

  if (fireExitRoom == true) {
    // world.sendMessage(`Fre exit placed`)
    return
  };

  console.warn(JSON.stringify(tileSet))
  console.warn(roomName)
  const defaultTilePool = TILES[roomName].tileSets;
  let tilePool = {};

  for (let tile in tileSet) {
    if (defaultTilePool.hasOwnProperty(tile)) {
      tilePool[tile] = tileSet[tile] + defaultTilePool[tile];
    }
  }

  console.warn(`Pool ${JSON.stringify(tilePool)}`);

  if (Object.keys(tilePool).length === 0) {
    if (facilityType == "facility") {
      tileSet = {
         "2x1catwalk": 20,
         "2x1jump1": 20,
         hallway: 25,
         hallway_t: 15,
         hallway_lt: 15,
         hallway_rt: 15,
         hallway_x: 15,
         hallway_doorway: 7,
         stair1: 30,
         stair2: 30,
         hallway_maze: 1,
         "2x1storage": 15,
         "2x2bigroom": 10,
         "2x2server": 15,
         "2x2storage": 15,
         "3x2apparatus": 5,
         "3x3apparatus": 5,
         "3x6hugeroom": 5,
         backrooms: 5,
       };
     } else {
       tileSet = {
         "m_stair2": 1,
         "m_stair1": 1,
         "m_hallway_2": 10,
         "m_hallway_1": 10,
         "m_hallway_x": 5,
         "m_3x2window": 1,
         "m_hallway_l": 5,
         "m_3x2fireplace": 1,
         "m_3x2bigroom1": 1,
         "m_2x3stair3": 1,
         "m_hallway_t": 5,
         "m_2x2kitchen": 1,
         "m_2x2bigroom2": 1,
         "m_hallway_3": 5
       }
     }
     for (let tile in tileSet) {
      if (defaultTilePool.hasOwnProperty(tile)) {
        tilePool[tile] = tileSet[tile] + defaultTilePool[tile];
      }
    }
  }

  let chosenTile;
  let successStatus = 0;
  let attempts = 0;
  const maxAttempts = 48;
  do {
    if (Object.keys(tilePool).length === 0) {
      break;
    }

    let totalWeight = 0;
    for (let tile in tilePool) {
      totalWeight += tilePool[tile];
    }

    let randomWeight = Math.random() * totalWeight;

    for (let tile in tilePool) {
      randomWeight -= tilePool[tile];
      if (randomWeight <= 0) {
        chosenTile = tile;
        break;
      }
    }
    console.warn(`Chosing: ${JSON.stringify(chosenTile)}`);
    ;

    let startCorner = { x: 0, y: 0, z: 0 };
    let endCorner = { x: 0, y: 0, z: 0 };

    if (roomDirection === "north") {
      startCorner.x = roomLocation.x + TILES[chosenTile].north.offset.x;
      startCorner.y = roomLocation.y + TILES[chosenTile].north.offset.y;
      startCorner.z = roomLocation.z + TILES[chosenTile].north.offset.z;

      endCorner.x = startCorner.x + TILES[chosenTile].north.size.x - 2; // Shrink by 1
      endCorner.y = startCorner.y + TILES[chosenTile].north.size.y - 2;
      endCorner.z = startCorner.z + TILES[chosenTile].north.size.z - 2;
    } else if (roomDirection === "east") {
      startCorner.x = roomLocation.x + TILES[chosenTile].east.offset.x;
      startCorner.y = roomLocation.y + TILES[chosenTile].east.offset.y;
      startCorner.z = roomLocation.z + TILES[chosenTile].east.offset.z;

      endCorner.x = startCorner.x + TILES[chosenTile].east.size.x - 2;
      endCorner.y = startCorner.y + TILES[chosenTile].east.size.y - 2;
      endCorner.z = startCorner.z + TILES[chosenTile].east.size.z - 2;
    } else if (roomDirection === "south") {
      startCorner.x = roomLocation.x + TILES[chosenTile].south.offset.x;
      startCorner.y = roomLocation.y + TILES[chosenTile].south.offset.y;
      startCorner.z = roomLocation.z + TILES[chosenTile].south.offset.z;

      endCorner.x = startCorner.x + TILES[chosenTile].south.size.x - 2;
      endCorner.y = startCorner.y + TILES[chosenTile].south.size.y - 2;
      endCorner.z = startCorner.z + TILES[chosenTile].south.size.z - 2;
    } else if (roomDirection === "west") {
      startCorner.x = roomLocation.x + TILES[chosenTile].west.offset.x;
      startCorner.y = roomLocation.y + TILES[chosenTile].west.offset.y;
      startCorner.z = roomLocation.z + TILES[chosenTile].west.offset.z;

      endCorner.x = startCorner.x + TILES[chosenTile].west.size.x - 2;
      endCorner.y = startCorner.y + TILES[chosenTile].west.size.y - 2;
      endCorner.z = startCorner.z + TILES[chosenTile].west.size.z - 2;
    }

    ;

    const roomsMap = new Map(
      world.getDynamicProperty("rooms") ? JSON.parse(world.getDynamicProperty("rooms")) : []
    );

    for (const [key, { min, max }] of roomsMap.entries()) {

      successStatus = 0;

      // Check for intersection using math (no shrinking)
      const intersects =
        startCorner.x <= max.x &&
        endCorner.x >= min.x &&
        startCorner.y <= max.y &&
        endCorner.y >= min.y &&
        startCorner.z <= max.z &&
        endCorner.z >= min.z;

      if (intersects) {
        console.warn(
          `${JSON.stringify(chosenTile)} ${JSON.stringify(startCorner)} to ${JSON.stringify(endCorner)} intersects ` +
          `${key.split("_")[0]} volume at ${JSON.stringify(min)} to ${JSON.stringify(max)}`
        );

        // Handle intersection with the "main" volume
        if (key.split("_")[0] === "main") {
          successStatus = 1;

          delete tilePool[chosenTile];

          console.warn(`Deleted ${chosenTile}, due to intersect main new pool ${JSON.stringify(tilePool)}`);
          break;
        } else {

          // Handle general intersection
          successStatus = 2;

          delete tilePool[chosenTile];
  
          console.warn(
            `Deleted ${chosenTile}, due to intersection, new pool ${JSON.stringify(tilePool)}`
          );
          break;
        }
      } else {
        successStatus = 3;
      }

    }
    attempts++;
    if (attempts >= maxAttempts) {
      successStatus = 0
    }
  } while (successStatus < 3 && attempts < maxAttempts);
  //successStatus 0 = failed due to none selected,
  //successStatus 1 = failed due to intersect main,
  //successStatus 2 = failed due to intersect extent,
  //successStatus 3 = success

  if (attempts >= maxAttempts || Object.keys(tilePool).length === 0) {

    let fillBlock = "ding:sheet_wall"
    if (facilityType == "mansion") {
      fillBlock = "ding:mansion_wallpaper"
    }

    switch (successStatus) {
      case 0:
        //successStatus 0 = failed due to none selected,
        closeOffOpenDoorway(room, roomLocation, roomDirection) 
        console.warn(`Closing at ${JSON.stringify(roomLocation)} due to NONE SELECTED`);
        break;
      case 1:
        //successStatus 1 = failed due to intersect main,
        closeOffOpenDoorway(room, roomLocation, roomDirection) 
        console.warn(`Closing at ${JSON.stringify(roomLocation)} due to INTERSECT MAIN`);
        break;
      case 2:
        //successStatus 2 = failed due to intersect extent,
        closeOffOpenDoorway(room, roomLocation, roomDirection) 
        console.warn(`Closing at ${JSON.stringify(roomLocation)} due to INTERSECT EXTENT`);


        break;
      default:
        closeOffOpenDoorway(room, roomLocation, roomDirection) 
        console.warn(`Closing at ${JSON.stringify(roomLocation)} due to NONE`);

        break;
    }
  } else {
    console.warn(`Final Selection: ${chosenTile} at ${JSON.stringify(roomLocation)}`);

    system.runJob(placeTile(roomLocation, chosenTile, roomDirection));

    if (ONE_TIME_TILES.includes(chosenTile)) {
      delete tileSet[chosenTile];
      console.warn(`Removed ${chosenTile} from tileSet`);

      console.warn(`New Tile Set${JSON.stringify(tileSet)}`);
    }

    if (room.nameTag.split("_")[0] == "hallway") {
      //world.sendMessage(`Hallway selected at ${JSON.stringify(roomLocation)}`);
      hallway(room, roomLocation, roomDirection);
    } else if (room.nameTag == "m_stair1" || room.nameTag == "m_stair2" || chosenTile == "m_stair1" || chosenTile == "m_stair2") {
      let clearWallMin = roomLocation
      let clearWallMax = roomLocation
      let addFenceMin = roomLocation
      let addFenceMax = roomLocation
      if (roomDirection == "north" || roomDirection == "south") {
        clearWallMin = {
          x: roomLocation.x - 3,
          y: roomLocation.y,
          z: roomLocation.z
        }
        clearWallMax = {
          x: roomLocation.x + 3,
          y: roomLocation.y + 5,
          z: roomLocation.z
        }
        addFenceMin = {
          x: roomLocation.x + 1,
          y: roomLocation.y,
          z: roomLocation.z
        }
        addFenceMax = {
          x: roomLocation.x - 3,
          y: roomLocation.y,
          z: roomLocation.z
        }
      }
      if (roomDirection == "east" || roomDirection == "west") {
        clearWallMin = {
          x: roomLocation.x,
          y: roomLocation.y,
          z: roomLocation.z - 3
        }
        clearWallMax = {
          x: roomLocation.x,
          y: roomLocation.y + 5,
          z: roomLocation.z + 3
        }
        addFenceMin = {
          x: roomLocation.x,
          y: roomLocation.y,
          z: roomLocation.z + 1
        }
        addFenceMax = {
          x: roomLocation.x,
          y: roomLocation.y,
          z: roomLocation.z - 3
        }
      }
      const clearWall = new BlockVolume(clearWallMin, clearWallMax)
      const addFence = new BlockVolume(addFenceMin, addFenceMax)
      OVERWORLD.fillBlocks(clearWall, "minecraft:air")
      OVERWORLD.fillBlocks(addFence, "minecraft:oak_fence")
      room.remove()

      //world.sendMessage(`fence at ${JSON.stringify(roomLocation)}`)

    } else if (room.nameTag == "m_hallway_2" || chosenTile == "m_hallway_2") {
      room.remove()
    } else {

      //world.sendMessage(`${room.nameTag}`)

      let fillBlock = "ding:concrete_brick_wall"
      let fillAreaNS = `~-1 ~ ~ ~1 ~3 ~`
      let fillAreaEW = `~ ~ ~-1 ~ ~3 ~1`
      if (facilityType == "mansion") {
        fillBlock = "ding:mansion_wallpaper"
        fillAreaNS = `~-3 ~ ~ ~3 ~5 ~`
        fillAreaEW = `~ ~ ~-3 ~ ~5 ~3`
      }

      let doorChance = Math.random() * 100;

      let baseDoorChance = 80
      if (room.nameTag == "3x6hugeroom") {
        baseDoorChance = 20
      }

      if (doorChance <= baseDoorChance) {
        if (room.nameTag !== "3x6hugeroom") {
          if (roomDirection == "north" || roomDirection == "south") {
            room.runCommand(`fill ${fillAreaNS} ${fillBlock} replace air`);
            room.runCommand(`fill ${fillAreaNS} ${fillBlock} replace ding:tiny_pipe`);
            room.runCommand(`fill ${fillAreaNS} ${fillBlock} replace ding:tiny_pipe_curve`);
            room.runCommand(`fill ${fillAreaNS} ${fillBlock} replace ding:tiny_pipe_curve2`);
            room.runCommand(`fill ${fillAreaNS} ${fillBlock} replace ding:tiny_pipe_curve3`);
            room.runCommand(`fill ${fillAreaNS} ${fillBlock} replace ding:tiny_pipe_curve4`);
          }
          if (roomDirection == "east" || roomDirection == "west") {
            room.runCommand(`fill ${fillAreaEW} ${fillBlock} replace air`);
            room.runCommand(`fill ${fillAreaEW} ${fillBlock} replace ding:tiny_pipe`);
            room.runCommand(`fill ${fillAreaEW} ${fillBlock} replace ding:tiny_pipe_curve`);
            room.runCommand(`fill ${fillAreaEW} ${fillBlock} replace ding:tiny_pipe_curve2`);
            room.runCommand(`fill ${fillAreaEW} ${fillBlock} replace ding:tiny_pipe_curve3`);
            room.runCommand(`fill ${fillAreaEW} ${fillBlock} replace ding:tiny_pipe_curve4`);
          }
        } 
        let lockChance = Math.random() * 100;
        let locked = false
        if (lockChance <= 15) {
          locked = true
          system.runJob(spawnKey(roomLocation));
        }

        const doorsMap = new Map(
          world.getDynamicProperty("doors") ? JSON.parse(world.getDynamicProperty("doors")) : []
        );
        const key = `Door_${Date.now()}`;

        doorsMap.set(key, { roomLocation, roomDirection, locked });
        world.setDynamicProperty("doors", JSON.stringify([...doorsMap]));

        //world.sendMessage(`Not Hallway 2 ${JSON.stringify(roomLocation)}`)
      } else {
        if (room.nameTag == "3x6hugeroom") {
          if (roomDirection == "north" || roomDirection == "south") {
            room.runCommand(`fill ${fillAreaNS} air`);
          }
          if (roomDirection == "east" || roomDirection == "west") {
            room.runCommand(`fill ${fillAreaEW} air`);
          }
        }
      }
      room.remove();
      //world.sendMessage(`Not Hallway ${JSON.stringify(roomLocation)}`)

    }


    currentRooms = world.getDynamicProperty("currentRooms");
    world.setDynamicProperty("currentRooms", currentRooms + 1);
    currentRooms = world.getDynamicProperty("currentRooms");

    generationPercentage = Math.round((currentRooms / roomsToGenerate) * 100);
    world.setDynamicProperty("generationPercentage", generationPercentage);
    // //world.sendMessage(`Generation ${generationPercentage}% complete out of ${roomsToGenerate}`)

    worldPlayers.forEach((player) => {
      const scaledScore = Math.round(world.getDynamicProperty("generationPercentage"));
      player.uiManager.updateGenerationPercent(scaledScore)
    });

  }

  // }
}

// system.runInterval(() => {
//   worldPlayers.forEach(player => {
//     player.onScreenDisplay.setActionBar(
//       `
//       room ${world.getDynamicProperty("currentRooms")}
//       % ${world.getDynamicProperty("generationPercentage")}
//       `
//     )
//   })
// })




function closeOffOpenDoorway(room, roomLocation, roomDirection) {
  const roomName = room.nameTag
  let fillBlock = "ding:concrete_brick_wall"
  if (facilityType == "mansion") {
    fillBlock = "ding:mansion_wallpaper"
  }

  if (roomName.split("_")[0] == "hallway") {
    hallwayCutoff(room, roomLocation, roomDirection);

  } else if (roomName == "m_hallway_1" || roomName == "m_hallway_x") {
    let shelfChance = Math.random() * 100;
    if (shelfChance <= 25) {

      if (roomDirection == "north") {
        room.runCommand(`fill ~-2 ~ ~1 ~2 ~3 ~1 ding:mansion_bookshelf replace air`)
      } 
      if (roomDirection == "south") {
        room.runCommand(`fill ~-2 ~ ~-1 ~2 ~3 ~-1 ding:mansion_bookshelf replace air`)
      } 
      if (roomDirection == "west") {
        room.runCommand(`fill ~1 ~ ~-2 ~1 ~3 ~2 ding:mansion_bookshelf replace air`)
      } 
      if (roomDirection == "east") {
        room.runCommand(`fill ~-1 ~ ~-2 ~-1 ~3 ~2 ding:mansion_bookshelf replace air`)
      } 
      room.remove();
      
    } else if (shelfChance > 25 && shelfChance < 50) {
      let lanternLocation = {
        x: roomLocation.x,
        y: roomLocation.y + 2,
        z: roomLocation.z
      }
      if (roomDirection == "north") {
        lanternLocation = {
          x: roomLocation.x,
          y: roomLocation.y + 2,
          z: roomLocation.z + 1
        }
      } 
      if (roomDirection == "south") {
        lanternLocation = {
          x: roomLocation.x,
          y: roomLocation.y + 2,
          z: roomLocation.z - 1
        }
      } 
      if (roomDirection == "west") {
        lanternLocation = {
          x: roomLocation.x + 1,
          y: roomLocation.y + 2,
          z: roomLocation.z
        }
      } 
      if (roomDirection == "east") {
        lanternLocation = {
          x: roomLocation.x - 1,
          y: roomLocation.y + 2,
          z: roomLocation.z
        }
      } 
      OVERWORLD.setBlockType(lanternLocation, "ding:wall_lantern");
      const lanternSpawned = OVERWORLD.getBlock(lanternLocation);
      lanternSpawned.setPermutation(lanternSpawned.permutation.withState("js:on", true));

      let lanternDirection = "north"
      if (roomDirection == "north") {
        lanternDirection = "south"
      }
      if (roomDirection == "south") {
        lanternDirection = "north"
      }
      if (roomDirection == "east") {
        lanternDirection = "west"
      }
      if (roomDirection == "west") {
        lanternDirection = "east"
      }
      lanternSpawned.setPermutation(lanternSpawned.permutation.withState("minecraft:cardinal_direction", lanternDirection));

      const fillVol = new BlockVolume(roomLocation, {
        x: roomLocation.x,
        y: roomLocation.y + 1,
        z: roomLocation.z,
      });

      OVERWORLD.fillBlocks(fillVol, fillBlock);
      room.remove();

    } else if (shelfChance >= 50 && shelfChance < 60) {
      let ventLocation = {
        x: roomLocation.x,
        y: roomLocation.y,
        z: roomLocation.z
      }
      if (roomDirection == "north") {
        ventLocation = {
          x: roomLocation.x,
          y: roomLocation.y,
          z: roomLocation.z + 1
        }
      } 
      if (roomDirection == "south") {
        ventLocation = {
          x: roomLocation.x,
          y: roomLocation.y,
          z: roomLocation.z - 1
        }
      } 
      if (roomDirection == "west") {
        ventLocation = {
          x: roomLocation.x + 1,
          y: roomLocation.y,
          z: roomLocation.z
        }
      } 
      if (roomDirection == "east") {
        ventLocation = {
          x: roomLocation.x - 1,
          y: roomLocation.y,
          z: roomLocation.z
        }
      } 
      let ventDirection = "north"
      if (roomDirection == "north") {
        ventDirection = "south"
      }
      if (roomDirection == "south") {
        ventDirection = "north"
      }
      if (roomDirection == "east") {
        ventDirection = "west"
      }
      if (roomDirection == "west") {
        ventDirection = "east"
      }
      OVERWORLD.setBlockType(ventLocation, "js:vent");
      const ventSpawned = OVERWORLD.getBlock(ventLocation);
      ventSpawned.setPermutation(ventSpawned.permutation.withState("js:open", false));
      ventSpawned.setPermutation(ventSpawned.permutation.withState("minecraft:cardinal_direction", ventDirection));

      const ventMap = new Map(world.getDynamicProperty("vents") ? JSON.parse(world.getDynamicProperty("vents")) : []);
      const key = `Vent_${Date.now()}`;

      let active = false;

      ventMap.set(key, { ventLocation, active });

      // console.warn(`${JSON.stringify([...ventMap])}`);

      world.setDynamicProperty("vents", JSON.stringify([...ventMap]));

      const fillVol = new BlockVolume(roomLocation, {
        x: roomLocation.x,
        y: roomLocation.y + 1,
        z: roomLocation.z,
      });

      OVERWORLD.fillBlocks(fillVol, fillBlock);
      room.remove();

    } else {
      const fillVol = new BlockVolume(roomLocation, {
        x: roomLocation.x,
        y: roomLocation.y + 1,
        z: roomLocation.z,
      });

      OVERWORLD.fillBlocks(fillVol, fillBlock);
      console.warn(`Default to Sheet Wall at ${JSON.stringify(roomLocation)} due to INTERSECT EXTENT`);
      room.remove();
    }

  } else if (roomName == "m_hallway_2" || roomName == "m_stair1" || roomName == "m_stair2") {

    if (roomDirection == "north" || roomDirection == "south") {
      room.runCommand(`fill ~-4 ~ ~ ~4 ~ ~ ding:mansion_wallpaper_bottom replace air`)
      room.runCommand(`fill ~-4 ~ ~ ~4 ~6 ~ ding:mansion_wallpaper replace air`)
    }
    if (roomDirection == "east" || roomDirection == "west") {
      room.runCommand(`fill ~ ~ ~-4 ~ ~ ~4 ding:mansion_wallpaper_bottom replace air`)
      room.runCommand(`fill ~ ~ ~-4 ~ ~6 ~4 ding:mansion_wallpaper replace air`)
    }
    room.remove()
    //world.sendMessage(`closed closeoffopendors at ${JSON.stringify(roomLocation)}`)

  } else {
    const fillVol = new BlockVolume(roomLocation, {
      x: roomLocation.x,
      y: roomLocation.y + 1,
      z: roomLocation.z,
    });

    OVERWORLD.fillBlocks(fillVol, fillBlock);
    console.warn(`Default to Sheet Wall at ${JSON.stringify(roomLocation)} due to INTERSECT EXTENT`);
    room.remove();

  }
}



function overlappingDoorwayCheck(room, roomLocation, roomDirection) {
  let isOverlappingDoorway = false;

  if (OVERWORLD.getBlock(roomLocation).typeId !== "minecraft:air" && OVERWORLD.getBlock(roomLocation).typeId !== "minecraft:oak_fence" ) {
    console.warn(`Room at ${JSON.stringify(roomLocation)} is inside a wall, cancelling this room`);
    isOverlappingDoorway = true;
    room.remove();
    return true;
  }

  const overlappingDoorways = OVERWORLD.getEntities({
    type: "minecraft:armor_stand",
    location: roomLocation,
    maxDistance: 2,
  });

  let inFrontLocation = roomLocation;
  let secondaryLocation = roomLocation;

  if (roomDirection == "north") {
    inFrontLocation = {
      x: roomLocation.x,
      y: roomLocation.y - 1,
      z: roomLocation.z - 1,
    };
    secondaryLocation = {
      x: roomLocation.x,
      y: roomLocation.y,
      z: roomLocation.z - 8,
    };
  } else if (roomDirection == "south") {
    inFrontLocation = {
      x: roomLocation.x,
      y: roomLocation.y - 1,
      z: roomLocation.z + 1,
    };
    secondaryLocation = {
      x: roomLocation.x,
      y: roomLocation.y,
      z: roomLocation.z + 8,
    };
  } else if (roomDirection == "east") {
    inFrontLocation = {
      x: roomLocation.x + 1,
      y: roomLocation.y - 1,
      z: roomLocation.z,
    };
    secondaryLocation = {
      x: roomLocation.x + 8,
      y: roomLocation.y,
      z: roomLocation.z,
    };
  } else if (roomDirection == "west") {
    inFrontLocation = {
      x: roomLocation.x - 1,
      y: roomLocation.y - 1,
      z: roomLocation.z,
    };
    secondaryLocation = {
      x: roomLocation.x - 8,
      y: roomLocation.y,
      z: roomLocation.z,
    };
  }

  let heightToCheck = 5;
  for (let dy = 1; dy <= heightToCheck; dy++) {
    const block = OVERWORLD.getBlock({ x: inFrontLocation.x, y: inFrontLocation.y + dy, z: inFrontLocation.z });

    if (block.typeId !== "minecraft:air") {
      ////world.sendMessage(`${JSON.stringify(inFrontLocation)} Non-air block found at ${inFrontLocation.x}, ${inFrontLocation.y + dy}, ${inFrontLocation.z}`);
      isOverlappingDoorway = false;
    }
  }

  const roomsMap = new Map(world.getDynamicProperty("rooms") ? JSON.parse(world.getDynamicProperty("rooms")) : []);

  for (const [key, { min, max }] of roomsMap.entries()) {
    const block = OVERWORLD.getBlock(inFrontLocation);
    const block2 = OVERWORLD.getBlock(secondaryLocation);

    // Check if inFrontLocation is within the bounds of min and max coordinates
    const isInVolume =
      inFrontLocation.x >= Math.min(min.x, max.x) &&
      inFrontLocation.x <= Math.max(min.x, max.x) &&
      inFrontLocation.y >= Math.min(min.y, max.y) &&
      inFrontLocation.y <= Math.max(min.y, max.y) &&
      inFrontLocation.z >= Math.min(min.z, max.z) &&
      inFrontLocation.z <= Math.max(min.z, max.z);

    if (isInVolume && block.typeId !== "minecraft:air" && block2.typeId !== "minecraft:air") {
      isOverlappingDoorway = true;

      // Log that the location is an overlapping doorway
      console.warn(`${JSON.stringify(roomLocation)} is an overlapping doorway`);
    }
  }


  if (overlappingDoorways.length > 0) {
    for (let overlapEnt of overlappingDoorways) {
      if (overlapEnt == room) {
        continue;
      }
      isOverlappingDoorway = true;
      overlapEnt.remove();
    }
  }
  if (isOverlappingDoorway == true) {
    if (room.nameTag.split("_")[0] == "hallway") {
      console.warn(`overlapping hallway`);

      hallway(room, roomLocation, roomDirection);
      //world.sendMessage(`overlapping hallway ${JSON.stringify(roomLocation)}`)
      return true;
    } else if (room.nameTag == "m_stair1" || room.nameTag == "m_stair2") {    
      room.remove()
      return true;
    } else {  
      let fillBlock = "ding:concrete_brick_wall"
      let fillAreaNS = `~-1 ~ ~ ~1 ~3 ~`
      let fillAreaEW = `~ ~ ~-1 ~ ~3 ~1`
      if (facilityType == "mansion") {
        fillBlock = "ding:mansion_wallpaper"
        fillAreaNS = `~-3 ~ ~ ~3 ~5 ~`
        fillAreaEW = `~ ~ ~-3 ~ ~5 ~3`
      }

      let doorChance = Math.random() * 100;
      if (doorChance <= 80) {
        if (roomDirection == "north" || roomDirection == "south") {
          room.runCommand(`fill ${fillAreaNS} ${fillBlock} replace air`);
          room.runCommand(`fill ${fillAreaNS} ${fillBlock} replace ding:tiny_pipe`);
          room.runCommand(`fill ${fillAreaNS} ${fillBlock} replace ding:tiny_pipe_curve`);
          room.runCommand(`fill ${fillAreaNS} ${fillBlock} replace ding:tiny_pipe_curve2`);
          room.runCommand(`fill ${fillAreaNS} ${fillBlock} replace ding:tiny_pipe_curve3`);
          room.runCommand(`fill ${fillAreaNS} ${fillBlock} replace ding:tiny_pipe_curve4`);
        }
        if (roomDirection == "east" || roomDirection == "west") {
          room.runCommand(`fill ${fillAreaEW} ${fillBlock} replace air`);
          room.runCommand(`fill ${fillAreaEW} ${fillBlock} replace ding:tiny_pipe`);
          room.runCommand(`fill ${fillAreaEW} ${fillBlock} replace ding:tiny_pipe_curve`);
          room.runCommand(`fill ${fillAreaEW} ${fillBlock} replace ding:tiny_pipe_curve2`);
          room.runCommand(`fill ${fillAreaEW} ${fillBlock} replace ding:tiny_pipe_curve3`);
          room.runCommand(`fill ${fillAreaEW} ${fillBlock} replace ding:tiny_pipe_curve4`);
        }

        let lockChance = Math.random() * 100;
        if (lockChance <= 15) {
          spawnDoor(roomLocation, "js:facility_door", roomDirection, true, null, null);
          system.runJob(spawnKey(roomLocation));
        } else {

          spawnDoor(roomLocation, "js:facility_door", roomDirection, false, null, null);
        }
        //world.sendMessage(`Locked Overlapping ${JSON.stringify(roomLocation)}`)
  
      }
      room.remove();
      return true;
    }
  }
  return false;
}

function endGeneration(shipLocation) {
  const mainLocation = {
    x: shipLocation.x,
    y: shipLocation.y - 75 - 30,
    z: shipLocation.z,
  };

  if (facilityType == "facility") {
    const main = world.structureManager.get("mystructure:mainNoEntity");
    if (!main) throw `Failed to get main structure`;
    world.structureManager.place(main, OVERWORLD, mainLocation);
  
    const entranceDoorFillStart = {
      x: shipLocation.x + 3,
      y: shipLocation.y - 75 - 30 + 15,
      z: shipLocation.z - 1,
    };
    const entranceDoorFillEnd = {
      x: shipLocation.x + 4,
      y: shipLocation.y - 75 - 30 + 16,
      z: shipLocation.z - 1,
    };
    const entranceDoorFill = new BlockVolume(entranceDoorFillStart, entranceDoorFillEnd)
    OVERWORLD.fillBlocks(entranceDoorFill, 'ding:concrete_floor')
  } else {
    const main = world.structureManager.get("mystructure:m_mainNoEntity");
    if (!main) throw `Failed to get main structure`;
    world.structureManager.place(main, OVERWORLD, mainLocation);
  
    const entranceDoorFillStart = {
      x: shipLocation.x + 12,
      y: shipLocation.y - 74 - 30,
      z: shipLocation.z - 1,
    };
    const entranceDoorFillEnd = {
      x: shipLocation.x + 11,
      y: shipLocation.y - 73 - 30,
      z: shipLocation.z - 1,
    };
    const entranceDoorFill = new BlockVolume(entranceDoorFillStart, entranceDoorFillEnd)
    OVERWORLD.fillBlocks(entranceDoorFill, 'ding:mansion_wallpaper')
  }

  

  //fill 2003 4 -1 2004 5 -1 ding:concrete_floor

  const remainingRooms = OVERWORLD.getEntities({
    location: shipLocation,
    maxDistance: 500,
    type: "minecraft:armor_stand",
  });

  for (let room of remainingRooms) {
    if (!room) continue
    const rotation = room.getRotation().y;
    const roomLocation = room.location;
    let roomDirection = "north";
    if (rotation === -180) {
      roomDirection = "north";
    }
    if (rotation === 90) {
      roomDirection = "west";
    }
    if (rotation === -90) {
      roomDirection = "east";
    }
    if (rotation === 0) {
      roomDirection = "south";
    }

    const isOverlapping = overlappingDoorwayCheck(room, roomLocation, roomDirection);
    if (isOverlapping == true) continue;

    let inFrontLocation = roomLocation
    if (roomDirection == "north") {
      inFrontLocation = {
        x: roomLocation.x,
        y: roomLocation.y,
        z: roomLocation.z - 1,
      };
    } else if (roomDirection == "south") {
      inFrontLocation = {
        x: roomLocation.x,
        y: roomLocation.y,
        z: roomLocation.z + 1,
      };
    } else if (roomDirection == "east") {
      inFrontLocation = {
        x: roomLocation.x + 1,
        y: roomLocation.y,
        z: roomLocation.z,
      };
    } else if (roomDirection == "west") {
      inFrontLocation = {
        x: roomLocation.x - 1,
        y: roomLocation.y,
        z: roomLocation.z,
      };
    }
    const blockInFront = OVERWORLD.getBlock(inFrontLocation);

    const roomsMap = new Map(
      world.getDynamicProperty("rooms") ? JSON.parse(world.getDynamicProperty("rooms")) : []
    );

    let blockInsideRoom = false; 
    let blockInsideRoomName;

    for (const [key, { min, max }] of roomsMap.entries()) {
      const intersects =
        blockInFront.x >= min.x && blockInFront.x <= max.x &&
        blockInFront.y >= min.y && blockInFront.y <= max.y &&
        blockInFront.z >= min.z && blockInFront.z <= max.z;

      if (intersects) {
        blockInsideRoom = true;
        blockInsideRoomName = key.split('_')[0]
        break; 
      }
    }

    if (blockInsideRoom == false) {
      let fillBlock = "ding:concrete_brick_wall"
      let fillAreaNS = `~-1 ~ ~ ~1 ~3 ~`
      let fillAreaEW = `~ ~ ~-1 ~ ~3 ~1`
      if (facilityType == "mansion") {
        fillBlock = "ding:mansion_wall"
        fillAreaNS = `~-3 ~ ~ ~3 ~5 ~`
        fillAreaEW = `~ ~ ~-3 ~ ~5 ~3`
      }

      if (roomDirection == "north" || roomDirection == "south") {
        room.runCommand(`fill ${fillAreaNS} ${fillBlock} replace air`);
        room.runCommand(`fill ${fillAreaNS} ${fillBlock} replace ding:tiny_pipe`);
        room.runCommand(`fill ${fillAreaNS} ${fillBlock} replace ding:tiny_pipe_curve`);
        room.runCommand(`fill ${fillAreaNS} ${fillBlock} replace ding:tiny_pipe_curve2`);
        room.runCommand(`fill ${fillAreaNS} ${fillBlock} replace ding:tiny_pipe_curve3`);
        room.runCommand(`fill ${fillAreaNS} ${fillBlock} replace ding:tiny_pipe_curve4`);
      }
      if (roomDirection == "east" || roomDirection == "west") {
        room.runCommand(`fill ${fillAreaEW} ${fillBlock} replace air`);
        room.runCommand(`fill ${fillAreaEW} ${fillBlock} replace ding:tiny_pipe`);
        room.runCommand(`fill ${fillAreaEW} ${fillBlock} replace ding:tiny_pipe_curve`);
        room.runCommand(`fill ${fillAreaEW} ${fillBlock} replace ding:tiny_pipe_curve2`);
        room.runCommand(`fill ${fillAreaEW} ${fillBlock} replace ding:tiny_pipe_curve3`);
        room.runCommand(`fill ${fillAreaEW} ${fillBlock} replace ding:tiny_pipe_curve4`);
      }
      room.remove();
      continue;
    };


    if (room.nameTag == "hallway_doorway") {
      if (roomDirection == "north" || roomDirection == "south") {
        room.runCommand(`fill ~-1 ~ ~ ~1 ~3 ~ glass`);
      }
      if (roomDirection == "east" || roomDirection == "west") {
        room.runCommand(`fill ~ ~ ~-1 ~ ~3 ~1 glass`);
      }
      room.runCommand(`fill ~ ~ ~ ~ ~1 ~ air`);
      room.remove();
    } else if (room.nameTag == "hallway") {
      if (blockInsideRoom && blockInsideRoomName.split('_')[0] == "hallway") {
          // //world.sendMessage(`not filling this ${JSON.stringify(room.location)}`)
          room.remove();
      } else {
        if (roomDirection == "north") {
          room.runCommand(`fill ~-1 ~ ~2 ~1 ~3 ~2 ding:concrete_brick_wall`);
          room.runCommand(`fill ~-1 ~ ~ ~1 ~3 ~ ding:concrete_brick_wall`);
        }
        if (roomDirection == "south") {
          room.runCommand(`fill ~-1 ~ ~-2 ~1 ~3 ~-2 ding:concrete_brick_wall`);
          room.runCommand(`fill ~-1 ~ ~ ~1 ~3 ~ ding:concrete_brick_wall`);
        }
        if (roomDirection == "east") {
          room.runCommand(`fill ~-2 ~ ~-1 ~-2 ~3 ~1 ding:concrete_brick_wall`);
          room.runCommand(`fill ~ ~ ~-1 ~ ~3 ~1 ding:concrete_brick_wall`);
        }
        if (roomDirection == "west") {
          room.runCommand(`fill ~2 ~ ~-1 ~2 ~3 ~1 ding:concrete_brick_wall`);
          room.runCommand(`fill ~ ~ ~-1 ~ ~3 ~1 ding:concrete_brick_wall`);
        }
        room.remove();
      }
    } else if (room.nameTag == "3x2apparatus") {
      let doorChance = Math.random() * 100;
      if (doorChance <= 80) {
        spawnDoor(roomLocation, "js:facility_door", roomDirection, true, null, null);
        system.runJob(spawnKey(room.location));
      } else {
        spawnDoor(roomLocation, "js:facility_door", roomDirection, false, null, null);
      }
      room.remove();
    } else if (room.nameTag !== "hallway" && room.nameTag !== "hallway_doorway" && room.nameTag !== "3x2apparatus") {

      
      let fillBlock = "ding:sheet_wall"
      if (facilityType == "mansion") {
        fillBlock = "ding:mansion_wallpaper"
      }

      room.runCommand(`fill ~ ~ ~ ~ ~1 ~ ${fillBlock}`);
      room.remove();
    } else if (room.nameTag == "m_hallway_2" || room.nameTag == "m_stair1" || room.nameTag == "m_stair2") {

      if (roomDirection == "north" || roomDirection == "south") {
        room.runCommand(`fill ~-4 ~ ~ ~4 ~ ~ ding:mansion_wallpaper_bottom replace air`)
        room.runCommand(`fill ~-4 ~ ~ ~4 ~6 ~ ding:mansion_wallpaper replace air`)
      } 
      if (roomDirection == "east" || roomDirection == "west") {
        room.runCommand(`fill ~ ~ ~-4 ~ ~ ~4 ding:mansion_wallpaper_bottom replace air`)
        room.runCommand(`fill ~ ~ ~-4 ~ ~6 ~4 ding:mansion_wallpaper replace air`)
      } 
      room.remove()
      //world.sendMessage(`close endgen at ${JSON.stringify(roomLocation)}`)
    }
  }
}

function hallway(room, roomLocation, roomDirection) {
  if (room.nameTag == "hallway_doorway") {
    const mazeDoors = OVERWORLD.getEntities({
      location: roomLocation,
      maxDistance: 18,
      type: "minecraft:armor_stand",
      name: "hallway_doorway",
    });
    if (mazeDoors) {
      for (let mazeDoor of mazeDoors) {
        let doorChance = Math.random() * 100;

        if (doorChance <= 20) {
          if (roomDirection == "north" || roomDirection == "south") {
            room.runCommand(`fill ~-1 ~ ~ ~1 ~3 ~ glass`);
          }
          if (roomDirection == "east" || roomDirection == "west") {
            room.runCommand(`fill ~ ~ ~-1 ~ ~3 ~1 glass`);
          }
          room.runCommand(`fill ~ ~ ~ ~ ~1 ~ air`);
          room.remove();
        }
      }
    }
  } else {
    
    let fillBlock = "ding:concrete_brick_wall"
    let fillAreaNS = `~-1 ~ ~ ~1 ~3 ~`
    let fillAreaEW = `~ ~ ~-1 ~ ~3 ~1`
    if (facilityType == "mansion") {
      fillBlock = "ding:mansion_wallpaper"
      fillAreaNS = `~-3 ~ ~ ~3 ~5 ~`
      fillAreaEW = `~ ~ ~-3 ~ ~5 ~3`
    }

    let doorChance = Math.random() * 100;
    if (doorChance <= 80) {
      if (roomDirection == "north" || roomDirection == "south") {
        room.runCommand(`fill ${fillAreaNS} ${fillBlock} replace air`);
        room.runCommand(`fill ${fillAreaNS} ${fillBlock} replace ding:tiny_pipe`);
        room.runCommand(`fill ${fillAreaNS} ${fillBlock} replace ding:tiny_pipe_curve`);
        room.runCommand(`fill ${fillAreaNS} ${fillBlock} replace ding:tiny_pipe_curve2`);
        room.runCommand(`fill ${fillAreaNS} ${fillBlock} replace ding:tiny_pipe_curve3`);
        room.runCommand(`fill ${fillAreaNS} ${fillBlock} replace ding:tiny_pipe_curve4`);
      }
      if (roomDirection == "east" || roomDirection == "west") {
        room.runCommand(`fill ${fillAreaEW} ${fillBlock} replace air`);
        room.runCommand(`fill ${fillAreaEW} ${fillBlock} replace ding:tiny_pipe`);
        room.runCommand(`fill ${fillAreaEW} ${fillBlock} replace ding:tiny_pipe_curve`);
        room.runCommand(`fill ${fillAreaEW} ${fillBlock} replace ding:tiny_pipe_curve2`);
        room.runCommand(`fill ${fillAreaEW} ${fillBlock} replace ding:tiny_pipe_curve3`);
        room.runCommand(`fill ${fillAreaEW} ${fillBlock} replace ding:tiny_pipe_curve4`);
      }
      let lockChance = Math.random() * 100;
      let locked = false
      if (lockChance <= 15) {
        locked = true
        system.runJob(spawnKey(roomLocation));
      }

      const doorsMap = new Map(
        world.getDynamicProperty("doors") ? JSON.parse(world.getDynamicProperty("doors")) : []
      );
      const key = `Door_${Date.now()}`;

      doorsMap.set(key, { roomLocation, roomDirection, locked });
      world.setDynamicProperty("doors", JSON.stringify([...doorsMap]));

      //world.sendMessage(`hallway door ${JSON.stringify(room.location)}`)
    }
    room.remove();
  }
}

function hallwayCutoff(room, roomLocation, roomDirection) {

  
  let fillBlock = "ding:concrete_brick_wall"
  if (facilityType == "mansion") {
    fillBlock = "ding:mansion_wallpaper"
    if (roomDirection == "north") {
      room.runCommand(`fill ~-3 ~ ~2 ~3 ~5 ~2 ${fillBlock} replace air`);
      room.runCommand(`fill ~-3 ~ ~ ~3 ~5 ~ ${fillBlock} replace air`);

      room.runCommand(`fill ~-3 ~ ~2 ~3 ~5 ~2 ${fillBlock} replace ding:tiny_pipe`);
      room.runCommand(`fill ~-3 ~ ~ ~3 ~5 ~ ${fillBlock} replace ding:tiny_pipe`);

      room.runCommand(`fill ~-3 ~ ~2 ~3 ~5 ~2 ${fillBlock} replace ding:tiny_pipe_curve`);
      room.runCommand(`fill ~-3 ~ ~ ~3 ~5 ~ ${fillBlock} replace ding:tiny_pipe_curve`);
      room.runCommand(`fill ~-3 ~ ~2 ~3 ~5 ~2 ${fillBlock} replace ding:tiny_pipe_curve2`);
      room.runCommand(`fill ~-3 ~ ~ ~3 ~5 ~ ${fillBlock} replace ding:tiny_pipe_curve2`);
      room.runCommand(`fill ~-3 ~ ~2 ~3 ~5 ~2 ${fillBlock} replace ding:tiny_pipe_curve3`);
      room.runCommand(`fill ~-3 ~ ~ ~3 ~5 ~ ${fillBlock} replace ding:tiny_pipe_curve3`);
      room.runCommand(`fill ~-3 ~ ~2 ~3 ~5 ~2 ${fillBlock} replace ding:tiny_pipe_curve4`);
      room.runCommand(`fill ~-3 ~ ~ ~3 ~5 ~ ${fillBlock} replace ding:tiny_pipe_curve4`);
    }
    if (roomDirection == "south") {
      room.runCommand(`fill ~-3 ~ ~-2 ~3 ~5 ~-2 ${fillBlock} replace air`);
      room.runCommand(`fill ~-3 ~ ~ ~3 ~5 ~ ${fillBlock} replace air`);
      
      room.runCommand(`fill ~-3 ~ ~-2 ~3 ~5 ~-2 ${fillBlock} replace ding:tiny_pipe`);
      room.runCommand(`fill ~-3 ~ ~ ~3 ~5 ~ ${fillBlock} replace ding:tiny_pipe`);
      
      room.runCommand(`fill ~-3 ~ ~-2 ~3 ~5 ~-2 ${fillBlock} replace ding:tiny_pipe_curve`);
      room.runCommand(`fill ~-3 ~ ~ ~3 ~5 ~ ${fillBlock} replace ding:tiny_pipe_curve`);
      
      room.runCommand(`fill ~-3 ~ ~-2 ~3 ~5 ~-2 ${fillBlock} replace ding:tiny_pipe_curve2`);
      room.runCommand(`fill ~-3 ~ ~ ~3 ~5 ~ ${fillBlock} replace ding:tiny_pipe_curve2`);
      
      room.runCommand(`fill ~-3 ~ ~-2 ~3 ~5 ~-2 ${fillBlock} replace ding:tiny_pipe_curve3`);
      room.runCommand(`fill ~-3 ~ ~ ~3 ~5 ~ ${fillBlock} replace ding:tiny_pipe_curve3`);
      
      room.runCommand(`fill ~-3 ~ ~-2 ~3 ~5 ~-2 ${fillBlock} replace ding:tiny_pipe_curve4`);
      room.runCommand(`fill ~-3 ~ ~ ~3 ~5 ~ ${fillBlock} replace ding:tiny_pipe_curve4`);
    }
    if (roomDirection == "east") {
      room.runCommand(`fill ~-2 ~ ~-3 ~-2 ~5 ~3 ${fillBlock} replace air`);
      room.runCommand(`fill ~ ~ ~-3 ~ ~5 ~3 ${fillBlock} replace air`);
      
      room.runCommand(`fill ~-2 ~ ~-3 ~-2 ~5 ~3 ${fillBlock} replace ding:tiny_pipe`);
      room.runCommand(`fill ~ ~ ~-3 ~ ~5 ~3 ${fillBlock} replace ding:tiny_pipe`);
      room.runCommand(`fill ~-2 ~ ~-3 ~-2 ~5 ~3 ${fillBlock} replace ding:tiny_pipe_curve`);
      room.runCommand(`fill ~ ~ ~-3 ~ ~5 ~3 ${fillBlock} replace ding:tiny_pipe_curve`);
      room.runCommand(`fill ~-2 ~ ~-3 ~-2 ~5 ~3 ${fillBlock} replace ding:tiny_pipe_curve2`);
      room.runCommand(`fill ~ ~ ~-3 ~ ~5 ~3 ${fillBlock} replace ding:tiny_pipe_curve2`);
      room.runCommand(`fill ~-2 ~ ~-3 ~-2 ~5 ~3 ${fillBlock} replace ding:tiny_pipe_curve3`);
      room.runCommand(`fill ~ ~ ~-3 ~ ~5 ~3 ${fillBlock} replace ding:tiny_pipe_curve3`);
      room.runCommand(`fill ~-2 ~ ~-3 ~-2 ~5 ~3 ${fillBlock} replace ding:tiny_pipe_curve4`);
      room.runCommand(`fill ~ ~ ~-3 ~ ~5 ~3 ${fillBlock} replace ding:tiny_pipe_curve4`);
    }
    if (roomDirection == "west") {
      room.runCommand(`fill ~2 ~ ~-3 ~2 ~5 ~3 ${fillBlock} replace air`);
      room.runCommand(`fill ~ ~ ~-3 ~ ~5 ~3 ${fillBlock} replace air`);

      room.runCommand(`fill ~2 ~ ~-3 ~2 ~5 ~3 ${fillBlock} replace ding:tiny_pipe`);
      room.runCommand(`fill ~ ~ ~-3 ~ ~5 ~3 ${fillBlock} replace ding:tiny_pipe`);

      room.runCommand(`fill ~2 ~ ~-3 ~2 ~5 ~3 ${fillBlock} replace ding:tiny_pipe_curve`);
      room.runCommand(`fill ~ ~ ~-3 ~ ~5 ~3 ${fillBlock} replace ding:tiny_pipe_curve`);

      room.runCommand(`fill ~2 ~ ~-3 ~2 ~5 ~3 ${fillBlock} replace ding:tiny_pipe_curve2`);
      room.runCommand(`fill ~ ~ ~-3 ~ ~5 ~3 ${fillBlock} replace ding:tiny_pipe_curve2`);

      room.runCommand(`fill ~2 ~ ~-3 ~2 ~5 ~3 ${fillBlock} replace ding:tiny_pipe_curve3`);
      room.runCommand(`fill ~ ~ ~-3 ~ ~5 ~3 ${fillBlock} replace ding:tiny_pipe_curve3`);

      room.runCommand(`fill ~2 ~ ~-3 ~2 ~5 ~3 ${fillBlock} replace ding:tiny_pipe_curve4`);
      room.runCommand(`fill ~ ~ ~-3 ~ ~5 ~3 ${fillBlock} replace ding:tiny_pipe_curve4`);
    }
  } else {
    fillBlock = "ding:concrete_brick_wall"
    if (roomDirection == "north") {
      room.runCommand(`fill ~-1 ~ ~2 ~1 ~3 ~2 ding:concrete_brick_wall`);
      room.runCommand(`fill ~-1 ~ ~ ~1 ~3 ~ ding:concrete_brick_wall`);
    }
    if (roomDirection == "south") {
      room.runCommand(`fill ~-1 ~ ~-2 ~1 ~3 ~-2 ding:concrete_brick_wall`);
      room.runCommand(`fill ~-1 ~ ~ ~1 ~3 ~ ding:concrete_brick_wall`);
    }
    if (roomDirection == "east") {
      room.runCommand(`fill ~-2 ~ ~-1 ~-2 ~3 ~1 ding:concrete_brick_wall`);
      room.runCommand(`fill ~ ~ ~-1 ~ ~3 ~1 ding:concrete_brick_wall`);
    }
    if (roomDirection == "west") {
      room.runCommand(`fill ~2 ~ ~-1 ~2 ~3 ~1 ding:concrete_brick_wall`);
      room.runCommand(`fill ~ ~ ~-1 ~ ~3 ~1 ding:concrete_brick_wall`);
    }
  }
  room.remove();
}

//Place Tile and add volume
function* placeTile(location, tile, direction) {
  console.warn(direction);
  let placementLocation = {
    x: 0,
    y: 0,
    z: 0,
  };
  let placementDirection = "None";

  let structure = "mystructure:" + tile

  let endCorner = { x: 0, y: 0, z: 0 };
  if (direction == "north") {
    placementLocation.x = location.x + TILES[tile].north.offset.x;
    placementLocation.y = location.y + TILES[tile].north.offset.y;
    placementLocation.z = location.z + TILES[tile].north.offset.z;
    placementDirection = "Rotate180";

    endCorner.x = placementLocation.x + TILES[tile].north.size.x - 1;
    endCorner.y = placementLocation.y + TILES[tile].north.size.y - 1;
    endCorner.z = placementLocation.z + TILES[tile].north.size.z - 1;
  } else if (direction == "east") {
    placementLocation.x = location.x + TILES[tile].east.offset.x;
    placementLocation.y = location.y + TILES[tile].east.offset.y;
    placementLocation.z = location.z + TILES[tile].east.offset.z;
    placementDirection = "Rotate270";

    endCorner.x = placementLocation.x + TILES[tile].east.size.x - 1;
    endCorner.y = placementLocation.y + TILES[tile].east.size.y - 1;
    endCorner.z = placementLocation.z + TILES[tile].east.size.z - 1;
  } else if (direction == "south") {
    placementLocation.x = location.x + TILES[tile].south.offset.x;
    placementLocation.y = location.y + TILES[tile].south.offset.y;
    placementLocation.z = location.z + TILES[tile].south.offset.z;
    placementDirection = "None";

    endCorner.x = placementLocation.x + TILES[tile].south.size.x - 1;
    endCorner.y = placementLocation.y + TILES[tile].south.size.y - 1;
    endCorner.z = placementLocation.z + TILES[tile].south.size.z - 1;
  } else if (direction == "west") {
    placementLocation.x = location.x + TILES[tile].west.offset.x;
    placementLocation.y = location.y + TILES[tile].west.offset.y;
    placementLocation.z = location.z + TILES[tile].west.offset.z;
    placementDirection = "Rotate90";

    endCorner.x = placementLocation.x + TILES[tile].west.size.x - 1;
    endCorner.y = placementLocation.y + TILES[tile].west.size.y - 1;
    endCorner.z = placementLocation.z + TILES[tile].west.size.z - 1;
  }
  const startCorner = placementLocation;

  console.warn(`Placing at ${JSON.stringify(placementLocation)} in direction ${placementDirection}`);

  // //world.sendMessage(`Placing tile ${tile}`)

  const roomsMap = new Map(world.getDynamicProperty("rooms") ? JSON.parse(world.getDynamicProperty("rooms")) : []);
  const key = `${tile}_${Date.now()}`;

  const min = startCorner
  const max = endCorner
  roomsMap.set(key, { min, max });

  console.warn(`Map ${JSON.stringify([...roomsMap])}`)

  world.setDynamicProperty("rooms", JSON.stringify([...roomsMap]));

  const rand = Math.random() * 100
  if (structure == "mystructure:m_3x2bigroom1") {
    if (rand < 50) {
      structure += "a"
    }
  }
  if (structure == "mystructure:m_hallway_x") {
    if (rand < 25) {
      structure += "a"
    } else if (rand >= 25 && rand < 50) {
      structure += "b"
    } else if (rand >= 50 && rand < 75) {
      structure += "c"
    }
  }
  if (structure == "mystructure:hallway" || structure == "mystructure:hallway_lt" || structure == "mystructure:hallway_rt" || structure == "mystructure:hallway_t" || structure == "mystructure:hallway_x" || structure == "mystructure:hallway_big_x") {
    if (rand <= 33) {
      structure += "2"
    }
    if (rand > 33 && rand <= 66) {
      structure += "3"
    }
  }

  const structureName = world.structureManager.get(structure);
  
  world.structureManager.place(structureName, OVERWORLD, placementLocation, {
    rotation: placementDirection,
  });

  const moonId = world.getDynamicProperty("moon");
  let shipLocation = { x: 0, y: -60, z: 0 };

  for (const key of Object.keys(MAPS)) {
    if (MAPS[key].id === moonId) {
      shipLocation = MAPS[key].shipLocation;
      break;
    }
  }

  const dist = getDistanceXZ(placementLocation, shipLocation)
  // world.sendMessage(`Dist ${dist}`)
  if (dist > 64) {
    const worldTicker = OVERWORLD.spawnEntity('js:world_ticker', { 
      x: placementLocation.x,
      y: placementLocation.y - 10,
      z: placementLocation.z
    })
    // world.sendMessage(`world ticker ar ${placementLocation}`)
  }


  if (tile == "3x3apparatus" || tile == "3x2apparatus") {
    let currentApparatus = world.getDynamicProperty("apparatus");
    if (currentApparatus == 0) {
      let apparatusStructure = structure + "_hold";
      if (structure == "mystructure:3x2apparatus") {
        let appChance = Math.random() * 100;

        if (appChance <= 50) {
          let chance = Math.random() * 100;

          if (chance <= 50) {
            apparatusStructure = structure + "_hold2";
          }

          ////world.sendMessage(`Apparatus: ${apparatusStructure}`)

          const structureName2 = world.structureManager.get(apparatusStructure);
          world.setDynamicProperty("apparatus", currentApparatus + 1);

          world.structureManager.place(structureName2, OVERWORLD, placementLocation, {
            rotation: placementDirection,
          });
        }
      }
      if (structure == "mystructure:3x3apparatus") {
        let chance = Math.random() * 100;

        if (chance <= 50) {
          ////world.sendMessage(`Apparatus: ${apparatusStructure}`)

          delete tileSet["3x2apparatus"];
          console.warn(`Removed "3x2apparatus" from tileSet`);
          console.warn(`New Tile Set: ${JSON.stringify(tileSet)}`);

          const structureName2 = world.structureManager.get(apparatusStructure);
          world.setDynamicProperty("apparatus", currentApparatus + 1);

          world.structureManager.place(structureName2, OVERWORLD, placementLocation, {
            rotation: placementDirection,
          });
        }
      }
    }
  }
}


function getDistanceXZ(loc1, loc2) {
  const dx = loc2.x - loc1.x; // Difference in X coordinates
  const dz = loc2.z - loc1.z; // Difference in Z coordinates
  return Math.sqrt(dx * dx + dz * dz); // Euclidean distance
}



function* spawnScrap(mapName, mainLocation) {
  // const primarySpawners = OVERWORLD.getEntities({ location: mainLocation, maxDistance: 500, type: "js:primary_scrap_spawner" });
  let primarySpawners = [
    ...OVERWORLD.getEntities({ location: mainLocation, maxDistance: 500, type: "js:primary_scrap_spawner" }),
    ...OVERWORLD.getEntities({ location: mainLocation, maxDistance: 500, type: "js:table_top_spawner" }),
  ];
  
  // Shuffle the spawners to randomize the order
  for (let i = primarySpawners.length - 1; i > 0; i--) {
    const randomIndex = Math.floor(Math.random() * (i + 1));
    [primarySpawners[i], primarySpawners[randomIndex]] = [primarySpawners[randomIndex], primarySpawners[i]];
  }
  
  yield;
  
  const spawnersList = [...primarySpawners];
  
  // const minDistance = 0; // Minimum distance between entities
  const spawnedLocations = [];
  //  let totalScrapPossible = 0;

  // Define spawn parameters for scrap, mines, and turrets
  const spawnConfigurations = [
    {
      type: "scrap",
      minAmount: MAPS[mapName].scrap.min,
      maxAmount: MAPS[mapName].scrap.max,
      spawnEntity: function* (x, y, z) {
        const lootTable = MOON_LOOT_TABLE[mapName];
        const totalWeight = Object.values(lootTable).reduce((sum, weight) => sum + weight, 0);
        const random = Math.random() * totalWeight;
        let accumulatedPercentage = 0;
        let selectedScrap;

        for (const scrap in lootTable) {
          accumulatedPercentage += lootTable[scrap];
          if (random <= accumulatedPercentage) {
            selectedScrap = scrap;
            yield;
            break;
          }
        }
        if (selectedScrap) {
          const minValue = ITEM_LIST[selectedScrap].value[0];
          const maxValue = ITEM_LIST[selectedScrap].value[1];

          // const randomScrapValue = Math.floor(Math.random() * (maxValue - minValue + 1)) + minValue;
          const bias = 2; // Higher = more low values, Lower (<1) = more high values
          const skewed = Math.pow(Math.random(), bias);
          const randomScrapValue = Math.floor(skewed * (maxValue - minValue + 1)) + minValue;          


          const selectedScrapId = selectedScrap + "_ent";
          const scrap = OVERWORLD.spawnEntity(selectedScrapId, { x: x + 0.5, y: y + 1, z: z + 0.5 });

          const randomRot = Math.random() * 360;
          scrap.setRotation({ x: 0, y: randomRot });
          scrap.setDynamicProperty("scrapValue", randomScrapValue);
          // totalScrapPossible += randomScrapValue;

          // console.warn(`Total Scrap Possible ${totalScrapPossible}`)
          return { x, y, z };
        }
        return null;
      },
    },
    {
      type: "mine",
      minAmount: MAPS[mapName].hazards.mines.min,
      maxAmount: MAPS[mapName].hazards.mines.max,
      avgAmount: MAPS[mapName].hazards.mines.avg,
      spawnEntity: function* (x, y, z) {
        OVERWORLD.spawnEntity("js:mine", { x: x + 0.5, y: y + 1, z: z + 0.5 });
        return { x, y, z };
      },
    },
    {
      type: "spike_trap",
      minAmount: MAPS[mapName].hazards.spike_traps.min,
      maxAmount: MAPS[mapName].hazards.spike_traps.max,
      avgAmount: MAPS[mapName].hazards.spike_traps.avg,
      spawnEntity: function* (x, y, z) {
        OVERWORLD.spawnEntity("js:spike_trap", { x: x + 0.5, y: y + 1, z: z + 0.5 });
        return { x, y, z };
      },
    },
    {
      type: "turret",
      minAmount: MAPS[mapName].hazards.turrets.min,
      maxAmount: MAPS[mapName].hazards.turrets.max,
      avgAmount: MAPS[mapName].hazards.turrets.avg,
      spawnEntity: function* (x, y, z) {
        // Generate a unique ID for the turret
        const generateTurretId = () => {
          const letters = "abcdefghijklmnopqrstuvwxyz";
          const numbers = "0123456789";

          // Randomly pick one letter and one number
          const randomLetter = letters[Math.floor(Math.random() * letters.length)];
          const randomNumber = numbers[Math.floor(Math.random() * numbers.length)];
          return randomLetter + randomNumber;
        };

        const dynamicPropertyKey = "turretIds"; // Dynamic property to store all used turret IDs
        const turretIdMap = new Map(
          world.getDynamicProperty(dynamicPropertyKey)
            ? JSON.parse(world.getDynamicProperty(dynamicPropertyKey))
            : []
        );

        let turretId;
        do {
          turretId = generateTurretId(); // Generate new ID
        } while (turretIdMap.has(turretId)); // Ensure the ID is unique

        turretIdMap.set(turretId, true); // Add the ID to the map
        world.setDynamicProperty(dynamicPropertyKey, JSON.stringify([...turretIdMap])); // Save back to world property

        // Spawn the turret
        const turret = OVERWORLD.spawnEntity("js:turret", { x: x + 0.5, y: y + 1, z: z + 0.5 });

        // Assign the unique ID to the turret
        turret.setDynamicProperty("id", turretId);
        console.warn(`Turret spawned at (${x}, ${y}, ${z}) with ID: ${turretId}`);
        // world.sendMessage(`Turret spawned at (${x}, ${y}, ${z}) with ID: ${turretId}`);

        return { x, y, z };
      },
    },

  ];

  const shelfBlocks = [
    "ding:shelf_empty",
    "ding:shelf_collision",
    "ding:shelf_bluetote",
    "ding:shelf_bottles",
    "ding:shelf_bottles2",
    "ding:shelf_box",
    "ding:shelf_graytote",
    "ding:shelf_redtote",
    "ding:shelf_tarp",
    "ding:shelf_yellowtote",
    "minecraft:quartz_pillar",
    "ding:mansion_kitchen_floor",
    "ding:mansion_table"
  ];
  const roomsMap = new Map(
    world.getDynamicProperty("rooms") ? JSON.parse(world.getDynamicProperty("rooms")) : []
  );

  let mainDoorLocation = {
    x: mainLocation.x + 3.99,
    y: mainLocation.y + 75 - 60,
    z: mainLocation.z + 1.8,
  };

  if (world.getDynamicProperty('facilityType') == "mansion") {
    mainDoorLocation = {
      x: mainLocation.x + 12.0,
      y: mainLocation.y + 75 - 74,
      z: mainLocation.z + 1.5,
    };
  }
  
  for (const config of spawnConfigurations) {
    let spawnAmount = config.avgAmount
      ? Math.floor(generateRandomWithAverage(config.minAmount, config.maxAmount, config.avgAmount))
      : Math.floor(Math.random() * (config.maxAmount - config.minAmount + 1)) + config.minAmount;
  
    let successfullySpawned = 0; // Counter to track successfully spawned entities
    // world.sendMessage(`Spawn Amount for ${config.type}: ${spawnAmount}`);
  
    let retryAttempts = 0; // Total retry attempts across all spawners
  
    while (spawnAmount > 0 && retryAttempts < 5) {
      let spawnerIndex = 0; // Tracks current spawner
      retryAttempts++; // Increment retry count
  
      while (spawnerIndex < spawnersList.length && spawnAmount > 0) {
        let spawner = spawnersList[spawnerIndex];
        spawnerIndex++; // Move to the next spawner for retries
  
        let spawnRadius = spawner.typeId === "js:table_top_spawner" ? 4 : SCRAP_SPAWNERS[spawner.nameTag] ?? 6;
        let validBlocks = spawner.typeId === "js:table_top_spawner" ? shelfBlocks : SPAWNABLE_BLOCKS;
  
        let entitySpawned = false;
        let iterationCount = 0;
  
        while (!entitySpawned && iterationCount < 450) {
          iterationCount++;
  
          const randomX =
            Math.floor(spawner.location.x) + Math.floor(Math.random() * (2 * spawnRadius + 1)) - spawnRadius;
          const randomZ =
            Math.floor(spawner.location.z) + Math.floor(Math.random() * (2 * spawnRadius + 1)) - spawnRadius;
          const randomY = Math.floor(spawner.location.y) + Math.floor(Math.random() * 10) - 5;
  
          const block = OVERWORLD.getBlock({ x: randomX, y: randomY, z: randomZ });
          const blockAbove = OVERWORLD.getBlock({ x: randomX, y: randomY + 1, z: randomZ });
  
          if (!block || !validBlocks.includes(block.typeId) || blockAbove.typeId !== "minecraft:air") continue;
          
          if (config.type == "turret") {
            const distance = getDistance({x:randomX, y: randomY, z: randomZ}, mainDoorLocation)
            // world.sendMessage(`Turret config ${distance}`)
            if (distance < 12) {
              // world.sendMessage(`Targetted near main, continuin`)
              continue;
            }
          }

          if (
            spawner.typeId === "js:table_top_spawner" &&
            (blockAbove.typeId !== "minecraft:air" || !shelfBlocks.includes(block.typeId))
          ) {
            continue;
          }
  
          // Check if block is inside a room
          let isInsideRoom = false;
          for (const [key, { min, max }] of roomsMap.entries()) {
            const isInVolume =
              block.location.x >= Math.min(min.x + 1, max.x - 1) &&
              block.location.x <= Math.max(min.x + 1, max.x - 1) &&
              block.location.y + 1 >= Math.min(min.y + 1, max.y - 1) &&
              block.location.y + 1 <= Math.max(min.y + 1, max.y - 1) &&
              block.location.z >= Math.min(min.z + 1, max.z - 1) &&
              block.location.z <= Math.max(min.z + 1, max.z - 1);
          
            if (isInVolume) {
              isInsideRoom = true;
              break;
            }
          }
          
  
          if (!isInsideRoom) continue;

  
          // Try to spawn entity
          const newLoc = yield* config.spawnEntity(randomX, randomY, randomZ);
          if (newLoc) {
            spawnedLocations.push(newLoc);
            entitySpawned = true;
            spawnAmount--;
            successfullySpawned++;
            console.warn(
              `${config.type} spawned successfully at (${randomX}, ${randomY}, ${randomZ}). Remaining: ${spawnAmount}`
            );
          }
        }
  
        if (!entitySpawned) {
          console.warn(
            `Max iterations reached for spawner (${spawner.nameTag}) without spawning ${config.type}. Retrying other spawners...`
          );
        }
      }
  
      if (spawnAmount > 0) {
        console.warn(`Retry attempt ${retryAttempts} complete. Remaining: ${spawnAmount}`);
      }
    }
  
    // world.sendMessage(
    //   `For ${config.type}, successfully spawned: ${successfullySpawned}`
    // );
  }
  
  
  

  console.warn(`Removing spawners`);
  // Remove all spawners after spawning is complete
  for (const spawner of primarySpawners) {
    spawner.remove();
  }

  const allScrap = OVERWORLD.getEntities({ location: mainLocation, maxDistance: 500, families: ["scrap"] });

  for (let scrap of allScrap) {
    if (scrap.typeId == "js:key_ent") continue;
    let value = scrap.getDynamicProperty("scrapValue") ?? 0;

    if (scrap.typeId == "js:apparatus_ent") {
      ////world.sendMessage(`app ${value}`)
      scrap.setDynamicProperty("scrapValue", 80);
      scrap.setDynamicProperty("collected", false);
      value = 80;
    }
    let currentTotalScrapPossible = world.getDynamicProperty("totalScrapPossible");
    world.setDynamicProperty("totalScrapPossible", currentTotalScrapPossible + value);
    // console.warn(world.getDynamicProperty('totalScrapPossible'))
  }

  console.warn(`Generation fully complete`);
  world.setDynamicProperty("generationPercentage", 0);
  console.warn(`TOTAL SCRAP ${world.getDynamicProperty('totalScrapPossible')}`)
  
  worldPlayers.forEach((player) => {
    player.camera.fade({
      fadeTime: { fadeInTime: 0.25, holdTime: 0.5, fadeOutTime: 0.25 },
    });
    player.uiManager.updateGenerationPercent(0)
  });
  system.runTimeout(() => {
     shipEntity.runCommand(`scriptevent js:shipEnter 1`);
  }, 0.3 * 20)
}

function isInsideRoom(location, roomsMap) {
  for (const [, { min, max }] of roomsMap.entries()) {
    if (
      location.x >= Math.min(min.x, max.x) &&
      location.x <= Math.max(min.x, max.x) &&
      location.y >= Math.min(min.y, max.y) &&
      location.y <= Math.max(min.y, max.y) &&
      location.z >= Math.min(min.z, max.z) &&
      location.z <= Math.max(min.z, max.z)
    ) {
      return true;
    }
  }
  return false;
}

// Helper function to check proximity to other entities
function isTooClose(location, spawnedLocations, minDistance) {
  for (const loc of spawnedLocations) {
    if (
      Math.abs(loc.x - location.x) <= minDistance &&
      Math.abs(loc.y - location.y) <= minDistance &&
      Math.abs(loc.z - location.z) <= minDistance
    ) {
      return true;
    }
  }
  return false;
}


function generateRandomWithAverage(min, max, avg) {
  // Ensure avg is between min and max
  if (avg < min || avg > max) {
    throw new Error("Average must be between min and max");
  }

  // Calculate the standard deviation based on the range
  const stdDev = (max - min) / 6; // 99.7% of values in a normal distribution are within ±3 standard deviations

  // Box-Muller transform to generate a normally distributed random value
  function generateNormalRandom() {
    let u = 0,
      v = 0;
    while (u === 0) u = Math.random(); // Converting [0,1) to (0,1)
    while (v === 0) v = Math.random();
    return Math.sqrt(-2.0 * Math.log(u)) * Math.cos(2.0 * Math.PI * v); // Standard normal (mean 0, std dev 1)
  }

  // Get a normally distributed random number with mean 0 and std dev 1
  let randomValue = generateNormalRandom();

  // Scale the random number to the desired average and standard deviation
  let result = avg + randomValue * stdDev;

  // Clamp the result within the min-max range
  result = Math.max(min, Math.min(result, max));

  return result;
}

system.afterEvents.scriptEventReceive.subscribe((ev) => {
  const entity = ev.sourceEntity;
  const message = ev.id;

  if (!entity || message !== "js:spawnKey") return;

  system.runJob(spawnKey(entity.location));
});

system.afterEvents.scriptEventReceive.subscribe((ev) => {
  const entity = ev.sourceEntity;
  const message = ev.id;

  if (!entity || message !== "js:scrapGen") return;

  const moonId = world.getDynamicProperty("moon");
  let mapName;
  let shipLocation = { x: 0, y: -60, z: 0 };

  for (const key of Object.keys(MAPS)) {
    if (MAPS[key].id === moonId) {
      mapName = key;
      shipLocation = MAPS[key].shipLocation;
      break;
    }
  }
  const mainLocation = {
    x: shipLocation.x,
    y: shipLocation.y - 75 - 30,
    z: shipLocation.z,
  };
  system.runJob(spawnScrap(mapName, mainLocation));
});

function* spawnKey(location) {
  let keySpawned = false;
  let spawnRadius = 20;
  ////world.sendMessage(`Locked door at ${JSON.stringify(location)}`);

  // Pre-select potential locations
  const potentialLocations = [];
  for (let dx = -spawnRadius; dx <= spawnRadius; dx++) {
    for (let dz = -spawnRadius; dz <= spawnRadius; dz++) {
      for (let dy = -5; dy <= 5; dy++) {
        const x = location.x + dx;
        const y = location.y + dy;
        const z = location.z + dz;
        potentialLocations.push({ x, y, z });
      }
    }
  }

  // Shuffle potential locations to ensure randomness
  for (let i = potentialLocations.length - 1; i > 0; i--) {
    const j = Math.floor(Math.random() * (i + 1));
    [potentialLocations[i], potentialLocations[j]] = [potentialLocations[j], potentialLocations[i]];
  }

  let locationIndex = 0;

  while (!keySpawned && locationIndex < potentialLocations.length) {
    const { x, y, z } = potentialLocations[locationIndex];
    locationIndex++;

    const block = OVERWORLD.getBlock({ x, y, z });
    yield;

    const isSpawnableBlock = SPAWNABLE_BLOCKS.includes(block?.typeId);
    const blockAbove = OVERWORLD.getBlock({ x, y: y + 1, z });
    yield;

    if (isSpawnableBlock && blockAbove.typeId === "minecraft:air") {
      const roomsMap = new Map(
        world.getDynamicProperty("rooms") ? JSON.parse(world.getDynamicProperty("rooms")) : []
      );

      let isInsideRoom = false;

      for (const [, { min, max }] of roomsMap.entries()) {
        yield;

        // Check if the block is inside the room based on min and max coordinates
        const isInVolume =
          block.location.x >= Math.min(min.x, max.x) &&
          block.location.x <= Math.max(min.x, max.x) &&
          block.location.y + 1 >= Math.min(min.y, max.y) &&
          block.location.y + 1 <= Math.max(min.y, max.y) &&
          block.location.z >= Math.min(min.z, max.z) &&
          block.location.z <= Math.max(min.z, max.z);

        if (isInVolume) {
          isInsideRoom = true;
          yield;
          break;
        }
      }


      if (isInsideRoom) {
        const key = OVERWORLD.spawnEntity("js:key_ent", { x, y: y + 1, z });
        key.setDynamicProperty("scrapValue", 3);

        const random = Math.floor(Math.random() * 360);
        key.setRotation({ x: 0, y: random });

        ////world.sendMessage(`Spawned Key at ${x} ${y + 1} ${z}`);
        keySpawned = true;
        yield;
      }
    }
  }

  if (!keySpawned) {
    ////world.sendMessage(`No suitable location found to spawn key.`);
  }
}


/*
[Scripting][warning]-entCount_hoarding_bug 0

[Scripting][warning]-entCount_barber 0

[Scripting][warning]-entCount_coil_head 0

[Scripting][warning]-entCount_bunker_spider 0

[Scripting][warning]-entCount_bracken 0

[Scripting][warning]-entCount_thumper 0

[Scripting][warning]-entCount_nutcracker 0

[Scripting][warning]-entCount_jester 0

[Scripting][warning]-entCount_ghost_girl 0

[Scripting][warning]-entCount_spore_lizard 0

[Scripting][warning]-entCount_hygrodere 0

[Scripting][warning]-entCount_snare_flea 0

[Scripting][warning]-entCount_eyeless_dog 0

[Scripting][warning]-entCount_forest_keeper 0

[Scripting][warning]-entCount_old_bird 0

[Scripting][warning]-entCount_circuit_bees 0

[Scripting][warning]-entCount_wandering_locusts 0

[Scripting][warning]-Restarting Generation

[Scripting][warning]-Chose blocked

[Scripting][warning]-Chose 2x1jump1

[Scripting][warning]-Chose 2x1jump1

[Scripting][warning]-south

[Scripting][warning]-Placing at {"x":2000.5,"y":-4,"z":8.5} in direction None

[Scripting][warning]-Map [["main_1737035970715",{"min":{"x":2000,"y":-11,"z":0},"max":{"x":2009,"y":26,"z":9}}],["2x1jump1_1737035970759",{"min":{"x":2000.5,"y":-4,"z":8.5},"max":{"x":2016.5,"y":8,"z":16.5}}]]

[Scripting][warning]-east

[Scripting][warning]-Placing at {"x":2008.5,"y":-4,"z":-7.5} in direction Rotate270

[Scripting][warning]-Map [["main_1737035970715",{"min":{"x":2000,"y":-11,"z":0},"max":{"x":2009,"y":26,"z":9}}],["2x1jump1_1737035970759",{"min":{"x":2000.5,"y":-4,"z":8.5},"max":{"x":2016.5,"y":8,"z":16.5}}],["2x1jump1_1737035970838",{"min":{"x":2008.5,"y":-4,"z":-7.5},"max":{"x":2016.5,"y":8,"z":8.5}}]]

[Scripting][warning]-{"m_stair2":1,"m_stair1":1,"m_hallway_2":10,"m_hallway_1":10,"m_hallway_x":5,"m_3x2window":1,"m_hallway_l":5,"m_3x2fireplace":1,"m_3x2bigroom1":1,"m_2x3stair3":1,"m_hallway_t":5,"m_2x2kitchen":1,"m_2x2bigroom2":1,"m_hallway_3":5}

[Scripting][warning]-2x1jump1

[Scripting][warning]-Pool {}

[Scripting][warning]-Default to Sheet Wall at {"x":2008.5,"y":4,"z":-3.5} due to INTERSECT EXTENT

[Scripting][warning]-Closing at {"x":2008.5,"y":4,"z":-3.5} due to NONE SELECTED

[Scripting][warning]-{"m_stair2":1,"m_stair1":1,"m_hallway_2":10,"m_hallway_1":10,"m_hallway_x":5,"m_3x2window":1,"m_hallway_l":5,"m_3x2fireplace":1,"m_3x2bigroom1":1,"m_2x3stair3":1,"m_hallway_t":5,"m_2x2kitchen":1,"m_2x2bigroom2":1,"m_hallway_3":5}

[Scripting][warning]-2x1jump1

[Scripting][warning]-Pool {}

[Scripting][warning]-Default to Sheet Wall at {"x":2000.5,"y":4,"z":12.5} due to INTERSECT EXTENT

[Scripting][warning]-Closing at {"x":2000.5,"y":4,"z":12.5} due to NONE SELECTED

[Scripting][warning]-{"m_stair2":1,"m_stair1":1,"m_hallway_2":10,"m_hallway_1":10,"m_hallway_x":5,"m_3x2window":1,"m_hallway_l":5,"m_3x2fireplace":1,"m_3x2bigroom1":1,"m_2x3stair3":1,"m_hallway_t":5,"m_2x2kitchen":1,"m_2x2bigroom2":1,"m_hallway_3":5}

[Scripting][warning]-2x1jump1

[Scripting][warning]-Pool {}

[Scripting][warning]-Default to Sheet Wall at {"x":2012.5,"y":4,"z":-7.5} due to INTERSECT EXTENT

[Scripting][warning]-Closing at {"x":2012.5,"y":4,"z":-7.5} due to NONE SELECTED

[Scripting][warning]-{"x":2012.5,"y":4,"z":8.5} js:facility_door Dir north locked false Inv null fire null

[Scripting][warning]-{"m_stair2":1,"m_stair1":1,"m_hallway_2":10,"m_hallway_1":10,"m_hallway_x":5,"m_3x2window":1,"m_hallway_l":5,"m_3x2fireplace":1,"m_3x2bigroom1":1,"m_2x3stair3":1,"m_hallway_t":5,"m_2x2kitchen":1,"m_2x2bigroom2":1,"m_hallway_3":5}

[Scripting][warning]-2x1jump1

[Scripting][warning]-Pool {}

[Scripting][warning]-Default to Sheet Wall at {"x":2016.5,"y":4,"z":-3.5} due to INTERSECT EXTENT

[Scripting][warning]-Closing at {"x":2016.5,"y":4,"z":-3.5} due to NONE SELECTED

[Scripting][warning]-{"m_stair2":1,"m_stair1":1,"m_hallway_2":10,"m_hallway_1":10,"m_hallway_x":5,"m_3x2window":1,"m_hallway_l":5,"m_3x2fireplace":1,"m_3x2bigroom1":1,"m_2x3stair3":1,"m_hallway_t":5,"m_2x2kitchen":1,"m_2x2bigroom2":1,"m_hallway_3":5}

[Scripting][warning]-2x1jump1

[Scripting][warning]-Pool {}

[Scripting][warning]-Default to Sheet Wall at {"x":2004.5,"y":4,"z":16.5} due to INTERSECT EXTENT

[Scripting][warning]-Closing at {"x":2004.5,"y":4,"z":16.5} due to NONE SELECTED

[Scripting][warning]-{"m_stair2":1,"m_stair1":1,"m_hallway_2":10,"m_hallway_1":10,"m_hallway_x":5,"m_3x2window":1,"m_hallway_l":5,"m_3x2fireplace":1,"m_3x2bigroom1":1,"m_2x3stair3":1,"m_hallway_t":5,"m_2x2kitchen":1,"m_2x2bigroom2":1,"m_hallway_3":5}

[Scripting][warning]-2x1jump1

[Scripting][warning]-Pool {}

[Scripting][warning]-Default to Sheet Wall at {"x":2016.5,"y":4,"z":4.5} due to INTERSECT EXTENT

[Scripting][warning]-Closing at {"x":2016.5,"y":4,"z":4.5} due to NONE SELECTED

[Scripting][warning]-{"m_stair2":1,"m_stair1":1,"m_hallway_2":10,"m_hallway_1":10,"m_hallway_x":5,"m_3x2window":1,"m_hallway_l":5,"m_3x2fireplace":1,"m_3x2bigroom1":1,"m_2x3stair3":1,"m_hallway_t":5,"m_2x2kitchen":1,"m_2x2bigroom2":1,"m_hallway_3":5}

[Scripting][warning]-2x1jump1

[Scripting][warning]-Pool {}

[Scripting][warning]-Default to Sheet Wall at {"x":2012.5,"y":4,"z":16.5} due to INTERSECT EXTENT

[Scripting][warning]-Closing at {"x":2012.5,"y":4,"z":16.5} due to NONE SELECTED

[Scripting][warning]-{"m_stair2":1,"m_stair1":1,"m_hallway_2":10,"m_hallway_1":10,"m_hallway_x":5,"m_3x2window":1,"m_hallway_l":5,"m_3x2fireplace":1,"m_3x2bigroom1":1,"m_2x3stair3":1,"m_hallway_t":5,"m_2x2kitchen":1,"m_2x2bigroom2":1,"m_hallway_3":5}

[Scripting][warning]-2x1jump1

[Scripting][warning]-Pool {}

[Scripting][warning]-Default to Sheet Wall at {"x":2016.5,"y":4,"z":12.5} due to INTERSECT EXTENT

[Scripting][warning]-Closing at {"x":2016.5,"y":4,"z":12.5} due to NONE SELECTED

[Scripting][warning]-NO ROOMS

[Scripting][warning]-GENERATION INCOMPLETE. Clearing and queuing restart

[Scripting][warning]-Tile: main_1737035970715

[Scripting][warning]-"Min:", {"x":2000,"y":-11,"z":0}

[Scripting][warning]-"Max:", {"x":2009,"y":26,"z":9}

[Scripting][warning]-Tile: 2x1jump1_1737035970759

[Scripting][warning]-"Min:", {"x":2000.5,"y":-4,"z":8.5}

[Scripting][warning]-"Max:", {"x":2016.5,"y":8,"z":16.5}

[Scripting][warning]-Tile: 2x1jump1_1737035970838

[Scripting][warning]-"Min:", {"x":2008.5,"y":-4,"z":-7.5}

[Scripting][warning]-"Max:", {"x":2016.5,"y":8,"z":8.5}

[Scripting][warning]-entCount_undefined 0

[Scripting][warning]-entCount_undefined 0

[Scripting][warning]-entCount_mine 0

[Scripting][warning]-entCount_turret 0

[Scripting][warning]-entCount_hoarding_bug 0

[Scripting][warning]-entCount_barber 0

[Scripting][warning]-entCount_coil_head 0

[Scripting][warning]-entCount_bunker_spider 0

[Scripting][warning]-entCount_bracken 0

[Scripting][warning]-entCount_thumper 0

[Scripting][warning]-entCount_nutcracker 0

[Scripting][warning]-entCount_jester 0

[Scripting][warning]-entCount_ghost_girl 0

[Scripting][warning]-entCount_spore_lizard 0

[Scripting][warning]-entCount_hygrodere 0

[Scripting][warning]-entCount_snare_flea 0

[Scripting][warning]-entCount_eyeless_dog 0

[Scripting][warning]-entCount_forest_keeper 0

[Scripting][warning]-entCount_old_bird 0

[Scripting][warning]-entCount_circuit_bees 0

[Scripting][warning]-entCount_wandering_locusts 0


*/