diff --git a/README.md b/README.md index e2d8649..2fab438 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ [![GitHub Downloads](https://img.shields.io/github/downloads/ForestOfLight/Construct/total?label=Github%20downloads&logo=github)](https://github.com/ForestOfLight/Construct/releases) [![Curseforge Downloads](https://cf.way2muchnoise.eu/full_1283139_downloads.svg)](https://www.curseforge.com/minecraft-bedrock/addons/construct) -[![Minecraft - Version](https://img.shields.io/badge/Minecraft-v1.21.120_(Bedrock)-brightgreen)](https://feedback.minecraft.net/hc/en-us/sections/360001186971-Release-Changelogs) +[![Minecraft - Version](https://img.shields.io/badge/Minecraft-v1.21.130_(Bedrock)-brightgreen)](https://feedback.minecraft.net/hc/en-us/sections/360001186971-Release-Changelogs) [![Discord](https://badgen.net/discord/members/9KGche8fxm?icon=discord&label=Discord&list=what)](https://discord.gg/9KGche8fxm) @@ -71,6 +71,7 @@ Need help, want to discuss technical Minecraft, or follow future updates? [**Joi - [x] Automatic material gathering from inventories - [x] Material list - [x] Flexible structure movement +- [ ] Translation support - [ ] Block texture display ## Issues & Suggestions diff --git a/packs/BP/items/easy_place.json b/packs/BP/items/easy_place.json index af4ba61..66b9513 100644 --- a/packs/BP/items/easy_place.json +++ b/packs/BP/items/easy_place.json @@ -10,7 +10,7 @@ "texture": "construct:easy_place" }, "minecraft:display_name": { - "value": "Easy Place" + "value": "construct.easyplace.name" }, "minecraft:max_stack_size": 1, "minecraft:wearable": { diff --git a/packs/BP/items/material_grabber.json b/packs/BP/items/material_grabber.json index f3d45fd..23353bb 100644 --- a/packs/BP/items/material_grabber.json +++ b/packs/BP/items/material_grabber.json @@ -11,7 +11,7 @@ "texture": "construct:material_grabber" }, "minecraft:display_name": { - "value": "Material Grabber" + "value": "construct.materialgrabber.name" }, "minecraft:wearable": { "dispensable": true, diff --git a/packs/BP/items/menu.json b/packs/BP/items/menu.json index 7994039..cfb3fea 100644 --- a/packs/BP/items/menu.json +++ b/packs/BP/items/menu.json @@ -11,7 +11,7 @@ "texture": "construct:menu" }, "minecraft:display_name": { - "value": "Construct" + "value": "construct.menu.name" }, "minecraft:wearable": { "dispensable": true, diff --git a/packs/BP/manifest.json b/packs/BP/manifest.json index c342753..d594a20 100644 --- a/packs/BP/manifest.json +++ b/packs/BP/manifest.json @@ -1,11 +1,11 @@ { "format_version": 2, "header": { - "name": "Construct [BP] v1.0.5", + "name": "Construct [BP] v1.0.6", "description": "Survival building addon by §aForestOfLight§r.", "uuid": "8c0c0153-d8b9-482a-889f-aef922b8fe58", - "min_engine_version": [1, 21, 120], - "version": [1, 0, 5] + "min_engine_version": [1, 21, 130], + "version": [1, 0, 6] }, "modules": [ { @@ -26,7 +26,7 @@ "dependencies": [ { "module_name": "@minecraft/server", - "version": "2.4.0-beta" + "version": "2.5.0-beta" }, { "module_name": "@minecraft/server-ui", @@ -34,7 +34,7 @@ }, { "uuid": "375ec465-3dc1-429f-8b4c-a337889e1ed4", // Construct RP - "version": [1, 0, 5] + "version": [1, 0, 6] } ], "metadata": { diff --git a/packs/BP/scripts/classes/BlockInfo.js b/packs/BP/scripts/classes/BlockInfo.js index 95391dd..76e709f 100644 --- a/packs/BP/scripts/classes/BlockInfo.js +++ b/packs/BP/scripts/classes/BlockInfo.js @@ -16,29 +16,41 @@ class BlockInfo { static showStructureBlockInfo(player) { const block = Raycaster.getTargetedStructureBlock(player, { isFirst: true, collideWithWorldBlocks: true, useActiveLayer: true }); if (!block && this.shownToLastTick.has(player.id)) { - player.onScreenDisplay.setActionBar({ text: 'Structure:\n§7None' }); + player.onScreenDisplay.setActionBar({ rawtext: [ + { translate: 'construct.blockinfo.header' }, + { text: '\n' }, + { translate: 'construct.blockinfo.none' } + ]}); this.shownToLastTick.delete(player.id); } if (!block) return; - player.onScreenDisplay.setActionBar({ text: this.getFormattedBlockInfo(player, block.permutation) }); + player.onScreenDisplay.setActionBar(this.getFormattedBlockInfo(player, block.permutation)); this.shownToLastTick.add(player.id); } static getFormattedBlockInfo(player, block) { - return 'Structure:' + this.getSupplyMessage(player, block) + '\n' + this.getBlockMessage(block); + return { rawtext: [ + { translate: 'construct.blockinfo.header' }, + this.getSupplyMessage(player, block), + { text: '\n' }, + this.getBlockMessage(block) + ] }; } static getBlockMessage(block) { if (!block) - return '§7Unknown'; - let output = `§a${block.type.id}`; + return { translate: 'construct.blockinfo.unknown' }; + const message = { rawtext: [{ text: '§a' }, { translate: block.type.id }]}; const states = block.getAllStates(); if (Object.keys(states).length > 0) - output += `\n§7${this.getFormattedStates(states)}`; + message.rawtext.push({ text: `\n§7${this.getFormattedStates(states)}` }); if (block.isWaterlogged) - output += `\n§7isWaterlogged: §3true`; - return output; + message.rawtext.push({ rawtext: [ + { text: '\n§7' }, + { translate: 'construct.blockinfo.waterlogged' } + ]}); + return message; } static getFormattedStates(states) { @@ -49,8 +61,8 @@ class BlockInfo { const itemStack = fetchMatchingItemSlot(player, block.getItemStack()?.typeId); const isInSurvival = player.getGameMode() === GameMode.Survival; if (!itemStack && isInSurvival) - return ' §c[No Supply]'; - return ''; + return { translate: 'construct.blockinfo.nosupply' }; + return { text: '' }; } } diff --git a/packs/BP/scripts/classes/Builder/BuilderForm.js b/packs/BP/scripts/classes/Builder/BuilderForm.js index 174a718..71e9cae 100644 --- a/packs/BP/scripts/classes/Builder/BuilderForm.js +++ b/packs/BP/scripts/classes/Builder/BuilderForm.js @@ -20,10 +20,21 @@ export class BuilderForm { for (let i = 0; i < optionIds.length; i++) { const option = BuilderOptions.get(optionIds[i]); const changedToValue = option.setValue(this.player.id, formValues[i]); - 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.`) + if (changedToValue === true) { + this.player.sendMessage({ rawtext: [ + { text: `§a` }, + option.displayName, + { translate: 'construct.option.enabled' }, + { text: `§7 ` }, + option.howToUse + ]}); + } else if (changedToValue === false) { + this.player.sendMessage({ rawtext: [ + { text: `§c` }, + option.displayName, + { translate: 'construct.option.disabled' } + ]}); + } } } diff --git a/packs/BP/scripts/classes/Builder/BuilderFormBuilder.js b/packs/BP/scripts/classes/Builder/BuilderFormBuilder.js index dbcef2c..8b1bb37 100644 --- a/packs/BP/scripts/classes/Builder/BuilderFormBuilder.js +++ b/packs/BP/scripts/classes/Builder/BuilderFormBuilder.js @@ -8,9 +8,9 @@ export class BuilderFormBuilder { .title(MenuFormBuilder.menuTitle); for (const optionId of BuilderOptions.getOptionIds()) { const option = BuilderOptions.get(optionId); - form.toggle(`${option.displayName}`, { defaultValue: option.isEnabled(player.id), tooltip: option.description }); + form.toggle(option.displayName, { defaultValue: option.isEnabled(player.id), tooltip: option.description }); } - form.submitButton('§2Apply'); + form.submitButton({ translate: "construct.menu.submit" }); return form; } } \ No newline at end of file diff --git a/packs/BP/scripts/classes/Enums/InstanceButtons.js b/packs/BP/scripts/classes/Enums/InstanceButtons.js index ed8af25..06dc55d 100644 --- a/packs/BP/scripts/classes/Enums/InstanceButtons.js +++ b/packs/BP/scripts/classes/Enums/InstanceButtons.js @@ -1,16 +1,16 @@ export const InstanceButtons = Object.freeze({ - Unknown: 'Unknown', + Unknown: 'construct.menu.instance.button.unknown', MainMenu: '<<', - Place: '§aPlace Instance', - Enable: '§aEnable Instance', - Disable: '§cDisable Instance', - Rename: 'Rename Instance', - Delete: '§cDelete Instance', - NextLayer: 'Increase Layer', - PreviousLayer: 'Decrease Layer', - Move: 'Move Here', - FlexibleMove: 'Flexible Move', - Statistics: 'Statistics', - Settings: 'Settings', - Materials: 'Material List' + Place: 'construct.menu.instance.button.place', + Enable: 'construct.menu.instance.button.enable', + Disable: 'construct.menu.instance.button.disable', + Rename: 'construct.menu.instance.button.rename', + Delete: 'construct.menu.instance.button.delete', + NextLayer: 'construct.menu.instance.button.nextLayer', + PreviousLayer: 'construct.menu.instance.button.previousLayer', + Move: 'construct.menu.instance.button.move', + FlexibleMove: 'construct.menu.instance.button.flexibleMove', + Statistics: 'construct.menu.instance.button.statistics', + Settings: 'construct.menu.instance.button.settings', + Materials: 'construct.menu.instance.button.materials' }); \ No newline at end of file diff --git a/packs/BP/scripts/classes/Instance/FlexibleInstanceMove.js b/packs/BP/scripts/classes/Instance/FlexibleInstanceMove.js index a7def96..ed3820a 100644 --- a/packs/BP/scripts/classes/Instance/FlexibleInstanceMove.js +++ b/packs/BP/scripts/classes/Instance/FlexibleInstanceMove.js @@ -23,7 +23,7 @@ export class FlexibleInstanceMove { tryStart() { if (this.instance.isFlexibleMoving()) { - this.sendFeedback('§cThis instance is already being moved.'); + this.sendFeedback({ translate: 'construct.instance.flexibleMove.alreadyMoving' }); return; } this.start(); @@ -48,7 +48,7 @@ export class FlexibleInstanceMove { this.allowPlayerMovement(false); world.beforeEvents.itemUse.subscribe(this.onPlayerUseItemBound); world.beforeEvents.playerLeave.unsubscribe(this.onPlayerLeaveBound); - this.sendFeedback(`§aNow moving "${this.instance.getName()}". Use the Construct item when finished.`); + this.sendFeedback({ translate: 'construct.instance.flexibleMove.start', with: [this.instance.getName()] }); } onFlexibleMovementTick() { @@ -109,7 +109,10 @@ export class FlexibleInstanceMove { builder.flexibleInstanceMovement = void 0; world.beforeEvents.itemUse.unsubscribe(this.onPlayerUseItemBound); world.beforeEvents.playerLeave.unsubscribe(this.onPlayerLeaveBound); - this.sendFeedback(`§aMoved "${this.instance.getName()}" to ${this.currentInstanceLocation.floor()}.`); + this.sendFeedback({ translate: 'construct.instance.flexibleMove.finish', with: [ + this.instance.getName(), + String(this.currentInstanceLocation.floor()) + ] }); } allowPlayerMovement(enable) { diff --git a/packs/BP/scripts/classes/Instance/InstanceForm.js b/packs/BP/scripts/classes/Instance/InstanceForm.js index e9c7e9b..375fc4e 100644 --- a/packs/BP/scripts/classes/Instance/InstanceForm.js +++ b/packs/BP/scripts/classes/Instance/InstanceForm.js @@ -113,7 +113,7 @@ export class InstanceForm { new MenuForm(this.player, { jumpToInstance: false }); break; default: - this.player.sendMessage(`§cUnknown option: ${option}`); + this.player.sendMessage({ translate: 'construct.menu.instance.unknownOption', with: [option] }); break; } } @@ -124,15 +124,14 @@ export class InstanceForm { return; const newName = response.formValues[0]; if (newName === '') { - this.player.sendMessage('§cInstance name cannot be empty.'); + this.player.sendMessage({ translate: 'construct.menu.instance.nameEmpty' }); return; } try { structureCollection.rename(this.instanceName, newName); this.instanceName = newName; } catch (e) { - this.player.sendMessage(`§cError renaming instance: ${e.message}`); - return; + this.player.sendMessage({ translate: 'construct.instance.rename.error', with: [e.message] }); } }); } @@ -156,13 +155,13 @@ export class InstanceForm { statsForm = await InstanceFormBuilder.buildStatistics(this.instance); } catch (e) { if (e.message === 'StructureVerifier is already running.') { - this.player.sendMessage('§cA verification is already in progress. Please wait until it finishes.'); + this.player.sendMessage({ translate: 'construct.instance.validation.alreadyRunning' }); return; } throw e; } if (!statsForm) { - this.player.sendMessage('§cFailed to build statistics form.'); + this.player.sendMessage({ translation: 'construct.instance.validation.formfail' }); return; } statsForm.form.show(this.player).then((response) => { diff --git a/packs/BP/scripts/classes/Instance/InstanceFormBuilder.js b/packs/BP/scripts/classes/Instance/InstanceFormBuilder.js index d54c6f9..12cc33c 100644 --- a/packs/BP/scripts/classes/Instance/InstanceFormBuilder.js +++ b/packs/BP/scripts/classes/Instance/InstanceFormBuilder.js @@ -11,12 +11,17 @@ export class InstanceFormBuilder { const location = instance.getLocation(); const form = new ActionFormData() .title(MenuFormBuilder.menuTitle) - let body = `Instance: §a${instance.getName()}\n§fStructure: §2${instance.getStructureId()}\n`; + const body = { rawtext: [ + { translate: 'construct.instance.menu.body', with: [instance.getName(), instance.getStructureId()] } + ]}; if (instance.hasLocation()) - body += `§7(${location.location.x} ${location.location.y} ${location.location.z} in ${location.dimensionId})\n`; + body.rawtext.push(...[ + { text: '\n' }, + { translate: 'construct.instance.menu.location', with: [String(location.location.x), String(location.location.y), String(location.location.z), location.dimensionId] } + ]); form.body(body); options.forEach(option => { - form.button(`${option}`); + form.button({ translate: option }); }); return form; } @@ -24,8 +29,8 @@ export class InstanceFormBuilder { static buildRenameInstance(currentName) { return new ModalFormData() .title(MenuFormBuilder.menuTitle) - .textField('Enter a new name for the instance:', currentName) - .submitButton('Rename'); + .textField({ translate: 'construct.isntance.menu.rename' }, currentName) + .submitButton({ translate: 'construct.menu.instance.button.rename' }); } static async buildStatistics(instance) { @@ -45,9 +50,9 @@ export class InstanceFormBuilder { static buildSettings(instance) { return new ModalFormData() .title(MenuFormBuilder.menuTitle) - .toggle('Block Validation', { defaultValue: instance.options.verifier.isEnabled, tooltip: 'Shows missing and incorrect block overlay.' }) - .slider("Layer", 0, instance.getMaxLayer(), { defaultValue: instance.getLayer(), valueStep: 1, tooltip: 'Changes the active layer. Use 0 for all layers.' }) - .submitButton('§2Apply'); + .toggle({ translate: 'construct.instance.option.validation' }, { defaultValue: instance.options.verifier.isEnabled, tooltip: { translate: 'construct.instance.option.validation.description' }}) + .slider({ translate: 'construct.instance.option.layer'}, 0, instance.getMaxLayer(), { defaultValue: instance.getLayer(), valueStep: 1, tooltip: { translate: 'construct.instance.option.layer.description' }}) + .submitButton({ translate: 'construct.menu.submit' }); } static buildMaterialList(instance, onlyMissing = false, player = false) { @@ -59,25 +64,25 @@ export class InstanceFormBuilder { if (onlyMissing) { const inventoryContainer = player?.getComponent(EntityComponentTypes.Inventory)?.container; if (!inventoryContainer) { - form.body('§cNo player inventory found.'); + form.body({ translate: 'construct.instance.materials.noinventory' }); return form; } - bodyText.rawtext.push({ text: `§cMaterials Missing From Inventory:` }); + bodyText.rawtext.push({ translate: 'construct.instance.materials.missing.header' }); if (instance.hasLayerSelected()) - bodyText.rawtext.push({ text: ` §7(layer ${instance.getLayer()})` }); + bodyText.rawtext.push({ translate: 'construct.instance.materials.layer', with: [String(instance.getLayer())] }); bodyText.rawtext.push({ text: `§f\n\n` }); bodyText.rawtext.push(materials.formatString(materials.getMaterialsDifference(inventoryContainer))); - buttonText = "Show All Materials"; + buttonText = "construct.instance.materials.all.button"; } else { - bodyText.rawtext.push({ text: `§aAll Materials:` }); + bodyText.rawtext.push({ translate: `construct.instance.materials.all.header` }); if (instance.hasLayerSelected()) - bodyText.rawtext.push({ text: ` §7(layer ${instance.getLayer()})` }); + bodyText.rawtext.push({ translate: 'construct.instance.materials.layer', with: [String(instance.getLayer())] }); bodyText.rawtext.push({ text: `§f\n\n` }); bodyText.rawtext.push(materials.formatString()); - buttonText = "Show Missing Materials"; + buttonText = "construct.instance.materials.missing.button"; } form.body(bodyText); - form.button(buttonText); + form.button({ translate: buttonText }); return form; } } \ No newline at end of file diff --git a/packs/BP/scripts/classes/Materials/MaterialGrabberForm.js b/packs/BP/scripts/classes/Materials/MaterialGrabberForm.js index 45c05fa..37a0002 100644 --- a/packs/BP/scripts/classes/Materials/MaterialGrabberForm.js +++ b/packs/BP/scripts/classes/Materials/MaterialGrabberForm.js @@ -17,13 +17,13 @@ export class MaterialGrabberForm { const selectedInstanceName = structureCollection.getInstanceNames()[response.selection]; if (selectedInstanceName) { this.setActiveInstance(selectedInstanceName); - this.player.sendMessage(`§7Selected instance for material grabber: §2${selectedInstanceName}`); + this.player.sendMessage({ translate: 'construct.materials.grabber.menu.success', with: [selectedInstanceName] }); return; } }); } catch (e) { if (e.message === 'Menu timed out.') { - this.player.sendMessage('§8Menu timed out.'); + this.player.sendMessage({ translate: 'construct.menu.open.timeout' }); return; } throw e; diff --git a/packs/BP/scripts/classes/Materials/MaterialGrabberFormBuilder.js b/packs/BP/scripts/classes/Materials/MaterialGrabberFormBuilder.js index b5a0fdd..1e30c93 100644 --- a/packs/BP/scripts/classes/Materials/MaterialGrabberFormBuilder.js +++ b/packs/BP/scripts/classes/Materials/MaterialGrabberFormBuilder.js @@ -4,18 +4,19 @@ import { structureCollection } from "../Structure/StructureCollection"; import { Builders } from "../Builder/Builders"; export class MaterialGrabberFormBuilder { - static menuTitle = MenuFormBuilder.menuTitle + ' Material Grabber'; + static menuTitle = { rawtext: [MenuFormBuilder.menuTitle, { translate: 'construct.materials.grabber.menu.title' }] }; static buildInstanceSelector(player) { const allInstanceNameForm = new ActionFormData() .title(this.menuTitle); const currInstanceName = Builders.get(player.id).materialInstanceName; - let body = '§7Current instance: '; + const body = { rawtext: [{ translate: 'construct.materials.grabber.menu.header' }] }; if (currInstanceName) - body += `§2${currInstanceName}`; + body.rawtext.push({ text: `§2${currInstanceName}` }); else - body += '§7None'; - body += '\n§7Select an instance:'; + body.rawtext.push({ translate: 'construct.materials.grabber.menu.noinstance' }); + body.rawtext.push({ text: '\n' }); + body.rawtext.push({ translate: 'construct.materials.grabber.menu.selectinstance' }); allInstanceNameForm.body(body); structureCollection.getInstanceNames().forEach(instanceName => { allInstanceNameForm.button(`§2${instanceName}`); diff --git a/packs/BP/scripts/classes/MenuForm.js b/packs/BP/scripts/classes/MenuForm.js index c5c0ea0..320ea2d 100644 --- a/packs/BP/scripts/classes/MenuForm.js +++ b/packs/BP/scripts/classes/MenuForm.js @@ -42,7 +42,7 @@ export class MenuForm { }); } catch (e) { if (e.message === 'Menu timed out.') { - this.player.sendMessage('§8Menu timed out.'); + this.player.sendMessage({ translate: 'construct.menu.open.timeout' }); return; } throw e; @@ -63,11 +63,11 @@ export class MenuForm { structureCollection.add(instanceName, structureId); } catch (e) { if (e.name === 'InvalidInstanceError') { - this.player.sendMessage(`§cInstance '${instanceName}' already exists. Try again with a new name.`); + this.player.sendMessage({ translate: 'construct.mainmenu.instance.exists', with: [instanceName] }); return void 0; } if (e.name === 'InvalidStructureError') { - this.player.sendMessage(`§cStructure ID '${structureId}' not found. If you're looking for a structure that you put in the structures folder, please restart your world and try again.`); + this.player.sendMessage({ translate: 'construct.mainmenu.instance.notfound', with: [structureId] }); return void 0; } throw e; diff --git a/packs/BP/scripts/classes/MenuFormBuilder.js b/packs/BP/scripts/classes/MenuFormBuilder.js index a362d28..a9a96ff 100644 --- a/packs/BP/scripts/classes/MenuFormBuilder.js +++ b/packs/BP/scripts/classes/MenuFormBuilder.js @@ -2,56 +2,58 @@ import { ActionFormData, ModalFormData } from '@minecraft/server-ui'; import { structureCollection } from './Structure/StructureCollection'; export class MenuFormBuilder { - static menuTitle = '§l§2Construct'; + static menuTitle = { translate: 'construct.mainmenu.title' }; static buildAllInstanceName() { const allInstanceNameForm = new ActionFormData() .title(this.menuTitle) - .body('Select an instance:'); - allInstanceNameForm.button('Builder Settings'); + .body({ translate: 'construct.mainmenu.selectinstance' }); + allInstanceNameForm.button({ translate: 'construct.mainmenu.settings' }); structureCollection.getInstanceNames().forEach(instanceName => { allInstanceNameForm.button(`${structureCollection.get(instanceName).isEnabled() ? '§2' : '§c'}${instanceName}`); }); - allInstanceNameForm.button('Create New Instance'); + allInstanceNameForm.button({ translate: 'construct.mainmenu.newinstance' }); return allInstanceNameForm; } static buildNewInstance() { return new ModalFormData() .title(this.menuTitle) - .textField('Enter a name for the new instance:', 'example_instance') - .submitButton('Submit'); + .textField({ translate: 'construct.mainmenu.newinstance.prompt' }, { translate: 'construct.mainmenu.newinstance.placeholder' }) + .submitButton({ translate: 'construct.menu.submit' }); } static buildAllStructures() { const allStructuresForm = new ActionFormData() .title(this.menuTitle) - .body('Select a structure:'); + .body({ translate: 'construct.mainmenu.selectstructure.header' }); structureCollection.getWorldStructureIds().forEach(structureId => { const structureName = structureId.replace('mystructure:', ''); allStructuresForm.button(`§2${structureName}`); }); - allStructuresForm.button('Other'); - allStructuresForm.button('How to Add/Remove Structures'); + allStructuresForm.button({ translate: 'construct.mainmenu.selectstructure.other' }); + allStructuresForm.button({ translate: 'construct.mainmenu.selectstructure.howto' }); return allStructuresForm; } static buildOtherStructure() { return new ModalFormData() .title(this.menuTitle) - .textField('Enter the Structure ID:', 'example_structure') - .submitButton('Submit'); + .textField({ translate: 'construct.mainmenu.selectstructure.other.prompt' }, { translate: 'construct.mainmenu.selectstructure.other.placeholder' }) + .submitButton({ translate: 'construct.menu.submit' }); } static buildHowTo() { - let body = "§aHow to Add Structures:\n" - body += "§7- Save a structure using a §fstructure block§7 or the §f/structure§7 command.\n" - body += "§7§lOR§r\n" - body += "§7- Add a §f.mcstructure§7 file to this pack's §fstructures folder§7. When selecting your structure, select the §fOther§7 option and then use the filename (without '.mcstructure') as the §fStructure ID§7. 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" + const message = { rawtext: [ + { translate: 'construct.mainmenu.selectstructure.howto.add.header' }, { text: '\n' }, + { translate: 'construct.mainmenu.selectstructure.howto.add.structureblock' }, { text: '\n' }, + { translate: 'construct.mainmenu.selectstructure.howto.add.or' }, { text: '\n' }, + { translate: 'construct.mainmenu.selectstructure.howto.add.mcstructure' }, { text: '\n' }, + { text: '\n' }, { translate: 'construct.mainmenu.selectstructure.howto.remove.header' }, { text: '\n' }, + { translate: 'construct.mainmenu.selectstructure.howto.remove.body' }, { text: '\n' }, + ] }; return new ActionFormData() .title(this.menuTitle) - .body(body); + .body(message); } } \ No newline at end of file diff --git a/packs/BP/scripts/classes/Structure/StructureStatistics.js b/packs/BP/scripts/classes/Structure/StructureStatistics.js index 1c89c53..eeec751 100644 --- a/packs/BP/scripts/classes/Structure/StructureStatistics.js +++ b/packs/BP/scripts/classes/Structure/StructureStatistics.js @@ -43,18 +43,22 @@ export class StructureStatistics { } getMessage() { - let message = ''; - message += `§fStatistics for §a${this.instance.getName()}§f:`; + const message = { rawtext: [] }; + message.rawtext.push({ translate: 'construct.structure.statistics.header', with: [this.instance.getName()] }); if (this.instance.hasLayerSelected()) - message += ` §7(layer ${this.instance.getLayer()})`; - message += `\n§7Blocks: §2${this.getNonAirBlocks()}\n`; + message.rawtext.push({ translate: 'construct.instance.materials.layer', with: [String(this.instance.getLayer())] }); + message.rawtext.push({ rawtext: [ + { text: '\n' }, + { translate: 'construct.structure.statistics.blocks', with: [String(this.getNonAirBlocks())] }, + { text: '\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`; + message.rawtext.push({ rawtext: [{ translate: 'construct.structure.statistics.skipped', with: [String(skipped)] }, { text: '\n' }] }); + message.rawtext.push({ rawtext: [{ translate: 'construct.structure.statistics.correct', with: [this.formatStat(this.getStat(BlockVerificationLevel.Match))] }, { text: '\n' }] }); + message.rawtext.push({ rawtext: [{ translate: 'construct.structure.statistics.stateincorrect', with: [this.formatStat(this.getStat(BlockVerificationLevel.TypeMatch))] }, { text: '\n' }] }); + message.rawtext.push({ rawtext: [{ translate: 'construct.structure.statistics.incorrect', with: [this.formatStat(this.getStat(BlockVerificationLevel.NoMatch))] }, { text: '\n' }] }); + message.rawtext.push({ rawtext: [{ translate: 'construct.structure.statistics.missing', with: [this.formatStat(this.getStat(BlockVerificationLevel.Missing))] }, { text: '\n' }] }); return message; } diff --git a/packs/BP/scripts/commands/construct.js b/packs/BP/scripts/commands/construct.js index c87925a..ca7a863 100644 --- a/packs/BP/scripts/commands/construct.js +++ b/packs/BP/scripts/commands/construct.js @@ -9,7 +9,7 @@ export const MENU_ITEM = 'construct:menu'; const menuCmd = new Command({ name: 'construct', - description: { text: 'Opens the Construct menu.' }, + description: { translate: 'construct.commands.construct' }, usage: 'construct', callback: (sender) => openMenu(sender) }); @@ -18,7 +18,7 @@ extension.addCommand(menuCmd); system.beforeEvents.startup.subscribe((event) => { const command = { name: 'construct:item', - description: 'Gives you the Construct item. Use it to open the Construct menu.', + description: 'construct.commands.item', permissionLevel: CommandPermissionLevel.Any, cheatsRequired: false }; @@ -28,13 +28,13 @@ system.beforeEvents.startup.subscribe((event) => { function givePlayerConstructItem(origin) { const player = origin.sourceEntity; if (player instanceof Player === false) - return { status: CustomCommandStatus.Failure, message: 'This command can only be used by players.' }; + return { status: CustomCommandStatus.Failure, message: 'construct.commands.item.denyorigin' }; system.run(() => { const givenItemStack = player.getComponent(EntityComponentTypes.Inventory)?.container?.addItem(new ItemStack(MENU_ITEM)); if (givenItemStack) - player.sendMessage('§cFailed to give you the Construct item.'); + player.sendMessage({ translate: 'construct.commands.item.fail' }); else - player.sendMessage('§aYou recieved the Construct item! Use it to open the Construct menu.'); + player.sendMessage({ translate: 'construct.commands.item.success' }); }); return { status: CustomCommandStatus.Success }; } diff --git a/packs/BP/scripts/config.js b/packs/BP/scripts/config.js index 573c44f..70a9f73 100644 --- a/packs/BP/scripts/config.js +++ b/packs/BP/scripts/config.js @@ -4,5 +4,5 @@ export const extension = new CanopyExtension({ author: 'ForestOfLight', name: 'Construct', description: 'Survival building addon by §aForestOfLight§r.', - version: '1.0.5' + version: '1.0.6' }); \ No newline at end of file diff --git a/packs/BP/scripts/options/easyPlace.js b/packs/BP/scripts/options/easyPlace.js index 72ad84f..07bdc5b 100644 --- a/packs/BP/scripts/options/easyPlace.js +++ b/packs/BP/scripts/options/easyPlace.js @@ -1,16 +1,15 @@ import { BuilderOption } from '../classes/Builder/BuilderOption'; import { BlockPermutation, EntityComponentTypes, EquipmentSlot, GameMode, ItemStack, system, world } from '@minecraft/server'; import { structureCollection } from '../classes/Structure/StructureCollection'; -import { bannedBlocks, bannedToValidBlockMap, whitelistedBlockStates, resetToBlockStates, bannedDimensionBlocks, - blockIdToItemStackMap } from '../data'; +import { bannedBlocks, bannedToValidBlockMap, whitelistedBlockStates, resetToBlockStates, bannedDimensionBlocks, blockIdToItemStackMap } from '../data'; import { fetchMatchingItemSlot, placeBlock } from '../utils'; import { Builders } from '../classes/Builder/Builders'; const builderOption = new BuilderOption({ identifier: 'easyPlace', - displayName: 'Easy Place', - description: 'Always place the correct structure block.', - howToUse: "Hold the Easy Place item in your offhand and place blocks in a structure to have them be corrected automatically.", + displayName: { translate: 'construct.option.easyplace.name' }, + description: { translate: 'construct.option.easyplace.description' }, + howToUse: { translate: 'construct.option.easyplace.howto' }, onEnableCallback: (playerId) => giveActionItem(playerId), onDisableCallback: (playerId) => removeActionItem(playerId) }); @@ -83,7 +82,7 @@ function shouldPreventAction(player, structureBlock) { function preventAction(event, player) { event.cancel = true; system.run(() => { - player.onScreenDisplay.setActionBar('§cAction prevented by Easy Place.'); + player.onScreenDisplay.setActionBar({ translate: 'construct.option.easyplace.actionprevented' }); }); } diff --git a/packs/BP/scripts/options/fastEasyPlace.js b/packs/BP/scripts/options/fastEasyPlace.js index d71c602..628db99 100644 --- a/packs/BP/scripts/options/fastEasyPlace.js +++ b/packs/BP/scripts/options/fastEasyPlace.js @@ -8,15 +8,15 @@ import { Builders } from '../classes/Builder/Builders'; import { Vector } from '../lib/Vector'; const locationsPlacedLastTick = new Set(); -const PLAYER_COLLISION_BOX = { width: 0.6, height: 1.8 }; const ACTION_ITEM = 'construct:easy_place'; +const PLAYER_COLLISION_BOX = { width: 0.6, height: 1.8 }; const runnerByPlayer = {}; const builderOption = new BuilderOption({ identifier: 'fastEasyPlace', - displayName: 'Fast Easy Place', - description: 'Place correct structure blocks just by clicking on them.', - howToUse: "Hold the Easy Place item in your main hand and use it on missing blocks in a structure to place them.", + displayName: { translate: 'construct.option.fasteasyplace.name' }, + description: { translate: 'construct.option.fasteasyplace.description' }, + howToUse: { translate: 'construct.option.fasteasyplace.howto' }, onEnableCallback: (playerId) => giveActionItem(playerId), onDisableCallback: (playerId) => removeActionItem(playerId) }); @@ -99,7 +99,7 @@ function processEasyPlace(player) { function preventAction(event, player) { event.cancel = true; system.run(() => { - player.onScreenDisplay.setActionBar('§cAction prevented by Easy Place.'); + player.onScreenDisplay.setActionBar({ translate: 'construct.option.easyplace.actionprevented' }); }); } diff --git a/packs/BP/scripts/options/materialGrabber.js b/packs/BP/scripts/options/materialGrabber.js index 28faeb3..b41ef14 100644 --- a/packs/BP/scripts/options/materialGrabber.js +++ b/packs/BP/scripts/options/materialGrabber.js @@ -6,9 +6,9 @@ import { structureCollection } from '../classes/Structure/StructureCollection'; const builderOption = new BuilderOption({ identifier: 'materialGrabber', - displayName: 'Material Grabber', - description: 'Pulls structure items from inventories.', - howToUse: "Interact with inventories using the Material Grabber item to pull structure items from them.", + displayName: { translate: 'construct.option.materialgrabber.name' }, + description: { translate: 'construct.option.materialgrabber.description' }, + howToUse: { translate: 'construct.option.materialgrabber.howto' }, onEnableCallback: (playerId) => giveActionItem(playerId), onDisableCallback: (playerId) => removeActionItem(playerId) }); @@ -113,13 +113,12 @@ function ignoreAlreadyGathered(materials, playerContainer) { } function sendTransferMessage(player, transferCount) { - if (transferCount === 0) { - player.onScreenDisplay.setActionBar('§7Grabbed 0 items.'); - } else if (transferCount === 1) { - player.onScreenDisplay.setActionBar('§aGrabbed 1 item.'); - } else { - player.onScreenDisplay.setActionBar(`§aGrabbed ${transferCount} item(s).`); - } + if (transferCount === 0) + player.onScreenDisplay.setActionBar({ translate: 'construct.option.materialgrabber.grabbed.zero' }); + else if (transferCount === 1) + player.onScreenDisplay.setActionBar({ translate: 'construct.option.materialgrabber.grabbed.one' }); + else + player.onScreenDisplay.setActionBar({ translate: 'construct.option.materialgrabber.grabbed.many', with: [String(transferCount)] }); } function tryTransferToPlayer(slot, playerContainer, materials) { diff --git a/packs/BP/scripts/utils.js b/packs/BP/scripts/utils.js index aa8a636..d345b2d 100644 --- a/packs/BP/scripts/utils.js +++ b/packs/BP/scripts/utils.js @@ -8,7 +8,7 @@ export async function forceShow(player, form, timeout = Infinity) { while ((system.currentTick - startTick) < timeout) { const response = await form.show(player); if (startTick + 1 === system.currentTick && response.cancelationReason === FormCancelationReason.UserBusy) - player.sendMessage("§8Close your chat window to access the menu."); + player.sendMessage({ translate: 'construct.menu.open.closechat' }); if (response.cancelationReason !== FormCancelationReason.UserBusy) return response; } diff --git a/packs/RP/manifest.json b/packs/RP/manifest.json index 46b0b94..f844e7a 100644 --- a/packs/RP/manifest.json +++ b/packs/RP/manifest.json @@ -1,10 +1,10 @@ { "format_version": 2, "header": { - "name": "Construct [RP] v1.0.5", + "name": "Construct [RP] v1.0.6", "description": "Survival building addon by §aForestOfLight§r.", "uuid": "375ec465-3dc1-429f-8b4c-a337889e1ed4", - "version": [1, 0, 5], + "version": [1, 0, 6], "min_engine_version": [1,17,1] }, "modules": [ @@ -17,7 +17,7 @@ "dependencies": [ { "uuid": "8c0c0153-d8b9-482a-889f-aef922b8fe58", // Construct BP - "version": [1, 0, 5] + "version": [1, 0, 6] } ], "metadata": { diff --git a/packs/RP/texts/en_US.lang b/packs/RP/texts/en_US.lang new file mode 100644 index 0000000..3856b6e --- /dev/null +++ b/packs/RP/texts/en_US.lang @@ -0,0 +1,109 @@ +## Items +construct.menu.name=Construct +construct.easyplace.name=Easy Place +construct.materialgrabber.name=Material Grabber + +## Menus +construct.menu.open.closechat=§8Close your chat window to access the menu. +construct.menu.open.timeout=§8Menu timed out. +construct.menu.submit=§2Apply +construct.menu.instance.button.unknown=Unknown +construct.menu.instance.button.place=§aPlace Instance +construct.menu.instance.button.enable=§aEnable Instance +construct.menu.instance.button.disable=§cDisable Instance +construct.menu.instance.button.rename=Rename Instance +construct.menu.instance.button.delete=§cDelete Instance +construct.menu.instance.button.nextLayer=Increase Layer +construct.menu.instance.button.previousLayer=Decrease Layer +construct.menu.instance.button.move=Move Here +construct.menu.instance.button.flexibleMove=Flexible Move +construct.menu.instance.button.statistics=Statistics +construct.menu.instance.button.settings=Settings +construct.menu.instance.button.materials=Material List +construct.menu.instance.unknownOption=§cUnknown option: %s +construct.menu.instance.nameEmpty=§cInstance name cannot be empty. + +construct.instance.flexibleMove.alreadyMoving=§cThis instance is already being moved. +construct.instance.flexibleMove.start=§aNow moving "%s". Use the Construct item when finished. ## Insert string: instance name +construct.instance.flexibleMove.finish=§aMoved "%1" to %2. ## Insert strings: instance name, coordinates +construct.instance.rename.error=§cError renaming instance: %s +construct.instance.validation.alreadyRunning=§cA verification is already in progress. Please wait until it finishes. +construct.instance.validation.formfail=§cFailed to build statistics form. +construct.instance.menu.body=Instance: §a%1\n§fStructure: §2%2 ## Insert strings: instance name, structure name +construct.instance.menu.location=§7(%1 %2 %3 in %4) ## Is added to the body when the instance has is placed. Insert strings: x, y, z coordinates, dimension +construct.isntance.menu.rename=Enter a new name for the instance: +construct.instance.option.validation=Block Validation +construct.instance.option.validation.description=Shows missing and incorrect block overlay. +construct.instance.option.layer=Layer +construct.instance.option.layer.description=Changes the active layer. Use 0 for all layers. +construct.instance.materials.noinventory=§cNo player inventory found. +construct.instance.materials.missing.header=§cMaterials Missing From Inventory: +construct.instance.materials.missing.button=Show Missing Materials +construct.instance.materials.layer= §7(layer %s) ## Is added to the header when the instance is in layer mode. Insert string: layer number +construct.instance.materials.all.header=§aAll Materials: +construct.instance.materials.all.button=Show All Materials + +construct.materials.grabber.menu.title= Material Grabber +construct.materials.grabber.menu.success=§7Selected instance for material grabber: §2%s ## Insert string: instance name +construct.materials.grabber.menu.header=§7Current instance: +construct.materials.grabber.menu.noinstance=§7None +construct.materials.grabber.menu.selectinstance=§7Select an instance: + +construct.structure.statistics.header=§fStatistics for §a%s§f: ## Insert string: instance name +construct.structure.statistics.blocks=§7Blocks: §2%s ## Insert string: number of non-air blocks in the structure +construct.structure.statistics.skipped=§c[!] This analysis skipped %s blocks. ## Insert string: number of blocks the analysis skipped +construct.structure.statistics.correct=§7Correct: §a%s ## Insert string: number of correctly placed blocks +construct.structure.statistics.stateincorrect=§7Block State Incorrect: §e%s ## Insert string: number of incorrectly stated blocks +construct.structure.statistics.incorrect=§7Incorrect: §c%s ## Insert string: number of incorrectly placed blocks +construct.structure.statistics.missing=§7Missing: §3%s ## Insert string: number of missing blocks + +## Structure Block Info Display +construct.blockinfo.header=Structure: +construct.blockinfo.none=§7None +construct.blockinfo.nosupply= §c[No Supply] ## When the targeted block is not in the player's inventory +construct.blockinfo.unknown=§7Unknown +construct.blockinfo.waterlogged=§7isWaterlogged: §3true + +construct.mainmenu.instance.exists=§cInstance '%s' already exists. Try again with a new name. ## Insert string: instance name +construct.mainmenu.instance.notfound=§cStructure ID '%s' not found. If you're looking for a structure that you put in the structures folder, please restart your world and try again. ## Insert string: structure name +construct.mainmenu.title=§l§2Construct ## This is the name of the pack. +construct.mainmenu.selectinstance=Select an instance: +construct.mainmenu.settings=Builder Settings +construct.mainmenu.newinstance=Create New Instance +construct.mainmenu.newinstance.prompt=Enter a name for the new instance: +construct.mainmenu.newinstance.placeholder=example_instance ## The placeholder text in the textbox where the user enters the instance name. +construct.mainmenu.selectstructure.header=Select a structure: +construct.mainmenu.selectstructure.other=Other +construct.mainmenu.selectstructure.howto=How to Add/Remove Structures +construct.mainmenu.selectstructure.other.prompt=Enter the Structure ID: +construct.mainmenu.selectstructure.other.placeholder=example_structure ## The placeholder text in the textbox where the user enters the structure name. +construct.mainmenu.selectstructure.howto.add.header=§aHow to Add Structures: +construct.mainmenu.selectstructure.howto.add.structureblock=§7- Save a structure using a §fstructure block§7 or the §f/structure§7 command. +construct.mainmenu.selectstructure.howto.add.or=§7§lOR§r +construct.mainmenu.selectstructure.howto.add.mcstructure=§7- Add a §f.mcstructure§7 file to this pack's §fstructures folder§7. When selecting your structure, select the §fOther§7 option and then use the filename (without '.mcstructure') as the §fStructure ID§7. After its first use, it will be added to the list of structures. +construct.mainmenu.selectstructure.howto.remove.header=§cHow to Remove Structures: +construct.mainmenu.selectstructure.howto.remove.body=§7- Use the §f/structure delete§7 command to remove a structure from the world. + +## Commands +construct.commands.construct=Opens the Construct menu. +construct.commands.item=Gives you the Construct item. Use it to open the Construct menu. +construct.commands.item.denyorigin=This command can only be used by players. +construct.commands.item.fail=§cFailed to give you the Construct item. +construct.commands.item.success=§aYou recieved the Construct item! Use it to open the Construct menu. + +## Options +construct.option.enabled= is now enabled! +construct.option.disabled= is now disabled. +construct.option.easyplace.name=Easy Place +construct.option.easyplace.description=Always place the correct structure block. +construct.option.easyplace.howto=Hold the Easy Place item in your offhand and place blocks in an instance to have them be corrected automatically. +construct.option.easyplace.actionprevented=§cAction prevented by Easy Place. +construct.option.fasteasyplace.name=Fast Easy Place +construct.option.fasteasyplace.description=Place correct structure blocks just by clicking on them. +construct.option.fasteasyplace.howto=Hold the Easy Place item in your main hand and use it on missing blocks in a structure to place them. +construct.option.materialgrabber.name=Material Grabber +construct.option.materialgrabber.description=Pulls structure items from inventories. +construct.option.materialgrabber.howto=Interact with inventories using the Material Grabber item to pull structure items from them. +construct.option.materialgrabber.grabbed.zero=§7Grabbed 0 items. +construct.option.materialgrabber.grabbed.one=§aGrabbed 1 item. +construct.option.materialgrabber.grabbed.many=§aGrabbed %s items. ## Insert string: number of items transferred to the player \ No newline at end of file diff --git a/packs/RP/texts/languages.json b/packs/RP/texts/languages.json new file mode 100644 index 0000000..52d2a01 --- /dev/null +++ b/packs/RP/texts/languages.json @@ -0,0 +1,3 @@ +[ + "en_US" +] \ No newline at end of file