Merge branch 'main' into StructureVerifier
This commit is contained in:
@@ -27,11 +27,8 @@ export class MenuForm {
|
|||||||
async getInstanceNameFromForm() {
|
async getInstanceNameFromForm() {
|
||||||
try {
|
try {
|
||||||
return forceShow(this.player, MenuFormBuilder.buildAllInstanceName()).then((response) => {
|
return forceShow(this.player, MenuFormBuilder.buildAllInstanceName()).then((response) => {
|
||||||
if (response.canceled) return;
|
if (response.canceled)
|
||||||
if (response.selection === structureCollection.getInstanceNames().length + 1) {
|
|
||||||
MenuFormBuilder.buildHowToAddNewStructures().show(this.player);
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
const selectedInstanceName = structureCollection.getInstanceNames()[response.selection];
|
const selectedInstanceName = structureCollection.getInstanceNames()[response.selection];
|
||||||
return selectedInstanceName || this.createNewInstance();
|
return selectedInstanceName || this.createNewInstance();
|
||||||
});
|
});
|
||||||
@@ -63,6 +60,10 @@ export class MenuForm {
|
|||||||
return MenuFormBuilder.buildAllStructures().show(this.player).then((response) => {
|
return MenuFormBuilder.buildAllStructures().show(this.player).then((response) => {
|
||||||
if (response.canceled)
|
if (response.canceled)
|
||||||
return;
|
return;
|
||||||
|
if (response.selection === structureCollection.getWorldStructureIds().length + 1) {
|
||||||
|
MenuFormBuilder.buildHowTo().show(this.player);
|
||||||
|
return;
|
||||||
|
}
|
||||||
const selectedStructureId = structureCollection.getWorldStructureIds()[response.selection];
|
const selectedStructureId = structureCollection.getWorldStructureIds()[response.selection];
|
||||||
return selectedStructureId || this.getOtherStructureId();
|
return selectedStructureId || this.getOtherStructureId();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ export class MenuFormBuilder {
|
|||||||
allInstanceNameForm.button(`§2${instanceName}`);
|
allInstanceNameForm.button(`§2${instanceName}`);
|
||||||
});
|
});
|
||||||
allInstanceNameForm.button('Create New Instance');
|
allInstanceNameForm.button('Create New Instance');
|
||||||
allInstanceNameForm.button('How to Add New Structures');
|
|
||||||
return allInstanceNameForm;
|
return allInstanceNameForm;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -32,6 +31,7 @@ export class MenuFormBuilder {
|
|||||||
allStructuresForm.button(`§2${structureName}`);
|
allStructuresForm.button(`§2${structureName}`);
|
||||||
});
|
});
|
||||||
allStructuresForm.button('Other');
|
allStructuresForm.button('Other');
|
||||||
|
allStructuresForm.button('How to Add/Remove Structures');
|
||||||
return allStructuresForm;
|
return allStructuresForm;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,11 +42,13 @@ export class MenuFormBuilder {
|
|||||||
.submitButton('Submit');
|
.submitButton('Submit');
|
||||||
}
|
}
|
||||||
|
|
||||||
static buildHowToAddNewStructures() {
|
static buildHowTo() {
|
||||||
let body = "How to Add Structures:\n"
|
let body = "§aHow to Add Structures:\n"
|
||||||
body += "§7- Save a structure using a structure block or the /structure command.\n"
|
body += "§7- Save a structure using a §fstructure block§7 or the §f/structure§7 command.\n"
|
||||||
body += "§7OR\n"
|
body += "§f§lOR§r\n"
|
||||||
body += "§7- Add a .mcstructure file to this pack's structures folder. When selecting your structure, select the 'Other' option and then use the filename (without '.mcstructure') as the Structure ID. After its first use, it will be added to the list of structures.";
|
body += "§7- Add a .mcstructure file to this pack's structures folder. When selecting your structure, select the 'Other' option and then use the filename (without '.mcstructure') as the Structure ID. After its first use, it will be added to the list of structures.";
|
||||||
|
body += "\n\n§cHow to Remove Structures:\n"
|
||||||
|
body += "§7- Use the §f/structure delete§7 command to remove a structure from the world.\n"
|
||||||
return new ActionFormData()
|
return new ActionFormData()
|
||||||
.title(this.menuTitle)
|
.title(this.menuTitle)
|
||||||
.body(body);
|
.body(body);
|
||||||
|
|||||||
+37
-20
@@ -1,38 +1,36 @@
|
|||||||
import { system, world } from "@minecraft/server";
|
import { system, world } from "@minecraft/server";
|
||||||
import { Vector } from "../lib/Vector";
|
import { Vector } from "../lib/Vector";
|
||||||
|
|
||||||
const drawFrequency = 8;
|
|
||||||
const drawParticle = "minecraft:villager_happy";
|
|
||||||
|
|
||||||
export class Outliner {
|
export class Outliner {
|
||||||
dimension;
|
dimension;
|
||||||
min = new Vector();
|
min = new Vector();
|
||||||
max = new Vector();
|
max = new Vector();
|
||||||
#shouldDraw = true;
|
drawParticle = "minecraft:villager_happy";
|
||||||
|
drawFrequency = 8;
|
||||||
|
|
||||||
#drawParticles = [];
|
#drawParticles = [];
|
||||||
#runner = null;
|
#runner = null;
|
||||||
|
|
||||||
constructor(dimension, min, max) {
|
constructor(dimension, min, max) {
|
||||||
this.dimension = world.getDimension(dimension);
|
this.dimension = dimension;
|
||||||
this.min = new Vector(min.x, min.y, min.z);
|
this.min = new Vector(min.x, min.y, min.z);
|
||||||
this.max = new Vector(max.x, max.y, max.z);
|
this.max = new Vector(max.x, max.y, max.z);
|
||||||
|
this.vertices = this.getVertices(min, max);
|
||||||
this.startDraw();
|
this.startDraw();
|
||||||
}
|
}
|
||||||
|
|
||||||
startDraw() {
|
startDraw() {
|
||||||
this.#shouldDraw = true;
|
this.#runner = system.runInterval(() => this.draw(), this.drawFrequency);
|
||||||
this.#runner = system.runInterval(() => this.draw(), drawFrequency);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
stopDraw() {
|
stopDraw() {
|
||||||
system.clearRun(this.#runner);
|
system.clearRun(this.#runner);
|
||||||
this.shouldDraw = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
draw() {
|
draw() {
|
||||||
if (!this.#shouldDraw) return;
|
|
||||||
this.#drawParticles.length = 0;
|
this.#drawParticles.length = 0;
|
||||||
|
this.#drawParticles.push(...this.getVerticeParticleLocations());
|
||||||
this.#drawParticles.push(...this.getCubiodParticleLocations());
|
this.#drawParticles.push(...this.getCubiodParticleLocations());
|
||||||
|
|
||||||
for (const [particleType, location] of this.#drawParticles) {
|
for (const [particleType, location] of this.#drawParticles) {
|
||||||
@@ -44,17 +42,31 @@ export class Outliner {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getCubiodParticleLocations() {
|
getVertices(min, max) {
|
||||||
const vertices = [
|
return [
|
||||||
new Vector(this.min.x, this.min.y, this.min.z),
|
new Vector(min.x, min.y, min.z),
|
||||||
new Vector(this.max.x, this.min.y, this.min.z),
|
new Vector(max.x, min.y, min.z),
|
||||||
new Vector(this.min.x, this.max.y, this.min.z),
|
new Vector(min.x, max.y, min.z),
|
||||||
new Vector(this.max.x, this.max.y, this.min.z),
|
new Vector(max.x, max.y, min.z),
|
||||||
new Vector(this.min.x, this.min.y, this.max.z),
|
new Vector(min.x, min.y, max.z),
|
||||||
new Vector(this.max.x, this.min.y, this.max.z),
|
new Vector(max.x, min.y, max.z),
|
||||||
new Vector(this.min.x, this.max.y, this.max.z),
|
new Vector(min.x, max.y, max.z),
|
||||||
new Vector(this.max.x, this.max.y, this.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 = [
|
const edges = [
|
||||||
[0, 1],
|
[0, 1],
|
||||||
[0, 2],
|
[0, 2],
|
||||||
@@ -71,13 +83,18 @@ export class Outliner {
|
|||||||
];
|
];
|
||||||
const edgePoints = [];
|
const edgePoints = [];
|
||||||
for (const edge of edges) {
|
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);
|
const resolution = Math.min(Math.floor(endVertex.subtract(startVertex).length), 16);
|
||||||
for (let i = 1; i < resolution; i++) {
|
for (let i = 1; i < resolution; i++) {
|
||||||
const t = i / resolution;
|
const t = i / resolution;
|
||||||
edgePoints.push(startVertex.lerp(endVertex, t));
|
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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -50,7 +50,18 @@ class StructureCollection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getStructures(dimensionId, location, options = {}) {
|
getStructures(dimensionId, location, options = {}) {
|
||||||
return Object.values(this.structures).filter(structure => structure.isLocationActive(dimensionId, structure.toStructureCoords(location), options));
|
return Object.values(this.structures).filter(structure => {
|
||||||
|
try {
|
||||||
|
return structure.isLocationActive(dimensionId, structure.toStructureCoords(location), options)
|
||||||
|
} catch (e) {
|
||||||
|
if (e.name === 'InvalidStructureError') {
|
||||||
|
structureCollection.delete(structure.name);
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getStructure(dimensionId, location, options = {}) {
|
getStructure(dimensionId, location, options = {}) {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { world } from "@minecraft/server";
|
import { world } from "@minecraft/server";
|
||||||
import { Outliner } from "./Outliner";
|
import { Outliner } from "./Outliner";
|
||||||
|
import { StructureOutliner } from "./StructureOutliner";
|
||||||
|
|
||||||
export class StructureInstance {
|
export class StructureInstance {
|
||||||
name;
|
name;
|
||||||
@@ -13,6 +14,7 @@ export class StructureInstance {
|
|||||||
mirror: false,
|
mirror: false,
|
||||||
currentLayer: 0
|
currentLayer: 0
|
||||||
};
|
};
|
||||||
|
outliner = void 0;
|
||||||
|
|
||||||
constructor(instanceName, structureId) {
|
constructor(instanceName, structureId) {
|
||||||
this.name = instanceName;
|
this.name = instanceName;
|
||||||
@@ -22,9 +24,8 @@ export class StructureInstance {
|
|||||||
this.#structure.saveToWorld();
|
this.#structure.saveToWorld();
|
||||||
this.#options = this.loadOptions();
|
this.#options = this.loadOptions();
|
||||||
this.#options.structureId = structureId;
|
this.#options.structureId = structureId;
|
||||||
if (this.#options.isEnabled)
|
|
||||||
this.refreshOutliner();
|
|
||||||
this.updateOptions();
|
this.updateOptions();
|
||||||
|
this.outliner = new StructureOutliner(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
loadOptions() {
|
loadOptions() {
|
||||||
@@ -75,6 +76,16 @@ export class StructureInstance {
|
|||||||
return this.#options.currentLayer || 0;
|
return this.#options.currentLayer || 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getDimension() {
|
||||||
|
let dimension;
|
||||||
|
try {
|
||||||
|
dimension = world.getDimension(this.#options.dimensionId);
|
||||||
|
} catch (e) {
|
||||||
|
dimension = world.getDimension("minecraft:overworld");
|
||||||
|
}
|
||||||
|
return dimension;
|
||||||
|
}
|
||||||
|
|
||||||
getBlock(structureLocation) {
|
getBlock(structureLocation) {
|
||||||
return this.#structure.getBlockPermutation(structureLocation);
|
return this.#structure.getBlockPermutation(structureLocation);
|
||||||
}
|
}
|
||||||
@@ -139,7 +150,7 @@ export class StructureInstance {
|
|||||||
disable() {
|
disable() {
|
||||||
this.#options.isEnabled = false;
|
this.#options.isEnabled = false;
|
||||||
this.updateOptions();
|
this.updateOptions();
|
||||||
this.outliner.stopDraw();
|
this.refreshOutliner();
|
||||||
}
|
}
|
||||||
|
|
||||||
move(dimensionId, location) {
|
move(dimensionId, location) {
|
||||||
@@ -158,16 +169,7 @@ export class StructureInstance {
|
|||||||
}
|
}
|
||||||
|
|
||||||
refreshOutliner() {
|
refreshOutliner() {
|
||||||
if (!this.#options.isEnabled)
|
this.outliner.refresh();
|
||||||
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));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
isLocationInStructure(dimensionId, structureLocation) {
|
isLocationInStructure(dimensionId, structureLocation) {
|
||||||
@@ -220,6 +222,10 @@ export class StructureInstance {
|
|||||||
return this.#options.dimensionId && this.#options.worldLocation.x !== 0 && this.#options.worldLocation.y !== 0 && this.#options.worldLocation.z !== 0;
|
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() {
|
hasLayers() {
|
||||||
return this.#structure.size.y > 1;
|
return this.#structure.size.y > 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
import { Outliner } from '../classes/Outliner';
|
||||||
|
|
||||||
|
export class StructureOutliner {
|
||||||
|
constructor(instance) {
|
||||||
|
this.instance = instance;
|
||||||
|
this.pullInstanceData();
|
||||||
|
this.outliner = new Outliner(this.dimension, this.bounds.min, this.bounds.max);
|
||||||
|
this.refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
pullInstanceData() {
|
||||||
|
try {
|
||||||
|
this.dimension = this.instance.getDimension();
|
||||||
|
this.bounds = this.instance.getBounds();
|
||||||
|
this.bounds.min = this.instance.toGlobalCoords(this.bounds.min);
|
||||||
|
this.bounds.max = this.instance.toGlobalCoords(this.bounds.max);
|
||||||
|
} catch (e) {
|
||||||
|
if (e.name === 'InvalidStructureError')
|
||||||
|
this.outliner.stopDraw();
|
||||||
|
else
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
refresh() {
|
||||||
|
this.pullInstanceData();
|
||||||
|
this.refreshDraw();
|
||||||
|
}
|
||||||
|
|
||||||
|
refreshDraw() {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,20 +5,16 @@ import { MenuForm } from '../classes/MenuForm';
|
|||||||
|
|
||||||
const ACTION_ITEM = 'minecraft:paper';
|
const ACTION_ITEM = 'minecraft:paper';
|
||||||
|
|
||||||
const structCmd = new Command({
|
const structoolCmd = new Command({
|
||||||
name: 'menu',
|
name: 'structool',
|
||||||
description: { text: 'Manages current StrucTool structures.' },
|
description: { text: 'Opens the StrucTool Menu. Using a paper will also open the menu.' },
|
||||||
usage: 'menu',
|
usage: 'structool',
|
||||||
callback: structCommand
|
callback: (sender) => new MenuForm(sender)
|
||||||
});
|
});
|
||||||
extension.addCommand(structCmd);
|
extension.addCommand(structoolCmd);
|
||||||
|
|
||||||
world.beforeEvents.itemUse.subscribe((event) => {
|
world.beforeEvents.itemUse.subscribe((event) => {
|
||||||
if (!event.source || event.itemStack?.typeId !== ACTION_ITEM) return;
|
if (!event.source || event.itemStack?.typeId !== ACTION_ITEM) return;
|
||||||
event.cancel = true;
|
event.cancel = true;
|
||||||
system.run(() => structCommand(event.source));
|
system.run(() => structoolCmd.getCallback()(event.source));
|
||||||
});
|
});
|
||||||
|
|
||||||
function structCommand(sender) {
|
|
||||||
new MenuForm(sender);
|
|
||||||
}
|
|
||||||
+1
-2
@@ -3,8 +3,7 @@ import './rules/easyPlace';
|
|||||||
import './rules/fastEasyPlace';
|
import './rules/fastEasyPlace';
|
||||||
|
|
||||||
// Commands
|
// Commands
|
||||||
import './commands/struct';
|
import './commands/structool';
|
||||||
import './commands/menu';
|
|
||||||
|
|
||||||
// Other
|
// Other
|
||||||
import './classes/BlockInfo';
|
import './classes/BlockInfo';
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ const ACTION_SLOT = 35;
|
|||||||
|
|
||||||
const easyPlace = new Rule({
|
const easyPlace = new Rule({
|
||||||
identifier: 'easyPlace',
|
identifier: 'easyPlace',
|
||||||
description: { text: "Simplifies placing blocks in a structure (paper named 'easyPlace' in bottom right inventory slot)." },
|
description: { text: "Automatically places the correct block in a structure (paper named 'easyPlace' in bottom right inventory slot)." },
|
||||||
onEnableCallback: () => { world.beforeEvents.playerPlaceBlock.subscribe(onPlayerPlaceBlock); },
|
onEnableCallback: () => { world.beforeEvents.playerPlaceBlock.subscribe(onPlayerPlaceBlock); },
|
||||||
onDisableCallback: () => { world.beforeEvents.playerPlaceBlock.unsubscribe(onPlayerPlaceBlock); }
|
onDisableCallback: () => { world.beforeEvents.playerPlaceBlock.unsubscribe(onPlayerPlaceBlock); }
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { Raycaster } from '../classes/Raycaster';
|
|||||||
let runner = void 0;
|
let runner = void 0;
|
||||||
const easyPlace = new Rule({
|
const easyPlace = new Rule({
|
||||||
identifier: 'fastEasyPlace',
|
identifier: 'fastEasyPlace',
|
||||||
description: { text: "Looking at structure blocks with a paper named 'easyPlace' in your hand will place them." },
|
description: { text: "Looking at a structure block with a paper named 'easyPlace' in your hand will place it." },
|
||||||
onEnableCallback: () => { runner = system.runInterval(onTick, 2); },
|
onEnableCallback: () => { runner = system.runInterval(onTick, 2); },
|
||||||
onDisableCallback: () => { system.clearRun(runner); }
|
onDisableCallback: () => { system.clearRun(runner); }
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user