diff --git a/StrucTool [BP]/manifest.json b/StrucTool [BP]/manifest.json index 901fa1c..c0c3d71 100644 --- a/StrucTool [BP]/manifest.json +++ b/StrucTool [BP]/manifest.json @@ -1,7 +1,7 @@ { "format_version": 2, "header": { - "name": "StrucTool", + "name": "StrucTool [BP] v1.0.0", "description": "Survival building extension for §l§aCanopy§r by §aForestOfLight§r.", "uuid": "8c0c0153-d8b9-482a-889f-aef922b8fe58", "min_engine_version": [1, 21, 70], @@ -32,6 +32,10 @@ "module_name": "@minecraft/server-ui", "version": "2.0.0-beta" }, + { + "uuid": "375ec465-3dc1-429f-8b4c-a337889e1ed4", // StrucTool RP + "version": [1, 0, 0] + }, { "uuid": "bcf34368-ed0c-4cf7-938e-582cccf9950d", // Canopy RP "version": [1, 0, 3] diff --git a/StrucTool [BP]/scripts/classes/BlockVerificationLevelRender.js b/StrucTool [BP]/scripts/classes/BlockVerificationLevelRender.js new file mode 100644 index 0000000..33ed279 --- /dev/null +++ b/StrucTool [BP]/scripts/classes/BlockVerificationLevelRender.js @@ -0,0 +1,69 @@ +import { MolangVariableMap } from "@minecraft/server"; +import { BlockVerificationLevel } from "./enums/BlockVerificationLevel"; +import { Vector } from "../lib/Vector"; + +export class BlockVerificationLevelRender { + opacity = 0.2; + lifetime = 0; + + constructor(dimensionLocation, verificationLevel, lifetime = 5) { + this.dimension = dimensionLocation.dimension; + this.location = new Vector(dimensionLocation.location.x, dimensionLocation.location.y, dimensionLocation.location.z); + this.verificationLevel = verificationLevel; + this.lifetime = lifetime; + this.renderBlock(); + } + + renderBlock() { + for (const particleLocation of this.getParticleLocations()) { + const color = this.getRGBAMolang(); + if (!color) + return; + color.setFloat("lifetime", this.lifetime); + try { + this.dimension.spawnParticle(particleLocation.particleType, particleLocation.location, color); + } catch { + /* pass */ + } + } + } + + getParticleLocations() { + const bottomFace = new Vector(0.5, 0, 0.5); + const topFace = new Vector(0.5, 1, 0.5); + const leftFace = new Vector(1, 0.5, 0.5); + const rightFace = new Vector(0, 0.5, 0.5); + const frontFace = new Vector(0.5, 0.5, 1); + const backFace = new Vector(0.5, 0.5, 0); + return [ + { particleType: "structool:blockoverlay_xz", location: this.location.add(topFace) }, + { particleType: "structool:blockoverlay_xz", location: this.location.add(bottomFace) }, + { particleType: "structool:blockoverlay_yz", location: this.location.add(leftFace) }, + { particleType: "structool:blockoverlay_yz", location: this.location.add(rightFace) }, + { particleType: "structool:blockoverlay_xy", location: this.location.add(frontFace) }, + { particleType: "structool:blockoverlay_xy", location: this.location.add(backFace) } + ]; + } + + getRGBAMolang() { + const rgb = this.verificationLevelToRGB(); + if (!rgb) return; + rgb.alpha = this.opacity; + const molang = new MolangVariableMap(); + molang.setColorRGBA("face_color", rgb); + return molang; + } + + verificationLevelToRGB() { + switch (this.verificationLevel) { + case BlockVerificationLevel.NoMatch: + return { red: 1, green: 0, blue: 0}; + case BlockVerificationLevel.TypeMatch: + return { red: 1, green: 1, blue: 0}; + case BlockVerificationLevel.Missing: + return { red: 0, green: 0, blue: 1}; + default: + return void 0; + } + } +} \ No newline at end of file diff --git a/StrucTool [BP]/scripts/classes/BlockVerifier.js b/StrucTool [BP]/scripts/classes/BlockVerifier.js index 5ac24e9..81b9a4e 100644 --- a/StrucTool [BP]/scripts/classes/BlockVerifier.js +++ b/StrucTool [BP]/scripts/classes/BlockVerifier.js @@ -1,4 +1,4 @@ -import { BlockVerificationLevel } from "./BlockVerificationLevel"; +import { BlockVerificationLevel } from "./enums/BlockVerificationLevel"; export class BlockVerifier { constructor(block, instance) { @@ -14,14 +14,14 @@ export class BlockVerifier { evaluatePermutations(worldPermutation, structPermutation) { if (this.isCorrectlyAir(worldPermutation, structPermutation)) - return this.air(); + return BlockVerificationLevel.Air; if (this.isMissing(worldPermutation, structPermutation)) - return this.missing(); + return BlockVerificationLevel.Missing; if (this.isExactMatch(worldPermutation, structPermutation)) - return this.matchingPermutations(); + return BlockVerificationLevel.Match; if (this.isTypeMatch(worldPermutation, structPermutation)) - return this.matchingTypes(); - return this.matchingNone(); + return BlockVerificationLevel.TypeMatch; + return BlockVerificationLevel.NoMatch; } isCorrectlyAir(worldPermutation, structPermutation) { @@ -39,24 +39,4 @@ export class BlockVerifier { isExactMatch(worldPermuation, structurePermuation) { return worldPermuation.matches(structurePermuation.type.id, structurePermuation.getAllStates()); } - - air() { - return BlockVerificationLevel.isAir; - } - - missing() { - return BlockVerificationLevel.Missing; - } - - matchingPermutations() { - return BlockVerificationLevel.TypeAndStateMatch; - } - - matchingTypes() { - return BlockVerificationLevel.TypeMatch; - } - - matchingNone() { - return BlockVerificationLevel.NoMatch; - } } \ No newline at end of file diff --git a/StrucTool [BP]/scripts/classes/InstanceEditForm.js b/StrucTool [BP]/scripts/classes/InstanceEditForm.js index 928a281..0a87d14 100644 --- a/StrucTool [BP]/scripts/classes/InstanceEditForm.js +++ b/StrucTool [BP]/scripts/classes/InstanceEditForm.js @@ -1,7 +1,8 @@ import { structureCollection } from './StructureCollection'; import { MenuForm } from '../classes/MenuForm'; -import { InstanceEditOptions } from './InstanceEditOptions'; +import { InstanceEditOptions } from './enums/InstanceEditOptions'; import { InstanceEditFormBuilder } from './InstanceEditFormBuilder'; +import { FormCancelationReason } from '@minecraft/server-ui'; export class InstanceEditForm { instanceName; @@ -135,7 +136,10 @@ export class InstanceEditForm { } async statisticsForm() { - const form = await InstanceEditFormBuilder.buildStatistics(this.instance) - form.show(this.player); + const statsForm = await InstanceEditFormBuilder.buildStatistics(this.instance) + statsForm.form.show(this.player).then((response) => { + if (response.canceled && response.cancelationReason === FormCancelationReason.UserBusy) + this.player.sendMessage(statsForm.stats); + }); } } \ No newline at end of file diff --git a/StrucTool [BP]/scripts/classes/InstanceEditFormBuilder.js b/StrucTool [BP]/scripts/classes/InstanceEditFormBuilder.js index 3564309..c98d61a 100644 --- a/StrucTool [BP]/scripts/classes/InstanceEditFormBuilder.js +++ b/StrucTool [BP]/scripts/classes/InstanceEditFormBuilder.js @@ -1,7 +1,7 @@ import { ActionFormData, ModalFormData } from '@minecraft/server-ui'; import { MenuFormBuilder } from './MenuFormBuilder'; import { StructureVerifier } from './StructureVerifier'; -import { BlockVerificationLevel } from './BlockVerificationLevel'; +import { StructureStatistics } from './StructureStatistics'; export class InstanceEditFormBuilder { static buildInstance(instance, options) { @@ -36,20 +36,11 @@ export class InstanceEditFormBuilder { static async buildStatistics(instance) { const buildStatisticsForm = new ActionFormData() .title(MenuFormBuilder.menuTitle) - let message = ''; const structureVerifier = new StructureVerifier(instance); - const statistics = await structureVerifier.verifyStructure(); - message += `§fStatistics for §a${instance.name}§f:\n`; - message += `§7Blocks: §2${instance.getTotalVolume() - statistics.correctlyAir}\n`; - message += `§7Correct: §a${this.getFormattedStatistic(statistics, BlockVerificationLevel.TypeAndStateMatch)}\n`; - message += `§7Block State Incorrect: §e${this.getFormattedStatistic(statistics, BlockVerificationLevel.TypeMatch)}\n`; - message += `§7Incorrect: §c${this.getFormattedStatistic(statistics, BlockVerificationLevel.NoMatch)}\n`; - message += `§7Missing: §c${this.getFormattedStatistic(statistics, BlockVerificationLevel.Missing)}\n`; - buildStatisticsForm.body(message); - return buildStatisticsForm; - } - - static getFormattedStatistic(statistics, blockVerificationLevel) { - return `${statistics[blockVerificationLevel]} (${statistics.percentages[blockVerificationLevel].toFixed(2)}%%)`; + const verification = await structureVerifier.verifyStructure(); + const statistics = new StructureStatistics(instance, verification); + const statsMessage = statistics.getMessage(); + buildStatisticsForm.body(statsMessage); + return { form: buildStatisticsForm, stats: statsMessage }; } } \ No newline at end of file diff --git a/StrucTool [BP]/scripts/classes/Outliner.js b/StrucTool [BP]/scripts/classes/Outliner.js index 08d8821..817604a 100644 --- a/StrucTool [BP]/scripts/classes/Outliner.js +++ b/StrucTool [BP]/scripts/classes/Outliner.js @@ -1,23 +1,21 @@ -import { system, world } from "@minecraft/server"; +import { MolangVariableMap, system, world } from "@minecraft/server"; import { Vector } from "../lib/Vector"; - export class Outliner { dimension; min = new Vector(); max = new Vector(); - drawParticle = "minecraft:villager_happy"; - drawFrequency = 8; + drawParticle = "structool:outline"; + drawFrequency = 10; #drawParticles = []; - #runner = null; + #runner = void 0; constructor(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); - this.startDraw(); } startDraw() { @@ -25,18 +23,28 @@ export class Outliner { } stopDraw() { + if (!this.#runner) + return; system.clearRun(this.#runner); + this.#runner = void 0; } draw() { - this.#drawParticles.length = 0; - this.#drawParticles.push(...this.getVerticeParticleLocations()); - this.#drawParticles.push(...this.getCubiodParticleLocations()); + this.drawParticles(this.getVerticeParticles(), () => { + return { red: 1, green: 1, blue: 1, alpha: 1 } + }); + this.drawParticles(this.getCubiodEdgeParticles(), this.getNextParticleColor.bind(this)); + } + drawParticles(particleLocations, colorCallback) { + this.#drawParticles.length = 0; + this.#drawParticles.push(...particleLocations); for (const [particleType, location] of this.#drawParticles) { + const molang = new MolangVariableMap(); + molang.setColorRGBA("dot_color", colorCallback()); try { - this.dimension.spawnParticle(particleType, location); - } catch { + this.dimension.spawnParticle(particleType, location, molang); + } catch (e) { /* pass */ } } @@ -62,11 +70,11 @@ export class Outliner { this.vertices = this.getVertices(min, max); } - getVerticeParticleLocations() { + getVerticeParticles() { return this.vertices.map((v) => [this.drawParticle, v]); } - getCubiodParticleLocations() { + getCubiodEdgeParticles() { const edges = [ [0, 1], [0, 2], @@ -97,4 +105,14 @@ export class Outliner { for (const location of locations) this.vertices.push(new Vector(location.x, location.y, location.z)); } + + getNextParticleColor() { + if (this.lastWasBlack) { + this.lastWasBlack = false; + return { red: 1, green: 1, blue: 0, alpha: 1 }; + } else { + this.lastWasBlack = true; + return { red: 0.15, green: 0.15, blue: 0.15, alpha: 1 }; + } + } } \ No newline at end of file diff --git a/StrucTool [BP]/scripts/classes/StructureInstance.js b/StrucTool [BP]/scripts/classes/StructureInstance.js index 82e3fc7..a507dae 100644 --- a/StrucTool [BP]/scripts/classes/StructureInstance.js +++ b/StrucTool [BP]/scripts/classes/StructureInstance.js @@ -1,6 +1,7 @@ import { world } from "@minecraft/server"; import { Outliner } from "./Outliner"; import { StructureOutliner } from "./StructureOutliner"; +import { StructureVerifier } from "./StructureVerifier"; export class StructureInstance { name; @@ -15,6 +16,7 @@ export class StructureInstance { currentLayer: 0 }; outliner = void 0; + verifier = void 0; constructor(instanceName, structureId) { this.name = instanceName; @@ -25,7 +27,7 @@ export class StructureInstance { this.#options = this.loadOptions(); this.#options.structureId = structureId; this.updateOptions(); - this.outliner = new StructureOutliner(this); + this.refreshBox(); } loadOptions() { @@ -102,6 +104,8 @@ export class StructureInstance { for (let x = 0; x < max.x; x++) { for (let z = 0; z < max.z; z++) { const blockPermutation = this.#structure.getBlockPermutation({ x, y, z }); + if (!blockPermutation) + yield void 0; blockPermutation.location = { x, y, z }; yield blockPermutation; } @@ -128,6 +132,14 @@ export class StructureInstance { return this.#structure.size.x * this.#structure.size.y * this.#structure.size.z; } + getActiveVolume() { + if (!this.#options.isEnabled) + return 0; + if (this.#options.currentLayer === 0) + return this.getTotalVolume(); + return this.#structure.size.x * this.#structure.size.z; + } + rename(newName) { world.setDynamicProperty(`structOptions:${this.name}`, void 0); this.name = newName; @@ -142,20 +154,20 @@ export class StructureInstance { enable() { this.#options.isEnabled = true; this.updateOptions(); - this.refreshOutliner(); + this.refreshBox(); } disable() { this.#options.isEnabled = false; this.updateOptions(); - this.refreshOutliner(); + this.refreshBox(); } move(dimensionId, location) { this.#options.dimensionId = dimensionId; this.#options.worldLocation = { x: Math.floor(location.x), y: Math.floor(location.y), z: Math.floor(location.z) }; this.updateOptions(); - this.refreshOutliner(); + this.refreshBox(); } setLayer(layer) { @@ -163,11 +175,18 @@ export class StructureInstance { throw new Error(`[StrucTool] Layer ${layer} is out of bounds.`); this.#options.currentLayer = layer; this.updateOptions(); - this.refreshOutliner(); + this.refreshBox(); } - refreshOutliner() { + refreshBox() { + if (!this.hasLocation()) + return; + if (!this.outliner) + this.outliner = new StructureOutliner(this); + if (!this.verifier) + this.verifier = new StructureVerifier(this, { shouldRender: true }); this.outliner.refresh(); + this.verifier.refresh(); } isLocationInStructure(dimensionId, structureLocation) { diff --git a/StrucTool [BP]/scripts/classes/StructureOutliner.js b/StrucTool [BP]/scripts/classes/StructureOutliner.js index 2d7bda7..a11cbc6 100644 --- a/StrucTool [BP]/scripts/classes/StructureOutliner.js +++ b/StrucTool [BP]/scripts/classes/StructureOutliner.js @@ -5,7 +5,6 @@ export class StructureOutliner { this.instance = instance; this.pullInstanceData(); this.outliner = new Outliner(this.dimension, this.bounds.min, this.bounds.max); - this.refresh(); } pullInstanceData() { diff --git a/StrucTool [BP]/scripts/classes/StructureStatistics.js b/StrucTool [BP]/scripts/classes/StructureStatistics.js new file mode 100644 index 0000000..d1612d4 --- /dev/null +++ b/StrucTool [BP]/scripts/classes/StructureStatistics.js @@ -0,0 +1,64 @@ +import { BlockVerificationLevel } from './enums/BlockVerificationLevel.js'; + +export class StructureStatistics { + constructor(instance, verification) { + this.instance = instance; + this.verification = verification; + this.parse(); + } + + init() { + this.statistics = {}; + for (const verificationLevel of Object.values(BlockVerificationLevel)) { + this.statistics[verificationLevel] = 0; + } + this.statistics.correctlyAir = 0; + } + + parse() { + this.init(); + for (const blockVerificationLevel of Object.values(BlockVerificationLevel)) { + this.parseStatistic(blockVerificationLevel); + } + } + + parseStatistic(blockVerificationLevel) { + for (const verificationlevel of Object.values(this.verification)) { + if (blockVerificationLevel === verificationlevel) { + this.statistics[verificationlevel]++; + } + } + } + + getNonAirBlocks() { + return this.instance.getActiveVolume() - this.verification.correctlyAir; + } + + getStat(blockVerificationLevel) { + return { num: this.statistics[blockVerificationLevel], percent: this.statistics[blockVerificationLevel] / (this.getNonAirBlocks()) * 100 }; + } + + getSkipped() { + return this.statistics[BlockVerificationLevel.Skipped] || 0; + } + + getMessage() { + let message = ''; + message += `§fStatistics for §a${this.instance.name}§f:`; + if (this.instance.isUsingLayers()) + message += ` §7(layer ${this.instance.getLayer()})`; + message += `\n§7Blocks: §2${this.getNonAirBlocks()}\n`; + const skipped = this.getSkipped(); + if (skipped > 0) + message += `§c[!] This analysis skipped ${skipped} blocks.\n`; + message += `§7Correct: §a${this.formatStat(this.getStat(BlockVerificationLevel.Match))}\n`; + message += `§7Block State Incorrect: §e${this.formatStat(this.getStat(BlockVerificationLevel.TypeMatch))}\n`; + message += `§7Incorrect: §c${this.formatStat(this.getStat(BlockVerificationLevel.NoMatch))}\n`; + message += `§7Missing: §3${this.formatStat(this.getStat(BlockVerificationLevel.Missing))}\n`; + return message; + } + + formatStat(stat) { + return `${stat.num} (${stat.percent.toFixed(2)}%%)`; + } +} \ No newline at end of file diff --git a/StrucTool [BP]/scripts/classes/StructureVerifier.js b/StrucTool [BP]/scripts/classes/StructureVerifier.js index 10ad29a..1d9d712 100644 --- a/StrucTool [BP]/scripts/classes/StructureVerifier.js +++ b/StrucTool [BP]/scripts/classes/StructureVerifier.js @@ -1,65 +1,85 @@ import { BlockVerifier } from "./BlockVerifier"; -import { BlockVerificationLevel } from "./BlockVerificationLevel"; +import { BlockVerificationLevel } from "./enums/BlockVerificationLevel"; +import { BlockVerificationLevelRender } from "./BlockVerificationLevelRender"; +import { system, TicksPerSecond } from "@minecraft/server"; export class StructureVerifier { - constructor(instance) { + shouldRender; + isComplete; + interval = 5*20; + #runner; + + constructor(instance, { shouldRender = false } = {}) { + this.shouldRender = shouldRender; this.instance = instance; - this.blockVerificationLevels = {}; - this.statistics = {}; - this.initStatistics(); + this.interval = Math.max(instance.getActiveVolume() / 50, 20); + } + + startContinuousVerification() { + this.#runner = system.runInterval(() => { + this.verifyStructure(); + }, this.interval); + } + + stopContinuousVerification() { + if (!this.#runner) + return; + system.clearRun(this.#runner); + this.#runner = void 0; + } + + refresh() { + this.stopContinuousVerification(); + if (!this.instance.isEnabled()) + return; + this.startContinuousVerification(); + } + + init(shouldRender) { + this.blockVerificationLevels = { correctlyAir: 0 }; + this.shouldRender = shouldRender; + this.isComplete = false; } async verifyStructure() { - await this.runVerifier(); - this.parseStatistics(); - return this.statistics; - } - - async runVerifier() { + this.init(this.shouldRender); return new Promise((resolve) => { - this.verifyBlocks(); - resolve(); + if (this.instance.isUsingLayers()) + system.runJob(this.verifyBlocks(this.instance.getLayerBlocks(this.instance.getLayer()-1))); + else + system.runJob(this.verifyBlocks(this.instance.getBlocks())); + const checker = system.runInterval(() => { + if (this.isComplete) { + system.clearRun(checker); + resolve(this.blockVerificationLevels); + } + }, 1); }); } - - verifyBlocks() { - for (const block of this.instance.getBlocks()) { + + *verifyBlocks(blocks) { + for (const block of blocks) { const verificationLevel = this.verifyBlock(block.location); - if (verificationLevel !== BlockVerificationLevel.isAir) + if (verificationLevel === BlockVerificationLevel.Air) { + this.blockVerificationLevels.correctlyAir++; + } else { this.blockVerificationLevels[JSON.stringify(block.location)] = verificationLevel; - else - this.statistics.correctlyAir++; + if (this.shouldRender) { + const dimensionLocation = { dimension: this.instance.getDimension(), location: this.instance.toGlobalCoords(block.location) }; + new BlockVerificationLevelRender(dimensionLocation, verificationLevel, this.interval/TicksPerSecond); + } + } + yield void 0; } + this.isComplete = true; } verifyBlock(location) { const worldBlock = this.instance.getDimension().getBlock(this.instance.toGlobalCoords(location)); - if (!worldBlock) - throw new Error(`Block at ${JSON.stringify(location)} could not be accessed.`); + if (!worldBlock) { + return BlockVerificationLevel.Skipped; + } const blockVerifier = new BlockVerifier(worldBlock, this.instance); return blockVerifier.verify(); } - - initStatistics() { - for (const verificationlevel of Object.values(BlockVerificationLevel)) { - this.statistics[verificationlevel] = 0; - } - this.statistics.percentages = {}; - this.statistics.correctlyAir = 0; - } - - parseStatistics() { - for (const blockVerificationLevel of Object.values(BlockVerificationLevel)) { - this.parseStatistic(blockVerificationLevel); - } - } - - parseStatistic(blockVerificationLevel) { - for (const verificationlevel of Object.values(this.blockVerificationLevels)) { - if (blockVerificationLevel === verificationlevel) { - this.statistics[verificationlevel]++; - } - } - this.statistics.percentages[blockVerificationLevel] = this.statistics[blockVerificationLevel] / (this.instance.getTotalVolume() - this.statistics.correctlyAir) * 100; - } } \ No newline at end of file diff --git a/StrucTool [BP]/scripts/classes/BlockVerificationLevel.js b/StrucTool [BP]/scripts/classes/enums/BlockVerificationLevel.js similarity index 75% rename from StrucTool [BP]/scripts/classes/BlockVerificationLevel.js rename to StrucTool [BP]/scripts/classes/enums/BlockVerificationLevel.js index cdc5a32..fad3307 100644 --- a/StrucTool [BP]/scripts/classes/BlockVerificationLevel.js +++ b/StrucTool [BP]/scripts/classes/enums/BlockVerificationLevel.js @@ -2,7 +2,8 @@ export const BlockVerificationLevel = Object.freeze({ Unknown: 0, NoMatch: 1, TypeMatch: 2, - TypeAndStateMatch: 3, + Match: 3, Missing: 4, - isAir: 5 + Air: 5, + Skipped: 6 }); \ No newline at end of file diff --git a/StrucTool [BP]/scripts/classes/InstanceEditOptions.js b/StrucTool [BP]/scripts/classes/enums/InstanceEditOptions.js similarity index 100% rename from StrucTool [BP]/scripts/classes/InstanceEditOptions.js rename to StrucTool [BP]/scripts/classes/enums/InstanceEditOptions.js diff --git a/StrucTool [BP]/scripts/commands/struct.js b/StrucTool [BP]/scripts/commands/struct.js deleted file mode 100644 index 320f4af..0000000 --- a/StrucTool [BP]/scripts/commands/struct.js +++ /dev/null @@ -1,115 +0,0 @@ -import { Command } from '../lib/canopy/CanopyExtension'; -import { extension } from '../config'; -import { structureCollection } from '../classes/StructureCollection'; -import { MaterialCounter } from '../classes/MaterialCounter'; - -const structCmd = new Command({ - name: 'struct', - description: { text: 'Manages current StrucTool structures.' }, - usage: 'struct [args...]', - callback: structCommand, - args: [ - { type: 'string', name: 'name' }, - { type: 'string', name: 'option' }, - { type: 'string|number', name: 'arg3' } - ] -}); -extension.addCommand(structCmd); - -function structCommand(sender, args) { - const { name, option, arg3 } = args; - switch (option) { - case 'add': - addStructure(sender, name); - break; - case 'remove': - removeStructure(sender, name); - break; - case 'place': - placeStructure(sender, name); - break; - case 'layer': - setLayer(sender, name, arg3); - break; - case 'info': - printInfo(sender, name); - break; - default: - structCmd.sendUsage(sender); - } -} - -function addStructure(sender, name) { - try { - structureCollection.add(name, name); - } catch (e) { - if (e.message.includes('already exists')) { - sender.sendMessage({ text: `§cStructure '${name}' already exists.` }); - return; - } else { - sender.sendMessage({ text: `§cFailed to add structure '${name}'.` }); - throw e; - } - } - sender.sendMessage({ text: `§7Added structure '${name}'` }); -} - -function removeStructure(sender, name) { - try { - structureCollection.remove(name); - } catch (e) { - sender.sendMessage({ text: `§cStructure '${name}' not found.` }); - return; - } - sender.sendMessage({ text: `Removed structure '${name}'` }); -} - -function placeStructure(sender, name) { - let structure; - try { - structure = structureCollection.get(name); - } catch (e) { - try { - structure = structureCollection.add(name, name); - } catch (e) { - if (e.message.includes('already exists')) { - sender.sendMessage({ text: `§cStructure '${name}' already exists.` }); - return; - } else if (e.message.includes('not found')) { - sender.sendMessage({ text: `§cStructure '${name}' not found.` }); - return; - } else { - sender.sendMessage({ text: `§cFailed to place structure '${name}'.` }); - throw e; - } - } - } - structure.place(sender.dimension.id, sender.location); - sender.sendMessage({ text: `§7Placed structure '${name}'.` }); -} - -function setLayer(sender, name, layer) { - let structure; - try { - structure = structureCollection.get(name); - } catch (e) { - sender.sendMessage({ text: `§cStructure '${name}' not found.` }); - return; - } - structure.setLayer(layer); - sender.sendMessage({ text: `§7Set layer of structure '${name}' to ${layer}.` }); -} - -function printInfo(sender, name) { - let structure; - try { - structure = structureCollection.get(name); - } catch (e) { - sender.sendMessage({ text: `§cStructure '${name}' not found.` }); - return; - } - const { dimensionId, location } = structure.getLocation(); - sender.sendMessage({ text: `§7Structure '${name}' at [${location.x} ${location.y} ${location.z}] in '${dimensionId}'` }); - sender.sendMessage({ text: `§7Current Layer: ${structure.getLayer()}` }); - sender.sendMessage({ text: `§7Materials: ${MaterialCounter.getPrintable(name)}` }); -} \ No newline at end of file diff --git a/StrucTool [BP]/scripts/rules/showStructBlockInfo.js b/StrucTool [BP]/scripts/rules/showStructBlockInfo.js deleted file mode 100644 index e69de29..0000000 diff --git a/StrucTool [BP]/structures/xmas.mcstructure b/StrucTool [BP]/structures/xmas.mcstructure new file mode 100644 index 0000000..0c4dde8 Binary files /dev/null and b/StrucTool [BP]/structures/xmas.mcstructure differ diff --git a/StrucTool [RP]/manifest.json b/StrucTool [RP]/manifest.json new file mode 100644 index 0000000..6ab353c --- /dev/null +++ b/StrucTool [RP]/manifest.json @@ -0,0 +1,31 @@ +{ + "format_version": 2, + "header": { + "name": "StrucTool [RP] v1.0.0", + "description": "Survival building extension for §l§aCanopy§r by §aForestOfLight§r.", + "uuid": "375ec465-3dc1-429f-8b4c-a337889e1ed4", + "version": [1, 0, 0], + "min_engine_version": [1,17,0] + }, + "modules": [ + { + "type": "resources", + "uuid": "7f6b23df-a583-476b-b0e4-87457e65f7c0", + "version": [1, 0, 0] + } + ], + "dependencies": [ + { + "uuid": "8c0c0153-d8b9-482a-889f-aef922b8fe58", // StrucTool BP + "version": [1, 0, 0] + }, + { + "uuid": "7f6b23df-a583-476b-b0e4-87457e65f7c0", // Canopy BP + "version": [1, 3, 9] + } + ], + "metadata": { + "authors": [ "ForestOfLight" ], + "license": "MIT" + } + } \ No newline at end of file diff --git a/StrucTool [RP]/particles/blockoverlay_xy.particle.json b/StrucTool [RP]/particles/blockoverlay_xy.particle.json new file mode 100644 index 0000000..541e12a --- /dev/null +++ b/StrucTool [RP]/particles/blockoverlay_xy.particle.json @@ -0,0 +1,36 @@ +{ + "format_version": "1.10.0", + "particle_effect": { + "description": { + "identifier": "structool:blockoverlay_xy", + "basic_render_parameters": { + "material": "particles_blend", + "texture": "textures/particle/white" + } + }, + "components": { + "minecraft:emitter_rate_instant": { + "num_particles": 1 + }, + "minecraft:emitter_lifetime_once": { + "active_time": 1 + }, + "minecraft:emitter_shape_point": {}, + "minecraft:particle_lifetime_expression": { + "max_lifetime": "variable.lifetime" + }, + "minecraft:particle_appearance_billboard": { + "size": [0.5, 0.5], + "facing_camera_mode": "emitter_transform_xy" + }, + "minecraft:particle_appearance_tinting": { + "color": [ + "variable.face_color.r", + "variable.face_color.g", + "variable.face_color.b", + "variable.face_color.a" + ] + } + } + } +} \ No newline at end of file diff --git a/StrucTool [RP]/particles/blockoverlay_xz.particle.json b/StrucTool [RP]/particles/blockoverlay_xz.particle.json new file mode 100644 index 0000000..4140060 --- /dev/null +++ b/StrucTool [RP]/particles/blockoverlay_xz.particle.json @@ -0,0 +1,36 @@ +{ + "format_version": "1.10.0", + "particle_effect": { + "description": { + "identifier": "structool:blockoverlay_xz", + "basic_render_parameters": { + "material": "particles_blend", + "texture": "textures/particle/white" + } + }, + "components": { + "minecraft:emitter_rate_instant": { + "num_particles": 1 + }, + "minecraft:emitter_lifetime_once": { + "active_time": 1 + }, + "minecraft:emitter_shape_point": {}, + "minecraft:particle_lifetime_expression": { + "max_lifetime": "variable.lifetime" + }, + "minecraft:particle_appearance_billboard": { + "size": [0.5, 0.5], + "facing_camera_mode": "emitter_transform_xz" + }, + "minecraft:particle_appearance_tinting": { + "color": [ + "variable.face_color.r", + "variable.face_color.g", + "variable.face_color.b", + "variable.face_color.a" + ] + } + } + } +} \ No newline at end of file diff --git a/StrucTool [RP]/particles/blockoverlay_yz.particle.json b/StrucTool [RP]/particles/blockoverlay_yz.particle.json new file mode 100644 index 0000000..76b4ef5 --- /dev/null +++ b/StrucTool [RP]/particles/blockoverlay_yz.particle.json @@ -0,0 +1,36 @@ +{ + "format_version": "1.10.0", + "particle_effect": { + "description": { + "identifier": "structool:blockoverlay_yz", + "basic_render_parameters": { + "material": "particles_blend", + "texture": "textures/particle/white" + } + }, + "components": { + "minecraft:emitter_rate_instant": { + "num_particles": 1 + }, + "minecraft:emitter_lifetime_once": { + "active_time": 1 + }, + "minecraft:emitter_shape_point": {}, + "minecraft:particle_lifetime_expression": { + "max_lifetime": "variable.lifetime" + }, + "minecraft:particle_appearance_billboard": { + "size": [0.5, 0.5], + "facing_camera_mode": "emitter_transform_yz" + }, + "minecraft:particle_appearance_tinting": { + "color": [ + "variable.face_color.r", + "variable.face_color.g", + "variable.face_color.b", + "variable.face_color.a" + ] + } + } + } +} \ No newline at end of file diff --git a/StrucTool [RP]/particles/outline.particle.json b/StrucTool [RP]/particles/outline.particle.json new file mode 100644 index 0000000..7fd6ad6 --- /dev/null +++ b/StrucTool [RP]/particles/outline.particle.json @@ -0,0 +1,42 @@ +{ + "format_version": "1.10.0", + "particle_effect": { + "description": { + "identifier": "structool:outline", + "basic_render_parameters": { + "material": "particles_alpha", + "texture": "textures/particle/particles" + } + }, + "components": { + "minecraft:emitter_rate_instant": { + "num_particles": 1 + }, + "minecraft:emitter_lifetime_once": { + "active_time": 1 + }, + "minecraft:emitter_shape_point": {}, + "minecraft:particle_lifetime_expression": { + "max_lifetime": 1 + }, + "minecraft:particle_appearance_billboard": { + "size": [0.2, 0.2], + "facing_camera_mode": "rotate_xyz", + "uv": { + "texture_width": 16, + "texture_height": 16, + "uv": [6, 11], + "uv_size": [1, 1] + } + }, + "minecraft:particle_appearance_tinting": { + "color": [ + "variable.dot_color.r", + "variable.dot_color.g", + "variable.dot_color.b", + "variable.dot_color.a" + ] + } + } + } +} \ No newline at end of file diff --git a/StrucTool [RP]/textures/particle/white.png b/StrucTool [RP]/textures/particle/white.png new file mode 100644 index 0000000..9f34bbd Binary files /dev/null and b/StrucTool [RP]/textures/particle/white.png differ