From e21167aa4aef3f38651478247a8a6159c3d889e0 Mon Sep 17 00:00:00 2001 From: ForestOfLight Date: Mon, 14 Apr 2025 13:37:37 -0700 Subject: [PATCH] add structure bounding box corners to layered outline --- scripts/classes/Outliner.js | 59 ++++++++++++++++++---------- scripts/classes/StructureInstance.js | 32 +++++++++------ scripts/classes/StructureOutliner.js | 38 ++++++++++++++++++ 3 files changed, 95 insertions(+), 34 deletions(-) create mode 100644 scripts/classes/StructureOutliner.js diff --git a/scripts/classes/Outliner.js b/scripts/classes/Outliner.js index f3a37a2..08d8821 100644 --- a/scripts/classes/Outliner.js +++ b/scripts/classes/Outliner.js @@ -1,38 +1,36 @@ import { system, world } from "@minecraft/server"; import { Vector } from "../lib/Vector"; -const drawFrequency = 8; -const drawParticle = "minecraft:villager_happy"; export class Outliner { dimension; min = new Vector(); max = new Vector(); - #shouldDraw = true; - + drawParticle = "minecraft:villager_happy"; + drawFrequency = 8; + #drawParticles = []; #runner = null; constructor(dimension, min, max) { - this.dimension = world.getDimension(dimension); + this.dimension = dimension; this.min = new Vector(min.x, min.y, min.z); this.max = new Vector(max.x, max.y, max.z); + this.vertices = this.getVertices(min, max); this.startDraw(); } startDraw() { - this.#shouldDraw = true; - this.#runner = system.runInterval(() => this.draw(), drawFrequency); + this.#runner = system.runInterval(() => this.draw(), this.drawFrequency); } stopDraw() { system.clearRun(this.#runner); - this.shouldDraw = false; } draw() { - if (!this.#shouldDraw) return; this.#drawParticles.length = 0; + this.#drawParticles.push(...this.getVerticeParticleLocations()); this.#drawParticles.push(...this.getCubiodParticleLocations()); for (const [particleType, location] of this.#drawParticles) { @@ -44,17 +42,31 @@ export class Outliner { } } - getCubiodParticleLocations() { - const vertices = [ - new Vector(this.min.x, this.min.y, this.min.z), - new Vector(this.max.x, this.min.y, this.min.z), - new Vector(this.min.x, this.max.y, this.min.z), - new Vector(this.max.x, this.max.y, this.min.z), - new Vector(this.min.x, this.min.y, this.max.z), - new Vector(this.max.x, this.min.y, this.max.z), - new Vector(this.min.x, this.max.y, this.max.z), - new Vector(this.max.x, this.max.y, this.max.z) + getVertices(min, max) { + return [ + new Vector(min.x, min.y, min.z), + new Vector(max.x, min.y, min.z), + new Vector(min.x, max.y, min.z), + new Vector(max.x, max.y, min.z), + new Vector(min.x, min.y, max.z), + new Vector(max.x, min.y, max.z), + new Vector(min.x, max.y, max.z), + new Vector(max.x, max.y, max.z) ]; + } + + setVertices(dimension, min, max) { + this.dimension = dimension; + this.min = new Vector(min.x, min.y, min.z); + this.max = new Vector(max.x, max.y, max.z); + this.vertices = this.getVertices(min, max); + } + + getVerticeParticleLocations() { + return this.vertices.map((v) => [this.drawParticle, v]); + } + + getCubiodParticleLocations() { const edges = [ [0, 1], [0, 2], @@ -71,13 +83,18 @@ export class Outliner { ]; const edgePoints = []; for (const edge of edges) { - const [startVertex, endVertex] = [vertices[edge[0]], vertices[edge[1]]]; + const [startVertex, endVertex] = [this.vertices[edge[0]], this.vertices[edge[1]]]; const resolution = Math.min(Math.floor(endVertex.subtract(startVertex).length), 16); for (let i = 1; i < resolution; i++) { const t = i / resolution; edgePoints.push(startVertex.lerp(endVertex, t)); } } - return vertices.concat(edgePoints).map((v) => [drawParticle, v]); + return edgePoints.map((v) => [this.drawParticle, v]); + } + + addStandaloneParticles(locations) { + for (const location of locations) + this.vertices.push(new Vector(location.x, location.y, location.z)); } } \ No newline at end of file diff --git a/scripts/classes/StructureInstance.js b/scripts/classes/StructureInstance.js index 1b35582..00d2696 100644 --- a/scripts/classes/StructureInstance.js +++ b/scripts/classes/StructureInstance.js @@ -1,5 +1,6 @@ import { world } from "@minecraft/server"; import { Outliner } from "./Outliner"; +import { StructureOutliner } from "./StructureOutliner"; export class StructureInstance { name; @@ -13,6 +14,7 @@ export class StructureInstance { mirror: false, currentLayer: 0 }; + outliner = void 0; constructor(instanceName, structureId) { this.name = instanceName; @@ -22,9 +24,8 @@ export class StructureInstance { this.#structure.saveToWorld(); this.#options = this.loadOptions(); this.#options.structureId = structureId; - if (this.#options.isEnabled) - this.refreshOutliner(); this.updateOptions(); + this.outliner = new StructureOutliner(this); } loadOptions() { @@ -75,6 +76,16 @@ export class StructureInstance { return this.#options.currentLayer || 0; } + getDimension() { + let dimension; + try { + dimension = world.getDimension(this.#options.dimensionId); + } catch (e) { + dimension = world.getDimension("minecraft:overworld"); + } + return dimension; + } + *getBlocks() { const max = this.#structure.size; for (let x = 0; x < max.x; x++) { @@ -135,7 +146,7 @@ export class StructureInstance { disable() { this.#options.isEnabled = false; this.updateOptions(); - this.outliner.stopDraw(); + this.refreshOutliner(); } move(dimensionId, location) { @@ -154,16 +165,7 @@ export class StructureInstance { } refreshOutliner() { - if (!this.#options.isEnabled) - return; - if (this.outliner) - this.outliner.stopDraw(); - if (this.#options.currentLayer > 0) { - const { min, max } = this.getLayeredBounds(); - this.outliner = new Outliner(this.#options.dimensionId, this.toGlobalCoords(min), this.toGlobalCoords(max)); - } else { - this.outliner = new Outliner(this.#options.dimensionId, this.toGlobalCoords(this.getBounds().min), this.toGlobalCoords(this.getBounds().max)); - } + this.outliner.refresh(); } isLocationInStructure(dimensionId, structureLocation) { @@ -216,6 +218,10 @@ export class StructureInstance { return this.#options.dimensionId && this.#options.worldLocation.x !== 0 && this.#options.worldLocation.y !== 0 && this.#options.worldLocation.z !== 0; } + isUsingLayers() { + return this.hasLayers() && this.#options.currentLayer !== 0; + } + hasLayers() { return this.#structure.size.y > 1; } diff --git a/scripts/classes/StructureOutliner.js b/scripts/classes/StructureOutliner.js new file mode 100644 index 0000000..fb31339 --- /dev/null +++ b/scripts/classes/StructureOutliner.js @@ -0,0 +1,38 @@ +import { Outliner } from '../classes/Outliner'; + +export class StructureOutliner { + constructor(instance) { + this.instance = instance; + this.dimension = instance.getDimension(); + this.bounds = instance.getBounds(); + this.bounds.min = instance.toGlobalCoords(this.bounds.min); + this.bounds.max = instance.toGlobalCoords(this.bounds.max); + this.outliner = new Outliner(this.dimension, this.bounds.min, this.bounds.max); + this.refresh(); + } + + refresh() { + this.outliner.stopDraw(); + if (!this.instance.isEnabled()) + return; + if (this.instance.isUsingLayers()) + this.layeredDraw(); + else + this.boxDraw(); + this.outliner.startDraw(); + } + + boxDraw() { + this.outliner.setVertices(this.dimension, this.bounds.min, this.bounds.max); + } + + layeredDraw() { + const { min, max } = this.instance.getLayeredBounds(); + this.outliner.setVertices(this.dimension, this.instance.toGlobalCoords(min), this.instance.toGlobalCoords(max)); + this.outliner.addStandaloneParticles(this.getCornerVertices()); + } + + getCornerVertices() { + return this.outliner.getVertices(this.bounds.min, this.bounds.max); + } +} \ No newline at end of file