diff --git a/.github/workflows/cl.yml b/.github/workflows/cl.yml index 317bb343..5ce18601 100644 --- a/.github/workflows/cl.yml +++ b/.github/workflows/cl.yml @@ -30,7 +30,7 @@ jobs: - name: Create Pull Request if: ${{ github.event_name == 'schedule' }} id: cpr - uses: peter-evans/create-pull-request@v6 + uses: peter-evans/create-pull-request@v7 with: token: ${{ secrets.JAYLYBOT_TOKEN }} push-to-fork: jayly-bot/ScriptAPI diff --git a/.github/workflows/dependency-update.yml b/.github/workflows/dependency-update.yml index 27f4b00a..55262cb3 100644 --- a/.github/workflows/dependency-update.yml +++ b/.github/workflows/dependency-update.yml @@ -28,7 +28,7 @@ jobs: - name: Create Pull Request id: cpr - uses: peter-evans/create-pull-request@v6 + uses: peter-evans/create-pull-request@v7 with: token: ${{ secrets.JAYLYBOT_TOKEN }} push-to-fork: jayly-bot/ScriptAPI diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 46de47a7..a854b2d4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -35,11 +35,7 @@ If the check did not pass, go to the 'details' section and see what section of t An editor extension sample should only be used in Minecraft Editor, otherwise the sample should be hosted in 'scripts' folder. -- Create an editor extension sample in [editorExtensions](./editorExtensions/) directory. - -- Create the same folder structure as used in scripts folder and a header in main file like creating a new script sample. - -- We recommend using TypeScript for editor extension samples. +Currently, we do not provide support uploading and maintaince for editor extension samples in this repository. Please check out [Mojang's Bedrock Editor Samples](https://github.com/Mojang/minecraft-editor-extension-samples/) instead. ## Don't edit docs folder diff --git a/README.md b/README.md index d0d41cd6..e18bab9e 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ There are two ways to use external Minecraft libraries in behavior pack scripts: 1. **Standalone file** - Download standalone files available from https://jaylydev.github.io/scriptapi-docs/meta/useful-links.html for quick, small-scale projects. + Download standalone files available from [jaylydev.github.io](https://jaylydev.github.io/scriptapi-docs/meta/cdn-links.html) for quick, small-scale projects. 2. **Bundling** @@ -42,12 +42,6 @@ Guide on bundle Minecraft Scripts with the following bundlers: - ESBuild (Recommended): [Bundle Minecraft Scripts with ESBuild](https://jaylydev.github.io/posts/bundle-minecraft-scripts-esbuild/) - Webpack: [Bundle Minecraft Scripts with Webpack](https://jaylydev.github.io/posts/scripts-bundle-minecraft/) -## [Editor Extensions](./editorExtensions/) - -Community driven editor extensions samples for editing Minecraft worlds. Only available on Editor projects in [Minecraft Editor](https://github.com/mojang/minecraft-editor). - -Highly recommend checking out Mojang's [editor extension starter kit](https://github.com/Mojang/minecraft-editor-extension-starter-kit) if you're experimenting with editor API for the first time! - ## Documentation Check out the following links for Script API documentation: diff --git a/editorExtensions/editor-fullbright/README.md b/editorExtensions/editor-fullbright/README.md deleted file mode 100644 index 833bb11e..00000000 --- a/editorExtensions/editor-fullbright/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# editor-fullbright - -## Description -> This README is auto generated, Edit the README so that users know what this package does. - -## Credits -These scripts were written by [Jayly](https://github.com/JaylyDev) diff --git a/editorExtensions/editor-fullbright/index.js b/editorExtensions/editor-fullbright/index.js deleted file mode 100644 index e37c05dc..00000000 --- a/editorExtensions/editor-fullbright/index.js +++ /dev/null @@ -1,33 +0,0 @@ -// Script example for ScriptAPI -// Author: Jayly -// Project: https://github.com/JaylyDev/ScriptAPI -import { ActionTypes, EditorInputContext, InputModifier, KeyboardKey } from "@minecraft/server-editor"; -import { MinecraftEffectTypes } from "@minecraft/vanilla-data"; -/** - * Class to enable toggles for full bright in menu in editor mode - */ -export class FullbrightToggle { - constructor(uiSession, menu) { - const player = uiSession.extensionContext.player; - // Set actions - const enableAction = uiSession.actionManager.createAction({ - actionType: ActionTypes.NoArgsAction, - onExecute: () => { - player.addEffect(MinecraftEffectTypes.NightVision, 20000000, { amplifier: 1, showParticles: false }); - }, - }); - const disableAction = uiSession.actionManager.createAction({ - actionType: ActionTypes.NoArgsAction, - onExecute: () => { - player.removeEffect(MinecraftEffectTypes.NightVision); - }, - }); - // Add actions to menu - menu.addItem({ name: 'Enable', displayStringId: "Enable" }, enableAction); - menu.addItem({ name: 'Disable', displayStringId: "Disable" }, disableAction); - // Create key bindings - uiSession.inputManager.registerKeyBinding(EditorInputContext.GlobalEditor, enableAction, KeyboardKey.KEY_Z, InputModifier.Control); - uiSession.inputManager.registerKeyBinding(EditorInputContext.GlobalEditor, disableAction, KeyboardKey.KEY_Y, InputModifier.Control); - } - ; -} diff --git a/editorExtensions/editor-fullbright/index.ts b/editorExtensions/editor-fullbright/index.ts deleted file mode 100644 index 4644c861..00000000 --- a/editorExtensions/editor-fullbright/index.ts +++ /dev/null @@ -1,33 +0,0 @@ -// Script example for ScriptAPI -// Author: Jayly -// Project: https://github.com/JaylyDev/ScriptAPI -import { ActionTypes, EditorInputContext, IMenu, InputModifier, IPlayerUISession, KeyboardKey } from "@minecraft/server-editor"; -import { MinecraftEffectTypes } from "@minecraft/vanilla-data"; - -/** - * Class to enable toggles for full bright in menu in editor mode - */ -export class FullbrightToggle { - constructor (uiSession: IPlayerUISession, menu: IMenu) { - const player = uiSession.extensionContext.player; - // Set actions - const enableAction = uiSession.actionManager.createAction({ - actionType: ActionTypes.NoArgsAction, - onExecute: () => { - player.addEffect(MinecraftEffectTypes.NightVision, 20000000, { amplifier: 1, showParticles: false }); - }, - }); - const disableAction = uiSession.actionManager.createAction({ - actionType: ActionTypes.NoArgsAction, - onExecute: () => { - player.removeEffect(MinecraftEffectTypes.NightVision); - }, - }); - // Add actions to menu - menu.addItem({ name: 'Enable', displayStringId: "Enable" }, enableAction); - menu.addItem({ name: 'Disable', displayStringId: "Disable" }, disableAction); - // Create key bindings - uiSession.inputManager.registerKeyBinding(EditorInputContext.GlobalEditor, enableAction, KeyboardKey.KEY_Z, InputModifier.Control); - uiSession.inputManager.registerKeyBinding(EditorInputContext.GlobalEditor, disableAction, KeyboardKey.KEY_Y, InputModifier.Control); - }; -} \ No newline at end of file diff --git a/editorExtensions/editor-fullbright/tests.js b/editorExtensions/editor-fullbright/tests.js deleted file mode 100644 index ad0e0e56..00000000 --- a/editorExtensions/editor-fullbright/tests.js +++ /dev/null @@ -1,28 +0,0 @@ -import { FullbrightToggle } from "./index"; -import { registerEditorExtension } from "@minecraft/server-editor"; -export function createMenu(uiSession) { - if (!uiSession.scratchStorage) { - throw new Error('Core UI initialization order incorrect'); - } - const edit = uiSession.createMenu({ - name: 'FullBright', - displayStringId: 'FullBright', - }); - edit.show(); - return edit; -} -; -registerEditorExtension('nightVision', (uiSession) => { - uiSession.scratchStorage = {}; - // Initialize tool rail. - uiSession.toolRail.show(); - // Add selection functionality - new FullbrightToggle(uiSession, createMenu(uiSession)); - return [ - { - teardown() { - this.uiSession.log.debug("Shutting down FullbrightToggle behavior\n"); - } - } - ]; -}, () => { }); diff --git a/editorExtensions/editor-fullbright/tests.ts b/editorExtensions/editor-fullbright/tests.ts deleted file mode 100644 index 3ed59dcb..00000000 --- a/editorExtensions/editor-fullbright/tests.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { FullbrightToggle } from "./index"; -import { IPlayerUISession, registerEditorExtension } from "@minecraft/server-editor"; - -export function createMenu(uiSession: IPlayerUISession) { - if (!uiSession.scratchStorage) { - throw new Error('Core UI initialization order incorrect'); - } - const edit = uiSession.menuBar.createMenu({ - name: 'FullBright', - displayStringId: 'FullBright', - }); - edit.show(); - return edit; -}; - -registerEditorExtension('nightVision', (uiSession) => { - uiSession.scratchStorage = {}; - // Initialize tool rail. - uiSession.toolRail.show(); - // Add selection functionality - new FullbrightToggle(uiSession, createMenu(uiSession)); - return [ - { - teardown() { - this.uiSession.log.debug("Shutting down FullbrightToggle behavior\n"); - } - } - ]; -}, () => {}); \ No newline at end of file diff --git a/editorExtensions/editor-random-fill/README.md b/editorExtensions/editor-random-fill/README.md deleted file mode 100644 index c3884653..00000000 --- a/editorExtensions/editor-random-fill/README.md +++ /dev/null @@ -1,14 +0,0 @@ -# Editor Random Fill Tool - -## Description - -Fill random blocks in a selection via Minecraft Editor. - -This script contains partial source code for editor's selection extension. - -This is proof of concept, where you can use a slider to choose how many block types you want the editor to fill randomly with a click of a button. - -Obviously this is still a WIP. - -## Credits -These scripts were written by [Jayly](https://github.com/JaylyDev) diff --git a/editorExtensions/editor-random-fill/functions.js b/editorExtensions/editor-random-fill/functions.js deleted file mode 100644 index d7c3900c..00000000 --- a/editorExtensions/editor-random-fill/functions.js +++ /dev/null @@ -1,182 +0,0 @@ -import { Block, BlockVolume, BoundingBoxUtils, Vector } from "@minecraft/server"; -import { Direction, getRotationCorrectedDirection } from "editor-utilities/index"; -/** - * @beta - */ -var AxisPlanes; -(function (AxisPlanes) { - AxisPlanes[AxisPlanes["XZ"] = 0] = "XZ"; - AxisPlanes[AxisPlanes["XY"] = 1] = "XY"; - AxisPlanes[AxisPlanes["YZ"] = 2] = "YZ"; -})(AxisPlanes || (AxisPlanes = {})); -; -/** - * @beta - */ -const axisNormalLookup = { - [AxisPlanes.XZ]: Vector.up, - [AxisPlanes.XY]: Vector.forward, - [AxisPlanes.YZ]: Vector.left, -}; -/** - * @beta - */ -export function getRelativeXYAxisAsNormal(rotation) { - const direction = getRotationCorrectedDirection(rotation, Direction.Forward); - switch (direction) { - case Direction.Forward: - case Direction.Back: - return axisNormalLookup[AxisPlanes.XY]; - case Direction.Right: - case Direction.Left: - return axisNormalLookup[AxisPlanes.YZ]; - default: - throw 'Invalid quadrant'; - } -} -/** - * @beta - */ -function VectorDot(a, b) { - return a.x * b.x + a.y * b.y + a.z * b.z; -} -/** - * @beta - */ -function VectorScale(a, s) { - const v = new Vector(a.x, a.y, a.z); - v.x *= s; - v.y *= s; - v.z *= s; - return v; -} -/** - * @beta - */ -export function intersectRayPlane(rayLocation, rayDirection, planeNormal, planeDistance) { - const denominator = VectorDot(rayDirection, planeNormal); - if (denominator !== 0) { - const t = -(VectorDot(rayLocation, planeNormal) + planeDistance) / denominator; - if (t < 0) { - return undefined; - } - const scaledDirection = VectorScale(rayDirection, t); - const result = Vector.add(rayLocation, scaledDirection); - return result; - } - else if (VectorDot(planeNormal, rayLocation) + planeDistance === 0) { - return rayLocation; - } - return undefined; -} -/** - * @beta - */ -export function shrinkVolumeAlongViewAxis(volume, rotationY, direction, amount) { - const relativeDirection = getRotationCorrectedDirection(rotationY, direction); - return shrinkVolumeAlongAbsoluteAxis(volume, relativeDirection, amount); -} -export function growVolumeAlongViewAxis(volume, rotationY, direction, amount) { - const relativeDirection = getRotationCorrectedDirection(rotationY, direction); - return growVolumeAlongAbsoluteAxis(volume, relativeDirection, amount); -} -function growVolumeAlongAbsoluteAxis(volume, direction, amount) { - const maxAxialLength = 32; - if (amount > maxAxialLength) { - amount = maxAxialLength; - } - const bounds = new BlockVolume(volume); - const boundSize = BoundingBoxUtils.getSpan(bounds); - const min = bounds.min; - const max = bounds.max; - const spanX = boundSize.x; - const spanY = boundSize.y; - const spanZ = boundSize.z; - switch (direction) { - case Direction.Up: - if (spanY + amount > maxAxialLength) { - amount = maxAxialLength - spanY; - } - max.y += amount; - break; - case Direction.Down: - if (spanY + amount > maxAxialLength) { - amount = maxAxialLength - spanY; - } - min.y -= amount; - break; - case Direction.Forward: - if (spanZ + amount > maxAxialLength) { - amount = maxAxialLength - spanZ; - } - max.z += amount; - break; - case Direction.Back: - if (spanZ + amount > maxAxialLength) { - amount = maxAxialLength - spanZ; - } - min.z -= amount; - break; - case Direction.Left: - if (spanX + amount > maxAxialLength) { - amount = maxAxialLength - spanX; - } - max.x += amount; - break; - case Direction.Right: - if (spanX + amount > maxAxialLength) { - amount = maxAxialLength - spanX; - } - min.x -= amount; - break; - } - return { - from: min, - to: max - }; -} -function shrinkVolumeAlongAbsoluteAxis(volume, direction, amount) { - const bounds = BlockVolumeUtils.getBoundingBox(volume); - const boundSize = BoundingBoxUtils.getSpan(bounds); - const min = bounds.min; - const max = bounds.max; - const spanX = boundSize.x; - const spanY = boundSize.y; - const spanZ = boundSize.z; - switch (direction) { - case Direction.Up: - if (spanY > amount) { - max.y -= amount; - } - break; - case Direction.Down: - if (spanY > amount) { - min.y += amount; - } - break; - case Direction.Forward: - if (spanZ > amount) { - max.z -= amount; - } - break; - case Direction.Back: - if (spanZ > amount) { - min.z += amount; - } - break; - case Direction.Left: - if (spanX > amount) { - max.x -= amount; - } - break; - case Direction.Right: - if (spanX > amount) { - min.x += amount; - } - break; - } - return { - from: min, - to: max - }; -} diff --git a/editorExtensions/editor-random-fill/functions.ts b/editorExtensions/editor-random-fill/functions.ts deleted file mode 100644 index c6ea73a7..00000000 --- a/editorExtensions/editor-random-fill/functions.ts +++ /dev/null @@ -1,191 +0,0 @@ -import { BlockVolume, BoundingBoxUtils, Vector3 } from "@minecraft/server"; -import { VECTOR3_FORWARD, VECTOR3_LEFT, VECTOR3_UP, Vector3Builder, Vector3Utils } from "@minecraft/math"; -import { Direction, getRotationCorrectedDirection } from "editor-utilities/index"; - -/** - * @beta - */ -enum AxisPlanes { - XZ = 0, - XY = 1, - YZ = 2 -}; - -/** - * @beta - */ -const axisNormalLookup = { - [AxisPlanes.XZ]: VECTOR3_UP, - [AxisPlanes.XY]: VECTOR3_FORWARD, - [AxisPlanes.YZ]: VECTOR3_LEFT, -}; -/** - * @beta - */ -export function getRelativeXYAxisAsNormal(rotation: number) { - const direction = getRotationCorrectedDirection(rotation, Direction.Forward); - switch (direction) { - case Direction.Forward: - case Direction.Back: - return axisNormalLookup[AxisPlanes.XY]; - case Direction.Right: - case Direction.Left: - return axisNormalLookup[AxisPlanes.YZ]; - default: - throw 'Invalid quadrant'; - } -} -/** - * @beta - */ -function VectorDot(a: Vector3, b: Vector3) { - return a.x * b.x + a.y * b.y + a.z * b.z; -} -/** - * @beta - */ -function VectorScale(a: Vector3, s: number) { - const v = new Vector3Builder(a); - v.x *= s; - v.y *= s; - v.z *= s; - return v; -} -/** - * @beta - */ -export function intersectRayPlane(rayLocation: Vector3, rayDirection: Vector3, planeNormal: Vector3, planeDistance: number) { - const denominator = VectorDot(rayDirection, planeNormal); - if (denominator !== 0) { - const t = -(VectorDot(rayLocation, planeNormal) + planeDistance) / denominator; - if (t < 0) { - return undefined; - } - const scaledDirection = VectorScale(rayDirection, t); - const result = Vector3Utils.add(rayLocation, scaledDirection); - return result; - } - else if (VectorDot(planeNormal, rayLocation) + planeDistance === 0) { - return rayLocation; - } - return undefined; -} -/** - * @beta - */ -export function shrinkVolumeAlongViewAxis(volume: any, rotationY: number, direction: Direction, amount: any) { - const relativeDirection = getRotationCorrectedDirection(rotationY, direction); - return shrinkVolumeAlongAbsoluteAxis(volume, relativeDirection, amount); -} - - -export function growVolumeAlongViewAxis(volume: BlockVolume, rotationY: number, direction: Direction, amount: number) { - const relativeDirection = getRotationCorrectedDirection(rotationY, direction); - return growVolumeAlongAbsoluteAxis(volume, relativeDirection, amount); -} - -function growVolumeAlongAbsoluteAxis(volume: BlockVolume, direction: number | Direction, amount: number): BlockVolume { - const maxAxialLength = 32; - if (amount > maxAxialLength) { - amount = maxAxialLength; - } - const bounds = volume.getBoundingBox(); - const boundSize = BoundingBoxUtils.getSpan(bounds); - const min = bounds.min; - const max = bounds.max; - const spanX = boundSize.x; - const spanY = boundSize.y; - const spanZ = boundSize.z; - switch (direction) { - case Direction.Up: - if (spanY + amount > maxAxialLength) { - amount = maxAxialLength - spanY; - } - max.y += amount; - break; - - case Direction.Down: - if (spanY + amount > maxAxialLength) { - amount = maxAxialLength - spanY; - } - min.y -= amount; - break; - - case Direction.Forward: - if (spanZ + amount > maxAxialLength) { - amount = maxAxialLength - spanZ; - } - max.z += amount; - break; - - case Direction.Back: - if (spanZ + amount > maxAxialLength) { - amount = maxAxialLength - spanZ; - } - min.z -= amount; - break; - - case Direction.Left: - if (spanX + amount > maxAxialLength) { - amount = maxAxialLength - spanX; - } - max.x += amount; - break; - - case Direction.Right: - if (spanX + amount > maxAxialLength) { - amount = maxAxialLength - spanX; - } - min.x -= amount; - break; - } - return new BlockVolume(min, max); -} - -function shrinkVolumeAlongAbsoluteAxis(volume: BlockVolume, direction: Direction | number, amount: number): BlockVolume { - const bounds = volume.getBoundingBox(); - const boundSize = BoundingBoxUtils.getSpan(bounds); - const min = bounds.min; - const max = bounds.max; - const spanX = boundSize.x; - const spanY = boundSize.y; - const spanZ = boundSize.z; - switch (direction) { - case Direction.Up: - if (spanY > amount) { - max.y -= amount; - } - break; - - case Direction.Down: - if (spanY > amount) { - min.y += amount; - } - break; - - case Direction.Forward: - if (spanZ > amount) { - max.z -= amount; - } - break; - - case Direction.Back: - if (spanZ > amount) { - min.z += amount; - } - break; - - case Direction.Left: - if (spanX > amount) { - max.x -= amount; - } - break; - - case Direction.Right: - if (spanX > amount) { - min.x += amount; - } - break; - } - return new BlockVolume(min, max); -} \ No newline at end of file diff --git a/editorExtensions/editor-random-fill/index.js b/editorExtensions/editor-random-fill/index.js deleted file mode 100644 index 31abdb26..00000000 --- a/editorExtensions/editor-random-fill/index.js +++ /dev/null @@ -1,888 +0,0 @@ -// Script example for ScriptAPI -// Author: Jayly -// Project: https://github.com/JaylyDev/ScriptAPI -import { system, Vector, CompoundBlockVolumeAction, BlockVolumeUtils, BoundingBoxUtils, BlockTypes } from "@minecraft/server"; -import { KeyboardKey, ActionTypes, MouseActionType, MouseInputType, CursorControlMode, InputModifier, getLocalizationId, CursorTargetMode, EditorInputContext, executeLargeOperation, bindDataSource, registerEditorExtension } from "@minecraft/server-editor"; -import { getRotationCorrectedDirectionVector, Direction, } from "editor-utilities/index"; -import { getRelativeXYAxisAsNormal, growVolumeAlongViewAxis, intersectRayPlane, shrinkVolumeAlongViewAxis, } from "./functions"; -// ------------------------------------------------------------------------------------------------ -// General collection of selection related variables for this instance -// ------------------------------------------------------------------------------------------------ -var SelectionCursorMode; -(function (SelectionCursorMode) { - SelectionCursorMode[SelectionCursorMode["Freeform"] = 0] = "Freeform"; - SelectionCursorMode[SelectionCursorMode["FixedDistance"] = 1] = "FixedDistance"; - SelectionCursorMode[SelectionCursorMode["AdjacentFace"] = 2] = "AdjacentFace"; -})(SelectionCursorMode || (SelectionCursorMode = {})); -; -const Controls = { - Up: KeyboardKey.PAGE_UP, - Down: KeyboardKey.PAGE_DOWN, - Forward: KeyboardKey.UP, - Back: KeyboardKey.DOWN, - Left: KeyboardKey.LEFT, - Right: KeyboardKey.RIGHT, - Select: KeyboardKey.ENTER, - Clear: KeyboardKey.KEY_D, -}; -const TicksRefreshRate = 5; -// ------------------------------------------------------------------------------------------------ -export class SelectionBehavior { - get toolId() { - return this.tool.id; - } - constructor(uiSession) { - this.uiSession = uiSession; - this.fnUnregisterToolBindings = () => { - this.tool.unregisterInputBindings(); - }; - this.singleClick = (uiSession, mouseRay, shiftPressed, ctrlPressed, altPressed) => { - const clickLoc = mouseRay.cursorBlockLocation; - // Nothing pressed, then clear the stack and create a single 1x1x1 - if (!shiftPressed && !ctrlPressed && !altPressed) { - uiSession.extensionContext.selectionManager.selection.clear(); - uiSession.extensionContext.selectionManager.selection.pushVolume({ - action: CompoundBlockVolumeAction.Add, - volume: { - from: clickLoc, - to: clickLoc - } - }); - // Store this as the anchor point - this.lastAnchorPosition = clickLoc; - } - // Shift pressed, an no volume exists - create a single 1x1x1 - // if a volume does exist - use it to anchor the min corner and make a volume - // from anchor to new click - else if (shiftPressed && !ctrlPressed && !altPressed) { - if (uiSession.extensionContext.selectionManager.selection.isEmpty) { - // Create a new 1x1x1 selection volume at the click position - uiSession.extensionContext.selectionManager.selection.pushVolume({ - action: CompoundBlockVolumeAction.Add, - volume: { - from: clickLoc, - to: clickLoc - } - }); - // Store this as the anchor point - this.lastAnchorPosition = clickLoc; - } - else { - // Use the last anchor point (i.e. the first click selection) as the - // corner for the new click, and defining a new volume area - const lastAnchorPosition = this.lastAnchorPosition; - uiSession.extensionContext.selectionManager.selection.popVolume(); - const newVolume = { - from: lastAnchorPosition, - to: clickLoc - }; - uiSession.extensionContext.selectionManager.selection.pushVolume({ - action: CompoundBlockVolumeAction.Add, - volume: newVolume - }); - } - } - // Control pressed and no volume exists - create a single 1x1x1 - // If a volume exists, just push a new 1x1x1 to the stack - else if (ctrlPressed && !shiftPressed && !altPressed) { - uiSession.extensionContext.selectionManager.selection.pushVolume({ - action: CompoundBlockVolumeAction.Add, - volume: { - from: clickLoc, - to: clickLoc - } - }); - // Store this as the anchor point - this.lastAnchorPosition = clickLoc; - } - // If ALT is pressed, and there IS already a full volume, then we're going into 3-click volume - // mode and we need to do some intersection calculations - else if (altPressed && !shiftPressed && !ctrlPressed) { - const currentItem = uiSession.extensionContext.selectionManager.selection.peekLastVolume(); - if (!currentItem) { - uiSession.extensionContext.selectionManager.selection.pushVolume({ - action: CompoundBlockVolumeAction.Add, - volume: { - from: clickLoc, - to: clickLoc - } - }); - this.lastAnchorPosition = clickLoc; - } - else { - const currentVolume = currentItem.volume; - const currentBounds = BlockVolumeUtils.getBoundingBox(currentVolume); - const translatedRayLocation = Vector.subtract(new Vector(mouseRay.location.x, mouseRay.location.y, mouseRay.location.z), new Vector(currentBounds.min.x, currentBounds.min.y, currentBounds.min.z)); - const XYPlaneNormal = getRelativeXYAxisAsNormal(uiSession.extensionContext.player.getRotation().y); - const intersection = intersectRayPlane(translatedRayLocation, mouseRay.direction, XYPlaneNormal, 0); - if (intersection) { - const translatedIntersection = Vector.add(intersection, new Vector(currentBounds.min.x, currentBounds.min.y, currentBounds.min.z)); - const newY = Math.ceil(translatedIntersection.y) - 1; - uiSession.extensionContext.selectionManager.selection.popVolume(); - uiSession.extensionContext.selectionManager.selection.pushVolume({ - action: currentItem.action, - volume: { - from: { - x: currentBounds.min.x, - y: currentBounds.min.y, - z: currentBounds.min.z - }, - to: { - x: currentBounds.max.x, - y: newY, - z: currentBounds.max.z - } - } - }); - } - } - } - }; - this.moveTopSelection = (uiSession, lastAnchor, direction) => { - const lastVolumeItem = uiSession.extensionContext.selectionManager.selection.peekLastVolume(); - if (!lastVolumeItem) { - return undefined; - } - const lastVolume = lastVolumeItem.volume; - uiSession.extensionContext.selectionManager.selection.popVolume(); - const rotationY = uiSession.extensionContext.player.getRotation().y; - const correctedVector = getRotationCorrectedDirectionVector(rotationY, direction); - const newVolume = BlockVolumeUtils.translate(lastVolume, { - x: correctedVector.x, - y: correctedVector.y, - z: correctedVector.z - }); - uiSession.extensionContext.selectionManager.selection.pushVolume({ - action: CompoundBlockVolumeAction.Add, - volume: newVolume - }); - // Update the last cursor click position with the move vector - // so that extend-click operations work correctly with the new corner position - const updatedClick = { - x: lastAnchor.x + correctedVector.x, - y: lastAnchor.y + correctedVector.y, - z: lastAnchor.z + correctedVector.z, - }; - return updatedClick; - }; - this.moveBlockCursorManually = (uiSession, direction) => { - const rotationY = uiSession.extensionContext.player.getRotation().y; - const rotationCorrectedVector = getRotationCorrectedDirectionVector(rotationY, direction); - uiSession.extensionContext.cursor.moveBy(rotationCorrectedVector); - }; - this.moveAllSelections = (uiSession, anchorPosition, direction) => { - if (uiSession.extensionContext.selectionManager.selection.isEmpty) { - return undefined; - } - const rotationY = uiSession.extensionContext.player.getRotation().y; - const correctedVector = getRotationCorrectedDirectionVector(rotationY, direction); - uiSession.extensionContext.selectionManager.selection.moveBy({ - x: correctedVector.x, - y: correctedVector.y, - z: correctedVector.z, - }); - const updatedClick = { - x: anchorPosition.x + correctedVector.x, - y: anchorPosition.y + correctedVector.y, - z: anchorPosition.z + correctedVector.z, - }; - return updatedClick; - }; - this.shrinkVolume = (uiSession, direction) => { - if (uiSession.extensionContext.selectionManager.selection.isEmpty) { - return; - } - const lastVolume = uiSession.extensionContext.selectionManager.selection.peekLastVolume; - uiSession.extensionContext.selectionManager.selection.popVolume(); - const rotationY = uiSession.extensionContext.player.getRotation().y; - const newVolume = shrinkVolumeAlongViewAxis(lastVolume, rotationY, direction, 1); - uiSession.extensionContext.selectionManager.selection.pushVolume({ - action: CompoundBlockVolumeAction.Add, - volume: newVolume - }); - }; - this.growVolume = (uiSession, direction) => { - const lastVolumeItem = uiSession.extensionContext.selectionManager.selection.peekLastVolume(); - if (!lastVolumeItem) { - return; - } - const lastVolume = lastVolumeItem.volume; - uiSession.extensionContext.selectionManager.selection.popVolume(); - const rotationY = uiSession.extensionContext.player.getRotation().y; - const newVolume = growVolumeAlongViewAxis(lastVolume, rotationY, direction, 1); - uiSession.extensionContext.selectionManager.selection.pushVolume({ - action: lastVolumeItem.action, - volume: newVolume - }); - }; - // Input and tool binding functions - // ------------------------------------------------------------------------------------------------ - this.bindToolInput = (uiSession) => { - // Bind Single Mouse Click - const singleClickAction = uiSession.actionManager.createAction({ - actionType: ActionTypes.MouseRayCastAction, - onExecute: (mouseRay, mouseProps) => { - if (mouseProps.mouseAction === MouseActionType.LeftButton) { - if (mouseProps.inputType === MouseInputType.ButtonDown) { - if (mouseRay.rayHit || this.toolCursorProperties.controlMode === CursorControlMode.Fixed) { - this.singleClick(uiSession, mouseRay, mouseProps.modifiers.shift, mouseProps.modifiers.ctrl, mouseProps.modifiers.alt); - } - else { - // If we're clicking on nothing or something too far away - clear the selection stack - uiSession.extensionContext.selectionManager.selection.clear(); - } - } - } - }, - }); - this.tool.registerMouseButtonBinding(singleClickAction); - // Bind Keyboard MOVE functions - const keyUpAction = uiSession.actionManager.createAction({ - actionType: ActionTypes.NoArgsAction, - onExecute: () => { - uiSession.extensionContext.cursor.moveBy(Vector.up); - }, - }); - const keyDownAction = uiSession.actionManager.createAction({ - actionType: ActionTypes.NoArgsAction, - onExecute: () => { - uiSession.extensionContext.cursor.moveBy(Vector.down); - }, - }); - const keyLeftAction = uiSession.actionManager.createAction({ - actionType: ActionTypes.NoArgsAction, - onExecute: () => { - this.moveBlockCursorManually(uiSession, Direction.Left); - }, - }); - const keyRightAction = uiSession.actionManager.createAction({ - actionType: ActionTypes.NoArgsAction, - onExecute: () => { - this.moveBlockCursorManually(uiSession, Direction.Right); - }, - }); - const keyForwardAction = uiSession.actionManager.createAction({ - actionType: ActionTypes.NoArgsAction, - onExecute: () => { - this.moveBlockCursorManually(uiSession, Direction.Forward); - }, - }); - const keyBackAction = uiSession.actionManager.createAction({ - actionType: ActionTypes.NoArgsAction, - onExecute: () => { - this.moveBlockCursorManually(uiSession, Direction.Back); - }, - }); - // Bind arrow keys to manual cursor control - this.tool.registerKeyBinding(keyForwardAction, Controls.Forward, InputModifier.None); - this.tool.registerKeyBinding(keyBackAction, Controls.Back, InputModifier.None); - this.tool.registerKeyBinding(keyLeftAction, Controls.Left, InputModifier.None); - this.tool.registerKeyBinding(keyRightAction, Controls.Right, InputModifier.None); - this.tool.registerKeyBinding(keyUpAction, Controls.Up, InputModifier.None); - this.tool.registerKeyBinding(keyDownAction, Controls.Down, InputModifier.None); - const mouseWheelAction = uiSession.actionManager.createAction({ - actionType: ActionTypes.MouseRayCastAction, - onExecute: (mouseRay, mouseProps) => { - if (mouseProps.inputType === MouseInputType.WheelOut) { - if (mouseProps.modifiers.shift) { - this.growVolume(uiSession, Direction.Left); - this.growVolume(uiSession, Direction.Right); - } - else if (mouseProps.modifiers.ctrl) { - this.growVolume(uiSession, Direction.Forward); - this.growVolume(uiSession, Direction.Back); - } - else if (mouseProps.modifiers.alt) { - this.growVolume(uiSession, Direction.Up); - this.growVolume(uiSession, Direction.Down); - } - else if (this.toolCursorProperties.controlMode === CursorControlMode.Fixed) { - uiSession.extensionContext.cursor.moveBy(Vector.forward); - } - } - else if (mouseProps.inputType === MouseInputType.WheelIn) { - if (mouseProps.modifiers.shift) { - this.shrinkVolume(uiSession, Direction.Left); - this.shrinkVolume(uiSession, Direction.Right); - } - else if (mouseProps.modifiers.ctrl) { - this.shrinkVolume(uiSession, Direction.Forward); - this.shrinkVolume(uiSession, Direction.Back); - } - else if (mouseProps.modifiers.alt) { - this.shrinkVolume(uiSession, Direction.Up); - this.shrinkVolume(uiSession, Direction.Down); - } - else if (this.toolCursorProperties.controlMode === CursorControlMode.Fixed) { - uiSession.extensionContext.cursor.moveBy(Vector.back); - } - } - }, - }); - this.tool.registerMouseWheelBinding(mouseWheelAction); - // Bind ARROWS+ALT for MOVE selection volume (single) - // ----------------------------------------- - const moveSelectionUpAction = uiSession.actionManager.createAction({ - actionType: ActionTypes.NoArgsAction, - onExecute: () => { - const updatedAnchor = this.moveTopSelection(uiSession, this.lastAnchorPosition, Direction.Up); - if (updatedAnchor) { - this.lastAnchorPosition = updatedAnchor; - } - }, - }); - const moveSelectionDownAction = uiSession.actionManager.createAction({ - actionType: ActionTypes.NoArgsAction, - onExecute: () => { - const updatedAnchor = this.moveTopSelection(uiSession, this.lastAnchorPosition, Direction.Down); - if (updatedAnchor) { - this.lastAnchorPosition = updatedAnchor; - } - }, - }); - const moveSelectionLeftAction = uiSession.actionManager.createAction({ - actionType: ActionTypes.NoArgsAction, - onExecute: () => { - const updatedAnchor = this.moveTopSelection(uiSession, this.lastAnchorPosition, Direction.Left); - if (updatedAnchor) { - this.lastAnchorPosition = updatedAnchor; - } - }, - }); - const moveSelectionRightAction = uiSession.actionManager.createAction({ - actionType: ActionTypes.NoArgsAction, - onExecute: () => { - const updatedAnchor = this.moveTopSelection(uiSession, this.lastAnchorPosition, Direction.Right); - if (updatedAnchor) { - this.lastAnchorPosition = updatedAnchor; - } - }, - }); - const moveSelectionForwardAction = uiSession.actionManager.createAction({ - actionType: ActionTypes.NoArgsAction, - onExecute: () => { - const updatedAnchor = this.moveTopSelection(uiSession, this.lastAnchorPosition, Direction.Forward); - if (updatedAnchor) { - this.lastAnchorPosition = updatedAnchor; - } - }, - }); - const moveSelectionBackAction = uiSession.actionManager.createAction({ - actionType: ActionTypes.NoArgsAction, - onExecute: () => { - const updatedAnchor = this.moveTopSelection(uiSession, this.lastAnchorPosition, Direction.Back); - if (updatedAnchor) { - this.lastAnchorPosition = updatedAnchor; - } - }, - }); - // Bind arrow keys to manual cursor control - this.tool.registerKeyBinding(moveSelectionForwardAction, Controls.Forward, InputModifier.Alt); - this.tool.registerKeyBinding(moveSelectionBackAction, Controls.Back, InputModifier.Alt); - this.tool.registerKeyBinding(moveSelectionLeftAction, Controls.Left, InputModifier.Alt); - this.tool.registerKeyBinding(moveSelectionRightAction, Controls.Right, InputModifier.Alt); - this.tool.registerKeyBinding(moveSelectionUpAction, Controls.Up, InputModifier.Alt); - this.tool.registerKeyBinding(moveSelectionDownAction, Controls.Down, InputModifier.Alt); - // Bind ARROWS+ALT+CTRL to move ALL selections - const moveAllSelectionUpAction = uiSession.actionManager.createAction({ - actionType: ActionTypes.NoArgsAction, - onExecute: () => { - const updatedAnchor = this.moveAllSelections(uiSession, this.lastAnchorPosition, Direction.Up); - if (updatedAnchor) { - this.lastAnchorPosition = updatedAnchor; - } - }, - }); - const moveAllSelectionDownAction = uiSession.actionManager.createAction({ - actionType: ActionTypes.NoArgsAction, - onExecute: () => { - const updatedAnchor = this.moveAllSelections(uiSession, this.lastAnchorPosition, Direction.Down); - if (updatedAnchor) { - this.lastAnchorPosition = updatedAnchor; - } - }, - }); - const moveAllSelectionLeftAction = uiSession.actionManager.createAction({ - actionType: ActionTypes.NoArgsAction, - onExecute: () => { - const updatedAnchor = this.moveAllSelections(uiSession, this.lastAnchorPosition, Direction.Left); - if (updatedAnchor) { - this.lastAnchorPosition = updatedAnchor; - } - }, - }); - const moveAllSelectionRightAction = uiSession.actionManager.createAction({ - actionType: ActionTypes.NoArgsAction, - onExecute: () => { - const updatedAnchor = this.moveAllSelections(uiSession, this.lastAnchorPosition, Direction.Right); - if (updatedAnchor) { - this.lastAnchorPosition = updatedAnchor; - } - }, - }); - const moveAllSelectionForwardAction = uiSession.actionManager.createAction({ - actionType: ActionTypes.NoArgsAction, - onExecute: () => { - const updatedAnchor = this.moveAllSelections(uiSession, this.lastAnchorPosition, Direction.Forward); - if (updatedAnchor) { - this.lastAnchorPosition = updatedAnchor; - } - }, - }); - const moveAllSelectionBackAction = uiSession.actionManager.createAction({ - actionType: ActionTypes.NoArgsAction, - onExecute: () => { - const updatedAnchor = this.moveAllSelections(uiSession, this.lastAnchorPosition, Direction.Back); - if (updatedAnchor) { - this.lastAnchorPosition = updatedAnchor; - } - }, - }); - this.tool.registerKeyBinding(moveAllSelectionForwardAction, Controls.Forward, InputModifier.Alt | InputModifier.Control); - this.tool.registerKeyBinding(moveAllSelectionBackAction, Controls.Back, InputModifier.Alt | InputModifier.Control); - this.tool.registerKeyBinding(moveAllSelectionLeftAction, Controls.Left, InputModifier.Alt | InputModifier.Control); - this.tool.registerKeyBinding(moveAllSelectionRightAction, Controls.Right, InputModifier.Alt | InputModifier.Control); - this.tool.registerKeyBinding(moveAllSelectionUpAction, Controls.Up, InputModifier.Alt | InputModifier.Control); - this.tool.registerKeyBinding(moveAllSelectionDownAction, Controls.Down, InputModifier.Alt | InputModifier.Control); - // Bind ARROW+SHIFT - const keyGrowUpAction = uiSession.actionManager.createAction({ - actionType: ActionTypes.NoArgsAction, - onExecute: () => { - this.growVolume(uiSession, Direction.Up); - }, - }); - this.tool.registerKeyBinding(keyGrowUpAction, Controls.Up, InputModifier.Shift); - const keyGrowDownAction = uiSession.actionManager.createAction({ - actionType: ActionTypes.NoArgsAction, - onExecute: () => { - this.growVolume(uiSession, Direction.Down); - }, - }); - this.tool.registerKeyBinding(keyGrowDownAction, Controls.Down, InputModifier.Shift); - const keyGrowForwardAction = uiSession.actionManager.createAction({ - actionType: ActionTypes.NoArgsAction, - onExecute: () => { - this.growVolume(uiSession, Direction.Forward); - }, - }); - this.tool.registerKeyBinding(keyGrowForwardAction, Controls.Forward, InputModifier.Shift); - const keyGrowBackAction = uiSession.actionManager.createAction({ - actionType: ActionTypes.NoArgsAction, - onExecute: () => { - this.growVolume(uiSession, Direction.Back); - }, - }); - this.tool.registerKeyBinding(keyGrowBackAction, Controls.Back, InputModifier.Shift); - const keyGrowLeftAction = uiSession.actionManager.createAction({ - actionType: ActionTypes.NoArgsAction, - onExecute: () => { - this.growVolume(uiSession, Direction.Left); - }, - }); - this.tool.registerKeyBinding(keyGrowLeftAction, Controls.Left, InputModifier.Shift); - const keyGrowRightAction = uiSession.actionManager.createAction({ - actionType: ActionTypes.NoArgsAction, - onExecute: () => { - this.growVolume(uiSession, Direction.Right); - }, - }); - this.tool.registerKeyBinding(keyGrowRightAction, Controls.Right, InputModifier.Shift); - // Bind ARROW+CTRL - const keyShrinkUpAction = uiSession.actionManager.createAction({ - actionType: ActionTypes.NoArgsAction, - onExecute: () => { - this.shrinkVolume(uiSession, Direction.Up); - }, - }); - this.tool.registerKeyBinding(keyShrinkUpAction, Controls.Up, InputModifier.Control); - const keyShrinkDownAction = uiSession.actionManager.createAction({ - actionType: ActionTypes.NoArgsAction, - onExecute: () => { - this.shrinkVolume(uiSession, Direction.Down); - }, - }); - this.tool.registerKeyBinding(keyShrinkDownAction, Controls.Down, InputModifier.Control); - const keyShrinkForwardAction = uiSession.actionManager.createAction({ - actionType: ActionTypes.NoArgsAction, - onExecute: () => { - this.shrinkVolume(uiSession, Direction.Forward); - }, - }); - this.tool.registerKeyBinding(keyShrinkForwardAction, Controls.Forward, InputModifier.Control); - const keyShrinkBackAction = uiSession.actionManager.createAction({ - actionType: ActionTypes.NoArgsAction, - onExecute: () => { - this.shrinkVolume(uiSession, Direction.Back); - }, - }); - this.tool.registerKeyBinding(keyShrinkBackAction, Controls.Back, InputModifier.Control); - const keyShrinkLeftAction = uiSession.actionManager.createAction({ - actionType: ActionTypes.NoArgsAction, - onExecute: () => { - this.shrinkVolume(uiSession, Direction.Left); - }, - }); - this.tool.registerKeyBinding(keyShrinkLeftAction, Controls.Left, InputModifier.Control); - const keyShrinkRightAction = uiSession.actionManager.createAction({ - actionType: ActionTypes.NoArgsAction, - onExecute: () => { - this.shrinkVolume(uiSession, Direction.Right); - }, - }); - this.tool.registerKeyBinding(keyShrinkRightAction, Controls.Right, InputModifier.Control); - }; - this.onTickRefresh = (uiSession, tool) => { - let ticks = 0; - this.tickRefreshHandle = system.run(() => { - if (uiSession.extensionContext.selectionManager === undefined) { - return; - } - if (!this.settingsObject) { - console.error('Pane settings object not defined, unable to refresh values for selection.'); - return; - } - if (ticks++ % TicksRefreshRate === 0) { - ticks = 0; - let x = 0, y = 0, z = 0; - let sx = 0, sy = 0, sz = 0; - const selection = uiSession.extensionContext.selectionManager.selection; - const lastVolumeItem = selection.peekLastVolume(); - if (lastVolumeItem) { - const lastVolume = lastVolumeItem.volume; - const bounds = BlockVolumeUtils.getBoundingBox(lastVolume); - const boundSize = BoundingBoxUtils.getSpan(bounds); - x = bounds.min.x; - y = bounds.min.y; - z = bounds.min.z; - sx = boundSize.x; - sy = boundSize.y; - sz = boundSize.z; - if (!this.originPropertyItem?.enable) { - if (this.originPropertyItem) { - this.originPropertyItem.enable = true; - } - } - if (!this.sizePropertyItem?.enable) { - if (this.sizePropertyItem) { - this.sizePropertyItem.enable = true; - } - } - } - else { - if (this.originPropertyItem?.enable) { - if (this.originPropertyItem) { - this.originPropertyItem.enable = false; - } - } - if (this.sizePropertyItem?.enable) { - if (this.sizePropertyItem) { - this.sizePropertyItem.enable = false; - } - } - } - if (this.settingsObject.origin.x !== x || this.settingsObject.origin.y !== y || this.settingsObject.origin.z !== z || this.settingsObject.size.x !== sx || this.settingsObject.size.y !== sy || this.settingsObject.size.z !== sz) { - this.settingsObject.origin.x = Math.trunc(x); - this.settingsObject.origin.y = Math.trunc(y); - this.settingsObject.origin.z = Math.trunc(z); - this.settingsObject.size.x = Math.trunc(sx); - this.settingsObject.size.y = Math.trunc(sy); - this.settingsObject.size.z = Math.trunc(sz); - } - } - if (uiSession.toolRail.selectedOptionId === tool.id) { - this.tickRefreshHandle = system.run(() => this.onTickRefresh(uiSession, tool)); - } - }); - }; - // Add a settings pane for the modal Tool - this.addSettingsPane = (uiSession) => { - this.pane.addDropdown(this.settingsObject, 'selectionMode', { - titleStringId: getLocalizationId('selectionTool.selectionMode'), - titleAltText: 'Mode', - enable: true, - dropdownItems: [ - { - displayAltText: 'Freeform', - displayStringId: getLocalizationId('selectionTool.selectionMode.mouseAndKeyboard'), - value: SelectionCursorMode.Freeform, - }, - { - displayAltText: 'Fixed Distance', - displayStringId: getLocalizationId('selectionTool.selectionMode.fixedDistance'), - value: SelectionCursorMode.FixedDistance, - }, - { - displayAltText: 'Adjacent Face', - displayStringId: getLocalizationId('selectionTool.selectionMode.adjacent'), - value: SelectionCursorMode.AdjacentFace, - }, - ], - onChange: (_obj, _property, _oldValue, _newValue) => { - let cursorControlMode = CursorControlMode.KeyboardAndMouse; - let cursorTargetMode = CursorTargetMode.Block; - if (_oldValue !== _newValue) { - switch (_newValue) { - case SelectionCursorMode.Freeform: - cursorControlMode = CursorControlMode.KeyboardAndMouse; - cursorTargetMode = CursorTargetMode.Block; - break; - case SelectionCursorMode.FixedDistance: - cursorControlMode = CursorControlMode.Fixed; - cursorTargetMode = CursorTargetMode.Block; - break; - case SelectionCursorMode.AdjacentFace: - cursorControlMode = CursorControlMode.KeyboardAndMouse; - cursorTargetMode = CursorTargetMode.Face; - break; - default: - console.error(`Unknown value from selection mode drop-down`); - return; - } - this.toolCursorProperties = uiSession.extensionContext.cursor.getProperties(); - this.toolCursorProperties.controlMode = cursorControlMode; - this.toolCursorProperties.targetMode = cursorTargetMode; - uiSession.extensionContext.cursor.setProperties(this.toolCursorProperties); - } - }, - }); - const onOriginOrSizeChange = (_obj, _property, _oldValue, _newValue) => { - if (_oldValue === _newValue) { - return; - } - const selection = uiSession.extensionContext.selectionManager.selection; - if (!selection.isEmpty) { - const lastVolume = selection.peekLastVolume; - if (lastVolume) { - const min = { - x: this.settingsObject.origin.x, - y: this.settingsObject.origin.y, - z: this.settingsObject.origin.z, - }; - const max = { - x: this.settingsObject.origin.x + this.settingsObject.size.x - 1, - y: this.settingsObject.origin.y + this.settingsObject.size.y - 1, - z: this.settingsObject.origin.z + this.settingsObject.size.z - 1, - }; - const newVolume = { - from: min, - to: max - }; - selection.popVolume(); - selection.pushVolume({ - action: CompoundBlockVolumeAction.Add, - volume: newVolume - }); - } - } - }; - const subPaneTransform = this.pane.createPropertyPane({ - titleStringId: getLocalizationId('selectionTool.transformPane.title'), - titleAltText: 'Transform', - }); - this.originPropertyItem = subPaneTransform.addVector3(this.settingsObject, 'origin', { - titleStringId: getLocalizationId('selectionTool.transformPane.origin'), - titleAltText: 'Origin', - enable: true, - minX: -0x80000000, - minY: -0x80000000, - minZ: -0x80000000, - onChange: onOriginOrSizeChange, - }); - this.sizePropertyItem = subPaneTransform.addVector3(this.settingsObject, 'size', { - titleStringId: getLocalizationId('selectionTool.transformPane.size'), - titleAltText: 'Size', - enable: true, - minX: 1, - minY: 1, - minZ: 1, - maxX: 100, - maxY: 100, - maxZ: 100, - onChange: onOriginOrSizeChange, - }); - // Fill - const subPaneFill = this.pane.createPropertyPane({ - titleStringId: getLocalizationId('selectionTool.fillPane.title'), - titleAltText: 'Fill Selection', - }); - const blockPickers = []; - subPaneFill.addNumber(bindDataSource(subPaneFill, { - size: 1, - }), 'size', { - titleStringId: getLocalizationId('toolRail.cubeBrushSettings.size'), - titleAltText: 'Brush Size', - min: 1, - max: 16, - showSlider: true, - onChange: (_obj, _property, _oldValue, _newValue) => { - function adjustBlockPickers() { - if (blockPickers.length < _newValue) { - blockPickers.push(subPaneFill.addBlockPicker(this.settingsObject, 'block', { - titleAltText: 'Block Type', - allowedBlocks - })); - } - else if (blockPickers.length > _newValue) { - const lastBlockPicker = blockPickers[blockPickers.length - 1]; - lastBlockPicker.visible = false; - lastBlockPicker.enable = false; - lastBlockPicker.dispose(); - blockPickers.pop(); - } - if (blockPickers.length === _newValue) { - system.clearRun(id); - } - } - const id = system.runInterval(adjustBlockPickers); - }, - }); - subPaneFill.addButton(this.executeFillAction, { - titleStringId: getLocalizationId('selectionTool.fillPane.fillAction'), - titleAltText: 'Fill Selection', - }); - this.pane.addDivider(); - // CTRL+D - const actionClearSelection = uiSession.actionManager.createAction({ - actionType: ActionTypes.NoArgsAction, - onExecute: () => { - uiSession.extensionContext.selectionManager.selection.clear(); - }, - }); - this.pane.addButton(actionClearSelection, { - titleStringId: getLocalizationId('selectionTool.deselect'), - titleAltText: 'Deselect', - variant: 'secondary', - }); - this.tool.bindPropertyPane(this.pane); - }; - // Add a modal tool to the tool rail and set up an activation subscription to set/unset the cursor states - this.addTool = (uiSession) => { - const tool = uiSession.toolRail.addTool({ - displayAltText: 'Random Fill (CTRL + S)', - icon: 'pack://textures/editor/Select-Fill.png?filtering=point', - tooltipStringId: 'Random Fill Tool', - }); - tool.onModalToolActivation.subscribe((eventData) => { - if (eventData.isActiveTool) { - uiSession.extensionContext.cursor.setProperties(this.toolCursorProperties); - // Start refreshing the position - this.onTickRefresh(uiSession, tool); - } - }); - return tool; - }; - // Bind the tool activation to a keypress on a global level - this.bindGlobalActivationShortcut = (uiSession, storage) => { - const toggleAction = uiSession.actionManager.createAction({ - actionType: ActionTypes.NoArgsAction, - onExecute: () => { - uiSession.toolRail.setSelectedOptionId(this.tool.id, true); - }, - }); - const deselectAction = uiSession.actionManager.createAction({ - actionType: ActionTypes.NoArgsAction, - onExecute: () => { - uiSession.extensionContext.selectionManager.selection.clear(); - }, - }); - uiSession.inputManager.registerKeyBinding(EditorInputContext.GlobalEditor, toggleAction, KeyboardKey.KEY_S, InputModifier.Control); - uiSession.inputManager.registerKeyBinding(EditorInputContext.GlobalToolMode, this.executeFillAction, KeyboardKey.KEY_F, InputModifier.Control); - uiSession.inputManager.registerKeyBinding(EditorInputContext.GlobalEditor, deselectAction, KeyboardKey.KEY_D, InputModifier.Control); - storage.coreMenuItems?.edit.addItem({ name: 'menuBar.edit.quickFill', displayStringId: getLocalizationId('menuBar.edit.quickFill') }, this.executeFillAction); - storage.coreMenuItems?.edit.addItem({ name: 'menuBar.edit.deselect', displayStringId: getLocalizationId('menuBar.edit.deselect') }, deselectAction); - }; - this.performFillOperation = async (context, fillType) => { - const player = context.player; - const dimension = player.dimension; - if (context.selectionManager.selection.isEmpty) { - // Need a better way to surface errors and warnings to the user - this only prints to the - // chat window, so if it's not open - you don't see it - player.sendMessage('No selection available to fill'); - return; - } - context.transactionManager.openTransaction("Select-Fill"); - const bounds = context.selectionManager.selection.getBoundingBox(); - context.transactionManager.trackBlockChangeArea(bounds.min, bounds.max); - await executeLargeOperation(context.selectionManager.selection, (blockLocation => { - const block = dimension.getBlock(blockLocation); - if (block) { - block.isWaterlogged = false; - block.setType(fillType); - } - })).catch((e => { - console.error(e); - context.transactionManager.discardOpenTransaction(); - })).then((() => { - context.transactionManager.commitOpenTransaction(); - })); - }; - const storage = uiSession.scratchStorage; - if (!storage) { - throw new Error('Can not instantiate Selection functionality without valid CoreEditor storage.'); - } - // Add the tool to the tool rail - this.tool = this.addTool(uiSession); - // Create pane. - this.pane = uiSession.createPropertyPane({ - titleAltText: 'Random Fill', - titleStringId: getLocalizationId('selectionTool.title'), - }); - /** - * Allowed blocks for the block picker - */ - const allowedBlocks = BlockTypes.getAll().map(blockType => blockType.id.replace('minecraft:', '')); - // Here is the binding created. - this.settingsObject = bindDataSource(this.pane, { - selectionMode: SelectionCursorMode.Freeform, - origin: { x: 0, y: 0, z: 0 }, - size: { x: 0, y: 0, z: 0 }, - block: "minecraft:bedrock", - }); - // This is the initial cursor state for Selection - this.toolCursorProperties = uiSession.extensionContext.cursor.getProperties(); - this.toolCursorProperties.outlineColor = { red: 1, green: 1, blue: 0, alpha: 1 }; // Yellow - this.toolCursorProperties.controlMode = CursorControlMode.KeyboardAndMouse; - this.toolCursorProperties.targetMode = CursorTargetMode.Block; - this.toolCursorProperties.visible = true; - this.lastAnchorPosition = { x: 0, y: 0, z: 0 }; - this.executeFillAction = uiSession.actionManager.createAction({ - actionType: ActionTypes.NoArgsAction, - onExecute: () => { - this.performFillOperation(uiSession.extensionContext, this.settingsObject.block).catch(e => console.error(e)); - }, - }); - // Add a settings pane for options - this.addSettingsPane(uiSession); - // bind mouse actions - this.bindToolInput(uiSession); - // We want global activation, so bind it into a keypress - this.bindGlobalActivationShortcut(uiSession, storage); - uiSession.toolRail.setSelectedOptionId(this.tool.id, true); - } - teardown() { - // Shutdown - console.log('Shutting down minecraft::selection behavior\n'); - if (this.tickRefreshHandle !== undefined) { - system.clearRun(this.tickRefreshHandle); - this.tickRefreshHandle = undefined; - } - this.fnUnregisterToolBindings(); - // If we're doing a /reload - clear the selection - this.uiSession.extensionContext.selectionManager.selection.clear(); - } -} -registerEditorExtension('randomFill', (uiSession) => { - uiSession.scratchStorage = {}; - // Initialize tool rail. - uiSession.toolRail.show(); - // Add selection functionality - return [ - new SelectionBehavior(uiSession) - ]; -}, (uiSession) => { - uiSession.log.info('Shutting down minecraft::selection behavior'); - // Shutdown - uiSession.scratchStorage = undefined; -}, { - description: 'Randomly fills blocks in the selection', -}); diff --git a/editorExtensions/editor-random-fill/index.ts b/editorExtensions/editor-random-fill/index.ts deleted file mode 100644 index 7aedbc5b..00000000 --- a/editorExtensions/editor-random-fill/index.ts +++ /dev/null @@ -1,934 +0,0 @@ -// Script example for ScriptAPI -// Author: Jayly -// Project: https://github.com/JaylyDev/ScriptAPI -import { - system, - BlockType, - Vector3, - CompoundBlockVolumeAction, - BlockVolume, - BoundingBoxUtils, - BlockTypes -} from "@minecraft/server"; -import { - KeyboardKey, - IPlayerUISession, - Ray, - IModalTool, - ActionTypes, - MouseActionType, - MouseInputType, - CursorControlMode, - InputModifier, - getLocalizationId, - CursorTargetMode, - EditorInputContext, - executeLargeOperation, - bindDataSource, - registerEditorExtension, - IPropertyPane, - IPropertyItem, - ExtensionContext, - CursorProperties, - PropertyBag, - RegisteredAction, - NoArgsAction -} from "@minecraft/server-editor"; -import { - getRotationCorrectedDirectionVector, - Direction, -} from "editor-utilities/index"; -import { - getRelativeXYAxisAsNormal, - growVolumeAlongViewAxis, - intersectRayPlane, - shrinkVolumeAlongViewAxis, -} from "./functions"; -import { VECTOR3_BACK, VECTOR3_DOWN, VECTOR3_FORWARD, VECTOR3_UP, Vector3Utils } from "@minecraft/math"; - -// ------------------------------------------------------------------------------------------------ -// General collection of selection related variables for this instance -// ------------------------------------------------------------------------------------------------ -enum SelectionCursorMode { - Freeform = 0, - FixedDistance = 1, - AdjacentFace = 2 -}; - -const Controls = { - Up: KeyboardKey.PAGE_UP, - Down: KeyboardKey.PAGE_DOWN, - Forward: KeyboardKey.UP, - Back: KeyboardKey.DOWN, - Left: KeyboardKey.LEFT, - Right: KeyboardKey.RIGHT, - Select: KeyboardKey.ENTER, - Clear: KeyboardKey.KEY_D, -}; - -interface SettingsObject extends PropertyBag { - origin: Vector3; - size: Vector3; - block: BlockType | string; - selectionMode: SelectionCursorMode; -} - -const TicksRefreshRate = 5; -// ------------------------------------------------------------------------------------------------ -export class SelectionBehavior { - tool: IModalTool; - uiSession: IPlayerUISession; - fnUnregisterToolBindings: () => void; - singleClick: (uiSession: IPlayerUISession, mouseRay: Ray, shiftPressed: boolean, ctrlPressed: boolean, altPressed: boolean) => void; - lastAnchorPosition: Vector3; - moveTopSelection: (uiSession: IPlayerUISession, lastAnchor: Vector3, direction: Direction) => Vector3; - moveBlockCursorManually: (uiSession: IPlayerUISession, direction: Direction) => void; - moveAllSelections: (uiSession: IPlayerUISession, anchorPosition: Vector3, direction: Direction) => Vector3; - shrinkVolume: (uiSession: IPlayerUISession, direction: Direction) => void; - growVolume: (uiSession: IPlayerUISession, direction: Direction) => void; - bindToolInput: (uiSession: IPlayerUISession) => void; - toolCursorProperties: CursorProperties; - onTickRefresh: (uiSession: IPlayerUISession, tool: IModalTool) => void; - tickRefreshHandle: number; - settingsObject: SettingsObject; - originPropertyItem: IPropertyItem; - sizePropertyItem: IPropertyItem; - addSettingsPane: (uiSession: IPlayerUISession) => void; - pane: IPropertyPane; - addTool: (uiSession: IPlayerUISession) => IModalTool; - bindGlobalActivationShortcut: (uiSession: IPlayerUISession, storage: Record) => void; - performFillOperation: (context: ExtensionContext, fillType: BlockType | string) => Promise; - executeFillAction: RegisteredAction; - get toolId() { - return this.tool.id; - } - constructor(uiSession: IPlayerUISession) { - this.uiSession = uiSession; - this.fnUnregisterToolBindings = () => { - this.tool.unregisterInputBindings(); - }; - this.singleClick = (uiSession: IPlayerUISession, mouseRay: Ray, shiftPressed: boolean, ctrlPressed: boolean, altPressed: boolean) => { - const clickLoc = mouseRay.cursorBlockLocation; - // Nothing pressed, then clear the stack and create a single 1x1x1 - if (!shiftPressed && !ctrlPressed && !altPressed) { - uiSession.extensionContext.selectionManager.selection.clear(); - uiSession.extensionContext.selectionManager.selection.pushVolume({ - action: CompoundBlockVolumeAction.Add, - volume: new BlockVolume(clickLoc, clickLoc) - }); - // Store this as the anchor point - this.lastAnchorPosition = clickLoc; - } - // Shift pressed, an no volume exists - create a single 1x1x1 - // if a volume does exist - use it to anchor the min corner and make a volume - // from anchor to new click - else if (shiftPressed && !ctrlPressed && !altPressed) { - if (uiSession.extensionContext.selectionManager.selection.isEmpty) { - // Create a new 1x1x1 selection volume at the click position - uiSession.extensionContext.selectionManager.selection.pushVolume({ - action: CompoundBlockVolumeAction.Add, - volume: new BlockVolume(clickLoc, clickLoc) - }); - // Store this as the anchor point - this.lastAnchorPosition = clickLoc; - } - else { - // Use the last anchor point (i.e. the first click selection) as the - // corner for the new click, and defining a new volume area - const lastAnchorPosition = this.lastAnchorPosition; - uiSession.extensionContext.selectionManager.selection.popVolume(); - const newVolume = new BlockVolume(lastAnchorPosition, clickLoc); - uiSession.extensionContext.selectionManager.selection.pushVolume({ - action: CompoundBlockVolumeAction.Add, - volume: newVolume - }); - } - } - // Control pressed and no volume exists - create a single 1x1x1 - // If a volume exists, just push a new 1x1x1 to the stack - else if (ctrlPressed && !shiftPressed && !altPressed) { - uiSession.extensionContext.selectionManager.selection.pushVolume({ - action: CompoundBlockVolumeAction.Add, - volume: new BlockVolume(clickLoc, clickLoc) - }); - // Store this as the anchor point - this.lastAnchorPosition = clickLoc; - } - // If ALT is pressed, and there IS already a full volume, then we're going into 3-click volume - // mode and we need to do some intersection calculations - else if (altPressed && !shiftPressed && !ctrlPressed) { - const currentItem = uiSession.extensionContext.selectionManager.selection.peekLastVolume(); - if (!currentItem) { - uiSession.extensionContext.selectionManager.selection.pushVolume({ - action: CompoundBlockVolumeAction.Add, - volume: new BlockVolume(clickLoc, clickLoc) - }); - this.lastAnchorPosition = clickLoc; - } else { - const currentVolume = currentItem.volume; - const currentBounds = currentVolume.getBoundingBox(); - const translatedRayLocation = Vector3Utils.subtract(mouseRay.location, currentBounds.min); - const XYPlaneNormal = getRelativeXYAxisAsNormal(uiSession.extensionContext.player.getRotation().y); - const intersection = intersectRayPlane(translatedRayLocation, mouseRay.direction, XYPlaneNormal, 0); - if (intersection) { - const translatedIntersection = Vector3Utils.add(intersection, currentBounds.min); - const newY = Math.ceil(translatedIntersection.y) - 1; - uiSession.extensionContext.selectionManager.selection.popVolume(); - uiSession.extensionContext.selectionManager.selection.pushVolume({ - action: currentItem.action, - volume: new BlockVolume(currentBounds.min, { - x: currentBounds.max.x, - y: newY, - z: currentBounds.max.z - }) - }); - } - } - } - }; - this.moveTopSelection = (uiSession: IPlayerUISession, lastAnchor: Vector3, direction: Direction): Vector3 => { - const lastVolumeItem = uiSession.extensionContext.selectionManager.selection.peekLastVolume(); - if (!lastVolumeItem) { - return undefined; - } - const lastVolume = lastVolumeItem.volume; - uiSession.extensionContext.selectionManager.selection.popVolume(); - const rotationY = uiSession.extensionContext.player.getRotation().y; - const correctedVector = getRotationCorrectedDirectionVector(rotationY, direction); - lastVolume.translate({ - x: correctedVector.x, - y: correctedVector.y, - z: correctedVector.z - }); - uiSession.extensionContext.selectionManager.selection.pushVolume({ - action: CompoundBlockVolumeAction.Add, - volume: lastVolume - }); - // Update the last cursor click position with the move vector - // so that extend-click operations work correctly with the new corner position - const updatedClick = { - x: lastAnchor.x + correctedVector.x, - y: lastAnchor.y + correctedVector.y, - z: lastAnchor.z + correctedVector.z, - }; - return updatedClick; - }; - this.moveBlockCursorManually = (uiSession: IPlayerUISession, direction: Direction) => { - const rotationY = uiSession.extensionContext.player.getRotation().y; - const rotationCorrectedVector = getRotationCorrectedDirectionVector(rotationY, direction); - uiSession.extensionContext.cursor.moveBy(rotationCorrectedVector); - }; - this.moveAllSelections = (uiSession: IPlayerUISession, anchorPosition: Vector3, direction: Direction): Vector3 => { - if (uiSession.extensionContext.selectionManager.selection.isEmpty) { - return undefined; - } - const rotationY = uiSession.extensionContext.player.getRotation().y; - const correctedVector = getRotationCorrectedDirectionVector(rotationY, direction); - uiSession.extensionContext.selectionManager.selection.moveBy({ - x: correctedVector.x, - y: correctedVector.y, - z: correctedVector.z, - }); - const updatedClick = { - x: anchorPosition.x + correctedVector.x, - y: anchorPosition.y + correctedVector.y, - z: anchorPosition.z + correctedVector.z, - }; - return updatedClick; - }; - this.shrinkVolume = (uiSession: IPlayerUISession, direction: Direction) => { - if (uiSession.extensionContext.selectionManager.selection.isEmpty) { - return; - } - const lastVolume = uiSession.extensionContext.selectionManager.selection.peekLastVolume; - uiSession.extensionContext.selectionManager.selection.popVolume(); - const rotationY = uiSession.extensionContext.player.getRotation().y; - const newVolume = shrinkVolumeAlongViewAxis(lastVolume, rotationY, direction, 1); - uiSession.extensionContext.selectionManager.selection.pushVolume({ - action: CompoundBlockVolumeAction.Add, - volume: newVolume - }); - }; - this.growVolume = (uiSession: IPlayerUISession, direction: Direction) => { - const lastVolumeItem = uiSession.extensionContext.selectionManager.selection.peekLastVolume(); - if (!lastVolumeItem) { - return; - } - const lastVolume = lastVolumeItem.volume; - uiSession.extensionContext.selectionManager.selection.popVolume(); - const rotationY = uiSession.extensionContext.player.getRotation().y; - const newVolume = growVolumeAlongViewAxis(lastVolume, rotationY, direction, 1); - uiSession.extensionContext.selectionManager.selection.pushVolume({ - action: lastVolumeItem.action, - volume: newVolume - }); - }; - // Input and tool binding functions - // ------------------------------------------------------------------------------------------------ - this.bindToolInput = (uiSession: IPlayerUISession) => { - // Bind Single Mouse Click - const singleClickAction = uiSession.actionManager.createAction({ - actionType: ActionTypes.MouseRayCastAction, - onExecute: (mouseRay, mouseProps) => { - if (mouseProps.mouseAction === MouseActionType.LeftButton) { - if (mouseProps.inputType === MouseInputType.ButtonDown) { - if (mouseRay.rayHit || this.toolCursorProperties.controlMode === CursorControlMode.Fixed) { - this.singleClick(uiSession, mouseRay, mouseProps.modifiers.shift, mouseProps.modifiers.ctrl, mouseProps.modifiers.alt); - } - else { - // If we're clicking on nothing or something too far away - clear the selection stack - uiSession.extensionContext.selectionManager.selection.clear(); - } - } - } - }, - }); - this.tool.registerMouseButtonBinding(singleClickAction); - // Bind Keyboard MOVE functions - const keyUpAction = uiSession.actionManager.createAction({ - actionType: ActionTypes.NoArgsAction, - onExecute: () => { - uiSession.extensionContext.cursor.moveBy(VECTOR3_UP); - }, - }); - const keyDownAction = uiSession.actionManager.createAction({ - actionType: ActionTypes.NoArgsAction, - onExecute: () => { - uiSession.extensionContext.cursor.moveBy(VECTOR3_DOWN); - }, - }); - const keyLeftAction = uiSession.actionManager.createAction({ - actionType: ActionTypes.NoArgsAction, - onExecute: () => { - this.moveBlockCursorManually(uiSession, Direction.Left); - }, - }); - const keyRightAction = uiSession.actionManager.createAction({ - actionType: ActionTypes.NoArgsAction, - onExecute: () => { - this.moveBlockCursorManually(uiSession, Direction.Right); - }, - }); - const keyForwardAction = uiSession.actionManager.createAction({ - actionType: ActionTypes.NoArgsAction, - onExecute: () => { - this.moveBlockCursorManually(uiSession, Direction.Forward); - }, - }); - const keyBackAction = uiSession.actionManager.createAction({ - actionType: ActionTypes.NoArgsAction, - onExecute: () => { - this.moveBlockCursorManually(uiSession, Direction.Back); - }, - }); - // Bind arrow keys to manual cursor control - this.tool.registerKeyBinding(keyForwardAction, Controls.Forward, InputModifier.None); - this.tool.registerKeyBinding(keyBackAction, Controls.Back, InputModifier.None); - this.tool.registerKeyBinding(keyLeftAction, Controls.Left, InputModifier.None); - this.tool.registerKeyBinding(keyRightAction, Controls.Right, InputModifier.None); - this.tool.registerKeyBinding(keyUpAction, Controls.Up, InputModifier.None); - this.tool.registerKeyBinding(keyDownAction, Controls.Down, InputModifier.None); - const mouseWheelAction = uiSession.actionManager.createAction({ - actionType: ActionTypes.MouseRayCastAction, - onExecute: (mouseRay, mouseProps) => { - if (mouseProps.inputType === MouseInputType.WheelOut) { - if (mouseProps.modifiers.shift) { - this.growVolume(uiSession, Direction.Left); - this.growVolume(uiSession, Direction.Right); - } - else if (mouseProps.modifiers.ctrl) { - this.growVolume(uiSession, Direction.Forward); - this.growVolume(uiSession, Direction.Back); - } - else if (mouseProps.modifiers.alt) { - this.growVolume(uiSession, Direction.Up); - this.growVolume(uiSession, Direction.Down); - } - else if (this.toolCursorProperties.controlMode === CursorControlMode.Fixed) { - uiSession.extensionContext.cursor.moveBy(VECTOR3_FORWARD); - } - } - else if (mouseProps.inputType === MouseInputType.WheelIn) { - if (mouseProps.modifiers.shift) { - this.shrinkVolume(uiSession, Direction.Left); - this.shrinkVolume(uiSession, Direction.Right); - } - else if (mouseProps.modifiers.ctrl) { - this.shrinkVolume(uiSession, Direction.Forward); - this.shrinkVolume(uiSession, Direction.Back); - } - else if (mouseProps.modifiers.alt) { - this.shrinkVolume(uiSession, Direction.Up); - this.shrinkVolume(uiSession, Direction.Down); - } - else if (this.toolCursorProperties.controlMode === CursorControlMode.Fixed) { - uiSession.extensionContext.cursor.moveBy(VECTOR3_BACK); - } - } - }, - }); - this.tool.registerMouseWheelBinding(mouseWheelAction); - // Bind ARROWS+ALT for MOVE selection volume (single) - // ----------------------------------------- - const moveSelectionUpAction = uiSession.actionManager.createAction({ - actionType: ActionTypes.NoArgsAction, - onExecute: () => { - const updatedAnchor = this.moveTopSelection(uiSession, this.lastAnchorPosition, Direction.Up); - if (updatedAnchor) { - this.lastAnchorPosition = updatedAnchor; - } - }, - }); - const moveSelectionDownAction = uiSession.actionManager.createAction({ - actionType: ActionTypes.NoArgsAction, - onExecute: () => { - const updatedAnchor = this.moveTopSelection(uiSession, this.lastAnchorPosition, Direction.Down); - if (updatedAnchor) { - this.lastAnchorPosition = updatedAnchor; - } - }, - }); - const moveSelectionLeftAction = uiSession.actionManager.createAction({ - actionType: ActionTypes.NoArgsAction, - onExecute: () => { - const updatedAnchor = this.moveTopSelection(uiSession, this.lastAnchorPosition, Direction.Left); - if (updatedAnchor) { - this.lastAnchorPosition = updatedAnchor; - } - }, - }); - const moveSelectionRightAction = uiSession.actionManager.createAction({ - actionType: ActionTypes.NoArgsAction, - onExecute: () => { - const updatedAnchor = this.moveTopSelection(uiSession, this.lastAnchorPosition, Direction.Right); - if (updatedAnchor) { - this.lastAnchorPosition = updatedAnchor; - } - }, - }); - const moveSelectionForwardAction = uiSession.actionManager.createAction({ - actionType: ActionTypes.NoArgsAction, - onExecute: () => { - const updatedAnchor = this.moveTopSelection(uiSession, this.lastAnchorPosition, Direction.Forward); - if (updatedAnchor) { - this.lastAnchorPosition = updatedAnchor; - } - }, - }); - const moveSelectionBackAction = uiSession.actionManager.createAction({ - actionType: ActionTypes.NoArgsAction, - onExecute: () => { - const updatedAnchor = this.moveTopSelection(uiSession, this.lastAnchorPosition, Direction.Back); - if (updatedAnchor) { - this.lastAnchorPosition = updatedAnchor; - } - }, - }); - // Bind arrow keys to manual cursor control - this.tool.registerKeyBinding(moveSelectionForwardAction, Controls.Forward, InputModifier.Alt); - this.tool.registerKeyBinding(moveSelectionBackAction, Controls.Back, InputModifier.Alt); - this.tool.registerKeyBinding(moveSelectionLeftAction, Controls.Left, InputModifier.Alt); - this.tool.registerKeyBinding(moveSelectionRightAction, Controls.Right, InputModifier.Alt); - this.tool.registerKeyBinding(moveSelectionUpAction, Controls.Up, InputModifier.Alt); - this.tool.registerKeyBinding(moveSelectionDownAction, Controls.Down, InputModifier.Alt); - // Bind ARROWS+ALT+CTRL to move ALL selections - const moveAllSelectionUpAction = uiSession.actionManager.createAction({ - actionType: ActionTypes.NoArgsAction, - onExecute: () => { - const updatedAnchor = this.moveAllSelections(uiSession, this.lastAnchorPosition, Direction.Up); - if (updatedAnchor) { - this.lastAnchorPosition = updatedAnchor; - } - }, - }); - const moveAllSelectionDownAction = uiSession.actionManager.createAction({ - actionType: ActionTypes.NoArgsAction, - onExecute: () => { - const updatedAnchor = this.moveAllSelections(uiSession, this.lastAnchorPosition, Direction.Down); - if (updatedAnchor) { - this.lastAnchorPosition = updatedAnchor; - } - }, - }); - const moveAllSelectionLeftAction = uiSession.actionManager.createAction({ - actionType: ActionTypes.NoArgsAction, - onExecute: () => { - const updatedAnchor = this.moveAllSelections(uiSession, this.lastAnchorPosition, Direction.Left); - if (updatedAnchor) { - this.lastAnchorPosition = updatedAnchor; - } - }, - }); - const moveAllSelectionRightAction = uiSession.actionManager.createAction({ - actionType: ActionTypes.NoArgsAction, - onExecute: () => { - const updatedAnchor = this.moveAllSelections(uiSession, this.lastAnchorPosition, Direction.Right); - if (updatedAnchor) { - this.lastAnchorPosition = updatedAnchor; - } - }, - }); - const moveAllSelectionForwardAction = uiSession.actionManager.createAction({ - actionType: ActionTypes.NoArgsAction, - onExecute: () => { - const updatedAnchor = this.moveAllSelections(uiSession, this.lastAnchorPosition, Direction.Forward); - if (updatedAnchor) { - this.lastAnchorPosition = updatedAnchor; - } - }, - }); - const moveAllSelectionBackAction = uiSession.actionManager.createAction({ - actionType: ActionTypes.NoArgsAction, - onExecute: () => { - const updatedAnchor = this.moveAllSelections(uiSession, this.lastAnchorPosition, Direction.Back); - if (updatedAnchor) { - this.lastAnchorPosition = updatedAnchor; - } - }, - }); - this.tool.registerKeyBinding(moveAllSelectionForwardAction, Controls.Forward, InputModifier.Alt | InputModifier.Control); - this.tool.registerKeyBinding(moveAllSelectionBackAction, Controls.Back, InputModifier.Alt | InputModifier.Control); - this.tool.registerKeyBinding(moveAllSelectionLeftAction, Controls.Left, InputModifier.Alt | InputModifier.Control); - this.tool.registerKeyBinding(moveAllSelectionRightAction, Controls.Right, InputModifier.Alt | InputModifier.Control); - this.tool.registerKeyBinding(moveAllSelectionUpAction, Controls.Up, InputModifier.Alt | InputModifier.Control); - this.tool.registerKeyBinding(moveAllSelectionDownAction, Controls.Down, InputModifier.Alt | InputModifier.Control); - // Bind ARROW+SHIFT - const keyGrowUpAction = uiSession.actionManager.createAction({ - actionType: ActionTypes.NoArgsAction, - onExecute: () => { - this.growVolume(uiSession, Direction.Up); - }, - }); - this.tool.registerKeyBinding(keyGrowUpAction, Controls.Up, InputModifier.Shift); - const keyGrowDownAction = uiSession.actionManager.createAction({ - actionType: ActionTypes.NoArgsAction, - onExecute: () => { - this.growVolume(uiSession, Direction.Down); - }, - }); - this.tool.registerKeyBinding(keyGrowDownAction, Controls.Down, InputModifier.Shift); - const keyGrowForwardAction = uiSession.actionManager.createAction({ - actionType: ActionTypes.NoArgsAction, - onExecute: () => { - this.growVolume(uiSession, Direction.Forward); - }, - }); - this.tool.registerKeyBinding(keyGrowForwardAction, Controls.Forward, InputModifier.Shift); - const keyGrowBackAction = uiSession.actionManager.createAction({ - actionType: ActionTypes.NoArgsAction, - onExecute: () => { - this.growVolume(uiSession, Direction.Back); - }, - }); - this.tool.registerKeyBinding(keyGrowBackAction, Controls.Back, InputModifier.Shift); - const keyGrowLeftAction = uiSession.actionManager.createAction({ - actionType: ActionTypes.NoArgsAction, - onExecute: () => { - this.growVolume(uiSession, Direction.Left); - }, - }); - this.tool.registerKeyBinding(keyGrowLeftAction, Controls.Left, InputModifier.Shift); - const keyGrowRightAction = uiSession.actionManager.createAction({ - actionType: ActionTypes.NoArgsAction, - onExecute: () => { - this.growVolume(uiSession, Direction.Right); - }, - }); - this.tool.registerKeyBinding(keyGrowRightAction, Controls.Right, InputModifier.Shift); - // Bind ARROW+CTRL - const keyShrinkUpAction = uiSession.actionManager.createAction({ - actionType: ActionTypes.NoArgsAction, - onExecute: () => { - this.shrinkVolume(uiSession, Direction.Up); - }, - }); - this.tool.registerKeyBinding(keyShrinkUpAction, Controls.Up, InputModifier.Control); - const keyShrinkDownAction = uiSession.actionManager.createAction({ - actionType: ActionTypes.NoArgsAction, - onExecute: () => { - this.shrinkVolume(uiSession, Direction.Down); - }, - }); - this.tool.registerKeyBinding(keyShrinkDownAction, Controls.Down, InputModifier.Control); - const keyShrinkForwardAction = uiSession.actionManager.createAction({ - actionType: ActionTypes.NoArgsAction, - onExecute: () => { - this.shrinkVolume(uiSession, Direction.Forward); - }, - }); - this.tool.registerKeyBinding(keyShrinkForwardAction, Controls.Forward, InputModifier.Control); - const keyShrinkBackAction = uiSession.actionManager.createAction({ - actionType: ActionTypes.NoArgsAction, - onExecute: () => { - this.shrinkVolume(uiSession, Direction.Back); - }, - }); - this.tool.registerKeyBinding(keyShrinkBackAction, Controls.Back, InputModifier.Control); - const keyShrinkLeftAction = uiSession.actionManager.createAction({ - actionType: ActionTypes.NoArgsAction, - onExecute: () => { - this.shrinkVolume(uiSession, Direction.Left); - }, - }); - this.tool.registerKeyBinding(keyShrinkLeftAction, Controls.Left, InputModifier.Control); - const keyShrinkRightAction = uiSession.actionManager.createAction({ - actionType: ActionTypes.NoArgsAction, - onExecute: () => { - this.shrinkVolume(uiSession, Direction.Right); - }, - }); - this.tool.registerKeyBinding(keyShrinkRightAction, Controls.Right, InputModifier.Control); - }; - this.onTickRefresh = (uiSession: IPlayerUISession, tool) => { - let ticks = 0; - this.tickRefreshHandle = system.run(() => { - if (uiSession.extensionContext.selectionManager === undefined) { - return; - } - if (!this.settingsObject) { - console.error('Pane settings object not defined, unable to refresh values for selection.'); - return; - } - if (ticks++ % TicksRefreshRate === 0) { - ticks = 0; - let x = 0, y = 0, z = 0; - let sx = 0, sy = 0, sz = 0; - const selection = uiSession.extensionContext.selectionManager.selection; - const lastVolumeItem = selection.peekLastVolume(); - if (lastVolumeItem) { - const lastVolume = lastVolumeItem.volume; - const bounds = lastVolume.getBoundingBox(); - const boundSize = BoundingBoxUtils.getSpan(bounds); - x = bounds.min.x; - y = bounds.min.y; - z = bounds.min.z; - sx = boundSize.x; - sy = boundSize.y; - sz = boundSize.z; - if (!this.originPropertyItem?.enable) { - if (this.originPropertyItem) { - this.originPropertyItem.enable = true; - } - } - if (!this.sizePropertyItem?.enable) { - if (this.sizePropertyItem) { - this.sizePropertyItem.enable = true; - } - } - } else { - if (this.originPropertyItem?.enable) { - if (this.originPropertyItem) { - this.originPropertyItem.enable = false; - } - } - if (this.sizePropertyItem?.enable) { - if (this.sizePropertyItem) { - this.sizePropertyItem.enable = false; - } - } - } - if (this.settingsObject.origin.x !== x || this.settingsObject.origin.y !== y || this.settingsObject.origin.z !== z || this.settingsObject.size.x !== sx || this.settingsObject.size.y !== sy || this.settingsObject.size.z !== sz) { - this.settingsObject.origin.x = Math.trunc(x); - this.settingsObject.origin.y = Math.trunc(y); - this.settingsObject.origin.z = Math.trunc(z); - this.settingsObject.size.x = Math.trunc(sx); - this.settingsObject.size.y = Math.trunc(sy); - this.settingsObject.size.z = Math.trunc(sz); - } - } - if (uiSession.toolRail.selectedOptionId === tool.id) { - this.tickRefreshHandle = system.run(() => this.onTickRefresh(uiSession, tool)); - } - }); - }; - // Add a settings pane for the modal Tool - this.addSettingsPane = (uiSession: IPlayerUISession) => { - this.pane.addDropdown(this.settingsObject, 'selectionMode', { - titleStringId: getLocalizationId('selectionTool.selectionMode'), - titleAltText: 'Mode', - enable: true, - dropdownItems: [ - { - displayAltText: 'Freeform', - displayStringId: getLocalizationId('selectionTool.selectionMode.mouseAndKeyboard'), - value: SelectionCursorMode.Freeform, - }, - { - displayAltText: 'Fixed Distance', - displayStringId: getLocalizationId('selectionTool.selectionMode.fixedDistance'), - value: SelectionCursorMode.FixedDistance, - }, - { - displayAltText: 'Adjacent Face', - displayStringId: getLocalizationId('selectionTool.selectionMode.adjacent'), - value: SelectionCursorMode.AdjacentFace, - }, - ], - onChange: (_obj, _property, _oldValue: any, _newValue: any) => { - let cursorControlMode = CursorControlMode.KeyboardAndMouse; - let cursorTargetMode = CursorTargetMode.Block; - if (_oldValue !== _newValue) { - switch (_newValue) { - case SelectionCursorMode.Freeform: - cursorControlMode = CursorControlMode.KeyboardAndMouse; - cursorTargetMode = CursorTargetMode.Block; - break; - case SelectionCursorMode.FixedDistance: - cursorControlMode = CursorControlMode.Fixed; - cursorTargetMode = CursorTargetMode.Block; - break; - case SelectionCursorMode.AdjacentFace: - cursorControlMode = CursorControlMode.KeyboardAndMouse; - cursorTargetMode = CursorTargetMode.Face; - break; - default: - console.error(`Unknown value from selection mode drop-down`); - return; - } - this.toolCursorProperties = uiSession.extensionContext.cursor.getProperties(); - this.toolCursorProperties.controlMode = cursorControlMode; - this.toolCursorProperties.targetMode = cursorTargetMode; - uiSession.extensionContext.cursor.setProperties(this.toolCursorProperties); - } - }, - }); - const onOriginOrSizeChange = (_obj: any, _property: string, _oldValue: Vector3, _newValue: Vector3) => { - if (_oldValue === _newValue) { - return; - } - const selection = uiSession.extensionContext.selectionManager.selection; - if (!selection.isEmpty) { - const lastVolume = selection.peekLastVolume; - if (lastVolume) { - const min = { - x: this.settingsObject.origin.x, - y: this.settingsObject.origin.y, - z: this.settingsObject.origin.z, - }; - const max = { - x: this.settingsObject.origin.x + this.settingsObject.size.x - 1, - y: this.settingsObject.origin.y + this.settingsObject.size.y - 1, - z: this.settingsObject.origin.z + this.settingsObject.size.z - 1, - }; - const newVolume = new BlockVolume(min, max); - selection.popVolume(); - selection.pushVolume({ - action: CompoundBlockVolumeAction.Add, - volume: newVolume - }); - } - } - }; - const subPaneTransform = this.pane.createPropertyPane({ - titleStringId: getLocalizationId('selectionTool.transformPane.title'), - titleAltText: 'Transform', - }); - this.originPropertyItem = subPaneTransform.addVector3(this.settingsObject, 'origin', { - titleStringId: getLocalizationId('selectionTool.transformPane.origin'), - titleAltText: 'Origin', - enable: true, - minX: -0x80000000, - minY: -0x80000000, - minZ: -0x80000000, - onChange: onOriginOrSizeChange, - }); - this.sizePropertyItem = subPaneTransform.addVector3(this.settingsObject, 'size', { - titleStringId: getLocalizationId('selectionTool.transformPane.size'), - titleAltText: 'Size', - enable: true, - minX: 1, - minY: 1, - minZ: 1, - maxX: 100, - maxY: 100, - maxZ: 100, - onChange: onOriginOrSizeChange, - }); - // Fill - const subPaneFill = this.pane.createPropertyPane({ - titleStringId: getLocalizationId('selectionTool.fillPane.title'), - titleAltText: 'Fill Selection', - }); - const blockPickers: IPropertyItem[] = []; - subPaneFill.addNumber(bindDataSource(subPaneFill, { - size: 1, - }), 'size', { - titleStringId: getLocalizationId('toolRail.cubeBrushSettings.size'), - titleAltText: 'Brush Size', - min: 1, - max: 16, - showSlider: true, - onChange: (_obj, _property, _oldValue: any, _newValue: any) => { - function adjustBlockPickers() { - if (blockPickers.length < _newValue) { - blockPickers.push(subPaneFill.addBlockPicker(this.settingsObject, 'block', { - titleAltText: 'Block Type', - })); - } else if (blockPickers.length > _newValue) { - const lastBlockPicker = blockPickers[blockPickers.length - 1]; - lastBlockPicker.visible = false; - lastBlockPicker.enable = false; - lastBlockPicker.dispose(); - blockPickers.pop(); - } - - if (blockPickers.length === _newValue) { - system.clearRun(id); - } - } - const id = system.runInterval(adjustBlockPickers); - }, - }); - subPaneFill.addButton(this.executeFillAction, { - titleStringId: getLocalizationId('selectionTool.fillPane.fillAction'), - titleAltText: 'Fill Selection', - }); - this.pane.addDivider(); - // CTRL+D - const actionClearSelection = uiSession.actionManager.createAction({ - actionType: ActionTypes.NoArgsAction, - onExecute: () => { - uiSession.extensionContext.selectionManager.selection.clear(); - }, - }); - this.pane.addButton(actionClearSelection, { - titleStringId: getLocalizationId('selectionTool.deselect'), - titleAltText: 'Deselect', - variant: 'secondary', - }); - this.tool.bindPropertyPane(this.pane); - }; - // Add a modal tool to the tool rail and set up an activation subscription to set/unset the cursor states - this.addTool = (uiSession: IPlayerUISession) => { - const tool = uiSession.toolRail.addTool({ - displayAltText: 'Random Fill (CTRL + S)', - icon: 'pack://textures/editor/Select-Fill.png?filtering=point', - tooltipStringId: 'Random Fill Tool', - }); - tool.onModalToolActivation.subscribe((eventData) => { - if (eventData.isActiveTool) { - uiSession.extensionContext.cursor.setProperties(this.toolCursorProperties); - // Start refreshing the position - this.onTickRefresh(uiSession, tool); - } - }); - return tool; - }; - // Bind the tool activation to a keypress on a global level - this.bindGlobalActivationShortcut = (uiSession: IPlayerUISession, storage: Record) => { - const toggleAction = uiSession.actionManager.createAction({ - actionType: ActionTypes.NoArgsAction, - onExecute: () => { - uiSession.toolRail.setSelectedOptionId(this.tool.id, true); - }, - }); - const deselectAction = uiSession.actionManager.createAction({ - actionType: ActionTypes.NoArgsAction, - onExecute: () => { - uiSession.extensionContext.selectionManager.selection.clear(); - }, - }); - uiSession.inputManager.registerKeyBinding(EditorInputContext.GlobalEditor, toggleAction, KeyboardKey.KEY_S, InputModifier.Control); - uiSession.inputManager.registerKeyBinding(EditorInputContext.GlobalToolMode, this.executeFillAction, KeyboardKey.KEY_F, InputModifier.Control); - uiSession.inputManager.registerKeyBinding(EditorInputContext.GlobalEditor, deselectAction, KeyboardKey.KEY_D, InputModifier.Control); - storage.coreMenuItems?.edit.addItem({ name: 'menuBar.edit.quickFill', displayStringId: getLocalizationId('menuBar.edit.quickFill') }, this.executeFillAction); - storage.coreMenuItems?.edit.addItem({ name: 'menuBar.edit.deselect', displayStringId: getLocalizationId('menuBar.edit.deselect') }, deselectAction); - }; - this.performFillOperation = async (context, fillType) => { - const player = context.player; - const dimension = player.dimension; - if (context.selectionManager.selection.isEmpty) { - // Need a better way to surface errors and warnings to the user - this only prints to the - // chat window, so if it's not open - you don't see it - player.sendMessage('No selection available to fill'); - return; - } - context.transactionManager.openTransaction("Select-Fill"); - const bounds = context.selectionManager.selection.getBoundingBox(); - context.transactionManager.trackBlockChangeArea(bounds.min, bounds.max); - await executeLargeOperation(context.selectionManager.selection, (blockLocation => { - const block = dimension.getBlock(blockLocation); - if (block) { - block.setWaterlogged(false); - block.setType(fillType); - } - })).catch((e => { - console.error(e); - context.transactionManager.discardOpenTransaction(); - })).then((() => { - context.transactionManager.commitOpenTransaction(); - })); - - }; - const storage = uiSession.scratchStorage; - if (!storage) { - throw new Error('Can not instantiate Selection functionality without valid CoreEditor storage.'); - } - // Add the tool to the tool rail - this.tool = this.addTool(uiSession); - // Create pane. - this.pane = uiSession.createPropertyPane({ - titleAltText: 'Random Fill', - titleStringId: getLocalizationId('selectionTool.title'), - }); - /** - * Allowed blocks for the block picker - */ - const allowedBlocks = BlockTypes.getAll().map(blockType => blockType.id.replace('minecraft:', '')); - - // Here is the binding created. - this.settingsObject = bindDataSource(this.pane, { - selectionMode: SelectionCursorMode.Freeform, - origin: { x: 0, y: 0, z: 0 }, - size: { x: 0, y: 0, z: 0 }, - block: "minecraft:bedrock", - }); - // This is the initial cursor state for Selection - this.toolCursorProperties = uiSession.extensionContext.cursor.getProperties(); - this.toolCursorProperties.outlineColor = { red: 1, green: 1, blue: 0, alpha: 1 }; // Yellow - this.toolCursorProperties.controlMode = CursorControlMode.KeyboardAndMouse; - this.toolCursorProperties.targetMode = CursorTargetMode.Block; - this.toolCursorProperties.visible = true; - this.lastAnchorPosition = { x: 0, y: 0, z: 0 }; - this.executeFillAction = uiSession.actionManager.createAction({ - actionType: ActionTypes.NoArgsAction, - onExecute: () => { - this.performFillOperation(uiSession.extensionContext, this.settingsObject.block).catch(e => console.error(e)); - }, - }); - // Add a settings pane for options - this.addSettingsPane(uiSession); - // bind mouse actions - this.bindToolInput(uiSession); - // We want global activation, so bind it into a keypress - this.bindGlobalActivationShortcut(uiSession, storage); - uiSession.toolRail.setSelectedOptionId(this.tool.id, true); - } - teardown() { - // Shutdown - console.log('Shutting down minecraft::selection behavior\n'); - if (this.tickRefreshHandle !== undefined) { - system.clearRun(this.tickRefreshHandle); - this.tickRefreshHandle = undefined; - } - this.fnUnregisterToolBindings(); - // If we're doing a /reload - clear the selection - this.uiSession.extensionContext.selectionManager.selection.clear(); - } -} - -registerEditorExtension('randomFill', (uiSession) => { - uiSession.scratchStorage = {}; - // Initialize tool rail. - uiSession.toolRail.show(); - // Add selection functionality - return [ - new SelectionBehavior(uiSession) - ] -}, (uiSession) => { - uiSession.log.info('Shutting down minecraft::selection behavior'); - // Shutdown - uiSession.scratchStorage = undefined; -}, { - description: 'Randomly fills blocks in the selection', -}); diff --git a/editorExtensions/editor-utilities/README.md b/editorExtensions/editor-utilities/README.md deleted file mode 100644 index 7f0d0f34..00000000 --- a/editorExtensions/editor-utilities/README.md +++ /dev/null @@ -1,9 +0,0 @@ -# editor-utilities - -## Description - -Utilities for editor API. - -## Credits - -These scripts were written by [Mojang](https://github.com/Mojang) diff --git a/editorExtensions/editor-utilities/index.d.ts b/editorExtensions/editor-utilities/index.d.ts deleted file mode 100644 index a38527b4..00000000 --- a/editorExtensions/editor-utilities/index.d.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { Vector3 } from "@minecraft/server"; - -/** - * Direction - * @beta - * @remarks - * Direction maps to C++ Direction::FacingID - */ -declare enum Direction { - Forward = 'Forward', - Right = 'Right', - Back = 'Back', - Left = 'Left', - Up = 'Up', - Down = 'Down', -} -/** - * getDirectionVector - * @beta - * @remarks - * Return a unit vector for a given Direction - */ -declare function getDirectionVector(direction: Direction): Vector3 -/** - * getScaledDirectionVector - * @beta - * @remarks - * Return a scaled vector for a given Direction - */ -declare function getScaledDirectionVector(direction: Direction, scale: number): Vector3 -/** - * getRotationCorrectedDirection - * @beta - * @remarks - * Convert a given absolute Direction enum to one which is relative to the specified Y rotation - * (Generally Player view vector Y component) - */ -declare function getRotationCorrectedDirection(rotationY: number, realDirection: Direction): Direction | number -/** - * getRotationCorrectedDirectionVector - * @beta - * @remarks - * Convert a given absolute Direction enum to a direction vector which is relative to the Y rotation - * (Generally Player view vector Y component) - */ -declare function getRotationCorrectedDirectionVector(rotationY: number, realDirection: Direction): Vector3 - -export { - Direction, - getDirectionVector, - getRotationCorrectedDirection, - getRotationCorrectedDirectionVector, - getScaledDirectionVector, -} \ No newline at end of file diff --git a/editorExtensions/editor-utilities/index.js b/editorExtensions/editor-utilities/index.js deleted file mode 100644 index a99547e0..00000000 --- a/editorExtensions/editor-utilities/index.js +++ /dev/null @@ -1,95 +0,0 @@ -// Script example for ScriptAPI -// Author: Mojang's Editor Team -// Project: https://github.com/DarkGamerYT/Bedrock-Editor-Extension -import { VECTOR3_BACK, VECTOR3_DOWN, VECTOR3_FORWARD, VECTOR3_LEFT, VECTOR3_RIGHT, VECTOR3_UP } from '@minecraft/math'; - - -/** - * Direction - * @beta - * @remarks - * Direction maps to C++ Direction::FacingID - */ -var Direction = { - Forward: "Forward", - Right: "Right", - Back: "Back", - Left: "Left", - Up: "Up", - Down: "Down", -}; -/** - * directionLookup - * @private - * @remarks - * Unit direction vectors representing enum Direction - * Yes, I know Left/Right are reversed here -- that's because something is wrong, and I haven't been able to track - * it down. I blame Tom's dodgy code, tbh. - */ -const directionLookup = { - [Direction.Forward]: VECTOR3_FORWARD, - [Direction.Right]: VECTOR3_RIGHT, - [Direction.Back]: VECTOR3_BACK, - [Direction.Left]: VECTOR3_LEFT, - [Direction.Up]: VECTOR3_UP, - [Direction.Down]: VECTOR3_DOWN, -}; -/** - * getRotationCorrectedDirection - * @beta - * @remarks - * Convert a given absolute Direction enum to one which is relative to the specified Y rotation - * (Generally Player view vector Y component) - */ -function getRotationCorrectedDirection(rotationY, realDirection) { - if (realDirection === Direction.Up || realDirection === Direction.Down) { - // Up and Down are ALWAY up and down - return realDirection; - } - // 405 is the amount to do a full circle to remove negative rotations - // Plus 45° to put the end of the first quadrant at 45 degrees. - // Modulo to lock to [0, 360], then divide to convert to [0, 1, 2, 3] indices - const directionQuadrant = Math.floor(((rotationY + 405 + realDirection * 90) % 360) / 90); - return directionQuadrant; -} -/** - * getRotationCorrectedDirectionVector - * @beta - * @remarks - * Convert a given absolute Direction enum to a direction vector which is relative to the Y rotation - * (Generally Player view vector Y component) - */ -function getRotationCorrectedDirectionVector(rotationY, realDirection) { - const relativeDirection = getRotationCorrectedDirection(rotationY, realDirection); - return directionLookup[relativeDirection]; -} -/** - * getDirectionVector - * @beta - * @remarks - * Return a unit vector for a given Direction - */ -function getDirectionVector(direction) { - return directionLookup[direction]; -} -/** - * getScaledDirectionVector - * @beta - * @remarks - * Return a scaled vector for a given Direction - */ -function getScaledDirectionVector(direction, scale) { - const vec = getDirectionVector(direction); - vec.x = vec.x * scale; - vec.y = vec.y * scale; - vec.z = vec.z * scale; - return vec; -} - -export { - Direction, - getDirectionVector, - getRotationCorrectedDirection, - getRotationCorrectedDirectionVector, - getScaledDirectionVector -} \ No newline at end of file diff --git a/editorExtensions/editor-utilities/tests.js b/editorExtensions/editor-utilities/tests.js deleted file mode 100644 index 2a89b069..00000000 --- a/editorExtensions/editor-utilities/tests.js +++ /dev/null @@ -1,16 +0,0 @@ -import * as EditorUtilities from "./index"; - -EditorUtilities.Direction.Forward -EditorUtilities.Direction.Right -EditorUtilities.Direction.Back -EditorUtilities.Direction.Left -EditorUtilities.Direction.Up -EditorUtilities.Direction.Down - -EditorUtilities.getDirectionVector(EditorUtilities.Direction.Down) - -EditorUtilities.getRotationCorrectedDirection(0, EditorUtilities.Direction.Down) - -EditorUtilities.getRotationCorrectedDirectionVector(0, EditorUtilities.Direction.Down) - -EditorUtilities.getScaledDirectionVector(EditorUtilities.Direction.Up, 15) \ No newline at end of file diff --git a/editorExtensions/entity-spawner/README.md b/editorExtensions/entity-spawner/README.md deleted file mode 100644 index ee53897f..00000000 --- a/editorExtensions/entity-spawner/README.md +++ /dev/null @@ -1,11 +0,0 @@ -# entity-spawner - -## Description - -Editor extension that spawns an entity at the selected position. - -Spawn Entity using Ctrl + E - -## Credits - -These scripts were written by [Ciosciaa](https://github.com/Ciosciaa) diff --git a/editorExtensions/entity-spawner/index.js b/editorExtensions/entity-spawner/index.js deleted file mode 100644 index dd919101..00000000 --- a/editorExtensions/entity-spawner/index.js +++ /dev/null @@ -1,71 +0,0 @@ -// Script example for ScriptAPI -// Author: Ciosciaa -// Project: https://github.com/JaylyDev/ScriptAPI -import * as server from "@minecraft/server"; -import * as editor from "@minecraft/server-editor"; -const entityTypes = [...server.EntityTypes.getAll()].map(({ id }) => id); -editor.registerEditorExtension("entitySpawner", uiSession => { - const tool = uiSession.toolRail.addTool({ - displayAltText: "Spawn Entity (Ctrl + E)", - displayStringId: "editor.toolRail.entitySpawnerTool.title", - tooltipAltText: "Spawns an entity at the selected position", - tooltipStringId: "editor.toolRail.entitySpawnerTool.description", - icon: "pack://textures/editor/entity.png?filtering=point" - }); - const currentCursorState = uiSession.extensionContext.cursor.getProperties(); - currentCursorState.outlineColor = { red: 1, green: 0, blue: 1, alpha: 1 }; - currentCursorState.controlMode = editor.CursorControlMode.KeyboardAndMouse; - currentCursorState.targetMode = editor.CursorTargetMode.Face; - currentCursorState.visible = true; - uiSession.scratchStorage = { spawnerCursorState: currentCursorState }; - tool.onModalToolActivation.subscribe(eventData => { - if (eventData.isActiveTool) - uiSession.extensionContext.cursor.setProperties(uiSession.scratchStorage.spawnerCursorState); - }); - uiSession.inputManager.registerKeyBinding(editor.EditorInputContext.GlobalToolMode, uiSession.actionManager.createAction({ - actionType: editor.ActionTypes.NoArgsAction, - onExecute: () => { - uiSession.toolRail.setSelectedOptionId(tool.id, true); - }, - }), editor.KeyboardKey.KEY_E, editor.InputModifier.Control); - const settings = { - entityType: "minecraft:creeper" - }; - const pane = uiSession.createPropertyPane({ - titleStringId: "editor.toolRail.entitySpawnerTool.pane.title", - titleAltText: "Entity Spawner Settings", - }); - const binding = editor.bindDataSource(pane, settings); - pane.addDropdown(binding, "entityType", { - titleStringId: "editor.toolRail.entitySpawnerTool.pane.controls.entityType", - titleAltText: "Entity Type", - dropdownItems: entityTypes.map((entityType, index) => ({ - value: index, - displayAltText: entityType, - displayStringId: `entity.${entityType.replace("minecraft:", "")}.name` - })) - }); - tool.bindPropertyPane(pane); - tool.registerMouseButtonBinding(uiSession.actionManager.createAction({ - actionType: editor.ActionTypes.MouseRayCastAction, - onExecute: async (mouseRay, mouseProps) => { - if (mouseProps.mouseAction === editor.MouseActionType.LeftButton) { - if (mouseProps.inputType === editor.MouseInputType.ButtonDown) { - uiSession.extensionContext.transactionManager.openTransaction("tool.spawnEntity"); - uiSession.extensionContext.selectionManager.selection.clear(); - const cursorPosition = mouseRay.cursorBlockLocation; - server.world.getDimension("minecraft:overworld").spawnEntity(settings.entityType, { - x: cursorPosition.x + 0.5, - y: cursorPosition.y, - z: cursorPosition.z + 0.5 - }); - } - else if (mouseProps.inputType === editor.MouseInputType.ButtonUp) { - uiSession.extensionContext.transactionManager.commitOpenTransaction(); - uiSession.extensionContext.selectionManager.selection.clear(); - } - } - } - })); - return []; // Likely unneeded, but untested -}, () => { }); diff --git a/editorExtensions/entity-spawner/index.ts b/editorExtensions/entity-spawner/index.ts deleted file mode 100644 index 50da87c7..00000000 --- a/editorExtensions/entity-spawner/index.ts +++ /dev/null @@ -1,122 +0,0 @@ -// Script example for ScriptAPI -// Author: Ciosciaa -// Project: https://github.com/JaylyDev/ScriptAPI -import * as server from "@minecraft/server" -import * as editor from "@minecraft/server-editor" - -const entityTypes = [...server.EntityTypes.getAll()].map(({ id }) => id) - -interface ScratchStorage { - spawnerCursorState: editor.CursorProperties -} - -editor.registerEditorExtension( - "entitySpawner", - uiSession => { - const tool = uiSession.toolRail.addTool( - { - displayAltText: "Spawn Entity (Ctrl + E)", - displayStringId: "editor.toolRail.entitySpawnerTool.title", - tooltipAltText: "Spawns an entity at the selected position", - tooltipStringId: "editor.toolRail.entitySpawnerTool.description", - icon: "pack://textures/editor/entity.png?filtering=point" - } - ) - - const currentCursorState = uiSession.extensionContext.cursor.getProperties() - currentCursorState.outlineColor = { red: 1, green: 0, blue: 1, alpha: 1 } - currentCursorState.controlMode = editor.CursorControlMode.KeyboardAndMouse - currentCursorState.targetMode = editor.CursorTargetMode.Face - currentCursorState.visible = true - uiSession.scratchStorage = { spawnerCursorState: currentCursorState } - - tool.onModalToolActivation.subscribe( - eventData => { - if (eventData.isActiveTool) uiSession.extensionContext.cursor.setProperties(uiSession.scratchStorage.spawnerCursorState) - } - ) - - uiSession.inputManager.registerKeyBinding( - editor.EditorInputContext.GlobalToolMode, - uiSession.actionManager.createAction( - { - actionType: editor.ActionTypes.NoArgsAction, - onExecute: () => { - uiSession.toolRail.setSelectedOptionId(tool.id, true) - }, - } - ), - editor.KeyboardKey.KEY_E, - editor.InputModifier.Control - ) - - const settings = { - entityType: entityTypes.indexOf("minecraft:creeper") - } - - const pane = uiSession.createPropertyPane( - { - titleStringId: "editor.toolRail.entitySpawnerTool.pane.title", - titleAltText: "Entity Spawner Settings", - } - ) - - const binding = editor.bindDataSource( - pane, - settings - ) - - pane.addDropdown( - binding, - "entityType", - { - titleStringId: "editor.toolRail.entitySpawnerTool.pane.controls.entityType", - titleAltText: "Entity Type", - dropdownItems: entityTypes.map( - (entityType, index) => ( - { - value: index, - displayAltText: entityType, - displayStringId: `entity.${entityType.replace("minecraft:", "")}.name` - } - ) - ) - } - ) - tool.bindPropertyPane(pane) - - tool.registerMouseButtonBinding( - uiSession.actionManager.createAction( - { - actionType: editor.ActionTypes.MouseRayCastAction, - onExecute: - async (mouseRay, mouseProps) => { - if (mouseProps.mouseAction === editor.MouseActionType.LeftButton) { - if (mouseProps.inputType === editor.MouseInputType.ButtonDown) { - uiSession.extensionContext.transactionManager.openTransaction("tool.spawnEntity") - uiSession.extensionContext.selectionManager.selection.clear() - - const cursorPosition = mouseRay.cursorBlockLocation - server.world.getDimension("minecraft:overworld").spawnEntity( - entityTypes[settings.entityType], - { - x: cursorPosition.x + 0.5, - y: cursorPosition.y, - z: cursorPosition.z + 0.5 - } - ) - } - else if (mouseProps.inputType === editor.MouseInputType.ButtonUp) { - uiSession.extensionContext.transactionManager.commitOpenTransaction() - uiSession.extensionContext.selectionManager.selection.clear() - } - } - } - } - ) - ) - - return [] // Likely unneeded, but untested - }, - () => { } -) \ No newline at end of file diff --git a/editorExtensions/jsconfig.json b/editorExtensions/jsconfig.json deleted file mode 100644 index 48758431..00000000 --- a/editorExtensions/jsconfig.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "extends": "../tsconfig-base.json", - "compilerOptions": { - "baseUrl": "./", - "allowJs": true, - "checkJs": true, - "noEmit": true - }, - "include": ["**/*.ts", "**/*.js"], - "exclude": [] -} \ No newline at end of file diff --git a/editorExtensions/tsconfig.json b/editorExtensions/tsconfig.json deleted file mode 100644 index 724f512c..00000000 --- a/editorExtensions/tsconfig.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "extends": "../tsconfig-base.json", - "compilerOptions": { - "baseUrl": "./", - }, - "include": ["**/*.ts", "**/*.js"], - "exclude": [] -} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 335331cb..663424df 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,21 +9,20 @@ "version": "1.0.0", "license": "MIT", "dependencies": { - "@minecraft/server-admin": "1.0.0-beta.1.21.0-preview.26", - "@minecraft/server-editor": "0.1.0-beta.1.21.0-preview.26", - "@minecraft/server-gametest": "1.0.0-beta.1.21.0-preview.26", - "@minecraft/server-net": "1.0.0-beta.1.21.0-preview.26", - "@minecraft/server-ui": "1.2.0-beta.1.21.0-preview.26", - "@minecraft/vanilla-data": "1.21.0-preview.26" + "@minecraft/server-admin": "1.0.0-beta.1.21.50-preview.25", + "@minecraft/server-editor": "0.1.0-beta.1.21.50-preview.25", + "@minecraft/server-gametest": "1.0.0-beta.1.21.50-preview.25", + "@minecraft/server-net": "1.0.0-beta.1.21.50-preview.25", + "@minecraft/server-ui": "1.4.0-beta.1.21.50-preview.25" }, "devDependencies": { - "@minecraft/math": "^1.3.5", - "@npm/types": "^1.0.2", - "@types/node": "^20.12.12", + "@minecraft/math": "^1.4.0", + "@npm/types": "^2.0.0", + "@types/node": "^22.8.4", "@types/parsimmon": "^1.10.9", - "axios": "^1.6.8", + "axios": "^1.7.7", "parsimmon": "^1.18.1", - "typescript": "^5.4.5" + "typescript": "^5.6.3" } }, "lib": { @@ -38,85 +37,93 @@ "integrity": "sha512-stbUtINCXbcLNRlGNVX68xRC6ZYq3k3CYmfptwrCcPBEUjVOpVkSj3H4Y0qiSYB+1rVWv7DgiP7Uf9++50Ne5g==" }, "node_modules/@minecraft/math": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@minecraft/math/-/math-1.3.5.tgz", - "integrity": "sha512-5fKzTOTNZMOYJSHDGHOmP+/d5xsUV7BJsJ8pUQ7vGzEjy1dRf75JAKL7FN1VT0SVy6ioK1i4vjHIUWO+QRR7qw==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@minecraft/math/-/math-1.4.0.tgz", + "integrity": "sha512-syh24zBVPDIh/Xf+XxuPUUp98rvgcrycPjkNDdwcC7yWSLIGjyaBeaw88a2JsW3e8qoVQfjzTMQhRl5dJ01OkQ==", "dev": true, - "license": "MIT", "peerDependencies": { "@minecraft/server": "^1.6.0" } }, "node_modules/@minecraft/server": { - "version": "1.12.0-beta.1.21.0-preview.26", - "resolved": "https://registry.npmjs.org/@minecraft/server/-/server-1.12.0-beta.1.21.0-preview.26.tgz", - "integrity": "sha512-Ikpv8gZ10NPgnrcfoLH8SAmn2vw0yEO/jHdbuxQvCqzwQymowLbq7jupNMmocKP8XN7ZsmvBrbYEVmbqhN66+w==", + "version": "1.17.0-beta.1.21.50-preview.25", + "resolved": "https://registry.npmjs.org/@minecraft/server/-/server-1.17.0-beta.1.21.50-preview.25.tgz", + "integrity": "sha512-VvMmkCdBeuFlfM3VNHfCw9EoVja0xXGUX2w12tSpBl2idTaFO6KWP+L1emTv2AgKd5p35Kj3ZQIl16zjoVFOLA==", "dependencies": { "@minecraft/common": "^1.1.0" + }, + "peerDependencies": { + "@minecraft/vanilla-data": ">=1.20.70" } }, "node_modules/@minecraft/server-admin": { - "version": "1.0.0-beta.1.21.0-preview.26", - "resolved": "https://registry.npmjs.org/@minecraft/server-admin/-/server-admin-1.0.0-beta.1.21.0-preview.26.tgz", - "integrity": "sha512-Y4OS+YlWXuxR14g7+ff/8PJ0PX1Pa67MHoGs4+wL9KvXOdrfgU022VHdBXtQ6b/ORktMPvfN0LSNssvf+VIw4A==", + "version": "1.0.0-beta.1.21.50-preview.25", + "resolved": "https://registry.npmjs.org/@minecraft/server-admin/-/server-admin-1.0.0-beta.1.21.50-preview.25.tgz", + "integrity": "sha512-H1PeGW+F+cJkFSQt3hyoKnNwlD5tw0+EbZSFxkENZYgWNEhl2SJ7jI/C3sstAErAGESdXPa2Yg4xj8LAA3TFzA==", "dependencies": { - "@minecraft/common": "^1.0.0" + "@minecraft/common": "^1.0.0", + "@minecraft/server": "^1.0.0" } }, "node_modules/@minecraft/server-editor": { - "version": "0.1.0-beta.1.21.0-preview.26", - "resolved": "https://registry.npmjs.org/@minecraft/server-editor/-/server-editor-0.1.0-beta.1.21.0-preview.26.tgz", - "integrity": "sha512-yu8ums8pph7BJTCSPu+aqrLUiSDQaDN7YpQ8OHUV9RPYcUeyzmSEGxOtQ7yWWbGlRvB3kof74IMk982q+TKQcA==", + "version": "0.1.0-beta.1.21.50-preview.25", + "resolved": "https://registry.npmjs.org/@minecraft/server-editor/-/server-editor-0.1.0-beta.1.21.50-preview.25.tgz", + "integrity": "sha512-ncMuH/Q6AbHdf9XJSBVbhU1BCKQ/x51Z9g+ggo/VkWG459cIKwydhKCYftsoZ3Q6M6NKyyatQ/19N+ycXntCMw==", "dependencies": { "@minecraft/common": "^1.0.0", - "@minecraft/server": "^1.12.0-beta.1.21.0-preview.26" + "@minecraft/server": "^1.17.0-beta.1.21.50-preview.25" } }, "node_modules/@minecraft/server-gametest": { - "version": "1.0.0-beta.1.21.0-preview.26", - "resolved": "https://registry.npmjs.org/@minecraft/server-gametest/-/server-gametest-1.0.0-beta.1.21.0-preview.26.tgz", - "integrity": "sha512-xsk/l94VjJAyG4JmtOFp2WtINjrW3OVVxkHrEyCLtjc80mxbPXrZHCmSD0fkrXABfQ3RgKuII2cxFmABzHxdCQ==", + "version": "1.0.0-beta.1.21.50-preview.25", + "resolved": "https://registry.npmjs.org/@minecraft/server-gametest/-/server-gametest-1.0.0-beta.1.21.50-preview.25.tgz", + "integrity": "sha512-cUDU2O5gXT8rjzPrYAEYLVodyql7KNthKPU7lVtfRPjyB2LDakLkqkaLq7P9fG5/Ik9a/ICxZS6u29Ek6ucIrw==", "dependencies": { "@minecraft/common": "^1.0.0", "@minecraft/server": "^1.8.0" } }, "node_modules/@minecraft/server-net": { - "version": "1.0.0-beta.1.21.0-preview.26", - "resolved": "https://registry.npmjs.org/@minecraft/server-net/-/server-net-1.0.0-beta.1.21.0-preview.26.tgz", - "integrity": "sha512-LFlQwa8T9mUxJPqEJczqanvlcZTmsPpJn34n4azZWAJ3OnnMMjz6Y0iHgSSeqwuEtjn5S6VefnlBomIg8gDpng==", + "version": "1.0.0-beta.1.21.50-preview.25", + "resolved": "https://registry.npmjs.org/@minecraft/server-net/-/server-net-1.0.0-beta.1.21.50-preview.25.tgz", + "integrity": "sha512-FZXiUj2gk277wfQIszAeQ3d22vjM35HmWNCHe5MtriFEmWvRLiCBg5d0aVqAVrbAmGs2LRtPujY94snpSwDIwA==", "dependencies": { "@minecraft/common": "^1.0.0", - "@minecraft/server-admin": "^1.0.0-beta.1.21.0-preview.26" + "@minecraft/server": "^1.0.0", + "@minecraft/server-admin": "^1.0.0-beta.1.21.50-preview.25" } }, "node_modules/@minecraft/server-ui": { - "version": "1.2.0-beta.1.21.0-preview.26", - "resolved": "https://registry.npmjs.org/@minecraft/server-ui/-/server-ui-1.2.0-beta.1.21.0-preview.26.tgz", - "integrity": "sha512-WLUjZV+mAo7nFLkdWH+aMrB/g0naaQbiGm0OAcf13muBhE6mOzuyDxTnC2PAy3IYvi6TiDEtpupzMsF5JtW+RA==", + "version": "1.4.0-beta.1.21.50-preview.25", + "resolved": "https://registry.npmjs.org/@minecraft/server-ui/-/server-ui-1.4.0-beta.1.21.50-preview.25.tgz", + "integrity": "sha512-wO2TPInRofbZrJ6Nk+QFC+PZSWp3r5K8VZhPU0JsgS4z6YyO5Ose2xogiCUiLe9R00KNzR2PRgyZ9HjvkeRGfw==", "dependencies": { "@minecraft/common": "^1.0.0", "@minecraft/server": "^1.8.0" } }, "node_modules/@minecraft/vanilla-data": { - "version": "1.21.0-preview.26", - "resolved": "https://registry.npmjs.org/@minecraft/vanilla-data/-/vanilla-data-1.21.0-preview.26.tgz", - "integrity": "sha512-prbRfCw7Sl0aqysP1cHyg7lf72QLRkdiP6VTr9pok8rIgnIjBoTloFZc++ncF89Iow6ucpCOIJHESFLb9gVLxQ==" + "version": "1.21.50-preview.25", + "resolved": "https://registry.npmjs.org/@minecraft/vanilla-data/-/vanilla-data-1.21.50-preview.25.tgz", + "integrity": "sha512-PfYoRpdohjD0K0IdnCyActL9jo/+lZubNlQwbv0gppKEGvGg5Of0poE3QSApxJkgoSZI5JTKojYGpYWsG/IWaQ==", + "peer": true }, "node_modules/@npm/types": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@npm/types/-/types-1.0.2.tgz", - "integrity": "sha512-KXZccTDEnWqNrrx6JjpJKU/wJvNeg9BDgjS0XhmlZab7br921HtyVbsYzJr4L+xIvjdJ20Wh9dgxgCI2a5CEQw==", - "dev": true + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@npm/types/-/types-2.0.0.tgz", + "integrity": "sha512-4WqrAc16VKuD8ea+tT8QC/WO+hkn32Z9qMFrG1u3dIAEv3pn0DuIUc7uBpplDJLFIyV7gq1qtm3Yv6kAxJh8KA==", + "dev": true, + "engines": { + "node": ">=18.6.0" + } }, "node_modules/@types/node": { - "version": "20.12.12", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.12.tgz", - "integrity": "sha512-eWLDGF/FOSPtAvEqeRAQ4C8LSA7M1I7i0ky1I8U7kD1J5ITyW3AsRhQrKVoWf5pFKZ2kILsEGJhsI9r93PYnOw==", + "version": "22.8.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.8.4.tgz", + "integrity": "sha512-SpNNxkftTJOPk0oN+y2bIqurEXHTA2AOZ3EJDDKeJ5VzkvvORSvmQXGQarcOzWV1ac7DCaPBEdMDxBsM+d8jWw==", "dev": true, "dependencies": { - "undici-types": "~5.26.4" + "undici-types": "~6.19.8" } }, "node_modules/@types/parsimmon": { @@ -132,9 +139,9 @@ "dev": true }, "node_modules/axios": { - "version": "1.6.8", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.8.tgz", - "integrity": "sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==", + "version": "1.7.7", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz", + "integrity": "sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==", "dev": true, "dependencies": { "follow-redirects": "^1.15.6", @@ -231,9 +238,9 @@ "dev": true }, "node_modules/typescript": { - "version": "5.4.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", - "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", + "version": "5.6.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", + "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -244,9 +251,9 @@ } }, "node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", "dev": true } }, @@ -257,82 +264,85 @@ "integrity": "sha512-stbUtINCXbcLNRlGNVX68xRC6ZYq3k3CYmfptwrCcPBEUjVOpVkSj3H4Y0qiSYB+1rVWv7DgiP7Uf9++50Ne5g==" }, "@minecraft/math": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@minecraft/math/-/math-1.3.5.tgz", - "integrity": "sha512-5fKzTOTNZMOYJSHDGHOmP+/d5xsUV7BJsJ8pUQ7vGzEjy1dRf75JAKL7FN1VT0SVy6ioK1i4vjHIUWO+QRR7qw==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@minecraft/math/-/math-1.4.0.tgz", + "integrity": "sha512-syh24zBVPDIh/Xf+XxuPUUp98rvgcrycPjkNDdwcC7yWSLIGjyaBeaw88a2JsW3e8qoVQfjzTMQhRl5dJ01OkQ==", "dev": true, "requires": {} }, "@minecraft/server": { - "version": "1.12.0-beta.1.21.0-preview.26", - "resolved": "https://registry.npmjs.org/@minecraft/server/-/server-1.12.0-beta.1.21.0-preview.26.tgz", - "integrity": "sha512-Ikpv8gZ10NPgnrcfoLH8SAmn2vw0yEO/jHdbuxQvCqzwQymowLbq7jupNMmocKP8XN7ZsmvBrbYEVmbqhN66+w==", + "version": "1.17.0-beta.1.21.50-preview.25", + "resolved": "https://registry.npmjs.org/@minecraft/server/-/server-1.17.0-beta.1.21.50-preview.25.tgz", + "integrity": "sha512-VvMmkCdBeuFlfM3VNHfCw9EoVja0xXGUX2w12tSpBl2idTaFO6KWP+L1emTv2AgKd5p35Kj3ZQIl16zjoVFOLA==", "requires": { "@minecraft/common": "^1.1.0" } }, "@minecraft/server-admin": { - "version": "1.0.0-beta.1.21.0-preview.26", - "resolved": "https://registry.npmjs.org/@minecraft/server-admin/-/server-admin-1.0.0-beta.1.21.0-preview.26.tgz", - "integrity": "sha512-Y4OS+YlWXuxR14g7+ff/8PJ0PX1Pa67MHoGs4+wL9KvXOdrfgU022VHdBXtQ6b/ORktMPvfN0LSNssvf+VIw4A==", + "version": "1.0.0-beta.1.21.50-preview.25", + "resolved": "https://registry.npmjs.org/@minecraft/server-admin/-/server-admin-1.0.0-beta.1.21.50-preview.25.tgz", + "integrity": "sha512-H1PeGW+F+cJkFSQt3hyoKnNwlD5tw0+EbZSFxkENZYgWNEhl2SJ7jI/C3sstAErAGESdXPa2Yg4xj8LAA3TFzA==", "requires": { - "@minecraft/common": "^1.0.0" + "@minecraft/common": "^1.0.0", + "@minecraft/server": "1.17.0-beta.1.21.50-preview.25" } }, "@minecraft/server-editor": { - "version": "0.1.0-beta.1.21.0-preview.26", - "resolved": "https://registry.npmjs.org/@minecraft/server-editor/-/server-editor-0.1.0-beta.1.21.0-preview.26.tgz", - "integrity": "sha512-yu8ums8pph7BJTCSPu+aqrLUiSDQaDN7YpQ8OHUV9RPYcUeyzmSEGxOtQ7yWWbGlRvB3kof74IMk982q+TKQcA==", + "version": "0.1.0-beta.1.21.50-preview.25", + "resolved": "https://registry.npmjs.org/@minecraft/server-editor/-/server-editor-0.1.0-beta.1.21.50-preview.25.tgz", + "integrity": "sha512-ncMuH/Q6AbHdf9XJSBVbhU1BCKQ/x51Z9g+ggo/VkWG459cIKwydhKCYftsoZ3Q6M6NKyyatQ/19N+ycXntCMw==", "requires": { "@minecraft/common": "^1.0.0", - "@minecraft/server": "1.12.0-beta.1.21.0-preview.26" + "@minecraft/server": "1.17.0-beta.1.21.50-preview.25" } }, "@minecraft/server-gametest": { - "version": "1.0.0-beta.1.21.0-preview.26", - "resolved": "https://registry.npmjs.org/@minecraft/server-gametest/-/server-gametest-1.0.0-beta.1.21.0-preview.26.tgz", - "integrity": "sha512-xsk/l94VjJAyG4JmtOFp2WtINjrW3OVVxkHrEyCLtjc80mxbPXrZHCmSD0fkrXABfQ3RgKuII2cxFmABzHxdCQ==", + "version": "1.0.0-beta.1.21.50-preview.25", + "resolved": "https://registry.npmjs.org/@minecraft/server-gametest/-/server-gametest-1.0.0-beta.1.21.50-preview.25.tgz", + "integrity": "sha512-cUDU2O5gXT8rjzPrYAEYLVodyql7KNthKPU7lVtfRPjyB2LDakLkqkaLq7P9fG5/Ik9a/ICxZS6u29Ek6ucIrw==", "requires": { "@minecraft/common": "^1.0.0", - "@minecraft/server": "1.12.0-beta.1.21.0-preview.26" + "@minecraft/server": "1.17.0-beta.1.21.50-preview.25" } }, "@minecraft/server-net": { - "version": "1.0.0-beta.1.21.0-preview.26", - "resolved": "https://registry.npmjs.org/@minecraft/server-net/-/server-net-1.0.0-beta.1.21.0-preview.26.tgz", - "integrity": "sha512-LFlQwa8T9mUxJPqEJczqanvlcZTmsPpJn34n4azZWAJ3OnnMMjz6Y0iHgSSeqwuEtjn5S6VefnlBomIg8gDpng==", + "version": "1.0.0-beta.1.21.50-preview.25", + "resolved": "https://registry.npmjs.org/@minecraft/server-net/-/server-net-1.0.0-beta.1.21.50-preview.25.tgz", + "integrity": "sha512-FZXiUj2gk277wfQIszAeQ3d22vjM35HmWNCHe5MtriFEmWvRLiCBg5d0aVqAVrbAmGs2LRtPujY94snpSwDIwA==", "requires": { "@minecraft/common": "^1.0.0", - "@minecraft/server-admin": "^1.0.0-beta.1.21.0-preview.26" + "@minecraft/server": "1.17.0-beta.1.21.50-preview.25", + "@minecraft/server-admin": "^1.0.0-beta.1.21.50-preview.25" } }, "@minecraft/server-ui": { - "version": "1.2.0-beta.1.21.0-preview.26", - "resolved": "https://registry.npmjs.org/@minecraft/server-ui/-/server-ui-1.2.0-beta.1.21.0-preview.26.tgz", - "integrity": "sha512-WLUjZV+mAo7nFLkdWH+aMrB/g0naaQbiGm0OAcf13muBhE6mOzuyDxTnC2PAy3IYvi6TiDEtpupzMsF5JtW+RA==", + "version": "1.4.0-beta.1.21.50-preview.25", + "resolved": "https://registry.npmjs.org/@minecraft/server-ui/-/server-ui-1.4.0-beta.1.21.50-preview.25.tgz", + "integrity": "sha512-wO2TPInRofbZrJ6Nk+QFC+PZSWp3r5K8VZhPU0JsgS4z6YyO5Ose2xogiCUiLe9R00KNzR2PRgyZ9HjvkeRGfw==", "requires": { "@minecraft/common": "^1.0.0", - "@minecraft/server": "1.12.0-beta.1.21.0-preview.26" + "@minecraft/server": "1.17.0-beta.1.21.50-preview.25" } }, "@minecraft/vanilla-data": { - "version": "1.21.0-preview.26", - "resolved": "https://registry.npmjs.org/@minecraft/vanilla-data/-/vanilla-data-1.21.0-preview.26.tgz", - "integrity": "sha512-prbRfCw7Sl0aqysP1cHyg7lf72QLRkdiP6VTr9pok8rIgnIjBoTloFZc++ncF89Iow6ucpCOIJHESFLb9gVLxQ==" + "version": "1.21.50-preview.25", + "resolved": "https://registry.npmjs.org/@minecraft/vanilla-data/-/vanilla-data-1.21.50-preview.25.tgz", + "integrity": "sha512-PfYoRpdohjD0K0IdnCyActL9jo/+lZubNlQwbv0gppKEGvGg5Of0poE3QSApxJkgoSZI5JTKojYGpYWsG/IWaQ==", + "peer": true }, "@npm/types": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@npm/types/-/types-1.0.2.tgz", - "integrity": "sha512-KXZccTDEnWqNrrx6JjpJKU/wJvNeg9BDgjS0XhmlZab7br921HtyVbsYzJr4L+xIvjdJ20Wh9dgxgCI2a5CEQw==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@npm/types/-/types-2.0.0.tgz", + "integrity": "sha512-4WqrAc16VKuD8ea+tT8QC/WO+hkn32Z9qMFrG1u3dIAEv3pn0DuIUc7uBpplDJLFIyV7gq1qtm3Yv6kAxJh8KA==", "dev": true }, "@types/node": { - "version": "20.12.12", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.12.tgz", - "integrity": "sha512-eWLDGF/FOSPtAvEqeRAQ4C8LSA7M1I7i0ky1I8U7kD1J5ITyW3AsRhQrKVoWf5pFKZ2kILsEGJhsI9r93PYnOw==", + "version": "22.8.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.8.4.tgz", + "integrity": "sha512-SpNNxkftTJOPk0oN+y2bIqurEXHTA2AOZ3EJDDKeJ5VzkvvORSvmQXGQarcOzWV1ac7DCaPBEdMDxBsM+d8jWw==", "dev": true, "requires": { - "undici-types": "~5.26.4" + "undici-types": "~6.19.8" } }, "@types/parsimmon": { @@ -348,9 +358,9 @@ "dev": true }, "axios": { - "version": "1.6.8", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.8.tgz", - "integrity": "sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==", + "version": "1.7.7", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz", + "integrity": "sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==", "dev": true, "requires": { "follow-redirects": "^1.15.6", @@ -418,15 +428,15 @@ "dev": true }, "typescript": { - "version": "5.4.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", - "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", + "version": "5.6.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", + "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", "dev": true }, "undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", "dev": true } } diff --git a/package.json b/package.json index fd0745c2..554f2fe3 100644 --- a/package.json +++ b/package.json @@ -19,23 +19,23 @@ }, "homepage": "https://github.com/JaylyDev/ScriptAPI#readme", "overrides": { - "@minecraft/server": "1.12.0-beta.1.21.0-preview.26" + "@minecraft/server": "1.17.0-beta.1.21.50-preview.25", + "@minecraft/vanilla-data": "1.21.50-preview.25" }, "dependencies": { - "@minecraft/server-admin": "1.0.0-beta.1.21.0-preview.26", - "@minecraft/server-editor": "0.1.0-beta.1.21.0-preview.26", - "@minecraft/server-gametest": "1.0.0-beta.1.21.0-preview.26", - "@minecraft/server-net": "1.0.0-beta.1.21.0-preview.26", - "@minecraft/server-ui": "1.2.0-beta.1.21.0-preview.26", - "@minecraft/vanilla-data": "1.21.0-preview.26" + "@minecraft/server-admin": "1.0.0-beta.1.21.50-preview.25", + "@minecraft/server-editor": "0.1.0-beta.1.21.50-preview.25", + "@minecraft/server-gametest": "1.0.0-beta.1.21.50-preview.25", + "@minecraft/server-net": "1.0.0-beta.1.21.50-preview.25", + "@minecraft/server-ui": "1.4.0-beta.1.21.50-preview.25" }, "devDependencies": { - "@minecraft/math": "^1.3.5", - "@npm/types": "^1.0.2", - "@types/node": "^20.12.12", + "@minecraft/math": "^1.4.0", + "@npm/types": "^2.0.0", + "@types/node": "^22.8.4", "@types/parsimmon": "^1.10.9", - "axios": "^1.6.8", + "axios": "^1.7.7", "parsimmon": "^1.18.1", - "typescript": "^5.4.5" + "typescript": "^5.6.3" } } diff --git a/scripts/database/index.js b/scripts/database/index.js index f5ba4428..0ee3d7a1 100644 --- a/scripts/database/index.js +++ b/scripts/database/index.js @@ -1,7 +1,6 @@ // Script example for ScriptAPI // Author: iBlqzed // Project: https://github.com/JaylyDev/ScriptAPI - import { world, system } from "@minecraft/server"; export class Database { constructor(name, defaultValue = "{}") { @@ -72,7 +71,7 @@ export class Database { * @returns {Record} An object of all keys and values */ getAll() { - return this.cache ?? (this.cache = Database.getAll(this.name, this.defaultValue)); + return this.cache ??= Database.getAll(this.name, this.defaultValue); } /** * Save the database instantly @@ -80,7 +79,7 @@ export class Database { save() { const stringified = JSON.stringify(this.cache); const index = Math.ceil(stringified.length / 32000); - world.setDynamicProperty(`${this.name}Index`); + world.setDynamicProperty(`${this.name}Index`, index); for (let i = 0; i < index; i++) { world.setDynamicProperty(`${this.name}:${i}`, stringified.slice(i * 32000, (i + 1) * 32000)); } diff --git a/scripts/database/index.ts b/scripts/database/index.ts index 9c598a0f..fbbba1af 100644 --- a/scripts/database/index.ts +++ b/scripts/database/index.ts @@ -90,7 +90,7 @@ export class Database { public save(): void { const stringified = JSON.stringify(this.cache) const index = Math.ceil(stringified.length / 32000) - world.setDynamicProperty(`${this.name}Index`) + world.setDynamicProperty(`${this.name}Index`, index) for (let i = 0; i < index; i++) { world.setDynamicProperty(`${this.name}:${i}`, stringified.slice(i * 32000, (i + 1) * 32000)) } @@ -122,4 +122,4 @@ export class Database { system.runInterval(() => { //@ts-ignore Database.save() -}, 1200) \ No newline at end of file +}, 1200) diff --git a/scripts/fill-blocks/index.js b/scripts/fill-blocks/index.js index cb1ba323..3b8c8a68 100644 --- a/scripts/fill-blocks/index.js +++ b/scripts/fill-blocks/index.js @@ -1,7 +1,8 @@ // Script example for ScriptAPI // Author: Jayly#1397 // Project: https://github.com/JaylyDev/ScriptAPI -import { BlockVolumeUtils } from "@minecraft/server"; +import { BlockVolume, ListBlockVolume } from "@minecraft/server"; +import { Vector3Builder } from "@minecraft/math"; const MAX_BLOCKS_SINGLE_FILL = 32768; /** * Fetch a `Iterable` that represents all of @@ -10,17 +11,15 @@ const MAX_BLOCKS_SINGLE_FILL = 32768; * @private */ function* getBlockVolumeIterator(volume, delta) { - const box = BlockVolumeUtils.getBoundingBox(volume); - const blockVolume = { from: box.min, to: box.max }; - const span = BlockVolumeUtils.getSpan(blockVolume); + const box = volume.getBoundingBox(); + const blockVolume = new BlockVolume(box.min, box.max); + const span = blockVolume.getSpan(); for (let x = 0; x < span.x; x += delta) { for (let y = 0; y < span.y; y += delta) { for (let z = 0; z < span.z; z += delta) { - const part = BlockVolumeUtils.translate({ - from: { x, y, z }, - to: { x: x + delta - 1, y: y + delta - 1, z: z + delta - 1 } - }, blockVolume.from); - part.to = BlockVolumeUtils.getMin({ from: part.to, to: blockVolume.to }); + const part = new BlockVolume({ x, y, z }, { x: x + delta - 1, y: y + delta - 1, z: z + delta - 1 }); + part.translate(blockVolume.from); + part.to = new BlockVolume(part.to, blockVolume.to).getMin(); yield part; } } @@ -43,23 +42,24 @@ function* getBlockVolumeIterator(volume, delta) { */ export function fillBlocks(dimension, begin, end, block, options) { // Check if block volume is greater than 32768, if not return native fillblocks - const volume = { from: begin, to: end }; - if (BlockVolumeUtils.getCapacity(volume) <= MAX_BLOCKS_SINGLE_FILL) { - return dimension.fillBlocks(begin, end, block, options); + const volume = new BlockVolume(begin, end); + if (volume.getCapacity() <= MAX_BLOCKS_SINGLE_FILL) { + return dimension.fillBlocks(volume, block, options); } ; - let blocksFilled = 0; - for (const { from, to } of getBlockVolumeIterator(volume, 32)) { + let blockList = new ListBlockVolume([]); + for (const blockVolume of getBlockVolumeIterator(volume, 32)) { try { - blocksFilled += dimension.fillBlocks(from, to, block, options); + const blocksFilled = dimension.fillBlocks(blockVolume, block, options); + blockList.add(Array.from(blocksFilled.getBlockLocationIterator())); } catch (error) { // custom error message if (!(error instanceof Error)) throw error; - console.error(`${error.message} between ${Object.values(from).join(', ')} and ${Object.values(to).join(', ')}`); + console.error(`${error.message} between ${new Vector3Builder(begin).toString()} and ${new Vector3Builder(end).toString()}`); } } - return blocksFilled; + return blockList; } ; diff --git a/scripts/player-leave-event/index.js b/scripts/player-leave-event/index.js index 9b9acd9b..ee1fd1cd 100644 --- a/scripts/player-leave-event/index.js +++ b/scripts/player-leave-event/index.js @@ -1,8 +1,9 @@ // Script example for ScriptAPI // Author: Jayly // Project: https://github.com/JaylyDev/ScriptAPI -import { world, Vector, system } from "@minecraft/server"; +import { world, system } from "@minecraft/server"; import "@minecraft/server-gametest"; // import "@minecraft/server-gametest" native module to support Simulated Players +import { Vector3Builder } from "@minecraft/math"; /** * @license MIT * @author JaylyMC @@ -171,8 +172,8 @@ class Player { this.scoreboard = player.scoreboardIdentity; this.selectedSlotIndex = player.selectedSlotIndex; this.target = player.target; - this.velocity = new Vector(velocity.x, velocity.y, velocity.z); - this.viewDirection = new Vector(player.getViewDirection().x, player.getViewDirection().y, player.getViewDirection().z); + this.velocity = new Vector3Builder(velocity); + this.viewDirection = new Vector3Builder(player.getViewDirection()); } ; } diff --git a/scripts/quick-db/index.js b/scripts/quick-db/index.js new file mode 100644 index 00000000..a89df8a2 --- /dev/null +++ b/scripts/quick-db/index.js @@ -0,0 +1,107 @@ +/** + * # QUICK DB @DATABASE + * + * @format + * @author @Nperma fomo datang (jaskiding) use like map method: set(), delete(), get(), keys(), values(), entries() + * @example const db = new QuickDB("user"); + * + * + * @param {key: string} @param {value: any} @returns {boolean} //set item + * db.set("FomoKiwor", {money:20000}) + * + * @param {key} @returns {value} // log: {money:20000} + * db.get("FomoKiwor") + * + * @param {key} @returns {boolean} // log: true + * db.has("FomoKiwor") + * // log: false + * db.has("Lope387") + * + * @param {key} @returns {boolean} //delete item + * db.delete("FomoKiwor") + * + * // log: false + * db.has("FomoKiwor") + * + * @returns {keys[]} get all key on db + * db.keys() + * @returns {values[]} get all value on db + * db.values(); + * + * @returns {entries[key,value]} get all key and value on db + * db.entries(); + */ + +import { world,World} from "@minecraft/server"; + +const DATABASE_PREFIX = "\u0235\u0235"; + +const {getDynamicProperty:GET,setDynamicProperty:SET,getDynamicPropertyIds:IDS,getDynamicPropertyTotalByteCount:BYTES}=World.prototype; + +class QuickDB { + #identifier; + constructor(id) { + this.#identifier = `${DATABASE_PREFIX}${id}${DATABASE_PREFIX}`; + } + + get size(){return BYTES.call(world)} + + has(key){return !!GET.call(world, key)} + + get(key){ + return this.has(key)?JSON.parse(GET.call(world,key)):undefined + } + + set(key,value){ + if(!(key instanceof String)||typeof key!=="string") return false; + SET.call(world,key,JSON.stringify(value)) + return true; + } + + delete(key){ + if(!this.has(key)) return false; + SET.call(world,key,undefined); + return true; + } + + keys() { + return this.#UIDX("keys"); + } + + values() { + return this.#UIDX("values"); + } + + entries() { + return this.#UIDX("entries"); + } + + /** + * Helper method to iterate through database properties + * @param {"keys" | "values" | "entries"} type + * @returns {Array} + */ + #UIDX(type) { + const ids = IDS.call(world); + const result = []; + + for (const id of ids) { + if (!id.startsWith(this.#identifier)) continue; + + const key = id.replace(this.#identifier, ""); + if (type === "keys") { + result.push(key); + } else if (type === "values") { + const value = JSON.parse(GET.call(world, id)); + result.push(value); + } else if (type === "entries") { + const value = JSON.parse(GET.call(world, id)); + result.push([key, value]); + } + } + + return result; + } +} + +export default QuickDB diff --git a/scripts/quick-db/readme.md b/scripts/quick-db/readme.md new file mode 100644 index 00000000..7fdd5c59 --- /dev/null +++ b/scripts/quick-db/readme.md @@ -0,0 +1,165 @@ +# QuickDB - A Lightweight Database for Minecraft Bedrock ScriptAPI + +**QuickDB** is a simple and efficient database system designed for Minecraft Bedrock Edition ScriptAPI. It utilizes dynamic properties from the `@minecraft/server` module, allowing developers to store and manage key-value pairs in a way similar to JavaScript's `Map` object. + +--- + +## Features + +- **CRUD Operations**: + - `set(key, value)` - Save a value to the database. + - `get(key)` - Retrieve a value by its key. + - `delete(key)` - Remove a key-value pair from the database. + - `has(key)` - Check if a key exists in the database. + +- **Iteration**: + - `keys()` - Get all keys in the database. + - `values()` - Retrieve all values stored in the database. + - `entries()` - Retrieve all key-value pairs as an array of entries. + +- **Database Size**: + - `size` - Get the total byte count used by the dynamic properties. + +--- + +## Installation + +Import `QuickDB` into your ScriptAPI project. Ensure `QuickDB` is included in your `index.js` file for easy integration. + +```javascript +import QuickDB from "./index.js"; +``` + +--- + +## Documentation + +### **Constructor** + +```javascript +const db = new QuickDB("user"); +``` + +- **Parameters**: + - `id` *(string)*: A unique identifier for your database instance. + +--- + +### **Methods** + +#### `set(key, value)` +- **Description**: Stores a value associated with a key. +- **Parameters**: + - `key` *(string)*: The key to store the value. + - `value` *(any)*: The value to be stored. +- **Returns**: `boolean` - `true` if successful. + +```javascript +db.set("FomoKiwor", { money: 20000 }); +``` + +--- + +#### `get(key)` +- **Description**: Retrieves the value associated with a key. +- **Parameters**: + - `key` *(string)*: The key to retrieve the value. +- **Returns**: `any` - The value associated with the key. + +```javascript +const userData = db.get("FomoKiwor"); // { money: 20000 } +``` + +--- + +#### `has(key)` +- **Description**: Checks if a key exists in the database. +- **Parameters**: + - `key` *(string)*: The key to check. +- **Returns**: `boolean` - `true` if the key exists. + +```javascript +const exists = db.has("FomoKiwor"); // true +``` + +--- + +#### `delete(key)` +- **Description**: Removes a key-value pair from the database. +- **Parameters**: + - `key` *(string)*: The key to remove. +- **Returns**: `boolean` - `true` if successful. + +```javascript +db.delete("FomoKiwor"); +``` + +--- + +#### `keys()` +- **Description**: Retrieves all keys in the database. +- **Returns**: `string[]` - An array of all keys. + +```javascript +const allKeys = db.keys(); // ["key1", "key2"] +``` + +--- + +#### `values()` +- **Description**: Retrieves all values in the database. +- **Returns**: `any[]` - An array of all values. + +```javascript +const allValues = db.values(); // [{ money: 20000 }, { items: [] }] +``` + +--- + +#### `entries()` +- **Description**: Retrieves all key-value pairs in the database. +- **Returns**: `Array<[string, any]>` - An array of key-value entries. + +```javascript +const allEntries = db.entries(); // [["key1", { money: 20000 }], ["key2", { items: [] }]] +``` + +--- + +### **Property** + +#### `size` +- **Description**: Gets the total byte count used by dynamic properties. +- **Returns**: `number` - The total byte count. + +```javascript +console.log(db.size); // e.g., 512 +``` + +--- + +## Example Usage + +```javascript +import QuickDB from "./index.js"; + +const db = new QuickDB("user"); + +db.set("FomoKiwor", { money: 20000 }); +console.log(db.get("FomoKiwor")); // { money: 20000 } + +console.log(db.has("FomoKiwor")); // true +db.delete("FomoKiwor"); +console.log(db.has("FomoKiwor")); // false + +db.set("User1", { score: 100 }); +db.set("User2", { score: 150 }); + +console.log(db.keys()); // ["User1", "User2"] +console.log(db.values()); // [{ score: 100 }, { score: 150 }] +console.log(db.entries()); // [["User1", { score: 100 }], ["User2", { score: 150 }]] +``` + +--- + +Developed by [Nperma](https://github.com/nperma) diff --git a/scripts/quick-db/test.js b/scripts/quick-db/test.js new file mode 100644 index 00000000..a046603b --- /dev/null +++ b/scripts/quick-db/test.js @@ -0,0 +1,31 @@ +import QuickDB from "./index.js"; +import { world } from "@minecraft/server"; + +const db = new QuickDB("twst"); + +db.set("anjay", ["alok","ruok"]); + + +console.log(db.get("anjay")); //log: ["alok","ruok"] + +db.set("anjay", db.get("anjay").filter(value=>value!=="alok")); //value: ["alok"] + +db.set("anjay", "nandalopadit") //value: nandalopadit + +db.delete("anjay"); + +world.afterEvents.playerSpawn.subscribe((event)=>{ + if(event.initialSpawn) { + if(!db.has(player.id){ + + db.set(player.id,{ + name: player.name, + joinDate: Date.now() + }); + world.sendMessage("§aregister new player with name " + player.name); + return; + } + + world.sendMessage(`§a${player.name} join date: ${new Date(db.get(player.id)).toLocaleDateString()?.replace(new RegExp("/","g"),"-")}`); + } +}) diff --git a/scripts/ui-wrapper/ModalForm.js b/scripts/ui-wrapper/ModalForm.js index e8cf7d4a..dc64da86 100644 --- a/scripts/ui-wrapper/ModalForm.js +++ b/scripts/ui-wrapper/ModalForm.js @@ -47,6 +47,11 @@ export class ModalFormBuilder { */ this.content = []; } + submitButton(submitButtonText) { + this.submitButtonText = submitButtonText; + return this; + } + ; dropdown(label, options, defaultValueIndex) { this.content.push(new ModalFormDropdown(label, options, defaultValueIndex)); return this; @@ -66,6 +71,8 @@ export class ModalFormBuilder { form.toggle(item.label, item.defaultValue); } ; + if (!!this.submitButtonText) + form.submitButton(this.submitButtonText); return form.show(player); } slider(label, minimumValue, maximumValue, valueStep = 1, defaultValue) { diff --git a/scripts/vector3-polyfill/Vector.js b/scripts/vector3-polyfill/Vector.js index a2d4856e..eab86283 100644 --- a/scripts/vector3-polyfill/Vector.js +++ b/scripts/vector3-polyfill/Vector.js @@ -59,7 +59,7 @@ export class Vector { const DirectionX = this.x / magnitude; const DirectionY = this.y / magnitude; const DirectionZ = this.z / magnitude; - return new Vector(DirectionX, DirectionY, DirectionZ); + return new _a(DirectionX, DirectionY, DirectionZ); } /** * @remarks @@ -69,7 +69,7 @@ export class Vector { * @returns {Vector} */ static add(a, b) { - const vector = new Vector(a.x, a.y, a.z); + const vector = new _a(a.x, a.y, a.z); vector.x += b.x; vector.y += b.y; vector.z += b.z; @@ -83,7 +83,7 @@ export class Vector { * @returns {Vector} */ static cross(a, b) { - return new Vector(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x); + return new _a(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x); } /** * @remarks @@ -107,7 +107,7 @@ export class Vector { * @returns {Vector} */ static divide(a, b) { - const vector = new Vector(a.x, a.y, a.z); + const vector = new _a(a.x, a.y, a.z); if (typeof b === "number") { vector.x /= b; vector.y /= b; @@ -130,7 +130,7 @@ export class Vector { * @returns {Vector} */ static lerp(a, b, t) { - const dest = new Vector(a.x, a.y, a.z); + const dest = new _a(a.x, a.y, a.z); dest.x += (b.x - a.x) * t; dest.y += (b.y - a.y) * t; dest.z += (b.z - a.z) * t; @@ -146,11 +146,11 @@ export class Vector { */ static max(a, b) { const vectors = [a, b]; - const arr = vectors.map(({ x, y, z }) => new Vector(x, y, z).length()); + const arr = vectors.map(({ x, y, z }) => new _a(x, y, z).length()); const max = Math.max(...arr); const index = arr.indexOf(max); const vector3 = vectors[index]; - return new Vector(vector3.x, vector3.y, vector3.z); + return new _a(vector3.x, vector3.y, vector3.z); } /** * @remarks @@ -162,11 +162,11 @@ export class Vector { */ static min(a, b) { const vectors = [a, b]; - const arr = vectors.map(({ x, y, z }) => new Vector(x, y, z).length()); + const arr = vectors.map(({ x, y, z }) => new _a(x, y, z).length()); const min = Math.min(...arr); const index = arr.indexOf(min); const vector3 = vectors[index]; - return new Vector(vector3.x, vector3.y, vector3.z); + return new _a(vector3.x, vector3.y, vector3.z); } /** * @remarks @@ -176,7 +176,7 @@ export class Vector { * @returns {Vector} */ static multiply(a, b) { - const vector = new Vector(a.x, a.y, a.z); + const vector = new _a(a.x, a.y, a.z); if (typeof b === "number") { vector.x *= b; vector.y *= b; @@ -210,7 +210,7 @@ export class Vector { const θ = Math.acos(MathDot([a.x, a.y, a.z], [b.x, b.y, b.z])); const factor1 = Math.sin(θ * (1 - s)) / Math.sin(θ); const factor2 = Math.sin(θ * s) / Math.sin(θ); - return new Vector(a.x * factor1 + b.x * factor2, a.y * factor1 + b.y * factor2, a.z * factor1 + b.z * factor2); + return new _a(a.x * factor1 + b.x * factor2, a.y * factor1 + b.y * factor2, a.z * factor1 + b.z * factor2); } /** * @remarks @@ -220,7 +220,7 @@ export class Vector { * @returns {Vector} */ static subtract(a, b) { - const vector = new Vector(a.x, a.y, a.z); + const vector = new _a(a.x, a.y, a.z); vector.x -= b.x; vector.y -= b.y; vector.z -= b.z; diff --git a/tools/headerChecks.ts b/tools/headerChecks.ts index fd28a4a7..18eaccd3 100644 --- a/tools/headerChecks.ts +++ b/tools/headerChecks.ts @@ -114,11 +114,11 @@ function printMessages (messages: string[], packagesHaveError: number) { // main entry export function execute () { const results = checkScripts(); - const results2 = checkEditorExtensions(); - const statusCode = results.packagesHaveError + results2.packagesHaveError > 0 ? 1 : 0; + // const results2 = checkEditorExtensions(); + const statusCode = results.packagesHaveError > 0 ? 1 : 0; printMessages(results.errorMessages, results.packagesHaveError); - printMessages(results2.errorMessages, results2.packagesHaveError); + // printMessages(results2.errorMessages, results2.packagesHaveError); console.log('Exit task with code', statusCode); return statusCode; diff --git a/tools/utils.ts b/tools/utils.ts index 12442f42..0d3f510d 100644 --- a/tools/utils.ts +++ b/tools/utils.ts @@ -8,8 +8,11 @@ export const scriptsPath = path.resolve(process.cwd(), 'scripts'); // readdirSyn export const scriptsAll = fs.readdirSync(scriptsPath).filter(file => fs.statSync(path.resolve(scriptsPath, file)).isDirectory()); export const scripts = scriptsAll.filter(script => !legacyPackages.packages.includes(script)); -export const editorExtensionsPath = path.resolve(process.cwd(), 'editorExtensions'); // readdirSync(path.resolve(cwd, 'scripts')).map(name => name.replaceAll(path.win32.sep, path.posix.sep)); -export const editorExtensions = fs.readdirSync(editorExtensionsPath).filter(file => fs.statSync(path.resolve(editorExtensionsPath, file)).isDirectory()); +// export const editorExtensionsPath = path.resolve(process.cwd(), 'editorExtensions'); // readdirSync(path.resolve(cwd, 'scripts')).map(name => name.replaceAll(path.win32.sep, path.posix.sep)); +// export const editorExtensions = fs.readdirSync(editorExtensionsPath).filter(file => fs.statSync(path.resolve(editorExtensionsPath, file)).isDirectory()); + +export const editorExtensionsPath = path.resolve(process.cwd(), 'editorExtensions'); +export const editorExtensions: string[] = []; export const mainFilenames = ["index.ts", "index.js"]; export const readmeFilenames = ["readme.md", "readme.txt", "readme"]; diff --git a/tsconfig.json b/tsconfig.json index 47a37bce..c870cafe 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -4,8 +4,6 @@ "references": [ { "path": "tools/tsconfig.json" }, { "path": "scripts/tsconfig.json" }, - { "path": "scripts/jsconfig.json" }, - { "path": "editorExtensions/tsconfig.json" }, - { "path": "editorExtensions/jsconfig.json" } + { "path": "scripts/jsconfig.json" } ] } \ No newline at end of file