Now is standalone from Canopy
This commit is contained in:
@@ -1,22 +1,15 @@
|
|||||||
import { BuilderOptions } from "./BuilderOptions";
|
import { BuilderOptions } from "./BuilderOptions";
|
||||||
import { Builders } from "./Builders";
|
|
||||||
|
|
||||||
export class Builder {
|
export class Builder {
|
||||||
constructor(playerId) {
|
constructor(playerId) {
|
||||||
this.playerId = playerId;
|
this.playerId = playerId;
|
||||||
this.options = new BuilderOptions(playerId);
|
|
||||||
Builders.add(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getOptionIds() {
|
isOptionEnabled(optionId) {
|
||||||
return Object.keys(this.options.options).sort((a, b) => a.localeCompare(b));
|
return BuilderOptions.isEnabled(optionId, this.playerId);
|
||||||
}
|
}
|
||||||
|
|
||||||
getOption(id) {
|
setOption(optionId, value) {
|
||||||
return this.options.get(id);
|
return BuilderOptions.setValue(optionId, this.playerId, value);
|
||||||
}
|
|
||||||
|
|
||||||
setOption(id, value) {
|
|
||||||
return this.options.setValue(id, value);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,24 +1,37 @@
|
|||||||
import { BuilderFormBuilder } from "./BuilderFormBuilder";
|
import { BuilderFormBuilder } from "./BuilderFormBuilder";
|
||||||
import { Builders } from "./Builders";
|
import { BuilderOptions } from "./BuilderOptions";
|
||||||
|
import { forceShow } from '../../utils';
|
||||||
|
|
||||||
export class BuilderForm {
|
export class BuilderForm {
|
||||||
constructor(player) {
|
constructor(player) {
|
||||||
this.player = player;
|
this.player = player;
|
||||||
|
this.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
show() {
|
show() {
|
||||||
forceShow(this.player, BuilderFormBuilder.buildSettings(this.player)).then((response) => {
|
forceShow(this.player, BuilderFormBuilder.buildBuilderOptions(this.player)).then((response) => {
|
||||||
if (response.canceled) return;
|
if (response.canceled) return;
|
||||||
this.applySettings(response.formValues);
|
this.applySettings(response.formValues);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
applySettings(formValues) {
|
applySettings(formValues) {
|
||||||
const optionIds = Builders.get(this.player.id).getOptionIds();
|
const optionIds = BuilderOptions.getOptionIds();
|
||||||
for (let i = 0; i < optionIds.length; i++) {
|
for (let i = 0; i < optionIds.length; i++) {
|
||||||
const option = optionIds[i];
|
const option = BuilderOptions.get(optionIds[i]);
|
||||||
if (option.setValue(formValues[i]) && formValues[i] === true)
|
const changedToValue = option.setValue(this.player.id, formValues[i]);
|
||||||
this.player.sendMessage(`§a${option.displayName} is enabled!§7 ${option.howToUse}`);
|
if (changedToValue === true)
|
||||||
|
this.player.sendMessage(`§a${option.displayName} is now enabled!§7 ${option.howToUse}`);
|
||||||
|
else if (changedToValue === false)
|
||||||
|
this.player.sendMessage(`§c${option.displayName} is now disabled.`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
valueChangedToEnabled(hasChanged, newValue) {
|
||||||
|
return hasChanged && newValue === true;
|
||||||
|
}
|
||||||
|
|
||||||
|
valueChangedToDisabled(hasChanged, newValue) {
|
||||||
|
return hasChanged && newValue === false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,15 +1,16 @@
|
|||||||
import { ModalFormData } from "@minecraft/server-ui";
|
import { ModalFormData } from "@minecraft/server-ui";
|
||||||
import { MenuFormBuilder } from "../MenuFormBuilder";
|
import { MenuFormBuilder } from "../MenuFormBuilder";
|
||||||
import { Builders } from "./Builders";
|
import { BuilderOptions } from "./BuilderOptions";
|
||||||
|
|
||||||
export class BuilderFormBuilder {
|
export class BuilderFormBuilder {
|
||||||
static buildSettings(player) {
|
static buildBuilderOptions(player) {
|
||||||
const form = new ModalFormData()
|
const form = new ModalFormData()
|
||||||
.title(MenuFormBuilder.menuTitle);
|
.title(MenuFormBuilder.menuTitle);
|
||||||
const builder = Builders.get(player.id);
|
for (const optionId of BuilderOptions.getOptionIds()) {
|
||||||
for (const optionId of builder.getOptionIds()) {
|
const option = BuilderOptions.get(optionId);
|
||||||
const option = builder.getOption(optionId);
|
form.toggle(`${option.displayName} - ${option.description}`, option.isEnabled(player.id));
|
||||||
form.toggle(`${option.displayName} - ${option.description}`, option.getValue());
|
|
||||||
}
|
}
|
||||||
|
form.submitButton('§2Apply');
|
||||||
|
return form;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,18 +1,16 @@
|
|||||||
import { BuilderOptions } from "./BuilderOptions";
|
import { BuilderOptions } from "./BuilderOptions";
|
||||||
import { Option } from "../Option";
|
import { world } from "@minecraft/server";
|
||||||
|
|
||||||
export class BuilderOption extends Option {
|
export class BuilderOption {
|
||||||
playerId;
|
|
||||||
identifier;
|
identifier;
|
||||||
displayName;
|
displayName;
|
||||||
description;
|
description;
|
||||||
value;
|
howToUse;
|
||||||
#onEnable;
|
#onEnable;
|
||||||
#onDisable;
|
#onDisable;
|
||||||
#DP_NAMESPACE = "builderOptions";
|
#DP_NAMESPACE = "builderOptions";
|
||||||
|
|
||||||
constructor({ player, identifier, displayName, description, howToUse, onEnableCallback = () => {}, onDisableCallback = () => {} }) {
|
constructor({ identifier, displayName, description, howToUse, onEnableCallback = () => {}, onDisableCallback = () => {} }) {
|
||||||
this.playerId = player.id;
|
|
||||||
this.identifier = identifier;
|
this.identifier = identifier;
|
||||||
this.displayName = displayName;
|
this.displayName = displayName;
|
||||||
this.description = description;
|
this.description = description;
|
||||||
@@ -22,32 +20,24 @@ export class BuilderOption extends Option {
|
|||||||
BuilderOptions.add(this);
|
BuilderOptions.add(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
save() {
|
isEnabled(playerId) {
|
||||||
this.saveToDP(this.#DP_NAMESPACE, `${this.playerId}:${this.identifier}`, this);
|
return world.getDynamicProperty(`${this.#DP_NAMESPACE}:${playerId}:${this.identifier}`) === true;
|
||||||
}
|
}
|
||||||
|
|
||||||
load() {
|
setValue(playerId, value) {
|
||||||
this.loadFromDP(this.#DP_NAMESPACE, `${this.playerId}:${this.identifier}`);
|
|
||||||
this.value = this.value ?? false;
|
|
||||||
}
|
|
||||||
|
|
||||||
clear() {
|
|
||||||
this.clearDP(this.#DP_NAMESPACE, `${this.playerId}:${this.identifier}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
getValue() {
|
|
||||||
return this.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
setValue(value) {
|
|
||||||
if (value)
|
if (value)
|
||||||
this.#onEnable();
|
this.#onEnable(playerId);
|
||||||
else
|
else
|
||||||
this.#onDisable();
|
this.#onDisable(playerId);
|
||||||
if (this.value !== value) {
|
if (this.isEnabled(playerId) !== value) {
|
||||||
this.value = value;
|
this.save(playerId, value);
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
this.save(playerId, value);
|
||||||
return void 0;
|
return void 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
save(playerId, value) {
|
||||||
|
world.setDynamicProperty(`${this.#DP_NAMESPACE}:${playerId}:${this.identifier}`, value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,34 +1,23 @@
|
|||||||
import { world } from "@minecraft/server";
|
|
||||||
import { BuilderOption } from "./BuilderOption";
|
|
||||||
|
|
||||||
export class BuilderOptions {
|
export class BuilderOptions {
|
||||||
playerId = void 0;
|
static options = {};
|
||||||
options = {};
|
|
||||||
|
|
||||||
constructor(playerId) {
|
static add(builderOption) {
|
||||||
this.playerId = playerId;
|
this.options[builderOption.identifier] = builderOption;
|
||||||
this.loadOptions();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
loadOptions() {
|
static get(optionId) {
|
||||||
const optionDPs = world.getDynamicPropertyIds().filter((id) => id.startsWith(`builderOptions:${this.playerId}:`));
|
return this.options[optionId];
|
||||||
for (const optionDP of optionDPs)
|
|
||||||
new BuilderOption(JSON.parse(world.getDynamicProperty(optionDP)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
add(builderOption) {
|
static getOptionIds() {
|
||||||
this.options[builderOption.identifer] = builderOption;
|
return Object.keys(this.options).sort((a, b) => a - b);
|
||||||
}
|
}
|
||||||
|
|
||||||
get(id) {
|
static isEnabled(optionId, playerId) {
|
||||||
return this.options[id];
|
return this.options[optionId].isEnabled(playerId);
|
||||||
}
|
}
|
||||||
|
|
||||||
getValue(id) {
|
static setValue(optionId, playerId, value) {
|
||||||
return this.options[id].getValue();
|
return this.options[optionId].setValue(playerId, value);
|
||||||
}
|
|
||||||
|
|
||||||
setValue(id, value) {
|
|
||||||
return this.options[id].setValue(value);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4,22 +4,33 @@ import { Builder } from "./Builder";
|
|||||||
export class Builders {
|
export class Builders {
|
||||||
static builders = {};
|
static builders = {};
|
||||||
|
|
||||||
add(playerId) {
|
static add(playerId) {
|
||||||
|
if (this.builders[playerId])
|
||||||
|
return;
|
||||||
this.builders[playerId] = new Builder(playerId);
|
this.builders[playerId] = new Builder(playerId);
|
||||||
}
|
}
|
||||||
|
|
||||||
remove(playerId) {
|
static remove(playerId) {
|
||||||
delete this.builders[playerId];
|
delete this.builders[playerId];
|
||||||
}
|
}
|
||||||
|
|
||||||
get(id) {
|
static get(id) {
|
||||||
return this.builders[id];
|
return this.builders[id];
|
||||||
}
|
}
|
||||||
|
|
||||||
onJoin(playerId) {
|
static onJoin(playerId) {
|
||||||
this.add(playerId);
|
this.add(playerId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static onLeave(playerId) {
|
||||||
|
this.remove(playerId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
world.afterEvents.playerJoin.subscribe((event) => Builders.onJoin(event.playerId));
|
world.afterEvents.playerJoin.subscribe((event) => Builders.onJoin(event.playerId));
|
||||||
world.beforeEvents.playerLeave.subscribe((event) => Builders.onLeave(event.player));
|
world.beforeEvents.playerLeave.subscribe((event) => Builders.onLeave(event.player.id));
|
||||||
|
world.afterEvents.worldLoad.subscribe((event) => {
|
||||||
|
for (const player of world.getAllPlayers()) {
|
||||||
|
Builders.onJoin(player.id);
|
||||||
|
}
|
||||||
|
});
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
export class InvalidInstanceError extends Error {
|
||||||
|
constructor(message) {
|
||||||
|
super(message);
|
||||||
|
this.name = 'InvalidInstanceError';
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import { structureCollection } from './StructureCollection';
|
import { structureCollection } from '../Structure/StructureCollection';
|
||||||
import { MenuForm } from '../MenuForm';
|
import { MenuForm } from '../MenuForm';
|
||||||
import { forceShow } from '../../utils';
|
import { forceShow } from '../../utils';
|
||||||
import { InstanceButtons } from '../enums/InstanceButtons';
|
import { InstanceButtons } from '../Enums/InstanceButtons';
|
||||||
import { InstanceFormBuilder } from './InstanceFormBuilder';
|
import { InstanceFormBuilder } from './InstanceFormBuilder';
|
||||||
import { FormCancelationReason } from '@minecraft/server-ui';
|
import { FormCancelationReason } from '@minecraft/server-ui';
|
||||||
|
|
||||||
@@ -11,12 +11,11 @@ export class InstanceForm {
|
|||||||
isEnabled: [
|
isEnabled: [
|
||||||
InstanceButtons.NextLayer,
|
InstanceButtons.NextLayer,
|
||||||
InstanceButtons.PreviousLayer,
|
InstanceButtons.PreviousLayer,
|
||||||
InstanceButtons.SetLayer,
|
|
||||||
InstanceButtons.Move,
|
InstanceButtons.Move,
|
||||||
InstanceButtons.Statistics,
|
InstanceButtons.Statistics,
|
||||||
InstanceButtons.Settings,
|
InstanceButtons.Settings,
|
||||||
InstanceButtons.Rename,
|
InstanceButtons.Rename,
|
||||||
InstanceButtons.Disable,
|
InstanceButtons.Disable
|
||||||
],
|
],
|
||||||
isNotEnabledAndIsNotPlaced: [
|
isNotEnabledAndIsNotPlaced: [
|
||||||
InstanceButtons.Place,
|
InstanceButtons.Place,
|
||||||
@@ -149,7 +148,11 @@ export class InstanceForm {
|
|||||||
if (response.canceled)
|
if (response.canceled)
|
||||||
return;
|
return;
|
||||||
this.instance.setVerifierEnabled(response.formValues[0]);
|
this.instance.setVerifierEnabled(response.formValues[0]);
|
||||||
this.instance.setLayer(parseInt(response.formValues[1]));
|
if (response.formValues[1])
|
||||||
|
this.instance.setVerifierDistance(5);
|
||||||
|
else
|
||||||
|
this.instance.setVerifierDistance(0);
|
||||||
|
this.instance.setLayer(parseInt(response.formValues[2]));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import { ActionFormData, ModalFormData } from '@minecraft/server-ui';
|
import { ActionFormData, ModalFormData } from '@minecraft/server-ui';
|
||||||
import { MenuFormBuilder } from '../MenuFormBuilder';
|
import { MenuFormBuilder } from '../MenuFormBuilder';
|
||||||
import { StructureVerifier } from './StructureVerifier';
|
import { StructureVerifier } from '../Verifier/StructureVerifier';
|
||||||
import { StructureStatistics } from './StructureStatistics';
|
import { StructureStatistics } from '../Structure/StructureStatistics';
|
||||||
import { TicksPerSecond } from '@minecraft/server';
|
import { TicksPerSecond } from '@minecraft/server';
|
||||||
|
|
||||||
export class InstanceFormBuilder {
|
export class InstanceFormBuilder {
|
||||||
@@ -29,7 +29,7 @@ export class InstanceFormBuilder {
|
|||||||
static async buildStatistics(instance) {
|
static async buildStatistics(instance) {
|
||||||
const buildStatisticsForm = new ActionFormData()
|
const buildStatisticsForm = new ActionFormData()
|
||||||
.title(MenuFormBuilder.menuTitle)
|
.title(MenuFormBuilder.menuTitle)
|
||||||
const structureVerifier = new StructureVerifier(instance, { isEnabled: true, trackPlayerDistance: 0, intervalOrLifetime: 30 * TicksPerSecond });
|
const structureVerifier = new StructureVerifier(instance, { isEnabled: true, trackPlayerDistance: 0, intervalOrLifetime: 30 * TicksPerSecond, isStandalone: true });
|
||||||
const verification = await structureVerifier.verifyStructure();
|
const verification = await structureVerifier.verifyStructure();
|
||||||
const statistics = new StructureStatistics(instance, verification);
|
const statistics = new StructureStatistics(instance, verification);
|
||||||
const statsMessage = statistics.getMessage();
|
const statsMessage = statistics.getMessage();
|
||||||
@@ -42,7 +42,8 @@ export class InstanceFormBuilder {
|
|||||||
.title(MenuFormBuilder.menuTitle)
|
.title(MenuFormBuilder.menuTitle)
|
||||||
.label('Use the slider to select the layer. Use 0 for all layers.')
|
.label('Use the slider to select the layer. Use 0 for all layers.')
|
||||||
.toggle('Block Validation', instance.options.verifier.isEnabled)
|
.toggle('Block Validation', instance.options.verifier.isEnabled)
|
||||||
.slider("Layer", 0, maxLayer, 1, currentLayer)
|
.toggle('Distance-Based Block Validation', instance.verifier.getTrackPlayerDistance() !== 0)
|
||||||
.submitButton('§aApply');
|
.slider("Layer", 0, instance.getMaxLayer(), 1, instance.getLayer())
|
||||||
|
.submitButton('§2Apply');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -22,6 +22,7 @@ export class InstanceOptions extends Option {
|
|||||||
}
|
}
|
||||||
|
|
||||||
constructor(instanceName, structureId) {
|
constructor(instanceName, structureId) {
|
||||||
|
super();
|
||||||
this.instanceName = instanceName;
|
this.instanceName = instanceName;
|
||||||
this.structureId = structureId;
|
this.structureId = structureId;
|
||||||
this.load();
|
this.load();
|
||||||
|
|||||||
+5
-5
@@ -1,8 +1,8 @@
|
|||||||
import { Vector } from "../lib/Vector";
|
import { Vector } from "../../lib/Vector";
|
||||||
import { StructureOutliner } from "./StructureOutliner";
|
import { StructureOutliner } from "../Structure/StructureOutliner";
|
||||||
import { StructureVerifier } from "./StructureVerifier";
|
import { StructureVerifier } from "../Verifier/StructureVerifier";
|
||||||
|
import { Structure } from "../Structure/Structure";
|
||||||
import { InstanceOptions } from "./InstanceOptions";
|
import { InstanceOptions } from "./InstanceOptions";
|
||||||
import { Structure } from "./Structure";
|
|
||||||
import { TicksPerSecond } from "@minecraft/server";
|
import { TicksPerSecond } from "@minecraft/server";
|
||||||
|
|
||||||
export class StructureInstance {
|
export class StructureInstance {
|
||||||
@@ -19,11 +19,11 @@ export class StructureInstance {
|
|||||||
|
|
||||||
delete() {
|
delete() {
|
||||||
this.disable();
|
this.disable();
|
||||||
|
this.options.clear();
|
||||||
delete this.options;
|
delete this.options;
|
||||||
delete this.structure;
|
delete this.structure;
|
||||||
delete this.outliner;
|
delete this.outliner;
|
||||||
delete this.verifier;
|
delete this.verifier;
|
||||||
this.options.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
refreshBox() {
|
refreshBox() {
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
import { forceShow } from '../utils';
|
import { forceShow } from '../utils';
|
||||||
import { structureCollection } from './StructureCollection';
|
import { structureCollection } from './Structure/StructureCollection';
|
||||||
import { MenuFormBuilder } from './MenuFormBuilder';
|
import { MenuFormBuilder } from './MenuFormBuilder';
|
||||||
import { InstanceForm } from './InstanceForm';
|
import { InstanceForm } from './Instance/InstanceForm';
|
||||||
|
import { BuilderForm } from './Builder/BuilderForm';
|
||||||
|
|
||||||
export class MenuForm {
|
export class MenuForm {
|
||||||
constructor(player, { jumpToInstance = false, instanceName = void 0 } = {}) {
|
constructor(player, { jumpToInstance = false, instanceName = void 0 } = {}) {
|
||||||
@@ -13,7 +14,7 @@ export class MenuForm {
|
|||||||
if (jumpToInstance) {
|
if (jumpToInstance) {
|
||||||
if (!instanceName)
|
if (!instanceName)
|
||||||
instanceName = structureCollection.getStructure(this.player.dimension.id, this.player.location, { useActiveLayer: false })?.getName();
|
instanceName = structureCollection.getStructure(this.player.dimension.id, this.player.location, { useActiveLayer: false })?.getName();
|
||||||
if (structureCollection.get(instanceName)) {
|
if (instanceName) {
|
||||||
new InstanceForm(this.player, instanceName);
|
new InstanceForm(this.player, instanceName);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -29,8 +30,15 @@ export class MenuForm {
|
|||||||
return forceShow(this.player, MenuFormBuilder.buildAllInstanceName()).then((response) => {
|
return forceShow(this.player, MenuFormBuilder.buildAllInstanceName()).then((response) => {
|
||||||
if (response.canceled)
|
if (response.canceled)
|
||||||
return;
|
return;
|
||||||
const selectedInstanceName = structureCollection.getInstanceNames()[response.selection];
|
let selection = response.selection;
|
||||||
|
if (selection === 0) {
|
||||||
|
new BuilderForm(this.player);
|
||||||
|
return void 0;
|
||||||
|
} else {
|
||||||
|
selection--;
|
||||||
|
const selectedInstanceName = structureCollection.getInstanceNames()[selection];
|
||||||
return selectedInstanceName || this.createNewInstance();
|
return selectedInstanceName || this.createNewInstance();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e.message === 'Menu timed out.') {
|
if (e.message === 'Menu timed out.') {
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
import { ActionFormData, ModalFormData } from '@minecraft/server-ui';
|
import { ActionFormData, ModalFormData } from '@minecraft/server-ui';
|
||||||
import { structureCollection } from './StructureCollection';
|
import { structureCollection } from './Structure/StructureCollection';
|
||||||
|
|
||||||
export class MenuFormBuilder {
|
export class MenuFormBuilder {
|
||||||
static menuTitle = '§l§2Construct §8Menu';
|
static menuTitle = '§l§2Construct';
|
||||||
|
|
||||||
static buildAllInstanceName() {
|
static buildAllInstanceName() {
|
||||||
const allInstanceNameForm = new ActionFormData()
|
const allInstanceNameForm = new ActionFormData()
|
||||||
.title(this.menuTitle)
|
.title(this.menuTitle)
|
||||||
.body('Select an instance:');
|
.body('Select an instance:');
|
||||||
|
allInstanceNameForm.button('Builder Settings');
|
||||||
structureCollection.getInstanceNames().forEach(instanceName => {
|
structureCollection.getInstanceNames().forEach(instanceName => {
|
||||||
allInstanceNameForm.button(`§2${instanceName}`);
|
allInstanceNameForm.button(`§2${instanceName}`);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { structureCollection } from "./StructureCollection";
|
import { structureCollection } from "./Structure/StructureCollection";
|
||||||
import { world } from "@minecraft/server";
|
import { world } from "@minecraft/server";
|
||||||
|
|
||||||
export class Raycaster {
|
export class Raycaster {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { world } from "@minecraft/server";
|
import { world } from "@minecraft/server";
|
||||||
import { Vector } from "../lib/Vector";
|
import { Vector } from "../../lib/Vector";
|
||||||
|
|
||||||
export class Structure {
|
export class Structure {
|
||||||
structureId;
|
structureId;
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { InstanceOptions } from './InstanceOptions';
|
import { InvalidInstanceError } from '../Errors/InvalidInstanceError';
|
||||||
import { StructureInstance } from './StructureInstance';
|
import { InstanceOptions } from '../Instance/InstanceOptions';
|
||||||
|
import { StructureInstance } from '../Instance/StructureInstance';
|
||||||
import { world } from '@minecraft/server';
|
import { world } from '@minecraft/server';
|
||||||
|
|
||||||
class StructureCollection {
|
class StructureCollection {
|
||||||
@@ -26,7 +27,7 @@ class StructureCollection {
|
|||||||
|
|
||||||
add(instanceName, structureId) {
|
add(instanceName, structureId) {
|
||||||
if (this.structures[instanceName])
|
if (this.structures[instanceName])
|
||||||
throw new Error(`Instance ${instanceName} already exists.`);
|
throw new InvalidInstanceError(`Instance ${instanceName} already exists.`);
|
||||||
const structure = new StructureInstance(instanceName, structureId);
|
const structure = new StructureInstance(instanceName, structureId);
|
||||||
this.structures[instanceName] = structure;
|
this.structures[instanceName] = structure;
|
||||||
return structure;
|
return structure;
|
||||||
@@ -34,9 +35,8 @@ class StructureCollection {
|
|||||||
|
|
||||||
get(instanceName) {
|
get(instanceName) {
|
||||||
const structure = this.structures[instanceName];
|
const structure = this.structures[instanceName];
|
||||||
if (!structure) {
|
if (!structure)
|
||||||
throw new Error(`Instance ${instanceName} not found.`);
|
throw new InvalidInstanceError(`Instance ${instanceName} not found.`);
|
||||||
}
|
|
||||||
return structure;
|
return structure;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Outliner } from './Outliner';
|
import { Outliner } from '../Outliner';
|
||||||
|
|
||||||
export class StructureOutliner {
|
export class StructureOutliner {
|
||||||
constructor(instance) {
|
constructor(instance) {
|
||||||
@@ -42,7 +42,7 @@ export class StructureOutliner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
layeredDraw() {
|
layeredDraw() {
|
||||||
const { min, max } = this.instance.getLayeredBounds();
|
const { min, max } = this.instance.getLayerBounds(this.instance.getLayer());
|
||||||
this.outliner.setVertices(this.dimension, this.instance.toGlobalCoords(min), this.instance.toGlobalCoords(max));
|
this.outliner.setVertices(this.dimension, this.instance.toGlobalCoords(min), this.instance.toGlobalCoords(max));
|
||||||
this.outliner.addStandaloneParticles(this.getCornerVertices());
|
this.outliner.addStandaloneParticles(this.getCornerVertices());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { BlockVerificationLevel } from './enums/BlockVerificationLevel.js';
|
import { BlockVerificationLevel } from '../Enums/BlockVerificationLevel.js';
|
||||||
|
|
||||||
export class StructureStatistics {
|
export class StructureStatistics {
|
||||||
constructor(instance, verification) {
|
constructor(instance, verification) {
|
||||||
|
|||||||
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
import { MolangVariableMap } from "@minecraft/server";
|
import { MolangVariableMap } from "@minecraft/server";
|
||||||
import { BlockVerificationLevel } from "./enums/BlockVerificationLevel";
|
import { BlockVerificationLevel } from "../Enums/BlockVerificationLevel";
|
||||||
import { Vector } from "../lib/Vector";
|
import { Vector } from "../../lib/Vector";
|
||||||
|
|
||||||
export class BlockVerificationLevelRender {
|
export class BlockVerificationLevelRender {
|
||||||
opacity = 0.2;
|
opacity = 0.2;
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
import { BlockVerificationLevel } from "./enums/BlockVerificationLevel";
|
import { BlockVerificationLevel } from "../Enums/BlockVerificationLevel";
|
||||||
|
|
||||||
export class BlockVerifier {
|
export class BlockVerifier {
|
||||||
constructor(block, instance) {
|
constructor(block, instance) {
|
||||||
+18
-5
@@ -1,8 +1,8 @@
|
|||||||
import { BlockVerifier } from "./BlockVerifier";
|
import { BlockVerifier } from "./BlockVerifier";
|
||||||
import { BlockVerificationLevel } from "./enums/BlockVerificationLevel";
|
import { BlockVerificationLevel } from "../Enums/BlockVerificationLevel";
|
||||||
import { BlockVerificationLevelRender } from "./BlockVerificationLevelRender";
|
import { BlockVerificationLevelRender } from "../Verifier/BlockVerificationLevelRender";
|
||||||
import { system, TicksPerSecond } from "@minecraft/server";
|
import { system, TicksPerSecond } from "@minecraft/server";
|
||||||
import { Vector } from "../lib/Vector";
|
import { Vector } from "../../lib/Vector";
|
||||||
|
|
||||||
const MIN_TRACK_PLAYER_DISTANCE = 0;
|
const MIN_TRACK_PLAYER_DISTANCE = 0;
|
||||||
const MAX_TRACK_PLAYER_DISTANCE = 7;
|
const MAX_TRACK_PLAYER_DISTANCE = 7;
|
||||||
@@ -21,11 +21,17 @@ export class StructureVerifier {
|
|||||||
#verifyJob;
|
#verifyJob;
|
||||||
#populateJob = {};
|
#populateJob = {};
|
||||||
|
|
||||||
constructor(instance, { isEnabled = false, trackPlayerDistance = 0, intervalOrLifetime = 10 } = {}) {
|
constructor(instance, { isEnabled = false, trackPlayerDistance = 0, intervalOrLifetime = 10, isStandalone: isIndependent = false } = {}) {
|
||||||
this.instance = instance;
|
this.instance = instance;
|
||||||
this.intervalOrLifetime = Math.max(intervalOrLifetime, MIN_LIFETIME);
|
this.intervalOrLifetime = Math.max(intervalOrLifetime, MIN_LIFETIME);
|
||||||
|
if (isIndependent) {
|
||||||
|
this.isIndependent = isIndependent;
|
||||||
|
this.enabled = isEnabled;
|
||||||
|
this.trackPlayerDistance = trackPlayerDistance;
|
||||||
|
} else {
|
||||||
this.instance.options.setVerifierEnabled(isEnabled);
|
this.instance.options.setVerifierEnabled(isEnabled);
|
||||||
this.instance.options.setVerifierDistance(trackPlayerDistance);
|
this.instance.options.setVerifierDistance(trackPlayerDistance);
|
||||||
|
}
|
||||||
this.locationsToVerify = new Set();
|
this.locationsToVerify = new Set();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,11 +56,18 @@ export class StructureVerifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
isEnabled() {
|
isEnabled() {
|
||||||
|
if (this.isIndependent)
|
||||||
|
return this.enabled;
|
||||||
return this.instance.options.verifier.isEnabled;
|
return this.instance.options.verifier.isEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
getTrackPlayerDistance() {
|
getTrackPlayerDistance() {
|
||||||
return Math.min(MAX_TRACK_PLAYER_DISTANCE, Math.max(MIN_TRACK_PLAYER_DISTANCE, this.instance.options.verifier.trackPlayerDistance));
|
let distance;
|
||||||
|
if (this.isIndependent)
|
||||||
|
distance = this.trackPlayerDistance;
|
||||||
|
else
|
||||||
|
distance = this.instance.options.verifier.trackPlayerDistance
|
||||||
|
return Math.min(MAX_TRACK_PLAYER_DISTANCE, Math.max(MIN_TRACK_PLAYER_DISTANCE, distance));
|
||||||
}
|
}
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
@@ -2,6 +2,7 @@ import { Command } from '../lib/canopy/CanopyExtension';
|
|||||||
import { extension } from '../config';
|
import { extension } from '../config';
|
||||||
import { world, system } from '@minecraft/server';
|
import { world, system } from '@minecraft/server';
|
||||||
import { MenuForm } from '../classes/MenuForm';
|
import { MenuForm } from '../classes/MenuForm';
|
||||||
|
import { structureCollection } from '../classes/Structure/StructureCollection'
|
||||||
|
|
||||||
const ACTION_ITEM = 'minecraft:paper';
|
const ACTION_ITEM = 'minecraft:paper';
|
||||||
|
|
||||||
@@ -21,7 +22,11 @@ world.beforeEvents.itemUse.subscribe((event) => {
|
|||||||
|
|
||||||
function openMenu(sender, event = void 0) {
|
function openMenu(sender, event = void 0) {
|
||||||
const options = { jumpToInstance: true }
|
const options = { jumpToInstance: true }
|
||||||
if (event)
|
if (event) {
|
||||||
options.instanceName = event.itemStack?.typeId;
|
const instanceNames = structureCollection.getInstanceNames();
|
||||||
|
const instanceName = event.itemStack?.nameTag;
|
||||||
|
if (instanceNames.includes(instanceName))
|
||||||
|
options.instanceName = instanceName;
|
||||||
|
}
|
||||||
new MenuForm(sender, options);
|
new MenuForm(sender, options);
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
/**
|
||||||
|
* @license
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2024 ForestOfLight
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
import { world } from '@minecraft/server';
|
||||||
|
|
||||||
|
class Rule {
|
||||||
|
#identifier;
|
||||||
|
#description;
|
||||||
|
#contingentRules;
|
||||||
|
#independentRules;
|
||||||
|
|
||||||
|
constructor({ identifier, description, contingentRules = [], independentRules = [] }) {
|
||||||
|
this.#identifier = identifier;
|
||||||
|
this.#description = description;
|
||||||
|
this.#contingentRules = contingentRules;
|
||||||
|
this.#independentRules = independentRules;
|
||||||
|
}
|
||||||
|
|
||||||
|
getID() {
|
||||||
|
return this.#identifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
getDescription() {
|
||||||
|
return this.#description;
|
||||||
|
}
|
||||||
|
|
||||||
|
getContigentRules() {
|
||||||
|
return this.#contingentRules;
|
||||||
|
}
|
||||||
|
|
||||||
|
getIndependentRules() {
|
||||||
|
return this.#independentRules;
|
||||||
|
}
|
||||||
|
|
||||||
|
getValue() {
|
||||||
|
const value = world.getDynamicProperty(this.#identifier);
|
||||||
|
if (String(value) === 'true')
|
||||||
|
return true;
|
||||||
|
if (['false', 'undefined'].includes(String(value)))
|
||||||
|
return false;
|
||||||
|
throw new Error(`Rule ${this.#identifier} has an invalid value: ${value} (${typeof value})`);
|
||||||
|
}
|
||||||
|
|
||||||
|
setValue(value) {
|
||||||
|
world.setDynamicProperty(this.#identifier, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Rule;
|
||||||
@@ -1,7 +1,10 @@
|
|||||||
// Rules
|
// Setup
|
||||||
import './rules/easyPlace';
|
import './classes/Builder/Builders';
|
||||||
import './rules/fastEasyPlace';
|
|
||||||
import './rules/materialGrabber';
|
// Options
|
||||||
|
import './options/easyPlace';
|
||||||
|
import './options/fastEasyPlace';
|
||||||
|
import './options/materialGrabber';
|
||||||
|
|
||||||
// Commands
|
// Commands
|
||||||
import './commands/construct';
|
import './commands/construct';
|
||||||
|
|||||||
@@ -1,24 +1,24 @@
|
|||||||
import { BuilderOption } from '../classes/Builder/BuilderOption';
|
import { BuilderOption } from '../classes/Builder/BuilderOption';
|
||||||
import { BlockPermutation, EntityComponentTypes, GameMode, ItemStack, system, world } from '@minecraft/server';
|
import { BlockPermutation, EntityComponentTypes, GameMode, ItemStack, system, world } from '@minecraft/server';
|
||||||
import { structureCollection } from '../classes/StructureCollection';
|
import { structureCollection } from '../classes/Structure/StructureCollection';
|
||||||
import { bannedBlocks, bannedToValidBlockMap, whitelistedBlockStates, resetToBlockStates, bannedDimensionBlocks, specialItemPlacementConversions,
|
import { bannedBlocks, bannedToValidBlockMap, whitelistedBlockStates, resetToBlockStates, bannedDimensionBlocks, specialItemPlacementConversions,
|
||||||
blockIdToItemStackMap } from '../data';
|
blockIdToItemStackMap } from '../data';
|
||||||
import { fetchMatchingItemSlot } from '../utils';
|
import { fetchMatchingItemSlot } from '../utils';
|
||||||
|
|
||||||
const ACTION_SLOT = 35;
|
const ACTION_SLOT = 27;
|
||||||
|
|
||||||
new BuilderOption({
|
const builderOption = new BuilderOption({
|
||||||
identifier: 'easyPlace',
|
identifier: 'easyPlace',
|
||||||
displayName: 'Easy Place',
|
displayName: 'Easy Place',
|
||||||
description: 'Always place the correct block.',
|
description: 'Always place the correct structure block.',
|
||||||
howToUse: "Place blocks in a structure with a paper named 'Easy Place' in the bottom right slot of your inventory to always place the correct block.",
|
howToUse: "Place blocks in a structure with a paper named 'Easy Place' in the inventory slot above your first hotbar slot to always place the correct block."
|
||||||
onEnableCallback: () => { world.beforeEvents.playerPlaceBlock.subscribe(onPlayerPlaceBlock); },
|
});
|
||||||
onDisableCallback: () => { world.beforeEvents.playerPlaceBlock.unsubscribe(onPlayerPlaceBlock); }
|
|
||||||
})
|
world.beforeEvents.playerPlaceBlock.subscribe(onPlayerPlaceBlock);
|
||||||
|
|
||||||
function onPlayerPlaceBlock(event) {
|
function onPlayerPlaceBlock(event) {
|
||||||
const { player, block, permutationBeingPlaced } = event;
|
const { player, block } = event;
|
||||||
if (!player || !block || !hasActionItemInCorrectSlot(player)) return;
|
if (!player || !block || !builderOption.isEnabled(player.id) || !hasActionItemInCorrectSlot(player)) return;
|
||||||
const structureBlock = structureCollection.fetchStructureBlock(block.dimension.id, block.location);
|
const structureBlock = structureCollection.fetchStructureBlock(block.dimension.id, block.location);
|
||||||
if (!structureBlock)
|
if (!structureBlock)
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -4,19 +4,21 @@ import { bannedBlocks, bannedToValidBlockMap, whitelistedBlockStates, resetToBlo
|
|||||||
blockIdToItemStackMap } from '../data';
|
blockIdToItemStackMap } from '../data';
|
||||||
import { Raycaster } from '../classes/Raycaster';
|
import { Raycaster } from '../classes/Raycaster';
|
||||||
|
|
||||||
|
const PROCESS_INTERVAL = 2;
|
||||||
|
|
||||||
let runner = void 0;
|
let runner = void 0;
|
||||||
new BuilderOption({
|
const builderOption = new BuilderOption({
|
||||||
identifier: 'fastEasyPlace',
|
identifier: 'fastEasyPlace',
|
||||||
displayName: 'Fast Easy Place',
|
displayName: 'Fast Easy Place',
|
||||||
description: 'Place structure blocks just by looking at them.',
|
description: 'Place structure blocks just by looking at them.',
|
||||||
howToUse: "Look at structure blocks with a paper named 'Easy Place' in your hand to place them.",
|
howToUse: "Look at structure blocks with a paper named 'Easy Place' in your hand to place them.",
|
||||||
onEnableCallback: () => { runner = system.runInterval(onTick, 2); },
|
});
|
||||||
onDisableCallback: () => { system.clearRun(runner); }
|
|
||||||
})
|
system.runInterval(onTick, PROCESS_INTERVAL);
|
||||||
|
|
||||||
function onTick() {
|
function onTick() {
|
||||||
for (const player of world.getAllPlayers()) {
|
for (const player of world.getAllPlayers()) {
|
||||||
if (!player)
|
if (!player || !builderOption.isEnabled(player.id))
|
||||||
continue;
|
continue;
|
||||||
processEasyPlace(player);
|
processEasyPlace(player);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +1,15 @@
|
|||||||
import { BuilderOption } from '../classes/Builder/BuilderOption';
|
import { BuilderOption } from '../classes/Builder/BuilderOption';
|
||||||
import { world } from '@minecraft/server';
|
import { world } from '@minecraft/server';
|
||||||
|
|
||||||
new BuilderOption({
|
const builderOption = new BuilderOption({
|
||||||
identifier: 'materialGrabber',
|
identifier: 'materialGrabber',
|
||||||
displayName: 'Material Grabber',
|
displayName: 'Material Grabber',
|
||||||
description: 'Pulls structure items from inventories.',
|
description: 'Pulls structure items from inventories.',
|
||||||
howToUse: "Interact with inventories using a paper named 'Material Grabber' to pull structure items from them.",
|
howToUse: "Interact with inventories using a paper named 'Material Grabber' to pull structure items from them.",
|
||||||
onEnableCallback: () => {
|
});
|
||||||
world.beforeEvents.playerInteractWithBlock.subscribe(onPlayerInteract);
|
|
||||||
world.beforeEvents.playerInteractWithEntity.subscribe(onPlayerInteract);
|
world.beforeEvents.playerInteractWithBlock.subscribe(onPlayerInteract);
|
||||||
},
|
world.beforeEvents.playerInteractWithEntity.subscribe(onPlayerInteract);
|
||||||
onDisableCallback: () => {
|
|
||||||
world.beforeEvents.playerInteractWithBlock.unsubscribe(onPlayerInteract);
|
|
||||||
world.beforeEvents.playerInteractWithEntity.unsubscribe(onPlayerInteract);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
function onPlayerInteract(event) {
|
function onPlayerInteract(event) {
|
||||||
// get inventory
|
// get inventory
|
||||||
|
|||||||
Reference in New Issue
Block a user