diff --git a/README.md b/README.md index 792595af..bed39eec 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,9 @@ Builds the web app for production to the `build` folder. It correctly bundles Re ## Sample Command Lines -Once packaged, you can install the command line locally via `npx mctools-.tgz`. Some sample command lines: +Once packaged, you can install the command line locally via `npm install minecraft-creator-tools-.tgz`. If you'd like to make Minecraft Creator Tools available across your device, you can install it globally via `npm install -g minecraft-creator-tools-.tgz`. + +Some sample command lines: `npx mct` @@ -81,6 +83,14 @@ Loads the project folder `d:\mycontent\myprojectfolder`, validates using the 'ad Loads the project file `d:\mycontent\packages\myaddon.mcaddon`, validates using the 'addon' suite of strict tests and shows validation results on the command line. Also displays verbose logging messages. + +### New project creation + +`npx mct create` + +Asks a series of questions and creates a new project based on those preferences. + + ## Trademarks This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft trademarks or logos is subject to and must follow [Microsoft's Trademark & Brand Guidelines](https://www.microsoft.com/legal/intellectualproperty/trademarks/usage/general). Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship. Any use of third-party trademarks or logos are subject to those third-party’s policies. diff --git a/app/.vscode/launch.json b/app/.vscode/launch.json index 7c67429a..27765d1b 100644 --- a/app/.vscode/launch.json +++ b/app/.vscode/launch.json @@ -8,6 +8,48 @@ "url": "http://localhost:3000", "webRoot": "${workspaceFolder}" }, + { + "name": "cli (add)", + "cwd": "${workspaceRoot}/debugoutput/minecraft-gametests/", + "args": ["add", "-i", "../temp/test"], + "type": "node", + "request": "launch", + "program": "${workspaceRoot}/src/cli/index.ts", + "preLaunchTask": "gulp: jsncorebuild", + "sourceMaps":true, + "runtimeExecutable": null, + "localRoot": "${workspaceRoot}/src", + "runtimeArgs": ["--nolazy"], + "outFiles": ["${workspaceFolder}/toolbuild/jsn/**/*.js"] + }, + { + "name": "cli (info)", + "cwd": "${workspaceRoot}/debugoutput/gtbasicworld/", + "args": ["info"], + "type": "node", + "request": "launch", + "program": "${workspaceRoot}/src/cli/index.ts", + "preLaunchTask": "gulp: jsncorebuild", + "sourceMaps": true, + "runtimeExecutable": null, + "localRoot": "${workspaceRoot}/src", + "runtimeArgs": ["--nolazy"], + "outFiles": ["${workspaceFolder}/toolbuild/jsn/**/*.js"] + }, + { + "name": "cli (world)", + "cwd": "${workspaceRoot}/debugoutput/", + "args": ["world", "set", "-betaapis", "-o", "./worldtest/"], + "type": "node", + "request": "launch", + "program": "${workspaceRoot}/src/cli/index.ts", + "preLaunchTask": "gulp: jsncorebuild", + "sourceMaps": true, + "runtimeExecutable": null, + "localRoot": "${workspaceRoot}/src", + "runtimeArgs": ["--nolazy"], + "outFiles": ["${workspaceFolder}/toolbuild/jsn/**/*.js"] + }, { "name": "cli (val content1)", "cwd": "${workspaceRoot}/../samplecontent/addon/build/content1/", @@ -78,6 +120,20 @@ "runtimeArgs": ["--nolazy", "--max-old-space-size=32768"], "outFiles": ["${workspaceFolder}/toolbuild/jsn/**/*.js"] }, + { + "name": "cli (create)", + "cwd": "${workspaceRoot}/debugoutput/start/", + "args": ["create", "-i", "test", "custom_name", "addonStarter", "custom_creator", "florid description"], + "type": "node", + "request": "launch", + "program": "${workspaceRoot}/src/cli/index.ts", + "preLaunchTask": "gulp: jsncorebuild", + "sourceMaps":true, + "runtimeExecutable": null, + "localRoot": "${workspaceRoot}/src", + "runtimeArgs": ["--nolazy"], + "outFiles": ["${workspaceFolder}/toolbuild/jsn/**/*.js"] + }, { "type": "node", "request": "launch", diff --git a/app/gulpfile.js b/app/gulpfile.js index dd818779..a6719e82 100644 --- a/app/gulpfile.js +++ b/app/gulpfile.js @@ -248,16 +248,10 @@ function runUpdateVersions() { return gulp .src(versionSource, { base: "" }) .pipe( - updateVersions([ - "./package.json", - "./package-lock.json", - "./jsnode/package.json", - "./src/core/Constants.ts", - ]) + updateVersions(["./package.json", "./package-lock.json", "./jsnode/package.json", "./src/core/Constants.ts"]) ); } - function runDownloadSamples() { return gulp.src(mcreslistsamplesigs, { base: "" }).pipe(downloadResources("public/res/samples/microsoft/")); } @@ -277,7 +271,7 @@ function runDownloadVanillaResources() { gulp.task("jsnwebbuild", gulp.series("clean-jsnwebbuild", compileJsnWebBuild, "postclean-jsnwebbuild")); gulp.task("clean-webbuild", function () { - return del(["web"]); + return del(["out/web"]); }); gulp.task("clean-res", function () { diff --git a/app/public/data/gallery.json b/app/public/data/gallery.json index 5c8e3e2a..499ce8c3 100644 --- a/app/public/data/gallery.json +++ b/app/public/data/gallery.json @@ -155,119 +155,6 @@ "id": "fishBowlBlock", "type": 2 }, - { - "title": "Camera Grapple", - "gitHubOwner": "microsoft", - "gitHubRepoName": "minecraft-scripting-samples", - "gitHubFolder": "/editor-script-box", - "localLogo": "blocks/camera_front.png", - "id": "CameraGrapple.ts", - "codeLineStart": 18, - "tags": ["editor"], - "type": 5 - }, - { - "title": "Star Brush Shape", - "gitHubOwner": "microsoft", - "gitHubRepoName": "minecraft-scripting-samples", - "gitHubFolder": "/editor-script-box", - "localLogo": "items/nether_star.png", - "id": "StarBrushShape.ts", - "codeLineStart": 15, - "type": 5 - }, - { - "title": "Dye Brush", - "gitHubOwner": "microsoft", - "gitHubRepoName": "minecraft-scripting-samples", - "gitHubFolder": "/editor-script-box", - "localLogo": "items/dye_powder_red.png", - "id": "DyeBrush.ts", - "codeLineStart": 117, - "type": 5 - }, - { - "title": "Farm Generator", - "gitHubOwner": "microsoft", - "gitHubRepoName": "minecraft-scripting-samples", - "gitHubFolder": "/editor-script-box", - "localLogo": "blocks/farmland_wet.png", - "id": "FarmGenerator.ts", - "codeLineStart": 43, - "type": 5 - }, - { - "title": "Go to Mark", - "gitHubOwner": "microsoft", - "gitHubRepoName": "minecraft-scripting-samples", - "gitHubFolder": "/editor-script-box", - "localLogo": "blocks/cut_copper.png", - "id": "GotoMark.ts", - "codeLineStart": 100, - "type": 5 - }, - { - "title": "Portal Generator", - "gitHubOwner": "microsoft", - "gitHubRepoName": "minecraft-scripting-samples", - "gitHubFolder": "/editor-script-box", - "localLogo": "blocks/cut_copper.png", - "id": "PortalGenerator.ts", - "codeLineStart": 322, - "type": 5 - }, - { - "title": "Simple Tool", - "gitHubOwner": "microsoft", - "gitHubRepoName": "minecraft-scripting-samples", - "gitHubFolder": "/editor-script-box", - "localLogo": "blocks/cut_copper.png", - "id": "SimpleTool.ts", - "codeLineStart": 108, - "type": 5 - }, - { - "title": "Locate Biome", - "gitHubOwner": "microsoft", - "gitHubRepoName": "minecraft-scripting-samples", - "gitHubFolder": "/editor-script-box", - "localLogo": "blocks/cut_copper.png", - "id": "LocateBiome.ts", - "codeLineStart": 94, - "type": 5 - }, - { - "title": "Tree Generator", - "gitHubOwner": "microsoft", - "gitHubRepoName": "minecraft-scripting-samples", - "gitHubFolder": "/editor-script-box", - "localLogo": "blocks/cut_copper.png", - "id": "TreeGenerator.ts", - "codeLineStart": 43, - "type": 5 - }, - { - "title": "Starter Hello World GameTest", - "description": "A simple introduction to creating GameTests. See the tutorial at https://aka.ms/newgametest.", - "gitHubOwner": "microsoft", - "gitHubRepoName": "minecraft-gametests", - "gitHubFolder": "/starterTestsTutorial", - "logoImage": "behavior_packs/starterTestsTutorial/pack_icon.png", - "id": "helloWorldGameTest", - "tags": ["gametest"], - "type": 0 - }, - { - "title": "Basic GameTests", - "description": "A collection of GameTests focused on exploring different facets of Mob Behavior.", - "gitHubOwner": "microsoft", - "gitHubRepoName": "minecraft-gametests", - "gitHubFolder": "/js-gametests", - "logoImage": "behavior_packs/JsGameTests/pack_icon.png", - "id": "mobGameTest", - "tags": ["gametest"], - "type": 0 - }, { "title": "Create Explosion", "gitHubOwner": "microsoft", @@ -665,6 +552,116 @@ "/resource_pack/textures/entity/wolf/wolf_angry.png", "/resource_pack/textures/entity/wolf/wolf_tame.tga" ] + }, + { + "title": "Camera Grapple", + "gitHubOwner": "microsoft", + "gitHubRepoName": "minecraft-scripting-samples", + "gitHubFolder": "/editor-script-box", + "localLogo": "blocks/camera_front.png", + "id": "camera-grapple.ts", + "codeLineStart": 19, + "tags": ["editor"], + "type": 5 + }, + { + "title": "Star Shape Brush", + "gitHubOwner": "microsoft", + "gitHubRepoName": "minecraft-scripting-samples", + "gitHubFolder": "/editor-script-box", + "localLogo": "items/nether_star.png", + "id": "star-brush-shape.ts", + "codeLineStart": 15, + "tags": ["editor"], + "type": 5 + }, + { + "title": "Dye Brush", + "gitHubOwner": "microsoft", + "gitHubRepoName": "minecraft-scripting-samples", + "gitHubFolder": "/editor-script-box", + "localLogo": "items/dye_powder_red.png", + "id": "dye-brush.ts", + "codeLineStart": 117, + "tags": ["editor"], + "type": 5 + }, + { + "title": "Farm Generator", + "gitHubOwner": "microsoft", + "gitHubRepoName": "minecraft-scripting-samples", + "gitHubFolder": "/editor-script-box", + "localLogo": "blocks/farmland_wet.png", + "id": "farm-generator.ts", + "codeLineStart": 43, + "tags": ["editor"], + "type": 5 + }, + { + "title": "Go to Mark", + "gitHubOwner": "microsoft", + "gitHubRepoName": "minecraft-scripting-samples", + "gitHubFolder": "/editor-script-box", + "localLogo": "blocks/cut_copper.png", + "id": "goto-mark.ts", + "codeLineStart": 100, + "tags": ["editor"], + "type": 5 + }, + { + "title": "Portal Generator", + "gitHubOwner": "microsoft", + "gitHubRepoName": "minecraft-scripting-samples", + "gitHubFolder": "/editor-script-box", + "localLogo": "blocks/cut_copper.png", + "id": "portal-generator.ts", + "codeLineStart": 322, + "tags": ["editor"], + "type": 5 + }, + { + "title": "Locate Biome", + "gitHubOwner": "microsoft", + "gitHubRepoName": "minecraft-scripting-samples", + "gitHubFolder": "/editor-script-box", + "localLogo": "blocks/cut_copper.png", + "id": "locate-biome.ts", + "codeLineStart": 94, + "tags": ["editor"], + "type": 5 + }, + { + "title": "Tree Generator", + "gitHubOwner": "microsoft", + "gitHubRepoName": "minecraft-scripting-samples", + "gitHubFolder": "/editor-script-box", + "localLogo": "blocks/cut_copper.png", + "id": "tree-generator.ts", + "codeLineStart": 43, + "tags": ["editor"], + "type": 5 + }, + { + "title": "Starter GameTest", + "description": "A simple introduction to creating GameTests. See the tutorial at https://aka.ms/newgametest.", + "gitHubOwner": "microsoft", + "gitHubRepoName": "minecraft-gametests", + "gitHubFolder": "/starterTestsTutorial", + "logoImage": "behavior_packs/starterTestsTutorial/pack_icon.png", + "id": "helloWorldGameTest", + "tags": ["gametest"], + "type": 0 + }, + { + "title": "Basic GameTests", + "description": "A collection of GameTests focused on exploring different facets of Mob Behavior.", + "gitHubOwner": "microsoft", + "gitHubRepoName": "minecraft-gametests", + "gitHubFolder": "/js-gametests", + "logoImage": "behavior_packs/JsGameTests/pack_icon.png", + "id": "mobGameTest", + "tags": ["gametest"], + "type": 0 } ] } diff --git a/app/public/data/snippets/editor-samples.json b/app/public/data/snippets/editor-samples.json new file mode 100644 index 00000000..29a84580 --- /dev/null +++ b/app/public/data/snippets/editor-samples.json @@ -0,0 +1,2589 @@ +{ + "camera-grapple.ts": { + "description": "camera-grapple.ts ", + "prefix": ["mc"], + "body": [ + "// Copyright (c) Mojang AB. All rights reserved.", + "import { Vector3Utils } from '@minecraft/math';", + "import {", + " ActionTypes,", + " CursorControlMode,", + " EditorInputContext,", + " IPlayerUISession,", + " KeyboardKey,", + " registerEditorExtension,", + "} from '@minecraft/server-editor';", + "import { EasingType, TicksPerSecond, Vector3, system } from '@minecraft/server';", + "interface GrappleStorage {", + " latestRunId?: number;", + "}", + "type GrappleSession = IPlayerUISession;", + "function flyCameraToTarget(uiSession: GrappleSession, viewTarget: Vector3, radius: number) {", + " if (uiSession.scratchStorage) {", + " const player = uiSession.extensionContext.player;", + " // This is imperfect and causes a visible pop. Would be better if we could get the player's exact eye height", + " const eyeHeight = Vector3Utils.subtract(player.getHeadLocation(), player.location);", + " const viewVector = player.getViewDirection();", + " radius = Math.max(radius, 1);", + " // FOV in first_person.json is 66 degrees", + " const halfFOV = 66 / 2;", + " // Compute adjacent side of triangle (distance) when opposite side is radius", + " const distanceAway = radius / Math.tan((halfFOV * Math.PI) / 180);", + " const destCameraLocation = Vector3Utils.subtract(viewTarget, Vector3Utils.scale(viewVector, distanceAway));", + " const destPlayerLocation = Vector3Utils.subtract(destCameraLocation, eyeHeight);", + " const easeTimeInSeconds = 1.5;", + " // Unhook camera and have it start moving to the new location", + " player.camera.setCamera('minecraft:free', {", + " rotation: { x: player.getRotation().x, y: player.getRotation().y },", + " location: { x: destCameraLocation.x, y: destCameraLocation.y, z: destCameraLocation.z },", + " easeOptions: {", + " easeTime: easeTimeInSeconds,", + " easeType: EasingType.InOutQuad,", + " },", + " });", + " uiSession.scratchStorage.latestRunId = system.runTimeout(() => {", + " // Move the player to the final location and re-hook the camera to it", + " player.teleport(destPlayerLocation);", + " player.camera.clear();", + " }, easeTimeInSeconds * TicksPerSecond);", + " }", + "}", + "/**", + " * Provides a 'Grapple' extension for quickly moving the player around the world", + " * @beta", + " */", + "export function registerCameraGrapple() {", + " registerEditorExtension(", + " 'camera-grapple-sample',", + " (uiSession: GrappleSession) => {", + " uiSession.log.debug(`Initializing extension [${uiSession.extensionContext.extensionInfo.name}]`);", + " const grappleAction = uiSession.actionManager.createAction({", + " actionType: ActionTypes.NoArgsAction,", + " onExecute: () => {", + " // don't execute if there is already a command running as this can be visually disorienting", + " if (uiSession.scratchStorage?.latestRunId) {", + " return;", + " }", + " let destBlockLoc: Vector3 | undefined = undefined;", + " const cursor = uiSession.extensionContext.cursor;", + " // Fixed cursor mode will default to the player view direction", + " if (cursor.isVisible && cursor.getProperties().controlMode !== CursorControlMode.Fixed) {", + " destBlockLoc = cursor.getPosition();", + " } else {", + " const result = uiSession.extensionContext.player.getBlockFromViewDirection();", + " if (!result) {", + " uiSession.log.warning('No Block Found. Aborting Grapple');", + " return;", + " }", + " destBlockLoc = result?.block.location;", + " }", + " // Location of the center of the block", + " const viewTarget = Vector3Utils.add(destBlockLoc, { x: 0.5, y: 0.5, z: 0.5 });", + " flyCameraToTarget(uiSession, viewTarget, 2);", + " },", + " });", + " const frameAction = uiSession.actionManager.createAction({", + " actionType: ActionTypes.NoArgsAction,", + " onExecute: () => {", + " // don't execute if there is already a command running as this can be visually disorienting", + " if (uiSession.scratchStorage?.latestRunId) {", + " return;", + " }", + " const selection = uiSession.extensionContext.selectionManager.selection;", + " if (selection.isEmpty) {", + " return;", + " }", + " const bounds = selection.getBoundingBox();", + " bounds.max = Vector3Utils.add(bounds.max, { x: 1, y: 1, z: 1 });", + " const halfSize = Vector3Utils.scale(Vector3Utils.subtract(bounds.max, bounds.min), 0.5);", + " const viewTarget = Vector3Utils.add(bounds.min, halfSize);", + " const radius = Math.sqrt(", + " halfSize.x * halfSize.x + halfSize.y * halfSize.y + halfSize.z * halfSize.z", + " );", + " flyCameraToTarget(uiSession, viewTarget, radius);", + " },", + " });", + " uiSession.inputManager.registerKeyBinding(", + " EditorInputContext.GlobalToolMode,", + " grappleAction,", + " { key: KeyboardKey.KEY_G },", + " {", + " uniqueId: 'editorSamples:grapple:flyToCursor',", + " label: 'sample.cameragrapple.keyBinding.flyToCursor',", + " }", + " );", + " uiSession.inputManager.registerKeyBinding(", + " EditorInputContext.GlobalToolMode,", + " frameAction,", + " { key: KeyboardKey.KEY_F },", + " {", + " uniqueId: 'editorSamples:grapple:flyToSelection',", + " label: 'sample.cameragrapple.keyBinding.flyToSelection',", + " }", + " );", + " return [];", + " },", + " (uiSession: GrappleSession) => {", + " uiSession.log.debug(", + " `Shutting down extension [${uiSession.extensionContext.extensionInfo.name}] for player [${uiSession.extensionContext.player.name}]`", + " );", + " if (uiSession.scratchStorage?.latestRunId) {", + " system.clearRun(uiSession.scratchStorage.latestRunId);", + " uiSession.scratchStorage.latestRunId = undefined;", + " }", + " },", + " {", + " description: 'Camera Grapple Sample Extension',", + " notes: 'by Jonas',", + " }", + " );", + "}", + "" + ] + }, + "dye-brush.ts": { + "description": "dye-brush.ts ", + "prefix": ["mc"], + "body": [ + "// Copyright (c) Mojang AB. All rights reserved.", + "import {", + " ActionTypes,", + " ColorPickerPropertyItemVariant,", + " CursorTargetMode,", + " IDropdownItem,", + " IModalTool,", + " IObservable,", + " IPlayerUISession,", + " makeObservable,", + " ModalToolLifecycleEventPayload,", + " MouseActionType,", + " MouseInputType,", + " MouseProps,", + " registerEditorExtension,", + " Selection,", + "} from '@minecraft/server-editor';", + "import {", + " BlockVolume,", + " BoundingBox,", + " BoundingBoxUtils,", + " RGBA,", + " CompoundBlockVolumeAction,", + " Dimension,", + " Direction,", + " EntityColorComponent,", + " Player,", + " Vector3,", + " RGB,", + "} from '@minecraft/server';", + "import { Vector3Utils, VECTOR3_UP } from '@minecraft/math';", + "// Color identifiers expected by EntityColorComponent", + "enum EntityColor {", + " White = 0,", + " Orange = 1,", + " Magenta = 2,", + " LightBlue = 3,", + " Yellow = 4,", + " LightGreen = 5,", + " Pink = 6,", + " Gray = 7,", + " Silver = 8,", + " Cyan = 9,", + " Purple = 10,", + " Blue = 11,", + " Brown = 12,", + " Green = 13,", + " Red = 14,", + " Black = 15,", + "}", + "const directionLookup: Record = {", + " [Direction.North]: { x: 0, y: 0, z: 1 },", + " [Direction.East]: { x: -1, y: 0, z: 0 },", + " [Direction.South]: { x: 0, y: 0, z: -1 },", + " [Direction.West]: { x: 1, y: 0, z: 0 },", + " [Direction.Up]: { x: 0, y: 1, z: 0 },", + " [Direction.Down]: { x: 0, y: -1, z: 0 },", + "};", + "const directionToQuadrant: Record = {", + " [Direction.North]: 0,", + " [Direction.East]: 1,", + " [Direction.South]: 2,", + " [Direction.West]: 3,", + " [Direction.Up]: 4,", + " [Direction.Down]: 5,", + "};", + "const quadrantToDirection: Record = {", + " [0]: Direction.North,", + " [1]: Direction.East,", + " [2]: Direction.South,", + " [3]: Direction.West,", + " [4]: Direction.Up,", + " [5]: Direction.Down,", + "};", + "export function getRotationCorrectedDirection(rotationY: number, realDirection: Direction): Direction {", + " if (realDirection === Direction.Up || realDirection === Direction.Down) {", + " return realDirection;", + " }", + " const quadrant = directionToQuadrant[realDirection];", + " const rotatedQuadrant = Math.floor(((rotationY + 405 + quadrant * 90) % 360) / 90);", + " const rotatedDirection = quadrantToDirection[rotatedQuadrant];", + " return rotatedDirection;", + "}", + "export function getRotationCorrectedDirectionVector(rotationY: number, realDirection: Direction): Vector3 {", + " const relativeDirection = getRotationCorrectedDirection(rotationY, realDirection);", + " return directionLookup[relativeDirection];", + "}", + "// Calculate nearest entity color to an RGBA color", + "function findClosestColor(targetColor: RGBA, colorPalette: Map): EntityColor {", + " let minDistance = Number.MAX_VALUE;", + " let closestColor: EntityColor = EntityColor.White;", + " colorPalette.forEach((paletteColor, color) => {", + " const distance = Math.sqrt(", + " Math.pow(targetColor.red - paletteColor.red, 2) +", + " Math.pow(targetColor.green - paletteColor.green, 2) +", + " Math.pow(targetColor.blue - paletteColor.blue, 2)", + " );", + " if (distance < minDistance) {", + " minDistance = distance;", + " closestColor = color;", + " }", + " });", + " return closestColor;", + "}", + "const colorPalette = new Map([", + " [EntityColor.White, { red: 1, green: 1, blue: 1 }],", + " [EntityColor.Orange, { red: 0.95, green: 0.459, blue: 0 }],", + " [EntityColor.Magenta, { red: 0.94, green: 0, blue: 0.9 }],", + " [EntityColor.LightBlue, { red: 0, green: 0.85, blue: 0.95 }],", + " [EntityColor.Yellow, { red: 0.85, green: 0.95, blue: 0 }],", + " [EntityColor.LightGreen, { red: 0, green: 0.95, blue: 0.6 }],", + " [EntityColor.Pink, { red: 0.9, green: 0.65, blue: 0.85 }],", + " [EntityColor.Gray, { red: 0.6, green: 0.6, blue: 0.6 }],", + " [EntityColor.Silver, { red: 0.75, green: 0.75, blue: 0.75 }],", + " [EntityColor.Cyan, { red: 0, green: 0.9, blue: 0.9 }],", + " [EntityColor.Purple, { red: 0.45, green: 0, blue: 0.9 }],", + " [EntityColor.Blue, { red: 0, green: 0, blue: 1 }],", + " [EntityColor.Brown, { red: 0.8, green: 0.5, blue: 0.1 }],", + " [EntityColor.Green, { red: 0, green: 1, blue: 0 }],", + " [EntityColor.Red, { red: 1, green: 0, blue: 0 }],", + " [EntityColor.Black, { red: 0, green: 0, blue: 0 }],", + "]);", + "interface DyeBrushStorage {", + " previewSelection: Selection;", + " lastVolumePlaced?: BoundingBox;", + " currentColor: EntityColor;", + " brushColor: IObservable;", + " brushSize: number;", + "}", + "type DyeBrushSession = IPlayerUISession;", + "function onColorUpdated(newColor: RGBA, uiSession: DyeBrushSession) {", + " if (uiSession.scratchStorage) {", + " uiSession.scratchStorage.previewSelection.setFillColor(newColor);", + " uiSession.scratchStorage.previewSelection.setOutlineColor({ ...newColor, alpha: 1 });", + " const cursorProps = uiSession.extensionContext.cursor.getProperties();", + " cursorProps.outlineColor = { ...newColor, alpha: 1 };", + " cursorProps.targetMode = CursorTargetMode.Face;", + " uiSession.extensionContext.cursor.setProperties(cursorProps);", + " }", + "}", + "function addDyeBrushPane(uiSession: DyeBrushSession, tool: IModalTool) {", + " if (!uiSession.scratchStorage) {", + " throw Error('UI Session storage should exist');", + " }", + " const brushColor = uiSession.scratchStorage.brushColor;", + " const brushSize = uiSession.scratchStorage.brushSize;", + " const pane = uiSession.createPropertyPane({", + " title: 'sample.dyeBrush.pane.title',", + " });", + " const entityBrush = makeObservable(EntityColor.White);", + " onColorUpdated(brushColor.value, uiSession);", + " pane.addDropdown(entityBrush, {", + " title: 'Brush',", + " entries: Object.values(EntityColor).reduce((list, dye, index) => {", + " if (typeof dye === 'string') {", + " list.push({", + " label: dye,", + " value: index,", + " });", + " }", + " return list;", + " }, []),", + " onChange: (newVal: number) => {", + " if (newVal in EntityColor) {", + " const foundColor = colorPalette.get(newVal);", + " if (foundColor) {", + " brushColor.set({ ...foundColor, alpha: brushColor.value.alpha });", + " }", + " onColorUpdated(brushColor.value, uiSession);", + " }", + " },", + " });", + " pane.addColorPicker(brushColor, {", + " variant: ColorPickerPropertyItemVariant.Expanded,", + " onChange: (color: RGBA) => {", + " entityBrush.set(findClosestColor(color, colorPalette));", + " onColorUpdated(brushColor.value, uiSession);", + " },", + " });", + " tool.bindPropertyPane(pane);", + " const onExecuteBrush = () => {", + " if (uiSession.scratchStorage === undefined) {", + " uiSession.log.error('Storage was not initialized.');", + " return;", + " }", + " const previewSelection = uiSession.scratchStorage.previewSelection;", + " const player = uiSession.extensionContext.player;", + " const targetBlock = player.dimension.getBlock(uiSession.extensionContext.cursor.getPosition());", + " if (targetBlock === undefined) {", + " return;", + " }", + " const rotationY = uiSession.extensionContext.player.getRotation().y;", + " const directionRight = getRotationCorrectedDirectionVector(rotationY, Direction.East);", + " const directionForward = getRotationCorrectedDirectionVector(rotationY, Direction.South);", + " const relativeDirection = Vector3Utils.add(Vector3Utils.add(directionRight, directionForward), VECTOR3_UP);", + " const sizeHalf = Math.floor(brushSize / 2);", + " let fromOffset = Vector3Utils.scale(relativeDirection, -sizeHalf);", + " const toOffset = Vector3Utils.scale(relativeDirection, brushSize - 1);", + " const isEven = brushSize % 2 === 0;", + " if (isEven) {", + " fromOffset = Vector3Utils.add(fromOffset, VECTOR3_UP);", + " }", + " const location = targetBlock.location;", + " const from: Vector3 = {", + " x: location.x + fromOffset.x,", + " y: location.y + fromOffset.y,", + " z: location.z + fromOffset.z,", + " };", + " const to: Vector3 = { x: from.x + toOffset.x, y: from.y + toOffset.y, z: from.z + toOffset.z };", + " const blockVolume = new BlockVolume(from, to);", + " const bounds = blockVolume.getBoundingBox();", + " if (uiSession.scratchStorage.lastVolumePlaced) {", + " if (BoundingBoxUtils.equals(uiSession.scratchStorage.lastVolumePlaced, bounds)) {", + " return;", + " }", + " }", + " previewSelection.pushVolume({ action: CompoundBlockVolumeAction.Add, volume: blockVolume });", + " uiSession.scratchStorage.lastVolumePlaced = bounds;", + " };", + " const mouseButtonAction = uiSession.actionManager.createAction({", + " actionType: ActionTypes.MouseRayCastAction,", + " onExecute: (_, mouseProps: MouseProps) => {", + " if (uiSession.scratchStorage === undefined) {", + " uiSession.log.error('Storage was not initialized.');", + " return;", + " }", + " if (mouseProps.mouseAction === MouseActionType.LeftButton) {", + " if (mouseProps.inputType === MouseInputType.ButtonDown) {", + " uiSession.scratchStorage.previewSelection.clear();", + " onExecuteBrush();", + " } else if (mouseProps.inputType === MouseInputType.ButtonUp) {", + " const player: Player = uiSession.extensionContext.player;", + " const dimension: Dimension = player.dimension;", + " const iterator = uiSession.scratchStorage.previewSelection.getBlockLocationIterator();", + " for (const pos of iterator) {", + " const entities = dimension.getEntities({ location: pos, closest: 1 });", + " for (const entity of entities) {", + " const colorComp = entity.getComponent('minecraft:color') as EntityColorComponent;", + " if (colorComp) {", + " colorComp.value = entityBrush.value;", + " }", + " }", + " }", + " uiSession.scratchStorage.previewSelection.clear();", + " }", + " }", + " },", + " });", + " tool.registerMouseButtonBinding(mouseButtonAction);", + " const executeBrushRayAction = uiSession.actionManager.createAction({", + " actionType: ActionTypes.MouseRayCastAction,", + " onExecute: (_, mouseProps: MouseProps) => {", + " if (mouseProps.inputType === MouseInputType.Drag) {", + " onExecuteBrush();", + " }", + " },", + " });", + " tool.registerMouseDragBinding(executeBrushRayAction);", + " // Example for adding mouse wheel", + " const executeBrushSizeAction = uiSession.actionManager.createAction({", + " actionType: ActionTypes.MouseRayCastAction,", + " onExecute: (_, mouseProps: MouseProps) => {", + " if (mouseProps.mouseAction === MouseActionType.Wheel) {", + " if (mouseProps.inputType === MouseInputType.WheelOut) {", + " if (entityBrush.value > 0) {", + " entityBrush.set(entityBrush.value - 1);", + " }", + " } else if (mouseProps.inputType === MouseInputType.WheelIn) {", + " if (entityBrush.value < 15) {", + " entityBrush.set(entityBrush.value + 1);", + " }", + " }", + " onColorUpdated(brushColor.value, uiSession);", + " }", + " },", + " });", + " tool.registerMouseWheelBinding(executeBrushSizeAction);", + " tool.onModalToolActivation.subscribe((evt: ModalToolLifecycleEventPayload) => {", + " if (evt.isActiveTool) {", + " onColorUpdated(brushColor.value, uiSession);", + " }", + " uiSession.scratchStorage?.previewSelection?.clear();", + " });", + " pane.hide();", + "}", + "export function addDyeBrushTool(uiSession: DyeBrushSession) {", + " const tool = uiSession.toolRail.addTool({", + " title: 'sample.dyebrush.tool.title',", + " tooltip: 'sample.dyebrush.tool.tooltip',", + " icon: 'pack://textures/dye-brush.png',", + " });", + " return tool;", + "}", + "export function registerDyeBrushExtension() {", + " registerEditorExtension(", + " 'dye-brush-sample',", + " (uiSession: IPlayerUISession) => {", + " uiSession.log.debug(`Initializing extension [${uiSession.extensionContext.extensionInfo.name}]`);", + " const previewSelection = uiSession.extensionContext.selectionManager.create();", + " previewSelection.visible = true;", + " const storage: DyeBrushStorage = {", + " previewSelection: previewSelection,", + " currentColor: EntityColor.White,", + " brushColor: makeObservable({ red: 1, green: 1, blue: 1, alpha: 0.5 }),", + " brushSize: 4,", + " };", + " uiSession.scratchStorage = storage;", + " const cubeBrushTool = addDyeBrushTool(uiSession);", + " addDyeBrushPane(uiSession, cubeBrushTool);", + " return [];", + " },", + " (uiSession: IPlayerUISession) => {", + " uiSession.log.debug(`Shutting down extension [${uiSession.extensionContext.extensionInfo.name}] `);", + " },", + " {", + " description: 'Dye Brush Sample Extension',", + " notes: 'By Eser',", + " }", + " );", + "}", + "" + ] + }, + "farm-generator.ts": { + "description": "farm-generator.ts ", + "prefix": ["mc"], + "body": [ + "// Copyright (c) Mojang AB. All rights reserved.", + "import { VECTOR3_ZERO } from '@minecraft/math';", + "import {", + " ActionTypes,", + " EditorInputContext,", + " IModalTool,", + " IObservable,", + " IPlayerUISession,", + " InputModifier,", + " KeyboardKey,", + " MouseActionType,", + " MouseInputType,", + " MouseProps,", + " Ray,", + " makeObservable,", + " registerEditorExtension,", + "} from '@minecraft/server-editor';", + "import { Player, Vector3 } from '@minecraft/server';", + "import { MinecraftBlockTypes, MinecraftEntityTypes } from '@minecraft/vanilla-data';", + "type CommonSettingsType = {", + " farmWidth: IObservable;", + " farmLength: IObservable;", + " irrigation: IObservable;", + " fenceType: IObservable;", + "};", + "type CropSettingsType = {", + " wheat: IObservable;", + " pumpkin: IObservable;", + " potato: IObservable;", + " carrot: IObservable;", + " beetroot: IObservable;", + "};", + "type AnimalSettingsType = {", + " pig: IObservable;", + " sheep: IObservable;", + " cow: IObservable;", + "};", + "function getRandomInt(upper: number) {", + " return Math.floor(Math.random() * (upper + 1));", + "}", + "function fenceTypeToBlockType(fenceType: number): string {", + " switch (fenceType) {", + " case 0:", + " return MinecraftBlockTypes.OakFence;", + " case 1:", + " return MinecraftBlockTypes.BirchFence;", + " case 2:", + " return MinecraftBlockTypes.AcaciaFence;", + " case 3:", + " return MinecraftBlockTypes.BambooFence;", + " case 4:", + " return MinecraftBlockTypes.CherryFence;", + " case 5:", + " return MinecraftBlockTypes.JungleFence;", + " case 6:", + " return MinecraftBlockTypes.SpruceFence;", + " case 7:", + " return MinecraftBlockTypes.WarpedFence;", + " case 8:", + " return MinecraftBlockTypes.CrimsonFence;", + " default:", + " return MinecraftBlockTypes.OakFence;", + " }", + "}", + "const buildFarm = (", + " targetCorner: Vector3,", + " x: number,", + " z: number,", + " length: number,", + " width: number,", + " possibleAnimals: MinecraftEntityTypes[],", + " possibleCrops: string[],", + " player: Player,", + " commonSettings: CommonSettingsType", + ") => {", + " let didPlaceAnimal = false;", + " for (let i = 0; i < width; i++) {", + " for (let j = length - 1; j > -1; j--) {", + " const xOffset = i * x;", + " const zOffset = z * j;", + " const location: Vector3 = { x: targetCorner.x + xOffset, y: targetCorner.y, z: targetCorner.z + zOffset };", + " const locationAbove: Vector3 = {", + " x: targetCorner.x + xOffset,", + " y: targetCorner.y + 1,", + " z: targetCorner.z + zOffset,", + " };", + " const block = player.dimension.getBlock(location);", + " const blockAbove = player.dimension.getBlock(locationAbove);", + " const isBorder = i === 0 || i === width - 1 || j === 0 || j === length - 1;", + " if (xOffset % 3 === 0 && !isBorder && commonSettings.irrigation.value) {", + " block?.setType(MinecraftBlockTypes.Water);", + " } else {", + " block?.setType(MinecraftBlockTypes.Farmland);", + " }", + " if (isBorder) {", + " blockAbove?.setType(fenceTypeToBlockType(commonSettings.fenceType.value));", + " } else if (possibleAnimals.length > 0 && getRandomInt(5) === 5) {", + " const animal = getRandomInt(possibleAnimals.length - 1);", + " const entityType = possibleAnimals[animal];", + " player.dimension.spawnEntity(entityType, blockAbove?.location ?? VECTOR3_ZERO, {", + " initialPersistence: true,", + " });", + " didPlaceAnimal = true;", + " } else if (!block?.isLiquid && possibleCrops.length > 0) {", + " const crop = getRandomInt(possibleCrops.length - 1);", + " const blockType = possibleCrops[crop];", + " blockAbove?.setType(blockType);", + " }", + " }", + " }", + " // Guarantee there is at least one animal spawned if we haven't placed one yet and there is room to place one", + " if (!didPlaceAnimal && possibleAnimals.length > 0 && width > 2 && length > 2) {", + " const locationAbove: Vector3 = {", + " x: targetCorner.x + x,", + " y: targetCorner.y + 1,", + " z: targetCorner.z + z,", + " };", + " const blockAbove = player.dimension.getBlock(locationAbove);", + " const animal = getRandomInt(possibleAnimals.length - 1);", + " const entityType = possibleAnimals[animal];", + " player.dimension.spawnEntity(entityType, blockAbove?.location ?? VECTOR3_ZERO, { initialPersistence: true });", + " }", + "};", + "function addFarmGeneratorSettingsPane(uiSession: IPlayerUISession, tool: IModalTool) {", + " const windowPane = uiSession.createPropertyPane({", + " title: 'sample.farmgenerator.pane.title',", + " });", + " const cropPane = windowPane.createSubPane({", + " title: 'sample.farmgenerator.pane.crops.title',", + " });", + " const animalPane = windowPane.createSubPane({", + " title: 'sample.farmgenerator.pane.animals.title',", + " });", + " const commonSettings: CommonSettingsType = {", + " farmWidth: makeObservable(10),", + " farmLength: makeObservable(10),", + " irrigation: makeObservable(false),", + " fenceType: makeObservable(0),", + " };", + " const cropSettings: CropSettingsType = {", + " wheat: makeObservable(false),", + " pumpkin: makeObservable(false),", + " potato: makeObservable(false),", + " carrot: makeObservable(false),", + " beetroot: makeObservable(false),", + " };", + " const animalSettings: AnimalSettingsType = {", + " pig: makeObservable(false),", + " sheep: makeObservable(false),", + " cow: makeObservable(false),", + " };", + " const onExecuteGenerator = (ray?: Ray) => {", + " const player: Player = uiSession.extensionContext.player;", + " // Use the mouse ray if it is available", + " const raycastResult =", + " ray !== undefined", + " ? player.dimension.getBlockFromRay(ray.location, ray.direction)", + " : player.getBlockFromViewDirection();", + " if (!raycastResult) {", + " uiSession.log.error('No block from view vector');", + " return;", + " }", + " const targetBlock = raycastResult.block;", + " let targetCorner: Vector3 = { x: targetBlock.location.x, y: targetBlock.location.y, z: targetBlock.location.z };", + " const possibleCrops: string[] = [];", + " if (cropSettings.beetroot.value) {", + " possibleCrops.push(MinecraftBlockTypes.Beetroot);", + " }", + " if (cropSettings.carrot.value) {", + " possibleCrops.push(MinecraftBlockTypes.Carrots);", + " }", + " if (cropSettings.pumpkin.value) {", + " possibleCrops.push(MinecraftBlockTypes.Pumpkin);", + " }", + " if (cropSettings.wheat.value) {", + " possibleCrops.push(MinecraftBlockTypes.Wheat);", + " }", + " if (cropSettings.potato.value) {", + " possibleCrops.push(MinecraftBlockTypes.Potatoes);", + " }", + " const possibleAnimals: MinecraftEntityTypes[] = [];", + " if (animalSettings.sheep.value) {", + " possibleAnimals.push(MinecraftEntityTypes.Sheep);", + " }", + " if (animalSettings.cow.value) {", + " possibleAnimals.push(MinecraftEntityTypes.Cow);", + " }", + " if (animalSettings.pig.value) {", + " possibleAnimals.push(MinecraftEntityTypes.Pig);", + " }", + " let x = 1;", + " let z = 1;", + " let length = commonSettings.farmLength.value;", + " let width = commonSettings.farmWidth.value;", + " if (Math.round(player.getViewDirection().z) === -1) {", + " targetCorner = {", + " x: targetCorner.x + (commonSettings.farmWidth.value / 2 - 1),", + " y: targetCorner.y,", + " z: targetCorner.z - (commonSettings.farmLength.value / 2 - 1),", + " };", + " uiSession.log.info('Facing north');", + " x = -1;", + " } else if (Math.round(player.getViewDirection().x) === 1) {", + " targetCorner = {", + " x: targetCorner.x + (commonSettings.farmWidth.value / 2 - 1),", + " y: targetCorner.y,", + " z: targetCorner.z + (commonSettings.farmLength.value / 2 - 1),", + " };", + " uiSession.log.info('Facing east');", + " length = commonSettings.farmWidth.value;", + " width = commonSettings.farmLength.value;", + " x = -1;", + " z = -1;", + " }", + " if (Math.round(player.getViewDirection().z) === 1) {", + " targetCorner = {", + " x: targetCorner.x - (commonSettings.farmWidth.value / 2 - 1),", + " y: targetCorner.y,", + " z: targetCorner.z + (commonSettings.farmLength.value / 2 - 1),", + " };", + " uiSession.log.info('Facing south');", + " z = -1;", + " } else if (Math.round(player.getViewDirection().x) === -1) {", + " targetCorner = {", + " x: targetCorner.x - (commonSettings.farmWidth.value / 2 - 1),", + " y: targetCorner.y,", + " z: targetCorner.z - (commonSettings.farmLength.value / 2 - 1),", + " };", + " uiSession.log.info('Facing west');", + " length = commonSettings.farmWidth.value;", + " width = commonSettings.farmLength.value;", + " }", + " buildFarm(targetCorner, x, z, length, width, possibleAnimals, possibleCrops, player, commonSettings);", + " };", + " // Create an action that will be executed on left mouse click", + " const executeMouseAction = uiSession.actionManager.createAction({", + " actionType: ActionTypes.MouseRayCastAction,", + " onExecute: (mouseRay: Ray, mouseProps: MouseProps) => {", + " if (mouseProps.mouseAction === MouseActionType.LeftButton && mouseProps.inputType === MouseInputType.ButtonDown) {", + " onExecuteGenerator(mouseRay);", + " }", + " },", + " });", + " // Create and an action that will be executed on CTRL + P", + " const executeKeyAction = uiSession.actionManager.createAction({", + " actionType: ActionTypes.NoArgsAction,", + " onExecute: () => {", + " onExecuteGenerator();", + " },", + " });", + " // Register actions as input bindings to tool context", + " tool.registerKeyBinding(", + " executeKeyAction,", + " { key: KeyboardKey.KEY_P, modifier: InputModifier.Control },", + " {", + " uniqueId: 'editorSamples:farmGenerator:place',", + " label: 'sample.farmgenerator.keyBinding.place',", + " }", + " );", + " tool.registerMouseButtonBinding(executeMouseAction);", + " windowPane.addNumber(commonSettings.farmLength, {", + " title: 'sample.farmgenerator.pane.length',", + " min: 2,", + " max: 20,", + " isInteger: true,", + " });", + " windowPane.addNumber(commonSettings.farmWidth, {", + " title: 'sample.farmgenerator.pane.width',", + " min: 2,", + " max: 20,", + " isInteger: true,", + " });", + " windowPane.addDropdown(commonSettings.fenceType, {", + " title: 'sample.farmgenerator.pane.fence',", + " enable: true,", + " entries: [", + " {", + " label: 'Oak',", + " value: 0,", + " },", + " {", + " label: 'Birch',", + " value: 1,", + " },", + " {", + " label: 'Acacia',", + " value: 2,", + " },", + " {", + " label: 'Bamboo',", + " value: 3,", + " },", + " {", + " label: 'Cherry',", + " value: 4,", + " },", + " {", + " label: 'Jungle',", + " value: 5,", + " },", + " {", + " label: 'Spruce',", + " value: 6,", + " },", + " {", + " label: 'Warped',", + " value: 7,", + " },", + " {", + " label: 'Crimson',", + " value: 8,", + " },", + " ],", + " });", + " windowPane.addBool(commonSettings.irrigation, {", + " title: 'sample.farmgenerator.pane.irrigation',", + " tooltip: 'sample.farmgenerator.pane.irrigation.tooltip',", + " });", + " cropPane.addBool(cropSettings.wheat, {", + " title: 'sample.farmgenerator.pane.crops.wheat',", + " });", + " cropPane.addBool(cropSettings.potato, {", + " title: 'sample.farmgenerator.pane.crops.potato',", + " });", + " cropPane.addBool(cropSettings.beetroot, {", + " title: 'sample.farmgenerator.pane.crops.beets',", + " });", + " cropPane.addBool(cropSettings.pumpkin, {", + " title: 'sample.farmgenerator.pane.crops.pumpkin',", + " });", + " cropPane.addBool(cropSettings.carrot, {", + " title: 'sample.farmgenerator.pane.crops.carrot',", + " });", + " animalPane.addBool(animalSettings.cow, {", + " title: 'sample.farmgenerator.pane.animals.cow',", + " });", + " animalPane.addBool(animalSettings.sheep, {", + " title: 'sample.farmgenerator.pane.animals.sheep',", + " });", + " animalPane.addBool(animalSettings.pig, {", + " title: 'sample.farmgenerator.pane.animals.pig',", + " });", + " tool.bindPropertyPane(windowPane);", + "}", + "/**", + " * Create a new tool rail item for farm generator", + " */", + "function addFarmGeneratorTool(uiSession: IPlayerUISession) {", + " // Create action", + " const toolToggleAction = uiSession.actionManager.createAction({", + " actionType: ActionTypes.NoArgsAction,", + " onExecute: () => {", + " uiSession.toolRail.setSelectedToolId(tool.id);", + " },", + " });", + " const tool = uiSession.toolRail.addTool(", + " {", + " title: 'sample.farmgenerator.tool.title',", + " icon: 'pack://textures/farm-generator.png',", + " tooltip: 'sample.farmgenerator.tool.tooltip',", + " inputContextId: 'editorSamples:farmGenerator',", + " inputContextLabel: 'sample.farmgenerator.tool.title',", + " },", + " toolToggleAction", + " );", + " // Register a global shortcut (CTRL + SHIFT + P) to select the tool", + " uiSession.inputManager.registerKeyBinding(", + " EditorInputContext.GlobalToolMode,", + " toolToggleAction,", + " { key: KeyboardKey.KEY_F, modifier: InputModifier.Control | InputModifier.Shift },", + " {", + " uniqueId: 'editorSamples:farmGenerator:toggleTool',", + " label: 'sample.farmgenerator.keyBinding.toggleTool',", + " }", + " );", + " return tool;", + "}", + "/**", + " * Register Farm Generator extension", + " */", + "export function registerFarmGeneratorExtension() {", + " registerEditorExtension(", + " 'FarmGenerator-sample',", + " (uiSession: IPlayerUISession) => {", + " uiSession.log.debug(`Initializing [${uiSession.extensionContext.extensionInfo.name}] extension`);", + " // Add tool to tool rail", + " const farmGeneratorTool = addFarmGeneratorTool(uiSession);", + " // Create settings pane/window", + " addFarmGeneratorSettingsPane(uiSession, farmGeneratorTool);", + " return [];", + " },", + " (uiSession: IPlayerUISession) => {", + " uiSession.log.debug(`Initializing [${uiSession.extensionContext.extensionInfo.name}] extension`);", + " },", + " {", + " description: ''Farm Generator' Sample Extension',", + " notes: 'by Molly',", + " }", + " );", + "}", + "" + ] + }, + "goto-mark.ts": { + "description": "goto-mark.ts ", + "prefix": ["mc"], + "body": [ + "// Copyright (c) Mojang AB. All rights reserved.", + "import {", + " ActionTypes,", + " IButtonPropertyItem,", + " IDropdownItem,", + " IDropdownPropertyItem,", + " IModalTool,", + " IObservable,", + " IPlayerUISession,", + " IPropertyPane,", + " UserDefinedTransactionHandle,", + " bindDataSource,", + " makeObservable,", + " registerEditorExtension,", + " registerUserDefinedTransactionHandler,", + "} from '@minecraft/server-editor';", + "import { Vector3, system } from '@minecraft/server';", + "const storedLocationDynamicPropertyName = 'goto-mark:storedLocations'; // The key of the stored location dynamic property", + "const storedLocationNameMaxLength = 16; // This is the maximum length of the name of a stored location", + "const storedLocationsMax = 9; // The maximum number of stored locations", + "type GotoTeleportTransactionPayload = {", + " current: Vector3;", + " destination: Vector3;", + "};", + "// The stored location data structure that represents each of the stored locations", + "// this is also the JSON format that is stored in the dynamic property", + "type LocationData = {", + " location: Vector3;", + " name: string;", + "};", + "// UI Pane data for the whole extension pane", + "type ParentPaneDataSourceType = {", + " playerLocation: Vector3;", + "};", + "// UI Pane data for the sub pane with the stored locations", + "type LocationPaneDataSourceType = {", + " newName: IObservable;", + "};", + "// Extension storage data which is pertinent to the the player's context of this extension", + "type ExtensionStorage = {", + " tool?: IModalTool; // The tool handle for the extension", + " previousLocation: Vector3; // The players last recorded position", + " updateHandle?: number; // The handle for the repeating interval that updates the player position", + " parentPaneDataSource?: ParentPaneDataSourceType; // The data source for the parent pane", + " parentPane?: IPropertyPane; // The parent pane", + " dropdownMenu?: IDropdownPropertyItem; // The dropdown", + " locationPaneDataSource?: LocationPaneDataSourceType; // The data source for the location pane", + " storedLocations: LocationData[]; // The list of stored locations", + " transactionHandler: UserDefinedTransactionHandle; // The transaction handler for the extension", + " teleportButton?: IButtonPropertyItem;", + "};", + "// Handy helper to turn a Vector3 into a pretty string", + "function vector3ToString(vec: Vector3): string {", + " return `(${vec.x}, ${vec.y}, ${vec.z})`;", + "}", + "// Equality check for a Vector3", + "function vector3Equals(vec1: Vector3, vec2: Vector3): boolean {", + " return vec1.x === vec2.x && vec1.y === vec2.y && vec1.z === vec2.z;", + "}", + "// Truncate a Vector3 to the nearest block", + "function vector3Truncate(vec: Vector3): Vector3 {", + " const blockLocation: Vector3 = { x: Math.floor(vec.x), y: Math.floor(vec.y), z: Math.floor(vec.z) };", + " return blockLocation;", + "}", + "function mapDropdownItems(storage: ExtensionStorage): IDropdownItem[] {", + " return storage.storedLocations.map((v, index): IDropdownItem => {", + " const item: IDropdownItem = {", + " label: `${index + 1}: ${v.name} (${vector3ToString(v.location)})`,", + " value: index,", + " };", + " return item;", + " });", + "}", + "function createTransaction(uiSession: IPlayerUISession, current: Vector3, destination: Vector3) {", + " const transactionPayload: GotoTeleportTransactionPayload = {", + " current,", + " destination,", + " };", + " if (!uiSession.scratchStorage) {", + " return;", + " }", + " uiSession.extensionContext.transactionManager.openTransaction('goto position');", + " uiSession.scratchStorage.transactionHandler.addUserDefinedOperation(transactionPayload, 'Goto(Teleport)');", + " uiSession.extensionContext.transactionManager.commitOpenTransaction();", + "}", + "function teleportTo(uiSession: IPlayerUISession, destination: Vector3) {", + " createTransaction(uiSession, uiSession.extensionContext.player.location, destination);", + " uiSession.log.info(`Teleporting to location ${vector3ToString(destination)}`);", + " try {", + " uiSession.extensionContext.player.teleport(destination);", + " } catch (e) {", + " uiSession.log.error(`Teleport failed: ${e}`);", + " }", + "}", + "// Add the extension to the tool rail and give it an icon", + "function addExtensionTool(uiSession: IPlayerUISession): IModalTool {", + " const tool = uiSession.toolRail.addTool({", + " title: 'sample.gotomark.tool.title',", + " icon: 'pack://textures/goto-mark.png',", + " tooltip: 'Set or Jump to a stored location',", + " });", + " return tool;", + "}", + "function buildParentPane(uiSession: IPlayerUISession, storage: ExtensionStorage): IPropertyPane {", + " const parentPane = uiSession.createPropertyPane({", + " title: 'sample.gotomark.pane.title',", + " });", + " const currentLocation = vector3Truncate(uiSession.extensionContext.player.location);", + " const initialPaneData: ParentPaneDataSourceType = {", + " playerLocation: currentLocation,", + " };", + " storage.parentPaneDataSource = bindDataSource(parentPane, initialPaneData);", + " storage.previousLocation = currentLocation;", + " parentPane.addVector3_deprecated(storage.parentPaneDataSource, 'playerLocation', {", + " title: 'sample.gotomark.pane.location',", + " });", + " // Run interval to refresh coordinate population", + " // Issue with refresh on tick rate with show/hide", + " storage.updateHandle = system.runInterval(() => {", + " if (!storage.parentPaneDataSource) {", + " return;", + " }", + " const currentLocation = vector3Truncate(uiSession.extensionContext.player.location);", + " const previousLocation = vector3Truncate(storage.previousLocation);", + " // Player hasn't moved - don't refresh", + " if (vector3Equals(currentLocation, previousLocation) || !parentPane.visible) {", + " return;", + " }", + " storage.previousLocation = currentLocation;", + " storage.parentPaneDataSource.playerLocation = { ...currentLocation };", + " }, 10);", + " // Jump directly to the location specified in the Vector3 UI control", + " parentPane.addButton(", + " uiSession.actionManager.createAction({", + " actionType: ActionTypes.NoArgsAction,", + " onExecute: () => {", + " if (!storage.parentPaneDataSource) {", + " uiSession.log.error('An error occurred: No UI pane datasource could be found');", + " return;", + " }", + " const panelLocation = storage.parentPaneDataSource.playerLocation;", + " teleportTo(uiSession, panelLocation);", + " },", + " }),", + " {", + " title: 'sample.gotomark.pane.button.teleport',", + " visible: true,", + " }", + " );", + " parentPane.addDivider();", + " // Set the players spawn location based on the current location (or the location typed into the", + " // Vector3 UI control)", + " parentPane.addButton(", + " uiSession.actionManager.createAction({", + " actionType: ActionTypes.NoArgsAction,", + " onExecute: () => {", + " if (!storage.parentPaneDataSource) {", + " uiSession.log.error('An error occurred: No UI pane datasource could be found');", + " return;", + " }", + " const currentLocation = storage.parentPaneDataSource.playerLocation;", + " uiSession.log.info(`Setting Spawn Location to ${vector3ToString(currentLocation)}`);", + " uiSession.extensionContext.player.setSpawnPoint({", + " ...currentLocation,", + " dimension: uiSession.extensionContext.player.dimension,", + " });", + " },", + " }),", + " {", + " title: 'sample.gotomark.pane.button.setspawn',", + " visible: true,", + " }", + " );", + " // Jump to the player's spawn location (stored in the entity)", + " parentPane.addButton(", + " uiSession.actionManager.createAction({", + " actionType: ActionTypes.NoArgsAction,", + " onExecute: () => {", + " const spawnLocation = uiSession.extensionContext.player.getSpawnPoint();", + " if (!spawnLocation) {", + " uiSession.log.error('Player Spawn Location is not yet set');", + " } else {", + " teleportTo(uiSession, spawnLocation);", + " }", + " },", + " }),", + " {", + " title: 'sample.gotomark.pane.button.gotospawn',", + " visible: true,", + " }", + " );", + " storage.parentPane = parentPane;", + " // Build/Rebuild a sub-pane with the more dynamic UI controls", + " buildLocationPane(uiSession, storage, 0);", + " return parentPane;", + "}", + "function buildLocationPane(", + " uiSession: IPlayerUISession,", + " storage: ExtensionStorage,", + " initialSelection: number", + ") {", + " if (!storage.parentPane) {", + " uiSession.log.error('An error occurred: No UI pane could be found');", + " return;", + " }", + " const locationPane = storage.parentPane.createSubPane({", + " title: 'sample.gotomark.pane.locationpane.title',", + " });", + " const currentSelection = makeObservable(initialSelection);", + " const initialPaneData: LocationPaneDataSourceType = {", + " newName: makeObservable(''),", + " };", + " storage.locationPaneDataSource = bindDataSource(locationPane, initialPaneData);", + " const dropdownItems = mapDropdownItems(storage);", + " storage.dropdownMenu = locationPane.addDropdown(currentSelection, {", + " title: 'sample.gotomark.pane.locationpane.dropdownLabel',", + " entries: dropdownItems,", + " onChange: (newValue: number) => {", + " if (storage.teleportButton) {", + " storage.teleportButton.setTitle({", + " id: 'sample.gotomark.pane.locationpane.button.teleport',", + " props: [`${newValue + 1}`],", + " });", + " }", + " },", + " });", + " locationPane.addDivider();", + " // Jump to the stored location selected in the dropdown", + " storage.teleportButton = locationPane.addButton(", + " uiSession.actionManager.createAction({", + " actionType: ActionTypes.NoArgsAction,", + " onExecute: () => {", + " if (!storage.locationPaneDataSource) {", + " uiSession.log.error('An error occurred: No UI pane datasource could be found');", + " return;", + " }", + " if (currentSelection.value < 0 || currentSelection.value >= storage.storedLocations.length) {", + " uiSession.log.error('No stored locations to delete');", + " return;", + " }", + " const destination = storage.storedLocations[currentSelection.value].location;", + " teleportTo(uiSession, destination);", + " },", + " }),", + " {", + " title: {", + " id: 'sample.gotomark.pane.locationpane.button.teleport',", + " props: [dropdownItems.length > 0 ? `${currentSelection.value + 1}` : ''],", + " },", + " visible: true,", + " }", + " );", + " // Delete the stored location selected in the dropdown", + " locationPane.addButton(", + " uiSession.actionManager.createAction({", + " actionType: ActionTypes.NoArgsAction,", + " onExecute: () => {", + " if (!storage.locationPaneDataSource) {", + " uiSession.log.error('An error occurred: No UI pane datasource could be found');", + " return;", + " }", + " const selectionValue = currentSelection.value;", + " if (selectionValue < 0 || selectionValue >= storage.storedLocations.length) {", + " uiSession.log.error('No stored locations to delete');", + " return;", + " }", + " const locationData = storage.storedLocations[selectionValue];", + " const locationName = locationData.name;", + " uiSession.log.info(`Deleting stored location name '${locationName}'`);", + " storage.storedLocations.splice(selectionValue, 1);", + " storeLocationsToPlayer(uiSession, storage);", + " const dropdownItems = mapDropdownItems(storage);", + " const newValue =", + " selectionValue >= dropdownItems.length && selectionValue > 0 ? selectionValue - 1 : selectionValue;", + " storage.dropdownMenu?.updateEntries(dropdownItems, newValue);", + " storage.teleportButton?.setTitle({", + " id: 'sample.gotomark.pane.locationpane.button.teleport',", + " props: [dropdownItems.length > 0 ? `${newValue + 1}` : ''],", + " });", + " },", + " }),", + " {", + " title: 'sample.gotomark.pane.locationpane.button.delete',", + " visible: true,", + " }", + " );", + " locationPane.addString(storage.locationPaneDataSource.newName, {", + " title: 'sample.gotomark.pane.locationpane.input.name',", + " });", + " locationPane.addButton(", + " uiSession.actionManager.createAction({", + " actionType: ActionTypes.NoArgsAction,", + " onExecute: () => {", + " if (!storage.parentPaneDataSource || !storage.locationPaneDataSource) {", + " uiSession.log.error('An error occurred: No UI pane datasource could be found');", + " return;", + " }", + " if (storage.storedLocations.length >= storedLocationsMax) {", + " uiSession.log.error(`Cannot store more than ${storedLocationsMax} locations`);", + " return;", + " }", + " const currentLocation = vector3Truncate(storage.parentPaneDataSource.playerLocation);", + " const newName = storage.locationPaneDataSource.newName;", + " if (!newName.value) {", + " newName.set(`Location ${storage.storedLocations.length + 1}`);", + " } else {", + " const trimmedName = newName.value.trim();", + " if (trimmedName.length > storedLocationNameMaxLength) {", + " newName.set(trimmedName.substring(0, storedLocationNameMaxLength));", + " }", + " }", + " uiSession.log.info(`Adding Location ${vector3ToString(currentLocation)} as '${newName.value}'`);", + " storage.storedLocations.push({", + " name: newName.value,", + " location: currentLocation,", + " });", + " storeLocationsToPlayer(uiSession, storage);", + " const newSelectionIndex = storage.storedLocations.length - 1;", + " const dropdownItems = mapDropdownItems(storage);", + " storage.dropdownMenu?.updateEntries(dropdownItems, newSelectionIndex);", + " storage.teleportButton?.setTitle({", + " id: 'sample.gotomark.pane.locationpane.button.teleport',", + " props: [`${newSelectionIndex + 1}`],", + " });", + " },", + " }),", + " {", + " title: 'sample.gotomark.pane.locationpane.button.store',", + " }", + " );", + "}", + "function storeLocationsToPlayer(uiSession: IPlayerUISession, storage: ExtensionStorage) {", + " const me = uiSession.extensionContext.player;", + " me.setDynamicProperty(storedLocationDynamicPropertyName, JSON.stringify(storage.storedLocations));", + "}", + "export function registerGotoMarkExtension() {", + " registerEditorExtension(", + " 'goto-mark-sample',", + " (uiSession) => {", + " uiSession.log.debug(", + " `Initializing extension [${uiSession.extensionContext.extensionInfo.name}] for player [${uiSession.extensionContext.player.name}]`", + " );", + " const storage: ExtensionStorage = {", + " previousLocation: uiSession.extensionContext.player.location,", + " storedLocations: [],", + " transactionHandler: registerUserDefinedTransactionHandler(", + " uiSession.extensionContext.transactionManager,", + " (payload: GotoTeleportTransactionPayload) => {", + " // undo handler", + " uiSession.log.info(`Teleporting to location ${vector3ToString(payload.current)}`);", + " try {", + " uiSession.extensionContext.player.teleport(payload.current);", + " } catch (e) {", + " uiSession.log.error(`Teleport failed: ${e}`);", + " }", + " },", + " (payload: GotoTeleportTransactionPayload) => {", + " // redo handler", + " uiSession.log.info(`Teleporting to location ${vector3ToString(payload.destination)}`);", + " try {", + " uiSession.extensionContext.player.teleport(payload.destination);", + " } catch (e) {", + " uiSession.log.error(`Teleport failed: ${e}`);", + " }", + " }", + " ),", + " };", + " const me = uiSession.extensionContext.player;", + " try {", + " const fetchedLocationsString = me.getDynamicProperty(storedLocationDynamicPropertyName) as string;", + " if (!fetchedLocationsString) {", + " uiSession.log.info('No stored locations found during initialization');", + " } else {", + " const fetchedLocationsArray = JSON.parse(fetchedLocationsString) as LocationData[];", + " if (fetchedLocationsArray) {", + " storage.storedLocations = fetchedLocationsArray;", + " }", + " uiSession.log.info(`Found ${storage.storedLocations.length} stored locations during initialization`);", + " }", + " } catch (e) {", + " uiSession.log.info('No stored locations found during initialization');", + " }", + " storage.tool = addExtensionTool(uiSession);", + " const pane = buildParentPane(uiSession, storage);", + " storage.tool.bindPropertyPane(pane);", + " uiSession.scratchStorage = storage;", + " return [];", + " },", + " (uiSession: IPlayerUISession) => {", + " uiSession.log.debug(", + " `Shutting down extension [${uiSession.extensionContext.extensionInfo.name}] for player [${uiSession.extensionContext.player.name}]`", + " );", + " if (uiSession.scratchStorage) {", + " // If we still have a system interval runner, then shut it down", + " if (uiSession.scratchStorage.updateHandle) {", + " system.clearRun(uiSession.scratchStorage.updateHandle);", + " }", + " }", + " },", + " {", + " description: 'Go to Bookmark Sample Extension',", + " notes: 'by Chloe, Eser & Dave',", + " }", + " );", + "}", + "" + ] + }, + "portal-generator.ts": { + "description": "portal-generator.ts ", + "prefix": ["mc"], + "body": [ + "// Copyright (c) Mojang AB. All rights reserved.", + "import {", + " BoolPropertyItemVariant,", + " CursorTargetMode,", + " IDisposable,", + " ImageResourceType,", + " IObservable,", + " makeObservable,", + " NumberPropertyItemVariant,", + " Ray,", + "} from '@minecraft/server-editor';", + "import {", + " IPlayerUISession,", + " registerEditorExtension,", + " IModalTool,", + " ActionTypes,", + " MouseProps,", + " MouseActionType,", + " MouseInputType,", + " KeyboardKey,", + " InputModifier,", + " EditorInputContext,", + " IPropertyPane,", + "} from '@minecraft/server-editor';", + "import { Vector3 } from '@minecraft/server';", + "import { MinecraftBlockTypes } from '@minecraft/vanilla-data';", + "enum PortalType {", + " Nether = 0,", + " End = 1,", + "}", + "enum PortalOrientation {", + " X = 0,", + " Z = 1,", + "}", + "type ExtensionStorage = {", + " tool?: IModalTool;", + "};", + "type PortalGeneratorSession = IPlayerUISession;", + "type PaneSettingsType = {", + " portalType: IObservable;", + " shouldReplaceFloor: IObservable;", + "};", + "interface IPortalGenerator {", + " set parentPane(value: IPropertyPane);", + " subPane(uiSession: PortalGeneratorSession): IPropertyPane | undefined;", + " activatePane(uiSession: PortalGeneratorSession): void;", + " deactivatePane(): void;", + " generatePortal(uiSession: PortalGeneratorSession): void;", + "}", + "class PortalGenerator implements IDisposable {", + " private _netherPortal: NetherPortal;", + " private _endPortal: EndPortal;", + " private _activePortal?: IPortalGenerator;", + " private _pane?: IPropertyPane;", + " private _settings: PaneSettingsType = {", + " portalType: makeObservable(PortalType.Nether),", + " shouldReplaceFloor: makeObservable(true),", + " };", + " constructor() {", + " this._netherPortal = new NetherPortal();", + " this._endPortal = new EndPortal();", + " }", + " public toolPane(uiSession: PortalGeneratorSession): IPropertyPane | undefined {", + " if (!this._pane) {", + " uiSession.log.error('Tool pane not initialized');", + " return undefined;", + " }", + " return this._pane;", + " }", + " initialize(uiSession: PortalGeneratorSession, storage: ExtensionStorage) {", + " // Create Action", + " const toolToggleAction = uiSession.actionManager.createAction({", + " actionType: ActionTypes.NoArgsAction,", + " onExecute: () => {", + " uiSession.toolRail.setSelectedToolId(tool.id);", + " },", + " });", + " // Add the extension to the tool rail and give it an icon", + " const tool = uiSession.toolRail.addTool(", + " {", + " title: 'sample.portalgenerator.title',", + " icon: 'pack://textures/portal-generator.png',", + " tooltip: 'sample.portalgenerator.tooltip',", + " },", + " toolToggleAction", + " );", + " // Register a global shortcut (CTRL + SHIFT + P) to select the tool", + " uiSession.inputManager.registerKeyBinding(", + " EditorInputContext.GlobalToolMode,", + " toolToggleAction,", + " { key: KeyboardKey.KEY_P, modifier: InputModifier.Control | InputModifier.Shift },", + " {", + " uniqueId: 'editorSamples:portalGenerator:toggleTool',", + " label: 'sample.portalgenerator.keyBinding.toggleTool',", + " }", + " );", + " // Create an action that will be executed on left mouse click", + " const executeMouseAction = uiSession.actionManager.createAction({", + " actionType: ActionTypes.MouseRayCastAction,", + " onExecute: (_mouseRay: Ray, mouseProps: MouseProps) => {", + " if (", + " mouseProps.mouseAction === MouseActionType.LeftButton &&", + " mouseProps.inputType === MouseInputType.ButtonDown &&", + " this._activePortal", + " ) {", + " this._activePortal.generatePortal(uiSession);", + " }", + " },", + " });", + " tool.registerMouseButtonBinding(executeMouseAction);", + " storage.tool = tool;", + " // Build the UI components (and the sub pane with the options)", + " this.buildPane(uiSession);", + " if (this._pane) {", + " tool.bindPropertyPane(this._pane);", + " this.activatePortalGenerator(uiSession, this._settings.portalType.value);", + " }", + " }", + " teardown(): void {}", + " buildPane(uiSession: PortalGeneratorSession) {", + " const pane = uiSession.createPropertyPane({", + " title: 'sample.portalgenerator.pane.title',", + " });", + " pane.addBool(this._settings.shouldReplaceFloor, {", + " title: 'sample.portalgenerator.pane.replacefloor',", + " onChange: (current: boolean) => {", + " const targetMode = current ? CursorTargetMode.Block : CursorTargetMode.Face;", + " uiSession.extensionContext.cursor.setProperties({ targetMode });", + " },", + " variant: BoolPropertyItemVariant.ToggleSwitch,", + " });", + " pane.addDropdown(this._settings.portalType, {", + " title: 'sample.portalgenerator.pane.portaltype',", + " entries: [", + " {", + " label: 'sample.portalgenerator.pane.portaltype.nether',", + " value: PortalType.Nether,", + " imageData: { path: 'portal', type: ImageResourceType.Block },", + " },", + " {", + " label: 'sample.portalgenerator.pane.portaltype.end',", + " value: PortalType.End,", + " imageData: { path: 'enderEyeIcon', type: ImageResourceType.Icon },", + " },", + " ],", + " onChange: (newValue: number) => {", + " this.activatePortalGenerator(uiSession, newValue);", + " },", + " });", + " this._pane = pane;", + " this._endPortal.parentPane = pane;", + " this._netherPortal.parentPane = pane;", + " }", + " activatePortalGenerator(uiSession: PortalGeneratorSession, portalType: PortalType): void {", + " this._pane?.hide();", + " if (this._activePortal) {", + " this._activePortal.deactivatePane();", + " }", + " if (portalType === PortalType.Nether) {", + " this._activePortal = this._netherPortal;", + " } else {", + " this._activePortal = this._endPortal;", + " }", + " this._activePortal.activatePane(uiSession);", + " this._pane?.show();", + " }", + "}", + "class NetherPortal implements IPortalGenerator {", + " private _pane?: IPropertyPane;", + " private _parentPane?: IPropertyPane;", + " // Settings", + " private _sizeX: IObservable = makeObservable(4);", + " private _sizeY: IObservable = makeObservable(5);", + " private _percentComplete: IObservable = makeObservable(100);", + " private _orientation: IObservable = makeObservable(PortalOrientation.X);", + " private _hasCorners: IObservable = makeObservable(true);", + " constructor() {}", + " public subPane(uiSession: PortalGeneratorSession): IPropertyPane | undefined {", + " if (!this._pane) {", + " uiSession.log.error('Sub pane not initialized');", + " return undefined;", + " }", + " return this._pane;", + " }", + " public set parentPane(value: IPropertyPane) {", + " this._parentPane = value;", + " }", + " activatePane(uiSession: PortalGeneratorSession): void {", + " if (this._pane) {", + " this.deactivatePane();", + " }", + " this._pane = this.buildSubPane(uiSession);", + " this._pane?.show();", + " }", + " deactivatePane(): void {", + " if (this._pane) {", + " this._pane.hide();", + " this._parentPane?.removeSubPane(this._pane);", + " }", + " this._pane = undefined;", + " }", + " buildSubPane(uiSession: PortalGeneratorSession): IPropertyPane | undefined {", + " const windowPane = this._parentPane;", + " if (!windowPane) {", + " uiSession.log.error('Failed to find window binding');", + " return undefined;", + " }", + " const subPane = windowPane.createSubPane({", + " title: 'sample.portalgenerator.pane.nether.pane.title',", + " });", + " subPane.addDropdown(this._orientation, {", + " title: 'sample.portalgenerator.pane.nether.pane.orientation',", + " entries: [", + " {", + " label: 'sample.portalgenerator.pane.nether.pane.orientation.x',", + " value: PortalOrientation.X,", + " },", + " {", + " label: 'sample.portalgenerator.pane.nether.pane.orientation.y',", + " value: PortalOrientation.Z,", + " },", + " ],", + " });", + " subPane.addNumber(this._sizeX, {", + " title: 'sample.portalgenerator.pane.nether.pane.width',", + " min: 4,", + " max: 33,", + " isInteger: true,", + " });", + " subPane.addNumber(this._sizeY, {", + " title: 'sample.portalgenerator.pane.nether.pane.height',", + " min: 5,", + " max: 33,", + " isInteger: true,", + " });", + " subPane.addBool(this._hasCorners, {", + " title: 'sample.portalgenerator.pane.nether.pane.corners',", + " tooltip: 'sample.portalgenerator.pane.nether.pane.corners.tooltip',", + " });", + " subPane.addNumber(this._percentComplete, {", + " title: 'sample.portalgenerator.pane.nether.pane.percentage',", + " min: 0,", + " max: 100,", + " variant: NumberPropertyItemVariant.InputFieldAndSlider,", + " });", + " return subPane;", + " }", + " generatePortal(uiSession: PortalGeneratorSession): void {", + " const me = uiSession.extensionContext.player;", + " const location = uiSession.extensionContext.cursor.getPosition();", + " const targetBlock = me.dimension.getBlock(location);", + " if (targetBlock === undefined) {", + " uiSession.log.warning('No block selected');", + " return;", + " }", + " if (this._percentComplete.value === 0) {", + " return;", + " }", + " if (me.dimension.id.endsWith('the_end')) {", + " uiSession.log.warning('You cannot create a nether portal in the end');", + " return;", + " }", + " uiSession.extensionContext.transactionManager.openTransaction('Transaction group portal generator');", + " let from: Vector3 = location;", + " let to: Vector3 = { x: 0, y: 0, z: 0 };", + " if (this._orientation.value === PortalOrientation.X) {", + " to = {", + " x: location.x + this._sizeX.value,", + " y: location.y + this._sizeY.value,", + " z: location.z,", + " };", + " } else if (this._orientation.value === PortalOrientation.Z) {", + " to = {", + " x: location.x,", + " y: location.y + this._sizeY.value,", + " z: location.z + this._sizeX.value,", + " };", + " } else {", + " uiSession.log.error('Failed to get valid orientation');", + " uiSession.extensionContext.transactionManager.discardOpenTransaction();", + " return;", + " }", + " const yEnd = this._sizeY.value - 1;", + " const xEnd = this._sizeX.value - 1;", + " uiSession.extensionContext.transactionManager.trackBlockChangeArea(from, to);", + " for (let y = 0; y < this._sizeY.value; ++y) {", + " for (let x = 0; x < this._sizeX.value; ++x) {", + " let block = MinecraftBlockTypes.Air;", + " // Percent complete is randomized percentage", + " if (this._percentComplete.value !== 100) {", + " const randVal = getRandomInt(100);", + " if (this._percentComplete.value - randVal < 0) {", + " continue;", + " }", + " }", + " // Set as obsidian for bottom, top, and edges of portal", + " if (", + " !this._hasCorners.value &&", + " ((y === 0 && x === 0) || (y === 0 && x === xEnd) || (y === yEnd && x === xEnd) || (y === yEnd && x === 0))", + " ) {", + " continue; // no corners", + " } else if (y === 0 || y === yEnd || x === 0 || x === xEnd) {", + " block = MinecraftBlockTypes.Obsidian;", + " } else {", + " continue;", + " }", + " const loc: Vector3 =", + " this._orientation.value === PortalOrientation.X", + " ? { x: location.x + x, y: location.y + y, z: location.z }", + " : { x: location.x, y: location.y + y, z: location.z + x };", + " me.dimension.getBlock(loc)?.setType(block);", + " }", + " }", + " let ori = 'x';", + " if (this._orientation.value === PortalOrientation.Z) {", + " ori = 'z';", + " from = { x: location.x, y: location.y + 1, z: location.z + 1 };", + " to = {", + " x: location.x,", + " y: location.y + this._sizeY.value - 2,", + " z: location.z + this._sizeX.value - 2,", + " };", + " } else {", + " from = { x: location.x + 1, y: location.y + 1, z: location.z };", + " to = {", + " x: location.x + this._sizeX.value - 2,", + " y: location.y + this._sizeY.value - 2,", + " z: location.z,", + " };", + " }", + " if (this._percentComplete.value === 100) {", + " // We must fill the portals as it must have the axis set while setting the type", + " // or the engine will destroy the block and the scripting API wont allow both in one operation", + " me.dimension.runCommand(", + " `FILL ${from.x} ${from.y} ${from.z} ${to.x} ${to.y} ${to.z} portal ['portal_axis':'${ori}']`", + " );", + " }", + " uiSession.extensionContext.transactionManager.commitOpenTransaction();", + " }", + "}", + "class EndPortal implements IPortalGenerator {", + " private _pane?: IPropertyPane;", + " private _parentPane?: IPropertyPane;", + " // Settings", + " private _filledEyeCount: IObservable = makeObservable(12);", + " constructor() {}", + " public subPane(uiSession: PortalGeneratorSession): IPropertyPane | undefined {", + " if (!this._pane) {", + " uiSession.log.error('Sub pane not initialized');", + " return undefined;", + " }", + " return this._pane;", + " }", + " public set parentPane(value: IPropertyPane) {", + " this._parentPane = value;", + " }", + " activatePane(uiSession: PortalGeneratorSession): void {", + " if (this._pane) {", + " this.deactivatePane();", + " }", + " this._pane = this.buildSubPane(uiSession);", + " this._pane?.show();", + " }", + " deactivatePane(): void {", + " if (this._pane) {", + " this._pane.hide();", + " this._parentPane?.removeSubPane(this._pane);", + " }", + " this._pane = undefined;", + " }", + " buildSubPane(uiSession: PortalGeneratorSession): IPropertyPane | undefined {", + " const windowPane = this._parentPane;", + " if (!windowPane) {", + " uiSession.log.error('Failed to find window pane');", + " return undefined;", + " }", + " const subPane = windowPane.createSubPane({", + " title: 'sample.portalgenerator.pane.end.pane.title',", + " });", + " subPane.addNumber(this._filledEyeCount, {", + " title: 'sample.portalgenerator.pane.end.pane.filledcount',", + " min: 0,", + " max: 12,", + " variant: NumberPropertyItemVariant.InputFieldAndSlider,", + " isInteger: true,", + " });", + " return subPane;", + " }", + " generatePortal(uiSession: PortalGeneratorSession): void {", + " const me = uiSession.extensionContext.player;", + " const location = uiSession.extensionContext.cursor.getPosition();", + " const targetBlock = me.dimension.getBlock(location);", + " if (targetBlock === undefined) {", + " uiSession.log.error('No block selected');", + " return;", + " }", + " uiSession.extensionContext.transactionManager.openTransaction('Transaction group portal generator');", + " const from: Vector3 = { x: location.x, y: location.y, z: location.z };", + " const to: Vector3 = { x: location.x + 4, y: location.y, z: location.z + 4 };", + " let eyesToUse: boolean[] = [false, false, false, false, false, false, false, false, false, false, false, false];", + " if (this._filledEyeCount.value === 12) {", + " eyesToUse = [true, true, true, true, true, true, true, true, true, true, true, true];", + " } else if (this._filledEyeCount.value !== 0) {", + " const possibleEyeLocs = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];", + " for (let i = 0; i < this._filledEyeCount.value; ++i) {", + " const rand = Math.floor(Math.random() * possibleEyeLocs.length);", + " eyesToUse[possibleEyeLocs[rand]] = true;", + " possibleEyeLocs.splice(rand, 1);", + " }", + " }", + " let i = 0;", + " uiSession.extensionContext.transactionManager.trackBlockChangeArea(from, to);", + " for (let z = 0; z < 5; ++z) {", + " for (let x = 0; x < 5; ++x) {", + " let rot = 0;", + " let blockType = MinecraftBlockTypes.Air;", + " if (x === 0 && z !== 0 && z !== 4) {", + " // west edge", + " blockType = MinecraftBlockTypes.EndPortalFrame;", + " rot = 3;", + " } else if (x === 4 && z !== 0 && z !== 4) {", + " // east edge", + " blockType = MinecraftBlockTypes.EndPortalFrame;", + " rot = 1;", + " } else if (z === 0 && x !== 0 && x !== 4) {", + " // south edge", + " blockType = MinecraftBlockTypes.EndPortalFrame;", + " rot = 0;", + " } else if (z === 4 && x !== 0 && x !== 4) {", + " // north edge", + " blockType = MinecraftBlockTypes.EndPortalFrame;", + " rot = 2;", + " } else if (this._filledEyeCount.value === 12 && x >= 1 && z >= 1 && x <= 3 && z <= 3) {", + " // center", + " blockType = MinecraftBlockTypes.EndPortal;", + " } else {", + " continue;", + " }", + " const block = me.dimension.getBlock({ x: location.x + x, y: location.y, z: location.z + z });", + " if (block) {", + " block.setType(blockType);", + " if (blockType === MinecraftBlockTypes.EndPortalFrame) {", + " const perm = block.permutation.withState('direction', rot).withState('end_portal_eye_bit', eyesToUse[i]);", + " block.setPermutation(perm);", + " i += 1;", + " }", + " } else {", + " uiSession.log.error('Failed to get block');", + " }", + " }", + " }", + " uiSession.extensionContext.transactionManager.commitOpenTransaction();", + " }", + "}", + "function getRandomInt(upper: number) {", + " return Math.ceil(Math.random() * (upper + 1));", + "}", + "/**", + " * Register Portal Generator extension", + " */", + "export function registerPortalGeneratorExtension() {", + " registerEditorExtension(", + " 'portal-generator-sample',", + " (uiSession) => {", + " uiSession.log.debug(`Initializing [${uiSession.extensionContext.extensionInfo.name}] extension`);", + " uiSession.scratchStorage = {};", + " const generator = new PortalGenerator();", + " generator.initialize(uiSession, uiSession.scratchStorage);", + " return [generator];", + " },", + " (uiSession) => {", + " uiSession.log.debug(`Shutting down [${uiSession.extensionContext.extensionInfo.name}] extension`);", + " },", + " {", + " description: 'Portal Generator Sample Extension',", + " notes: 'by Andrew',", + " }", + " );", + "}", + "" + ] + }, + "simple-locate-biome.ts": { + "description": "simple-locate-biome.ts ", + "prefix": ["mc"], + "body": [ + "// Copyright (c) Mojang AB. All rights reserved.", + "import { VECTOR3_ZERO, Vector3Utils } from '@minecraft/math';", + "import {", + " ActionTypes,", + " IDropdownItem,", + " IObservable,", + " IPlayerUISession,", + " ISimpleToolOptions,", + " ISimpleToolPaneComponent,", + " InputModifier,", + " KeyboardKey,", + " SimpleToolWrapper,", + " makeObservable,", + " registerEditorExtension,", + "} from '@minecraft/server-editor';", + "import { BiomeTypes, Player, Vector3 } from '@minecraft/server';", + "enum LocateMode {", + " Biome = 0,", + " Structure,", + "}", + "type LocateSelectorType = {", + " locateMode: IObservable;", + "};", + "type LocateBiomeSourceType = {", + " biomeId: IObservable;", + " biomePos: Vector3;", + "};", + "type ResultsType = {", + " foundType: string;", + " foundPos: Vector3;", + "};", + "// Implementation of a simple tool that allows the player to locate a biome", + "// This tool demonstrates the use of the SimpleToolWrapper class (and the associated", + "// ISimpleToolOptions interfaces)", + "export class SimpleLocate extends SimpleToolWrapper {", + " private _results: ResultsType = {", + " foundType: '',", + " foundPos: VECTOR3_ZERO,", + " };", + " // Activate the results pane with the found biome/structure and position in the", + " // world. This uses the SimpleToolWrapper's showPane method to display the results", + " // in a pre-constructed pane which is generally hidden until results are valid.", + " activateResultsPane(biome: string, pos: Vector3): void {", + " this.simpleTool.logInfo(`Found ${biome} at ${Vector3Utils.toString(pos)}`);", + " this._results.foundType = biome;", + " this._results.foundPos = pos;", + " // Hopefully, we'll be able to get rid of this function in the near future.", + " // reconstructing the pane is a last-resort hack to get the pane to update", + " // certain UI components which do not currently support dynamic data binding.", + " // It's a necessary evil for now, but we're working on a better solution.", + " // We certainly don't recommend doing this more than necessary - it causes a", + " // lot of classes to be re-created and can be very slow, especially if there", + " // are a lot of child panes and UI components.", + " const foundPane = this.simpleTool.pane.findPane('results-found');", + " foundPane?.reconstructPane();", + " // Show the results pane (this will cause the other sibling panes", + " // (like 'results-notfound') to be hidden because they're flagged as mutually", + " // exclusive)", + " this.simpleTool.showPane('results-found');", + " }", + " activateNoResultsPane(): void {", + " // Show the results-notfound pane (this will cause the other sibling panes", + " // (like 'results-found') to be hidden because they're flagged as mutually", + " // exclusive)", + " this.simpleTool.showPane('results-notfound');", + " }", + " hideResultsPane(): void {", + " // Hide the results pane", + " // We generally do this when we're changing options or don't have a valid set", + " // of results to display.", + " // Note that this will hide both the `results-found` and `results-notfound` panes", + " // because they're child panes of this one", + " this.simpleTool.hidePane('results');", + " }", + " // The 'typeSelector' pane is the initial pane that allows the player to select the", + " // type of 'thing' they want to locate (biome or structure). This function builds", + " // a dropdown containing the two options.", + " // The onChange event handler is used to show the appropriate sub-pane based on the", + " // selection.", + " buildTypeSelectionPane(component: ISimpleToolPaneComponent): void {", + " const actualPane = component.pane;", + " // We create a data binding between this pane/server script and the client-side", + " // UI component. This binding allows changes here to be reflected in the UI and", + " // changes made to the UI to be reflected here.", + " // It creates a bi-directional networking link between the client and server.", + " // We use this to ensure that the selected type is always up-to-date.", + " const locatorType: LocateSelectorType = {", + " locateMode: makeObservable(LocateMode.Biome),", + " };", + " // Create a dropdown with two options: Biome and Structure", + " // and an event handler to show the appropriate sub-pane when the selection changes", + " actualPane.addDropdown(locatorType.locateMode, {", + " title: 'sample.simplelocate.tool.locatetype.title',", + " entries: [", + " {", + " label: 'sample.simplelocate.tool.locatetype.biome',", + " value: LocateMode.Biome,", + " },", + " {", + " label: 'sample.simplelocate.tool.locatetype.structure',", + " value: LocateMode.Structure,", + " },", + " ],", + " onChange: (newValue: number) => {", + " const mode = newValue as LocateMode;", + " if (mode === LocateMode.Biome) {", + " component.simpleTool.showPane('type-biome');", + " } else {", + " component.simpleTool.showPane('type-structure');", + " }", + " component.simpleTool.hidePane('results');", + " },", + " });", + " }", + " buildBiomeSearchPane(component: ISimpleToolPaneComponent): void {", + " const actualPane = component.pane;", + " const biomeType: LocateBiomeSourceType = {", + " biomeId: makeObservable(0),", + " biomePos: VECTOR3_ZERO,", + " };", + " const listOfBiomes = BiomeTypes.getAll().map((v, i) => {", + " const names = v.id;", + " const item: IDropdownItem = {", + " label: names.replace('minecraft:', '').replace('_', ' '),", + " value: i,", + " };", + " return item;", + " });", + " actualPane.addDropdown(biomeType.biomeId, {", + " title: 'sample.simplelocate.tool.biome.title',", + " entries: listOfBiomes,", + " onChange: () => {", + " component.simpleTool.hidePane('results');", + " },", + " });", + " const locateBiomeAction = component.session.actionManager.createAction({", + " actionType: ActionTypes.NoArgsAction,", + " onExecute: () => {", + " const biome = BiomeTypes.getAll()[biomeType.biomeId.value].id;", + " const player: Player = component.session.extensionContext.player;", + " const biomePos = player.dimension.findClosestBiome(player.location, biome);", + " if (biomePos) {", + " this.activateResultsPane(biome, biomePos);", + " } else {", + " this.activateNoResultsPane();", + " }", + " },", + " });", + " actualPane.addButton(locateBiomeAction, {", + " title: 'sample.simplelocate.tool.biome.find',", + " visible: true,", + " icon: 'pinIcon',", + " });", + " }", + " buildStructurePane(component: ISimpleToolPaneComponent): void {", + " const actualPane = component.pane;", + " actualPane.addText('sample.simplelocate.tool.structure.message', {", + " border: true,", + " });", + " }", + " buildResultsPane(component: ISimpleToolPaneComponent): void {", + " const actualPane = component.pane;", + " actualPane.addText(`Found ${this._results.foundType}`);", + " actualPane.addVector3_deprecated(this._results, 'foundPos', {", + " title: 'sample.simplelocate.tool.results.foundat',", + " enable: false,", + " visible: true,", + " });", + " actualPane.addButton(", + " component.session.actionManager.createAction({", + " actionType: ActionTypes.NoArgsAction,", + " onExecute: () => {", + " const pos = this._results.foundPos;", + " component.session.extensionContext.player.teleport(pos);", + " },", + " }),", + " {", + " title: 'sample.simplelocate.tool.results.goto',", + " }", + " );", + " }", + " buildNoResultsPane(component: ISimpleToolPaneComponent): void {", + " const actualPane = component.pane;", + " actualPane.addText('sample.simplelocate.tool.results.notfound', {", + " border: true,", + " });", + " }", + " constructor(session: IPlayerUISession) {", + " super();", + " const toolOptions: ISimpleToolOptions = {", + " name: 'Simple Locate Biome',", + " activationKeyBinding: {", + " binding: {", + " key: KeyboardKey.KEY_L,", + " modifier: InputModifier.Control | InputModifier.Shift,", + " },", + " info: {", + " uniqueId: 'editorSample:locateBiomeToolKeyBinding:toggleTool',", + " label: 'sample.simplelocate.tool.keyBinding.toggleTool',", + " },", + " },", + " propertyPaneOptions: {", + " id: 'pane',", + " title: 'sample.simplelocate.tool.title',", + " childPaneInitiallyVisible: 'typeSelector',", + " // There are 2 sub-panes in the root window, and 2 sub-panes in the first sub-pane", + " // 1 typeSelector - The Locate Type Selector", + " // 1-1 type-biome - The Biome Locator", + " // 1-2 type-structure - The Structure Locator", + " // 2 results - The results", + " // 2-1 results-found - Actual Results", + " // 2-2 results-notfound - Not Found warning", + " childPanes: [", + " {", + " id: 'typeSelector',", + " title: 'sample.simplelocate.tool.locatetype.title',", + " onBeginFinalize: (component) => this.buildTypeSelectionPane(component),", + " childPaneInitiallyVisible: 'type-biome',", + " childPanesMutuallyExclusive: true,", + " childPanes: [", + " {", + " id: 'type-biome',", + " title: 'sample.simplelocate.tool.locatetype.biome.title',", + " onBeginFinalize: (component) => this.buildBiomeSearchPane(component),", + " },", + " {", + " id: 'type-structure',", + " title: 'sample.simplelocate.tool.locatetype.structure.title',", + " onBeginFinalize: (component) => this.buildStructurePane(component),", + " },", + " ],", + " },", + " {", + " id: 'results',", + " title: 'sample.simplelocate.tool.results.title',", + " childPanesMutuallyExclusive: true,", + " childPanes: [", + " {", + " id: 'results-found',", + " title: 'sample.simplelocate.tool.results.foundat.title',", + " onBeginFinalize: (component) => this.buildResultsPane(component),", + " },", + " {", + " id: 'results-notfound',", + " title: 'sample.simplelocate.tool.results.notfound.title',", + " onBeginFinalize: (component) => this.buildNoResultsPane(component),", + " },", + " ],", + " },", + " ],", + " },", + " };", + " this.setupSimpleTool(session, toolOptions);", + " }", + "}", + "/**", + " * Provides a 'Simple Biome Locate' extension to demonstrate the new Simple Tool wrapper system", + " * @beta", + " */", + "export function registerSimpleLocateBiomeExtension() {", + " registerEditorExtension(", + " 'simple-locate-sample',", + " (uiSession) => {", + " uiSession.log.debug(`Initializing extension [${uiSession.extensionContext.extensionInfo.name}]`);", + " // Just instantiate the tool and return it to the editor - the editor will deal with cleaning up", + " // and shutting down the tool when it's no longer required", + " const simpleLocateTool = new SimpleLocate(uiSession);", + " // Return an array of things for the editor to clean up.", + " // If you wanted to, you can create many individual tools in this single register function", + " // and return them all in the array, and the editor will clean them all up when the extension", + " // is unloaded", + " return [simpleLocateTool];", + " },", + " (uiSession) => {", + " uiSession.log.debug(", + " `Shutting down extension [${uiSession.extensionContext.extensionInfo.name}] for player [${uiSession.extensionContext.player.name}]`", + " );", + " },", + " {", + " description: 'Simple Locate Biome Tool Sample Extension',", + " notes: 'by Dave & Mitch',", + " }", + " );", + "}", + "" + ] + }, + "star-brush-shape.ts": { + "description": "star-brush-shape.ts ", + "prefix": ["mc"], + "body": [ + "// Copyright (c) Mojang AB. All rights reserved.", + "import {", + " BlockVolume,", + " CompoundBlockVolume,", + " CompoundBlockVolumeAction,", + " CompoundBlockVolumePositionRelativity,", + "} from '@minecraft/server';", + "import { IPlayerUISession, registerEditorExtension, SettingsUIElement } from '@minecraft/server-editor';", + "type Settings = {", + " radius: number;", + " includeVertical: boolean;", + "};", + "const MIN_RADIUS = 1;", + "const MAX_RADIUS = 12;", + "/**", + " * Register Star Brush extension", + " */", + "export function registerStarBrushExtension() {", + " registerEditorExtension(", + " 'StarBrush',", + " (uiSession: IPlayerUISession) => {", + " uiSession.log.debug(`Initializing ${uiSession.extensionContext.extensionInfo.name}`);", + " const settings: Settings = {", + " radius: 3,", + " includeVertical: true,", + " };", + " const rebuildStar = () => {", + " const compoundVolume = new CompoundBlockVolume();", + " // center", + " compoundVolume.pushVolume({", + " action: CompoundBlockVolumeAction.Add,", + " locationRelativity: CompoundBlockVolumePositionRelativity.Relative,", + " volume: new BlockVolume({ x: 0, y: 0, z: 0 }, { x: 0, y: 0, z: 0 }),", + " });", + " if (settings.radius > 1) {", + " const r = settings.radius;", + " // left", + " compoundVolume.pushVolume({", + " action: CompoundBlockVolumeAction.Add,", + " locationRelativity: CompoundBlockVolumePositionRelativity.Relative,", + " volume: new BlockVolume({ x: -r, y: 0, z: 0 }, { x: 0, y: 0, z: 0 }),", + " });", + " // right", + " compoundVolume.pushVolume({", + " action: CompoundBlockVolumeAction.Add,", + " locationRelativity: CompoundBlockVolumePositionRelativity.Relative,", + " volume: new BlockVolume({ x: 0, y: 0, z: 0 }, { x: r, y: 0, z: 0 }),", + " });", + " // front", + " compoundVolume.pushVolume({", + " action: CompoundBlockVolumeAction.Add,", + " locationRelativity: CompoundBlockVolumePositionRelativity.Relative,", + " volume: new BlockVolume({ x: 0, y: 0, z: 0 }, { x: 0, y: 0, z: r }),", + " });", + " // back", + " compoundVolume.pushVolume({", + " action: CompoundBlockVolumeAction.Add,", + " locationRelativity: CompoundBlockVolumePositionRelativity.Relative,", + " volume: new BlockVolume({ x: 0, y: 0, z: -r }, { x: 0, y: 0, z: 0 }),", + " });", + " if (settings.includeVertical) {", + " // up", + " compoundVolume.pushVolume({", + " action: CompoundBlockVolumeAction.Add,", + " locationRelativity: CompoundBlockVolumePositionRelativity.Relative,", + " volume: new BlockVolume({ x: 0, y: 0, z: 0 }, { x: 0, y: r, z: 0 }),", + " });", + " // down", + " compoundVolume.pushVolume({", + " action: CompoundBlockVolumeAction.Add,", + " locationRelativity: CompoundBlockVolumePositionRelativity.Relative,", + " volume: new BlockVolume({ x: 0, y: 0, z: 0 }, { x: 0, y: -r, z: 0 }),", + " });", + " }", + " }", + " return compoundVolume;", + " };", + " const getStarUISettings = (): SettingsUIElement[] => {", + " return [", + " new SettingsUIElement(", + " 'Radius',", + " settings.radius,", + " arg => {", + " if (arg !== undefined && typeof arg === 'number') {", + " settings.radius = arg;", + " }", + " },", + " {", + " min: MIN_RADIUS,", + " max: MAX_RADIUS,", + " }", + " ),", + " new SettingsUIElement(", + " 'includeVertical',", + " settings.includeVertical,", + " arg => {", + " if (arg !== undefined && typeof arg === 'boolean') {", + " settings.includeVertical = arg;", + " }", + " },", + " { refreshOnChange: true }", + " ),", + " new SettingsUIElement('Vector3', { x: 1, y: 2, z: 3 }, _value => {}),", + " ];", + " };", + " uiSession.extensionContext.brushShapeManager.registerBrushShape(", + " 'Star-sample',", + " 'star',", + " rebuildStar,", + " getStarUISettings", + " );", + " return [];", + " },", + " (uiSession: IPlayerUISession) => {", + " uiSession.log.debug(`Uninitializing ${uiSession.extensionContext.extensionInfo.name}`);", + " },", + " {", + " description: 'Star brush shape sample extension',", + " notes: 'An example of registering a custom brush shape.',", + " }", + " );", + "}", + "" + ] + }, + "tree-generator.ts": { + "description": "tree-generator.ts ", + "prefix": ["mc"], + "body": [ + "// Copyright (c) Mojang AB. All rights reserved.", + "import {", + " ActionTypes,", + " EditorInputContext,", + " IDropdownPropertyItemEntry,", + " IModalTool,", + " IObservable,", + " IPlayerUISession,", + " InputModifier,", + " KeyboardKey,", + " MouseActionType,", + " MouseInputType,", + " MouseProps,", + " NumberPropertyItemVariant,", + " Ray,", + " makeObservable,", + " registerEditorExtension,", + "} from '@minecraft/server-editor';", + "import { BlockPermutation, Vector3 } from '@minecraft/server';", + "import { MinecraftBlockTypes } from '@minecraft/vanilla-data';", + "interface TreeToolSettings {", + " height: IObservable;", + " randomHeightVariance: IObservable;", + " treeType: IObservable;", + "}", + "interface TreeBlockChangeData {", + " location: Vector3;", + " newBlock: BlockPermutation;", + "}", + "interface ITree {", + " place(location: Vector3, settings: TreeToolSettings): TreeBlockChangeData[];", + "}", + "export class SimpleTree implements ITree {", + " logType: BlockPermutation;", + " leafType: BlockPermutation;", + " constructor(logType: BlockPermutation, leafType: BlockPermutation) {", + " this.logType = logType;", + " this.leafType = leafType;", + " }", + " place(location: Vector3, settings: TreeToolSettings): TreeBlockChangeData[] {", + " const result: TreeBlockChangeData[] = [];", + " const heightOffset =", + " Math.floor(Math.random() * settings.randomHeightVariance.value) - settings.randomHeightVariance.value / 2;", + " const calculatedHeight = settings.height.value + heightOffset;", + " ///", + " // Trunk", + " ///", + " for (let y = 0; y <= calculatedHeight; ++y) {", + " const offsetLocation: Vector3 = {", + " x: location.x,", + " y: location.y + y,", + " z: location.z,", + " };", + " result.push({", + " location: offsetLocation,", + " newBlock: this.logType,", + " });", + " }", + " ///", + " // Leaves", + " ///", + " ///", + " // Plus sign on top", + " ///", + " const leafBlocks = [", + " { x: 0, y: 1, z: 0 },", + " { x: 1, y: 1, z: 0 },", + " { x: -1, y: 1, z: 0 },", + " { x: 0, y: 1, z: 1 },", + " { x: 0, y: 1, z: -1 },", + " { x: 1, y: 0, z: 0 },", + " { x: -1, y: 0, z: 0 },", + " { x: 0, y: 0, z: 1 },", + " { x: 0, y: 0, z: -1 },", + " ];", + " const randomPlusBlocks = [", + " { x: 1, y: 0, z: 1 },", + " { x: -1, y: 0, z: 1 },", + " { x: -1, y: 0, z: -1 },", + " { x: 1, y: 0, z: -1 },", + " ];", + " randomPlusBlocks.forEach((randBlock) => {", + " if (Math.random() > 0.5) {", + " leafBlocks.push(randBlock);", + " }", + " });", + " ///", + " // Fat bottom", + " ///", + " leafBlocks.push(", + " ...[", + " { x: 1, y: -1, z: -1 },", + " { x: 1, y: -1, z: 0 },", + " { x: 1, y: -1, z: 1 },", + " { x: 0, y: -1, z: 1 },", + " { x: 0, y: -1, z: -1 },", + " { x: -1, y: -1, z: -1 },", + " { x: -1, y: -1, z: 1 },", + " { x: -1, y: -1, z: 0 },", + " ]", + " );", + " if (calculatedHeight > 4) {", + " leafBlocks.push(", + " ...[", + " { x: 1, y: -2, z: -1 },", + " { x: 1, y: -2, z: 0 },", + " { x: 1, y: -2, z: 1 },", + " { x: 0, y: -2, z: 1 },", + " { x: 0, y: -2, z: -1 },", + " { x: -1, y: -2, z: -1 },", + " { x: -1, y: -2, z: 1 },", + " { x: -1, y: -2, z: 0 },", + " // Outer", + " { x: -2, y: -1, z: -1 },", + " { x: -2, y: -1, z: 0 },", + " { x: -2, y: -1, z: 1 },", + " { x: -1, y: -1, z: -2 },", + " { x: -1, y: -1, z: -1 },", + " { x: -1, y: -1, z: 0 },", + " { x: -1, y: -1, z: 1 },", + " { x: -1, y: -1, z: 2 },", + " { x: 0, y: -1, z: -2 },", + " { x: 0, y: -1, z: -1 },", + " { x: 0, y: -1, z: 1 },", + " { x: 0, y: -1, z: 2 },", + " { x: 1, y: -1, z: -2 },", + " { x: 1, y: -1, z: -1 },", + " { x: 1, y: -1, z: 0 },", + " { x: 1, y: -1, z: 1 },", + " { x: 1, y: -1, z: 2 },", + " { x: 2, y: -1, z: -1 },", + " { x: 2, y: -1, z: 0 },", + " { x: 2, y: -1, z: 1 },", + " { x: -2, y: -2, z: -1 },", + " { x: -2, y: -2, z: 0 },", + " { x: -2, y: -2, z: 1 },", + " { x: -1, y: -2, z: -2 },", + " { x: -1, y: -2, z: -1 },", + " { x: -1, y: -2, z: 0 },", + " { x: -1, y: -2, z: 1 },", + " { x: -1, y: -2, z: 2 },", + " { x: 0, y: -2, z: -2 },", + " { x: 0, y: -2, z: -1 },", + " { x: 0, y: -2, z: 1 },", + " { x: 0, y: -2, z: 2 },", + " { x: 1, y: -2, z: -2 },", + " { x: 1, y: -2, z: -1 },", + " { x: 1, y: -2, z: 0 },", + " { x: 1, y: -2, z: 1 },", + " { x: 1, y: -2, z: 2 },", + " { x: 2, y: -2, z: -1 },", + " { x: 2, y: -2, z: 0 },", + " { x: 2, y: -2, z: 1 },", + " ]", + " );", + " }", + " const randomFatBottomBlocks = [", + " { x: -2, y: -1, z: -2 },", + " { x: -2, y: -1, z: 2 },", + " { x: 2, y: -1, z: -2 },", + " { x: 2, y: -1, z: 2 },", + " ];", + " if (calculatedHeight > 4) {", + " randomFatBottomBlocks.push(", + " ...[", + " { x: -2, y: -2, z: -2 },", + " { x: -2, y: -2, z: 2 },", + " { x: 2, y: -2, z: -2 },", + " { x: 2, y: -2, z: 2 },", + " ]", + " );", + " }", + " leafBlocks.forEach((block) => {", + " const offsetLocation: Vector3 = {", + " x: location.x + block.x,", + " y: location.y + calculatedHeight + block.y,", + " z: location.z + block.z,", + " };", + " result.push({", + " location: offsetLocation,", + " newBlock: this.leafType,", + " });", + " });", + " return result;", + " }", + "}", + "const TreeTypes = [", + " {", + " name: 'Oak',", + " type: new SimpleTree(", + " BlockPermutation.resolve(MinecraftBlockTypes.OakLog),", + " BlockPermutation.resolve(MinecraftBlockTypes.OakLeaves)", + " ),", + " },", + " {", + " name: 'Spruce',", + " type: new SimpleTree(", + " BlockPermutation.resolve(MinecraftBlockTypes.SpruceLog),", + " BlockPermutation.resolve(MinecraftBlockTypes.SpruceLeaves)", + " ),", + " },", + " {", + " name: 'Birch',", + " type: new SimpleTree(", + " BlockPermutation.resolve(MinecraftBlockTypes.BirchLog),", + " BlockPermutation.resolve(MinecraftBlockTypes.BirchLeaves)", + " ),", + " },", + " {", + " name: 'Jungle',", + " type: new SimpleTree(", + " BlockPermutation.resolve(MinecraftBlockTypes.JungleLog),", + " BlockPermutation.resolve(MinecraftBlockTypes.JungleLeaves)", + " ),", + " },", + " {", + " name: 'Acacia',", + " type: new SimpleTree(", + " BlockPermutation.resolve(MinecraftBlockTypes.AcaciaLog),", + " BlockPermutation.resolve(MinecraftBlockTypes.AcaciaLeaves)", + " ),", + " },", + " {", + " name: 'Dark Oak',", + " type: new SimpleTree(", + " BlockPermutation.resolve(MinecraftBlockTypes.DarkOakLog),", + " BlockPermutation.resolve(MinecraftBlockTypes.DarkOakLeaves)", + " ),", + " },", + "];", + "function addToolSettingsPane(uiSession: IPlayerUISession, tool: IModalTool) {", + " // Create a pane that will be shown when the tool is selected", + " const pane = uiSession.createPropertyPane({", + " title: 'sample.treegenerator.pane.title',", + " });", + " // Settings", + " const settings: TreeToolSettings = {", + " height: makeObservable(5),", + " randomHeightVariance: makeObservable(0),", + " treeType: makeObservable(0),", + " };", + " const onExecuteTool = (ray?: Ray) => {", + " const player = uiSession.extensionContext.player;", + " let location: Vector3;", + " // Try finding a valid block to place a tree", + " if (ray) {", + " const raycastResult = player.dimension.getBlockFromRay(ray.location, ray.direction);", + " if (!raycastResult) {", + " uiSession.log.warning('Invalid target block!');", + " return;", + " }", + " location = raycastResult.block.location;", + " } else {", + " const targetBlock = player.dimension.getBlock(uiSession.extensionContext.cursor.getPosition());", + " if (!targetBlock) {", + " uiSession.log.warning('Invalid target block!');", + " return;", + " }", + " location = targetBlock.location;", + " }", + " // Begin transaction", + " uiSession.extensionContext.transactionManager.openTransaction('Tree Tool');", + " const selectedTreeType = TreeTypes[settings.treeType.value];", + " const affectedBlocks = selectedTreeType.type.place(location, settings);", + " // Track changes", + " uiSession.extensionContext.transactionManager.trackBlockChangeList(affectedBlocks.map((x) => x.location));", + " // Apply changes", + " let invalidBlockCount = 0;", + " affectedBlocks.forEach((item) => {", + " const block = player.dimension.getBlock(item.location);", + " if (block) {", + " block.setPermutation(item.newBlock);", + " } else {", + " ++invalidBlockCount;", + " }", + " });", + " if (invalidBlockCount > 0) {", + " uiSession.log.warning(`There were ${invalidBlockCount} invalid blocks while placing a tree!`);", + " }", + " // End transaction", + " uiSession.extensionContext.transactionManager.commitOpenTransaction();", + " };", + " // Add a dropdown for available tree types", + " pane.addDropdown(settings.treeType, {", + " title: 'sample.treegenerator.pane.type',", + " enable: true,", + " entries: TreeTypes.map((tree, index): IDropdownPropertyItemEntry => {", + " return {", + " label: tree.name,", + " value: index,", + " };", + " }, []),", + " });", + " pane.addNumber(settings.height, {", + " title: 'sample.treegenerator.pane.height',", + " min: 1,", + " max: 16,", + " variant: NumberPropertyItemVariant.InputFieldAndSlider,", + " isInteger: true,", + " });", + " pane.addNumber(settings.randomHeightVariance, {", + " title: 'sample.treegenerator.pane.variance',", + " min: 0,", + " max: 5,", + " variant: NumberPropertyItemVariant.InputFieldAndSlider,", + " isInteger: true,", + " });", + " // Create and an action that will be executed on key press", + " const executeAction = uiSession.actionManager.createAction({", + " actionType: ActionTypes.NoArgsAction,", + " onExecute: onExecuteTool,", + " });", + " // Register the action as a keyboard shortcut", + " tool.registerKeyBinding(", + " executeAction,", + " { key: KeyboardKey.KEY_T },", + " { uniqueId: 'editorSamples:treeGenerator:place', label: 'sample.treegenerator.keyBinding.place' }", + " );", + " tool.bindPropertyPane(pane);", + " pane.hide();", + " // Create an action that will be executed on left mouse click", + " const executeMouseAction = uiSession.actionManager.createAction({", + " actionType: ActionTypes.MouseRayCastAction,", + " onExecute: (mouseRay: Ray, mouseProps: MouseProps) => {", + " if (mouseProps.mouseAction === MouseActionType.LeftButton && mouseProps.inputType === MouseInputType.ButtonDown) {", + " onExecuteTool(mouseRay);", + " }", + " },", + " });", + " // Register the action for mouse button", + " tool.registerMouseButtonBinding(executeMouseAction);", + " return settings;", + "}", + "/**", + " * Create a new tool rail item for tree generator", + " */", + "function addTool(uiSession: IPlayerUISession) {", + " // Create action", + " const toolToggleAction = uiSession.actionManager.createAction({", + " actionType: ActionTypes.NoArgsAction,", + " onExecute: () => {", + " uiSession.toolRail.setSelectedToolId(tool.id);", + " },", + " });", + " const tool = uiSession.toolRail.addTool(", + " {", + " title: 'sample.treegenerator.tool.title',", + " icon: 'pack://textures/tree-generator.png',", + " tooltip: 'sample.treegenerator.tool.tooltip',", + " inputContextId: 'editorSamples:treeGenerator',", + " inputContextLabel: 'sample.treegenerator.tool.title',", + " },", + " toolToggleAction", + " );", + " // Register a global shortcut to select the tool", + " uiSession.inputManager.registerKeyBinding(", + " EditorInputContext.GlobalToolMode,", + " toolToggleAction,", + " { key: KeyboardKey.KEY_T, modifier: InputModifier.Control | InputModifier.Shift },", + " { uniqueId: 'editorSamples:treeGenerator:toggleTool', label: 'sample.treegenerator.keyBinding.toggleTool' }", + " );", + " return tool;", + "}", + "/**", + " * Register Tree Generator extension", + " */", + "export function registerTreeGeneratorExtension() {", + " registerEditorExtension(", + " 'TreeGenerator-sample',", + " (uiSession: IPlayerUISession) => {", + " uiSession.log.debug(`Initializing [${uiSession.extensionContext.extensionInfo.name}] extension`);", + " // Add extension tool to tool rail", + " const tool = addTool(uiSession);", + " // Create settings pane/window for the extension", + " addToolSettingsPane(uiSession, tool);", + " return [];", + " },", + " (uiSession: IPlayerUISession) => {", + " uiSession.log.debug(`Shutting down [${uiSession.extensionContext.extensionInfo.name}] extension`);", + " },", + " {", + " description: 'Tree Generator Sample Extension',", + " notes: 'by Jake',", + " }", + " );", + "}", + "" + ] + } +} diff --git a/app/public/data/snippets/index.json b/app/public/data/snippets/index.json new file mode 100644 index 00000000..4acf9d85 --- /dev/null +++ b/app/public/data/snippets/index.json @@ -0,0 +1,7 @@ +{ + "files": [ + "server-samples.json", + "server-ui-samples.json", + "editor-samples.json" + ] +} diff --git a/app/public/data/snippets/server-samples.json b/app/public/data/snippets/server-samples.json new file mode 100644 index 00000000..12b14a5d --- /dev/null +++ b/app/public/data/snippets/server-samples.json @@ -0,0 +1,647 @@ +{ +"buttonPushEvent": { + "description": "A simple button push before even See https://learn.microsoft.com/minecraft/creator/scriptapi/minecraft/server/buttonpushaftereventsignal", + "prefix": ["mc"], + "body": [" // set up a button on cobblestone", +" const cobblestone = targetLocation.dimension.getBlock(targetLocation);", +" const button = targetLocation.dimension.getBlock({", +" x: targetLocation.x,", +" y: targetLocation.y + 1,", +" z: targetLocation.z,", +" });", +" if (cobblestone === undefined || button === undefined) {", +" log('Could not find block at location.');", +" return -1;", +" }", +" cobblestone.setPermutation(BlockPermutation.resolve(MinecraftBlockTypes.Cobblestone));", +" button.setPermutation(", +" BlockPermutation.resolve(MinecraftBlockTypes.AcaciaButton).withState('facing_direction', 1 /* up */)", +" );", +" world.afterEvents.buttonPush.subscribe((buttonPushEvent: ButtonPushAfterEvent) => {", +" const eventLoc = buttonPushEvent.block.location;", +" if (eventLoc.x === targetLocation.x && eventLoc.y === targetLocation.y + 1 && eventLoc.z === targetLocation.z) {", +" log('Button push event at tick ' + system.currentTick);", +" }", +" });" +]}, +"leverActionEvent": { + "description": "A simple lever activate even See https://learn.microsoft.com/minecraft/creator/scriptapi/minecraft/server/leveractionaftereventsignal", + "prefix": ["mc"], + "body": [" // set up a lever", +" const cobblestone = targetLocation.dimension.getBlock(targetLocation);", +" const lever = targetLocation.dimension.getBlock({", +" x: targetLocation.x,", +" y: targetLocation.y + 1,", +" z: targetLocation.z,", +" });", +" if (cobblestone === undefined || lever === undefined) {", +" log('Could not find block at location.');", +" return -1;", +" }", +" cobblestone.setPermutation(BlockPermutation.resolve(MinecraftBlockTypes.Cobblestone));", +" lever.setPermutation(", +" BlockPermutation.resolve(MinecraftBlockTypes.Lever).withState('lever_direction', 'up_north_south' /* up */)", +" );", +" world.afterEvents.leverAction.subscribe((leverActionEvent: LeverActionAfterEvent) => {", +" const eventLoc = leverActionEvent.block.location;", +" if (eventLoc.x === targetLocation.x && eventLoc.y === targetLocation.y + 1 && eventLoc.z === targetLocation.z) {", +" log('Lever activate event at tick ' + system.currentTick);", +" }", +" });" +]}, +"tripWireTripEvent": { + "description": "A basic tripwire even See https://learn.microsoft.com/minecraft/creator/scriptapi/minecraft/server/tripwiretripaftereventsignal", + "prefix": ["mc"], + "body": [" // set up a tripwire", +" const redstone = targetLocation.dimension.getBlock({", +" x: targetLocation.x,", +" y: targetLocation.y - 1,", +" z: targetLocation.z,", +" });", +" const tripwire = targetLocation.dimension.getBlock(targetLocation);", +" if (redstone === undefined || tripwire === undefined) {", +" log('Could not find block at location.');", +" return -1;", +" }", +" redstone.setPermutation(BlockPermutation.resolve(MinecraftBlockTypes.RedstoneBlock));", +" tripwire.setPermutation(BlockPermutation.resolve(MinecraftBlockTypes.TripWire));", +" world.afterEvents.tripWireTrip.subscribe((tripWireTripEvent: TripWireTripAfterEvent) => {", +" const eventLoc = tripWireTripEvent.block.location;", +" if (eventLoc.x === targetLocation.x && eventLoc.y === targetLocation.y && eventLoc.z === targetLocation.z) {", +" log(", +" 'Tripwire trip event at tick ' +", +" system.currentTick +", +" (tripWireTripEvent.sources.length > 0 ? ' by entity ' + tripWireTripEvent.sources[0].id : '')", +" );", +" }", +" });" +]}, +"addBlockColorCube": { + "description": "Creates a multicolored block out of different colors of wool See https://learn.microsoft.com/minecraft/creator/scriptapi/minecraft/server/blockpermutation/resolve", + "prefix": ["mc"], + "body": [" const allWoolBlocks: string[] = [", +" MinecraftBlockTypes.WhiteWool,", +" MinecraftBlockTypes.OrangeWool,", +" MinecraftBlockTypes.MagentaWool,", +" MinecraftBlockTypes.LightBlueWool,", +" MinecraftBlockTypes.YellowWool,", +" MinecraftBlockTypes.LimeWool,", +" MinecraftBlockTypes.PinkWool,", +" MinecraftBlockTypes.GrayWool,", +" MinecraftBlockTypes.LightGrayWool,", +" MinecraftBlockTypes.CyanWool,", +" MinecraftBlockTypes.PurpleWool,", +" MinecraftBlockTypes.BlueWool,", +" MinecraftBlockTypes.BrownWool,", +" MinecraftBlockTypes.GreenWool,", +" MinecraftBlockTypes.RedWool,", +" MinecraftBlockTypes.BlackWool,", +" ];", +" const cubeDim = 7;", +" let colorIndex = 0;", +" for (let x = 0; x <= cubeDim; x++) {", +" for (let y = 0; y <= cubeDim; y++) {", +" for (let z = 0; z <= cubeDim; z++) {", +" colorIndex++;", +" targetLocation.dimension", +" .getBlock(Vector3Utils.add(targetLocation, { x, y, z }))", +" ?.setPermutation(BlockPermutation.resolve(allWoolBlocks[colorIndex % allWoolBlocks.length]));", +" }", +" }", +" }" +]}, +"createExplosion": { + "description": "Creates an explosion in the world See https://learn.microsoft.com/minecraft/creator/scriptapi/minecraft/server/dimension/createexplosion", + "prefix": ["mc"], + "body": [" log('Creating an explosion of radius 10.');", +" targetLocation.dimension.createExplosion(targetLocation, 10);" +]}, +"createNoBlockExplosion": { + "description": "Creates an explosion in the world that does not impact blocks See https://learn.microsoft.com/minecraft/creator/scriptapi/minecraft/server/dimension/createexplosion", + "prefix": ["mc"], + "body": [" const explodeNoBlocksLoc = Vector3Utils.floor(Vector3Utils.add(targetLocation, { x: 1, y: 2, z: 1 }));", +" log('Creating an explosion of radius 15 that does not break blocks.');", +" targetLocation.dimension.createExplosion(explodeNoBlocksLoc, 15, { breaksBlocks: false });" +]}, +"createExplosions": { + "description": "Creates a fire explosion and an underwater explosion in the world See https://learn.microsoft.com/minecraft/creator/scriptapi/minecraft/server/dimension/createexplosion", + "prefix": ["mc"], + "body": [" const explosionLoc = Vector3Utils.add(targetLocation, { x: 0.5, y: 0.5, z: 0.5 });", +" log('Creating an explosion of radius 15 that causes fire.');", +" targetLocation.dimension.createExplosion(explosionLoc, 15, { causesFire: true });", +" const belowWaterLoc = Vector3Utils.add(targetLocation, { x: 3, y: 1, z: 3 });", +" log('Creating an explosion of radius 10 that can go underwater.');", +" targetLocation.dimension.createExplosion(belowWaterLoc, 10, { allowUnderwater: true });" +]}, +"itemStacks": { + "description": "Creates free-floating item stacks in the world See https://learn.microsoft.com/minecraft/creator/scriptapi/minecraft/server/itemstack", + "prefix": ["mc"], + "body": [" const oneItemLoc = { x: targetLocation.x + targetLocation.y + 3, y: 2, z: targetLocation.z + 1 };", +" const fiveItemsLoc = { x: targetLocation.x + 1, y: targetLocation.y + 2, z: targetLocation.z + 1 };", +" const diamondPickaxeLoc = { x: targetLocation.x + 2, y: targetLocation.y + 2, z: targetLocation.z + 4 };", +" const oneEmerald = new ItemStack(MinecraftItemTypes.Emerald, 1);", +" const onePickaxe = new ItemStack(MinecraftItemTypes.DiamondPickaxe, 1);", +" const fiveEmeralds = new ItemStack(MinecraftItemTypes.Emerald, 5);", +" log(`Spawning an emerald at (${oneItemLoc.x}, ${oneItemLoc.y}, ${oneItemLoc.z})`);", +" targetLocation.dimension.spawnItem(oneEmerald, oneItemLoc);", +" log(`Spawning five emeralds at (${fiveItemsLoc.x}, ${fiveItemsLoc.y}, ${fiveItemsLoc.z})`);", +" targetLocation.dimension.spawnItem(fiveEmeralds, fiveItemsLoc);", +" log(`Spawning a diamond pickaxe at (${diamondPickaxeLoc.x}, ${diamondPickaxeLoc.y}, ${diamondPickaxeLoc.z})`);", +" targetLocation.dimension.spawnItem(onePickaxe, diamondPickaxeLoc);" +]}, +"quickFoxLazyDog": { + "description": "Creates a fox and, well, a wolf with effects applied See https://learn.microsoft.com/minecraft/creator/scriptapi/minecraft/server/dimension/spawnentity", + "prefix": ["mc"], + "body": [" const fox = targetLocation.dimension.spawnEntity(MinecraftEntityTypes.Fox, {", +" x: targetLocation.x + 1,", +" y: targetLocation.y + 2,", +" z: targetLocation.z + 3,", +" });", +" fox.addEffect(MinecraftEffectTypes.Speed, 10, {", +" amplifier: 2,", +" });", +" log('Created a fox.');", +" const wolf = targetLocation.dimension.spawnEntity(MinecraftEntityTypes.Wolf, {", +" x: targetLocation.x + 4,", +" y: targetLocation.y + 2,", +" z: targetLocation.z + 3,", +" });", +" wolf.addEffect(MinecraftEffectTypes.Slowness, 10, {", +" amplifier: 2,", +" });", +" wolf.isSneaking = true;", +" log('Created a sneaking wolf.', 1);" +]}, +"incrementDynamicProperty": { + "description": "Increments a dynamic numeric persisted property See https://learn.microsoft.com/minecraft/creator/scriptapi/minecraft/server/world/getdynamicproperty", + "prefix": ["mc"], + "body": [" let number = world.getDynamicProperty('samplelibrary:number');", +" log('Current value is: ' + number);", +" if (number === undefined) {", +" number = 0;", +" }", +" if (typeof number !== 'number') {", +" log('Number is of an unexpected type.');", +" return -1;", +" }", +" world.setDynamicProperty('samplelibrary:number', number + 1);" +]}, +"incrementDynamicPropertyInJsonBlob": { + "description": "Increments a dynamic numeric persisted property See https://learn.microsoft.com/minecraft/creator/scriptapi/minecraft/server/world/getdynamicproperty", + "prefix": ["mc"], + "body": [" let paintStr = world.getDynamicProperty('samplelibrary:longerjson');", +" let paint: { color: string; intensity: number } | undefined = undefined;", +" log('Current value is: ' + paintStr);", +" if (paintStr === undefined) {", +" paint = {", +" color: 'purple',", +" intensity: 0,", +" };", +" } else {", +" if (typeof paintStr !== 'string') {", +" log('Paint is of an unexpected type.');", +" return -1;", +" }", +" try {", +" paint = JSON.parse(paintStr);", +" } catch (e) {", +" log('Error parsing serialized struct.');", +" return -1;", +" }", +" }", +" if (!paint) {", +" log('Error parsing serialized struct.');", +" return -1;", +" }", +" paint.intensity++;", +" paintStr = JSON.stringify(paint); // be very careful to ensure your serialized JSON str cannot exceed limits", +" world.setDynamicProperty('samplelibrary:longerjson', paintStr);" +]}, +"triggerEvent": { + "description": "Creates a creeper and then triggers an explosion See https://learn.microsoft.com/minecraft/creator/scriptapi/minecraft/server/dimension/spawnentity", + "prefix": ["mc"], + "body": [" const creeper = targetLocation.dimension.spawnEntity(MinecraftEntityTypes.Creeper, targetLocation);", +" creeper.triggerEvent('minecraft:start_exploding_forced');" +]}, +"applyImpulse": { + "description": "Creates a zombie and then applies an impulse See https://learn.microsoft.com/minecraft/creator/scriptapi/minecraft/server/entity/applyimpulse", + "prefix": ["mc"], + "body": [" const zombie = targetLocation.dimension.spawnEntity(MinecraftEntityTypes.Zombie, targetLocation);", +" zombie.clearVelocity();", +" // throw the zombie up in the air", +" zombie.applyImpulse({ x: 0, y: 0.5, z: 0 });" +]}, +"getFireworkVelocity": { + "description": "Gets a velocity of a firewor See https://learn.microsoft.com/minecraft/creator/scriptapi/minecraft/server/entity/getvelocity", + "prefix": ["mc"], + "body": [" const fireworkRocket = targetLocation.dimension.spawnEntity(MinecraftEntityTypes.FireworksRocket, targetLocation);", +" system.runTimeout(() => {", +" const velocity = fireworkRocket.getVelocity();", +" log('Velocity of firework is: (x: ' + velocity.x + ', y:' + velocity.y + ', z:' + velocity.z + ')');", +" }, 5);" +]}, +"applyDamageThenHeal": { + "description": "Applies damage then heals an entity See https://learn.microsoft.com/minecraft/creator/scriptapi/minecraft/server/entity/applydamage", + "prefix": ["mc"], + "body": [" const skelly = targetLocation.dimension.spawnEntity(MinecraftEntityTypes.Skeleton, targetLocation);", +" skelly.applyDamage(19); // skeletons have max damage of 20 so this is a near-death skeleton", +" system.runTimeout(() => {", +" const health = skelly.getComponent(EntityComponentTypes.Health) as EntityHealthComponent;", +" log('Skeleton health before heal: ' + health?.currentValue);", +" health?.resetToMaxValue();", +" log('Skeleton health after heal: ' + health?.currentValue);", +" }, 20);" +]}, +"setOnFire": { + "description": "Applies damage then heals an entity See https://learn.microsoft.com/minecraft/creator/scriptapi/minecraft/server/entity/setonfire", + "prefix": ["mc"], + "body": [" const skelly = targetLocation.dimension.spawnEntity(MinecraftEntityTypes.Skeleton, targetLocation);", +" skelly.setOnFire(20, true);", +" system.runTimeout(() => {", +" const onfire = skelly.getComponent(EntityComponentTypes.OnFire) as EntityOnFireComponent;", +" log(onfire?.onFireTicksRemaining + ' fire ticks remaining.');", +" skelly.extinguishFire(true);", +" log('Never mind. Fire extinguished.');", +" }, 20);" +]}, +"teleport": { + "description": "Does a basic teleport action See https://learn.microsoft.com/minecraft/creator/scriptapi/minecraft/server/entity/teleport", + "prefix": ["mc"], + "body": [" const cow = targetLocation.dimension.spawnEntity(MinecraftEntityTypes.Cow, targetLocation);", +" system.runTimeout(() => {", +" cow.teleport(", +" { x: targetLocation.x + 2, y: targetLocation.y + 2, z: targetLocation.z + 2 },", +" {", +" facingLocation: targetLocation,", +" }", +" );", +" }, 20);" +]}, +"teleportMovement": { + "description": "Does a basic movements with frequent teleport actions See https://learn.microsoft.com/minecraft/creator/scriptapi/minecraft/server/entity/teleport", + "prefix": ["mc"], + "body": [" const pig = targetLocation.dimension.spawnEntity(MinecraftEntityTypes.Pig, targetLocation);", +" let inc = 1;", +" const runId = system.runInterval(() => {", +" pig.teleport(", +" { x: targetLocation.x + inc / 4, y: targetLocation.y + inc / 4, z: targetLocation.z + inc / 4 },", +" {", +" facingLocation: targetLocation,", +" }", +" );", +" if (inc > 100) {", +" system.clearRun(runId);", +" }", +" inc++;", +" }, 4);" +]}, +"bounceSkeletons": { + "description": "Amongst a set of entities, uses entity query to find specific entities and bounce them with applyKnockback See https://learn.microsoft.com/minecraft/creator/scriptapi/minecraft/server/dimension/getentities", + "prefix": ["mc"], + "body": [" let mobs = ['creeper', 'skeleton', 'sheep'];", +" // create some sample mob data", +" for (let i = 0; i < 10; i++) {", +" targetLocation.dimension.spawnEntity(mobs[i % mobs.length], targetLocation);", +" }", +" let eqo: EntityQueryOptions = {", +" type: 'skeleton',", +" };", +" for (let entity of targetLocation.dimension.getEntities(eqo)) {", +" entity.applyKnockback(0, 0, 0, 1);", +" }" +]}, +"tagsQuery": { + "description": "Amongst a set of entities, uses entity query to find specific entities based on a tag See https://learn.microsoft.com/minecraft/creator/scriptapi/minecraft/server/dimension/getentities", + "prefix": ["mc"], + "body": [" let mobs = ['creeper', 'skeleton', 'sheep'];", +" // create some sample mob data", +" for (let i = 0; i < 10; i++) {", +" let mobTypeId = mobs[i % mobs.length];", +" let entity = targetLocation.dimension.spawnEntity(mobTypeId, targetLocation);", +" entity.addTag('mobparty.' + mobTypeId);", +" }", +" let eqo: EntityQueryOptions = {", +" tags: ['mobparty.skeleton'],", +" };", +" for (let entity of targetLocation.dimension.getEntities(eqo)) {", +" entity.kill();", +" }" +]}, +"logEntitySpawnEvent": { + "description": "Registers and contains an entity spawned event handler See https://learn.microsoft.com/minecraft/creator/scriptapi/minecraft/server/entityspawnaftereventsignal/subscribe", + "prefix": ["mc"], + "body": [" // register a new function that is called when a new entity is created.", +" world.afterEvents.entitySpawn.subscribe((entityEvent: EntitySpawnAfterEvent) => {", +" if (entityEvent && entityEvent.entity) {", +" log(`New entity of type '${entityEvent.entity.typeId}' created!`, 1);", +" } else {", +" log(`The entity event didn't work as expected.`, -1);", +" }", +" });", +" system.runTimeout(() => {", +" spawnAdultHorse(log, targetLocation);", +" }, 20);" +]}, +"spawnAdultHorse": { + "description": "A simple function to create a horse See https://learn.microsoft.com/minecraft/creator/scriptapi/minecraft/server/dimension/spawnentity", + "prefix": ["mc"], + "body": [" log('Create a horse and triggering the 'ageable_grow_up' event, ensuring the horse is created as an adult');", +" targetLocation.dimension.spawnEntity(", +" 'minecraft:horse',", +" Vector3Utils.add(targetLocation, { x: 0, y: 1, z: 0 })", +" );" +]}, +"givePlayerElytra": { + "description": "Give a player elytra See https://learn.microsoft.com/minecraft/creator/scriptapi/minecraft/server/entityequipmentinventorycomponent", + "prefix": ["mc"], + "body": [" let players = world.getAllPlayers();", +" const equipment = players[0].getComponent(EntityComponentTypes.Equippable) as EntityEquippableComponent;", +" equipment?.setEquipment(EquipmentSlot.Chest, new ItemStack(MinecraftItemTypes.Elytra));", +" log('Player given Elytra');" +]}, +"givePlayerEquipment": { + "description": "Give a player, and an armorstand, a full set of equipment See https://learn.microsoft.com/minecraft/creator/scriptapi/minecraft/server/itemstack", + "prefix": ["mc"], + "body": [" let players = world.getAllPlayers();", +" const armorStandLoc = { x: targetLocation.x, y: targetLocation.y, z: targetLocation.z + 4 };", +" let armorStand = players[0].dimension.spawnEntity(MinecraftItemTypes.ArmorStand, armorStandLoc);", +" const equipmentCompPlayer = players[0].getComponent(EntityComponentTypes.Equippable) as EntityEquippableComponent;", +" if (equipmentCompPlayer) {", +" equipmentCompPlayer.setEquipment(EquipmentSlot.Head, new ItemStack(MinecraftItemTypes.GoldenHelmet));", +" equipmentCompPlayer.setEquipment(EquipmentSlot.Chest, new ItemStack(MinecraftItemTypes.IronChestplate));", +" equipmentCompPlayer.setEquipment(EquipmentSlot.Legs, new ItemStack(MinecraftItemTypes.DiamondLeggings));", +" equipmentCompPlayer.setEquipment(EquipmentSlot.Feet, new ItemStack(MinecraftItemTypes.NetheriteBoots));", +" equipmentCompPlayer.setEquipment(EquipmentSlot.Mainhand, new ItemStack(MinecraftItemTypes.WoodenSword));", +" equipmentCompPlayer.setEquipment(EquipmentSlot.Offhand, new ItemStack(MinecraftItemTypes.Shield));", +" }", +" const equipmentCompArmorStand = armorStand.getComponent(EntityComponentTypes.Equippable) as EntityEquippableComponent;", +" if (equipmentCompArmorStand) {", +" equipmentCompArmorStand.setEquipment(EquipmentSlot.Head, new ItemStack(MinecraftItemTypes.GoldenHelmet));", +" equipmentCompArmorStand.setEquipment(EquipmentSlot.Chest, new ItemStack(MinecraftItemTypes.IronChestplate));", +" equipmentCompArmorStand.setEquipment(EquipmentSlot.Legs, new ItemStack(MinecraftItemTypes.DiamondLeggings));", +" equipmentCompArmorStand.setEquipment(EquipmentSlot.Feet, new ItemStack(MinecraftItemTypes.NetheriteBoots));", +" equipmentCompArmorStand.setEquipment(EquipmentSlot.Mainhand, new ItemStack(MinecraftItemTypes.WoodenSword));", +" equipmentCompArmorStand.setEquipment(EquipmentSlot.Offhand, new ItemStack(MinecraftItemTypes.Shield));", +" }" +]}, +"playMusicAndSound": { + "description": "Plays some music and sound effects See https://learn.microsoft.com/minecraft/creator/scriptapi/minecraft/server/world/playmusic", + "prefix": ["mc"], + "body": [" const players = world.getPlayers();", +" const musicOptions: MusicOptions = {", +" fade: 0.5,", +" loop: true,", +" volume: 1.0,", +" };", +" world.playMusic('music.menu', musicOptions);", +" const worldSoundOptions: WorldSoundOptions = {", +" pitch: 0.5,", +" volume: 4.0,", +" };", +" world.playSound('ambient.weather.thunder', targetLocation, worldSoundOptions);", +" const playerSoundOptions: PlayerSoundOptions = {", +" pitch: 1.0,", +" volume: 1.0,", +" };", +" players[0].playSound('bucket.fill_water', playerSoundOptions);" +]}, +"spawnParticle": { + "description": "Spawns a cloud of colored flame particles See https://learn.microsoft.com/minecraft/creator/scriptapi/minecraft/server/dimension/spawnparticle", + "prefix": ["mc"], + "body": [" for (let i = 0; i < 100; i++) {", +" const molang = new MolangVariableMap();", +" molang.setColorRGB('variable.color', { red: random(), green: random(), blue: random() });", +" let newLocation = {", +" x: targetLocation.x + floor(random() * 8) - 4,", +" y: targetLocation.y + floor(random() * 8) - 4,", +" z: targetLocation.z + floor(random() * 8) - 4,", +" };", +" targetLocation.dimension.spawnParticle('minecraft:colored_flame_particle', newLocation, molang);", +" }" +]}, +"pistonAfterEvent": { + "description": "A simple piston after activate even See https://learn.microsoft.com/minecraft/creator/scriptapi/minecraft/server/pistonactivateaftereventsignal/subscribe", + "prefix": ["mc"], + "body": [" // set up a couple of piston blocks", +" const piston = targetLocation.dimension.getBlock(targetLocation);", +" const button = targetLocation.dimension.getBlock({", +" x: targetLocation.x,", +" y: targetLocation.y + 1,", +" z: targetLocation.z,", +" });", +" if (piston === undefined || button === undefined) {", +" log('Could not find block at location.');", +" return -1;", +" }", +" piston.setPermutation(BlockPermutation.resolve(MinecraftBlockTypes.Piston).withState('facing_direction', 3));", +" button.setPermutation(BlockPermutation.resolve(MinecraftBlockTypes.AcaciaButton).withState('facing_direction', 1));", +" world.afterEvents.pistonActivate.subscribe((pistonEvent: PistonActivateAfterEvent) => {", +" const eventLoc = pistonEvent.piston.block.location;", +" if (eventLoc.x === targetLocation.x && eventLoc.y === targetLocation.y && eventLoc.z === targetLocation.z) {", +" log(", +" 'Piston event at ' +", +" system.currentTick +", +" (pistonEvent.piston.isMoving ? ' Moving' : '') +", +" (pistonEvent.piston.state === BlockPistonState.Expanding ? ' Expanding' : '') +", +" (pistonEvent.piston.state === BlockPistonState.Expanded ? ' Expanded' : '') +", +" (pistonEvent.piston.state === BlockPistonState.Retracting ? ' Retracting' : '') +", +" (pistonEvent.piston.state === BlockPistonState.Retracted ? ' Retracted' : '')", +" );", +" }", +" });" +]}, +"updateScoreboard": { + "description": "Creates and updates a scoreboard objective, plus a player score See https://learn.microsoft.com/minecraft/creator/scriptapi/minecraft/server/scoreboard", + "prefix": ["mc"], + "body": [" const scoreboardObjectiveId = 'scoreboard_demo_objective';", +" const scoreboardObjectiveDisplayName = 'Demo Objective';", +" const players = world.getPlayers();", +" // Ensure a new objective.", +" let objective = world.scoreboard.getObjective(scoreboardObjectiveId);", +" if (!objective) {", +" objective = world.scoreboard.addObjective(scoreboardObjectiveId, scoreboardObjectiveDisplayName);", +" }", +" // get the scoreboard identity for player 0", +" const player0Identity = players[0].scoreboardIdentity;", +" if (player0Identity === undefined) {", +" log('Could not get a scoreboard identity for player 0.');", +" return -1;", +" }", +" // initialize player score to 100;", +" objective.setScore(player0Identity, 100);", +" world.scoreboard.setObjectiveAtDisplaySlot(DisplaySlotId.Sidebar, {", +" objective: objective,", +" sortOrder: ObjectiveSortOrder.Descending,", +" });", +" const playerScore = objective.getScore(player0Identity) ?? 0;", +" // score should now be 110.", +" objective.setScore(player0Identity, playerScore + 10);" +]}, +"setTitle": { + "description": "Sets a title overlay on the player's scree See https://learn.microsoft.com/minecraft/creator/scriptapi/minecraft/server/screendisplay", + "prefix": ["mc"], + "body": [" let players = world.getPlayers();", +" players[0].onScreenDisplay.setTitle('§o§6Fancy Title§r');" +]}, +"setTitleAndSubtitle": { + "description": "Sets a title and subtitle overlay on the player's scree See https://learn.microsoft.com/minecraft/creator/scriptapi/minecraft/server/screendisplay", + "prefix": ["mc"], + "body": [" const players = world.getPlayers();", +" players[0].onScreenDisplay.setTitle('Chapter 1', {", +" stayDuration: 100,", +" fadeInDuration: 2,", +" fadeOutDuration: 4,", +" subtitle: 'Trouble in Block Town',", +" });" +]}, +"countdown": { + "description": "Runs a countdown from 10 to 0 See https://learn.microsoft.com/minecraft/creator/scriptapi/minecraft/server/screendisplay", + "prefix": ["mc"], + "body": [" const players = world.getPlayers();", +" players[0].onScreenDisplay.setTitle('Get ready!', {", +" stayDuration: 220,", +" fadeInDuration: 2,", +" fadeOutDuration: 4,", +" subtitle: '10',", +" });", +" let countdown = 10;", +" const intervalId = system.runInterval(() => {", +" countdown--;", +" players[0].onScreenDisplay.updateSubtitle(countdown.toString());", +" if (countdown == 0) {", +" system.clearRun(intervalId);", +" }", +" }, 20);" +]}, +"sendBasicMessage": { + "description": "Sends a basic message See https://learn.microsoft.com/minecraft/creator/scriptapi/minecraft/server/player/sendmessage", + "prefix": ["mc"], + "body": [" const players = world.getPlayers();", +" players[0].sendMessage('Hello World!');" +]}, +"sendTranslatedMessage": { + "description": "Sends a translated message See https://learn.microsoft.com/minecraft/creator/scriptapi/minecraft/server/player/sendmessage", + "prefix": ["mc"], + "body": [" const players = world.getPlayers();", +" players[0].sendMessage({ translate: 'authentication.welcome', with: ['Amazing Player 1'] });" +]}, +"showTranslatedMessageForm": { + "description": "Shows an example translated two-button dialog dialog See https://learn.microsoft.com/minecraft/creator/scriptapi/minecraft/server/rawmessage", + "prefix": ["mc"], + "body": [" const players = world.getPlayers();", +" const messageForm = new MessageFormData()", +" .title({ translate: 'permissions.removeplayer' })", +" .body({ translate: 'accessibility.list.or.two', with: ['Player 1', 'Player 2'] })", +" .button1('Player 1')", +" .button2('Player 2');", +" messageForm", +" .show(players[0])", +" .then((formData: MessageFormResponse) => {", +" // player canceled the form, or another dialog was up and open.", +" if (formData.canceled || formData.selection === undefined) {", +" return;", +" }", +" log(`You selected ${formData.selection === 0 ? 'Player 1' : 'Player 2'}`);", +" })", +" .catch((error: Error) => {", +" log('Failed to show form: ' + error);", +" return -1;", +" });" +]}, +"addSign": { + "description": "Creates a single-sided simple sig See https://learn.microsoft.com/minecraft/creator/scriptapi/minecraft/server/blocksigncomponent", + "prefix": ["mc"], + "body": [" const players = world.getPlayers();", +" const dim = players[0].dimension;", +" const signBlock = dim.getBlock(targetLocation);", +" if (!signBlock) {", +" log('Could not find a block at specified location.');", +" return -1;", +" }", +" let signPerm = BlockPermutation.resolve(MinecraftBlockTypes.StandingSign, { ground_sign_direction: 8 });", +" signBlock.setPermutation(signPerm);", +" const signComponent = signBlock.getComponent(BlockComponentTypes.Sign) as BlockSignComponent;", +" signComponent?.setText(`Basic sign!/nThis is green on the front.`);" +]}, +"addTranslatedSign": { + "description": "Creates a single-sided simple sig See https://learn.microsoft.com/minecraft/creator/scriptapi/minecraft/server/blockpermutation", + "prefix": ["mc"], + "body": [" const players = world.getPlayers();", +" const dim = players[0].dimension;", +" const signBlock = dim.getBlock(targetLocation);", +" if (!signBlock) {", +" log('Could not find a block at specified location.');", +" return -1;", +" }", +" let signPerm = BlockPermutation.resolve(MinecraftBlockTypes.StandingSign, { ground_sign_direction: 8 });", +" signBlock.setPermutation(signPerm);", +" const signComponent = signBlock.getComponent(BlockComponentTypes.Sign) as BlockSignComponent;", +" signComponent?.setText({ translate: 'item.skull.player.name', with: [players[0].name] });" +]}, +"addTwoSidedSign": { + "description": "Creates a two-sided sign with custom colors and a read-only statu See https://learn.microsoft.com/minecraft/creator/scriptapi/minecraft/server/blocksigncomponent", + "prefix": ["mc"], + "body": [" const signBlock = targetLocation.dimension.getBlock(targetLocation);", +" if (!signBlock) {", +" log('Could not find a block at specified location.');", +" return -1;", +" }", +" let signPerm = BlockPermutation.resolve(MinecraftBlockTypes.StandingSign, { ground_sign_direction: 8 });", +" signBlock.setPermutation(signPerm);", +" const signComponent = signBlock.getComponent(BlockComponentTypes.Sign) as BlockSignComponent;", +" if (signComponent) {", +" signComponent.setText(`Party Sign!/nThis is green on the front.`);", +" signComponent.setText(`Party Sign!/nThis is red on the back.`, SignSide.Back);", +" signComponent.setTextDyeColor(DyeColor.Green);", +" signComponent.setTextDyeColor(DyeColor.Red, SignSide.Back);", +" // players cannot edit sign!", +" signComponent.setWaxed(true);", +" } else {", +" log('Could not find sign component.');", +" }" +]}, +"spawnFeatherItem": { + "description": "Creates a free-floating feather item in the world See https://learn.microsoft.com/minecraft/creator/scriptapi/minecraft/server/itemstack", + "prefix": ["mc"], + "body": [" const featherItem = new ItemStack(MinecraftItemTypes.Feather, 1);", +" targetLocation.dimension.spawnItem(featherItem, targetLocation);", +" log(`New feather created at ${targetLocation.x}, ${targetLocation.y}, ${targetLocation.z}!`);" +]}, +"testThatEntityIsFeatherItem": { + "description": "Tests whether there is a feather nearby a spot See https://learn.microsoft.com/minecraft/creator/scriptapi/minecraft/server/entityitemcomponent", + "prefix": ["mc"], + "body": [" const items = targetLocation.dimension.getEntities({", +" location: targetLocation,", +" maxDistance: 20,", +" });", +" for (const item of items) {", +" const itemComp = item.getComponent(EntityComponentTypes.Item) as EntityItemComponent;", +" if (itemComp) {", +" if (itemComp.itemStack.typeId.endsWith('feather')) {", +" log('Success! Found a feather', 1);", +" }", +" }", +" }" +]}, +"trapTick": { + "description": "A simple tick timer that runs a command every minute See https://learn.microsoft.com/minecraft/creator/scriptapi/minecraft/server/system/run", + "prefix": ["mc"], + "body": [" try {", +" // Minecraft runs at 20 ticks per second.", +" if (system.currentTick % 1200 === 0) {", +" world.sendMessage('Another minute passes...');", +" }", +" } catch (e) {", +" console.warn('Error: ' + e);", +" }", +" system.run(trapTick);" +]}, +"every30Seconds": { + "description": "An alternate interval timer that runs a command every 30 seconds See https://learn.microsoft.com/minecraft/creator/scriptapi/minecraft/server/system/runinterval", + "prefix": ["mc"], + "body": [" let intervalRunIdentifier = floor(random() * 10000);", +" system.runInterval(() => {", +" world.sendMessage('This is an interval run ' + intervalRunIdentifier + ' sending a message every 30 seconds.');", +" }, 600);" +]} +} \ No newline at end of file diff --git a/app/public/data/snippets/server-ui-samples.json b/app/public/data/snippets/server-ui-samples.json new file mode 100644 index 00000000..bbc28232 --- /dev/null +++ b/app/public/data/snippets/server-ui-samples.json @@ -0,0 +1,114 @@ +{ +"showActionForm": { + "description": "Shows a very basic action form See https://learn.microsoft.com/minecraft/creator/scriptapi/minecraft/server-ui/actionformdata", + "prefix": ["mc"], + "body": [" const playerList = world.getPlayers();", +" if (playerList.length >= 1) {", +" const form = new ActionFormData()", +" .title('Test Title')", +" .body('Body text here!')", +" .button('btn 1')", +" .button('btn 2')", +" .button('btn 3')", +" .button('btn 4')", +" .button('btn 5');", +" const result = await form.show(playerList[0]);", +" if (result.canceled) {", +" log('Player exited out of the dialog. Note that if the chat window is up, dialogs are automatically canceled.');", +" return -1;", +" } else {", +" log('Your result was: ' + result.selection);", +" }", +" }" +]}, +"showFavoriteMonth": { + "description": "Shows a dialog that lets a player pick their favorite month See https://learn.microsoft.com/minecraft/creator/scriptapi/minecraft/server-ui/actionformdata", + "prefix": ["mc"], + "body": [" const players = world.getPlayers();", +" if (players.length >= 1) {", +" const form = new ActionFormData()", +" .title('Months')", +" .body('Choose your favorite month!')", +" .button('January')", +" .button('February')", +" .button('March')", +" .button('April')", +" .button('May');", +" form.show(players[0]).then((response: ActionFormResponse) => {", +" if (response.selection === 3) {", +" log('I like April too!');", +" return -1;", +" }", +" });", +" }" +]}, +"showBasicMessageForm": { + "description": "Shows an example two-button dialog See https://learn.microsoft.com/minecraft/creator/scriptapi/minecraft/server-ui/messageformdata", + "prefix": ["mc"], + "body": [" const players = world.getPlayers();", +" const messageForm = new MessageFormData()", +" .title('Message Form Example')", +" .body('This shows a simple example using §o§7MessageFormData§r.')", +" .button1('Button 1')", +" .button2('Button 2');", +" messageForm", +" .show(players[0])", +" .then((formData: MessageFormResponse) => {", +" // player canceled the form, or another dialog was up and open.", +" if (formData.canceled || formData.selection === undefined) {", +" return;", +" }", +" log(`You selected ${formData.selection === 0 ? 'Button 1' : 'Button 2'}`);", +" })", +" .catch((error: Error) => {", +" log('Failed to show form: ' + error);", +" return -1;", +" });" +]}, +"showTranslatedMessageForm": { + "description": "Shows an example translated two-button dialog dialog See https://learn.microsoft.com/minecraft/creator/scriptapi/minecraft/server-ui/messageformdata", + "prefix": ["mc"], + "body": [" const players = world.getPlayers();", +" const messageForm = new MessageFormData()", +" .title({ translate: 'permissions.removeplayer' })", +" .body({ translate: 'accessibility.list.or.two', with: ['Player 1', 'Player 2'] })", +" .button1('Player 1')", +" .button2('Player 2');", +" messageForm", +" .show(players[0])", +" .then((formData: MessageFormResponse) => {", +" // player canceled the form, or another dialog was up and open.", +" if (formData.canceled || formData.selection === undefined) {", +" return;", +" }", +" log(`You selected ${formData.selection === 0 ? 'Player 1' : 'Player 2'}`);", +" })", +" .catch((error: Error) => {", +" log('Failed to show form: ' + error);", +" return -1;", +" });" +]}, +"showBasicModalForm": { + "description": "Shows an example multiple-control modal dialog See https://learn.microsoft.com/minecraft/creator/scriptapi/minecraft/server-ui/modalformdata", + "prefix": ["mc"], + "body": [" const players = world.getPlayers();", +" const modalForm = new ModalFormData().title('Example Modal Controls for §o§7ModalFormData§r');", +" modalForm.toggle('Toggle w/o default');", +" modalForm.toggle('Toggle w/ default', true);", +" modalForm.slider('Slider w/o default', 0, 50, 5);", +" modalForm.slider('Slider w/ default', 0, 50, 5, 30);", +" modalForm.dropdown('Dropdown w/o default', ['option 1', 'option 2', 'option 3']);", +" modalForm.dropdown('Dropdown w/ default', ['option 1', 'option 2', 'option 3'], 2);", +" modalForm.textField('Input w/o default', 'type text here');", +" modalForm.textField('Input w/ default', 'type text here', 'this is default');", +" modalForm", +" .show(players[0])", +" .then((formData) => {", +" players[0].sendMessage(`Modal form results: ${JSON.stringify(formData.formValues, undefined, 2)}`);", +" })", +" .catch((error: Error) => {", +" log('Failed to show form: ' + error);", +" return -1;", +" });" +]} +} \ No newline at end of file diff --git a/app/public/docs/index.html b/app/public/docs/index.html index f0fa0aca..46ffa9d4 100644 --- a/app/public/docs/index.html +++ b/app/public/docs/index.html @@ -155,6 +155,32 @@
 

What it does

+

New Project Starter

+
+ Start and extend your Minecraft projects from a growing set of GitHub-hosted sources of samples and + content. Start on the website and select from the gallery of projects. Add new items + from the set of Minecraft samples. With command line tools, use the + create command to start a new project, and add to add + additional elements. +
+

Project Editor

+
+ Minecraft Creator Tools includes editors for various files including JavaScript and JSON: editing JavaScript or + TypeScript, the Project Editor includes a modern editor with autocomplete and built-in support for Minecraft + types, plus a rich array of code snippets. + +

Accessibility Support

+
+ Where possible, additional capabilities are provided to help make Minecraft Creator Tools accessible to all users. + This section discusses using some of these tools and features. + +
Tab Trapping
+
+ By default, pressing Tab in the JavaScript/JSON editor inserts the Tab character and does not navigate to the next focusable element on the page. + You can toggle the trapping of Tab with Ctrl+M on Windows and Linux and with Ctrl+Shift+M on OSX, and subsequent Tab keys will move focus out of the editor. +
+
+

Validation and Analytics

Minecraft Creator Tools includes a suite of tests and analytics that can be used to build reports across diff --git a/app/src/UX/App.tsx b/app/src/UX/App.tsx index 67ede4ad..cc071138 100644 --- a/app/src/UX/App.tsx +++ b/app/src/UX/App.tsx @@ -588,7 +588,11 @@ export default class App extends Component { let nextMode = this.state.mode; if (nextMode === AppMode.home || nextMode === AppMode.loading) { - nextMode = AppMode.projectReadOnly; + if (startInReadOnly) { + nextMode = AppMode.projectReadOnly; + } else { + nextMode = AppMode.project; + } } this.initProject(newProject); @@ -1151,6 +1155,12 @@ export default class App extends Component { return

Loading...
; } + let isReadOnly = false; + + if (this.state.mode === AppMode.projectReadOnly) { + isReadOnly = true; + } + let top = <>; let borderStr = ""; let height = "100vh"; @@ -1224,7 +1234,7 @@ export default class App extends Component { selectedItem={this.state.selectedItem} viewMode={CartoEditorViewMode.mainFocus} mode={this.state.initialProjectEditorMode ? this.state.initialProjectEditorMode : undefined} - readOnly={true} + readOnly={isReadOnly} onModeChangeRequested={this._handleModeChangeRequested} /> ); @@ -1240,7 +1250,7 @@ export default class App extends Component { project={this.state.activeProject} mode={ProjectEditorMode.inspector} viewMode={CartoEditorViewMode.mainFocus} - readOnly={true} + readOnly={isReadOnly} onModeChangeRequested={this._handleModeChangeRequested} /> ); @@ -1282,7 +1292,7 @@ export default class App extends Component { project={this.state.activeProject} mode={this.state.initialProjectEditorMode ? this.state.initialProjectEditorMode : undefined} selectedItem={this.state.selectedItem} - readOnly={true} + readOnly={isReadOnly} onModeChangeRequested={this._handleModeChangeRequested} /> ); @@ -1296,7 +1306,7 @@ export default class App extends Component { project={this.state.activeProject} mode={this.state.initialProjectEditorMode ? this.state.initialProjectEditorMode : undefined} selectedItem={this.state.selectedItem} - readOnly={true} + readOnly={isReadOnly} onModeChangeRequested={this._handleModeChangeRequested} /> ); diff --git a/app/src/UX/Home.tsx b/app/src/UX/Home.tsx index e278a52a..e3ce37a4 100644 --- a/app/src/UX/Home.tsx +++ b/app/src/UX/Home.tsx @@ -4,11 +4,14 @@ import { AppMode } from "./App"; import "./Home.css"; import { List, + Button, Dialog, Input, InputProps, ThemeInput, + FormInput, MenuButton, + Toolbar, selectableListBehavior, selectableListItemBehavior, ListItemProps, @@ -27,17 +30,21 @@ import IGalleryItem from "../app/IGalleryItem"; import Database from "../minecraft/Database"; import { GalleryProjectCommand } from "./ProjectGallery"; import AppServiceProxy, { AppServiceProxyCommands } from "../core/AppServiceProxy"; +import ProjectGallery from "./ProjectGallery"; import { constants } from "../core/Constants"; import StorageUtilities from "../storage/StorageUtilities"; +import { LocalFolderLabel, ConnectLabel, ExportBackupLabel } from "./Labels"; import FileSystemStorage from "../storage/FileSystemStorage"; import CartoApp, { CartoThemeStyle } from "../app/CartoApp"; import UrlUtilities from "../core/UrlUtilities"; +import { ProjectTileDisplayMode } from "./ProjectTile"; import ProjectUtilities from "../app/ProjectUtilities"; import { ProjectEditorMode } from "./ProjectEditorUtilities"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faMagnifyingGlass } from "@fortawesome/free-solid-svg-icons"; import WebUtilities from "./WebUtilities"; import FileSystemFolder from "../storage/FileSystemFolder"; +import IStorage from "../storage/IStorage"; enum HomeDialogMode { none = 0, @@ -45,6 +52,7 @@ enum HomeDialogMode { errorMessage = 2, confirmProjectDelete = 3, infoMessage = 4, + webLocalDeploy = 5, } interface IHomeProps extends IAppProps { @@ -63,7 +71,8 @@ interface IHomeProps extends IAppProps { project: IGalleryItem, name?: string, creator?: string, - shortName?: string + shortName?: string, + description?: string ) => void; onNewProjectSelected?: ( name: string, @@ -89,6 +98,7 @@ interface IHomeState { gallery: IGallery | undefined; dialogMode: HomeDialogMode; effect: HomeEffect; + isDeployingToComMojang: boolean; selectedProject?: string; search?: string; errorMessage?: string; @@ -96,6 +106,7 @@ interface IHomeState { newProjectName?: string; newProjectShortName?: string; newProjectCreator?: string; + newProjectDescription?: string; newProjectPath?: string; contextFocusedProject?: number; newGalleryProject?: IGalleryItem; @@ -112,21 +123,26 @@ export default class Home extends Component { this.state = { gallery: undefined, effect: HomeEffect.none, + isDeployingToComMojang: this.props.carto.isDeployingToComMojang, dialogMode: HomeDialogMode.errorMessage, errorMessage: this.props.errorMessage, }; } else { this.state = { gallery: undefined, + isDeployingToComMojang: this.props.carto.isDeployingToComMojang, effect: HomeEffect.none, dialogMode: HomeDialogMode.none, }; } this._onCartoLoaded = this._onCartoLoaded.bind(this); + this._onDeploymentStorageChanged = this._onDeploymentStorageChanged.bind(this); + this._onDeploymentStorageChanged = this._onDeploymentStorageChanged.bind(this); this._handleNewProjectSelectedClick = this._handleNewProjectSelectedClick.bind(this); this._handleOpenFolderClick = this._handleOpenFolderClick.bind(this); this._handleOpenLocalFolderClick = this._handleOpenLocalFolderClick.bind(this); + this._handleOpenWebLocalDeployClick = this._handleOpenWebLocalDeployClick.bind(this); this._handleOpenLocalFolderForDocumentationClick = this._handleOpenLocalFolderForDocumentationClick.bind(this); this._handleProjectClicked = this._handleProjectClicked.bind(this); this._handleDialogCancel = this._handleDialogCancel.bind(this); @@ -141,6 +157,7 @@ export default class Home extends Component { this._handleNewProjectNameChange = this._handleNewProjectNameChange.bind(this); this._handleNewProjectShortNameChange = this._handleNewProjectShortNameChange.bind(this); this._handleNewProjectCreatorChange = this._handleNewProjectCreatorChange.bind(this); + this._handleNewProjectDescriptionChange = this._handleNewProjectDescriptionChange.bind(this); this._handleSelectFolderClick = this._handleSelectFolderClick.bind(this); this._handleExportToolClick = this._handleExportToolClick.bind(this); this._handleUpgradeStorageKey = this._handleUpgradeStorageKey.bind(this); @@ -166,6 +183,10 @@ export default class Home extends Component { } private _handleFileDragOut(event: any) { + if (this.state && this.state.dialogMode !== HomeDialogMode.none) { + return; + } + const top = event.pageY; const left = event.pageX; const right = document.body.clientWidth - left; @@ -182,6 +203,7 @@ export default class Home extends Component { this.setState({ gallery: this.state.gallery, dialogMode: this.state.dialogMode, + isDeployingToComMojang: this.props.carto.isDeployingToComMojang, search: this.state.search, effect: HomeEffect.none, newProjectName: this.state.newProjectName, @@ -199,6 +221,10 @@ export default class Home extends Component { private _handleFileDragOver(event: any) { if (this.state !== undefined) { + if (this.state.dialogMode !== HomeDialogMode.none) { + return; + } + if (this.state.effect !== HomeEffect.dragOver) { const top = event.pageY; const left = event.pageX; @@ -209,6 +235,7 @@ export default class Home extends Component { this.setState({ gallery: this.state.gallery, dialogMode: this.state.dialogMode, + isDeployingToComMojang: this.props.carto.isDeployingToComMojang, effect: HomeEffect.dragOver, newProjectName: this.state.newProjectName, newProjectPath: this.state.newProjectPath, @@ -244,6 +271,10 @@ export default class Home extends Component { } private async _handleFileDrop(ev: DragEvent): Promise { + if (this.state && this.state.dialogMode !== HomeDialogMode.none) { + return; + } + ev.preventDefault(); ev.stopPropagation(); @@ -329,10 +360,12 @@ export default class Home extends Component { gallery: this.props.carto.gallery, dialogMode: this.state.dialogMode, effect: this.state.effect, + isDeployingToComMojang: this.props.carto.isDeployingToComMojang, newProjectName: this.state.newProjectName, newProjectPath: this.state.newProjectPath, newProjectShortName: this.state.newProjectShortName, newProjectCreator: this.state.newProjectCreator, + newProjectDescription: this.state.newProjectDescription, }); } @@ -345,10 +378,30 @@ export default class Home extends Component { gallery: this.state.gallery, dialogMode: this.state.dialogMode, effect: this.state.effect, + isDeployingToComMojang: this.props.carto.isDeployingToComMojang, newProjectName: data.value, newProjectPath: this.state.newProjectPath, newProjectShortName: this.state.newProjectShortName, newProjectCreator: this.state.newProjectCreator, + newProjectDescription: this.state.newProjectDescription, + }); + } + + private _handleNewProjectDescriptionChange(e: SyntheticEvent, data: (InputProps & { value: string }) | undefined) { + if (data === undefined || this.state == null) { + return; + } + + this.setState({ + gallery: this.state.gallery, + dialogMode: this.state.dialogMode, + effect: this.state.effect, + isDeployingToComMojang: this.props.carto.isDeployingToComMojang, + newProjectName: this.state.newProjectName, + newProjectPath: this.state.newProjectPath, + newProjectShortName: this.state.newProjectShortName, + newProjectCreator: this.state.newProjectCreator, + newProjectDescription: data.value, }); } @@ -361,10 +414,12 @@ export default class Home extends Component { gallery: this.state.gallery, dialogMode: this.state.dialogMode, effect: this.state.effect, + isDeployingToComMojang: this.props.carto.isDeployingToComMojang, newProjectName: this.state.newProjectName, newProjectPath: this.state.newProjectPath, newProjectShortName: data.value, newProjectCreator: this.state.newProjectCreator, + newProjectDescription: this.state.newProjectDescription, }); } @@ -377,10 +432,12 @@ export default class Home extends Component { gallery: this.state.gallery, dialogMode: this.state.dialogMode, effect: this.state.effect, + isDeployingToComMojang: this.props.carto.isDeployingToComMojang, newProjectName: this.state.newProjectName, newProjectPath: this.state.newProjectPath, newProjectShortName: this.state.newProjectShortName, newProjectCreator: data.value, + newProjectDescription: this.state.newProjectDescription, }); if (this.props.carto) { @@ -423,6 +480,7 @@ export default class Home extends Component { this.setState({ errorMessage: "Could not change the browser's storage for this site from temporary to a more persistent state.", dialogMode: HomeDialogMode.errorMessage, + isDeployingToComMojang: this.props.carto.isDeployingToComMojang, }); return; } @@ -441,7 +499,9 @@ export default class Home extends Component { gallery: this.state.gallery, search: this.state.search, newProjectName: this.state.newProjectName, + isDeployingToComMojang: this.props.carto.isDeployingToComMojang, newProjectCreator: this.state.newProjectCreator, + newProjectDescription: this.state.newProjectDescription, newProjectPath: this.state.newProjectPath, newGalleryProject: this.state.newGalleryProject, effect: HomeEffect.none, @@ -463,7 +523,9 @@ export default class Home extends Component { gallery: this.state.gallery, search: this.state.search, newProjectName: this.state.newProjectName, + isDeployingToComMojang: this.props.carto.isDeployingToComMojang, newProjectCreator: this.state.newProjectCreator, + newProjectDescription: this.state.newProjectDescription, newProjectPath: this.state.newProjectPath, newGalleryProject: this.state.newGalleryProject, effect: HomeEffect.none, @@ -483,6 +545,7 @@ export default class Home extends Component { this.setState({ gallery: this.carto.gallery, dialogMode: this.state.dialogMode, + isDeployingToComMojang: this.props.carto.isDeployingToComMojang, }); } else { this.carto.onGalleryLoaded.subscribe(this._onGalleryLoaded); @@ -496,12 +559,29 @@ export default class Home extends Component { if (this._carto != null) { this._carto.onLoaded.subscribe(this._onCartoLoaded); - + this._carto.onDeploymentStorageChanged.subscribe(this._onDeploymentStorageChanged); await this._carto.load(); } } } + private _onDeploymentStorageChanged(source: Carto, deploymentStorage: IStorage | null) { + this.setState({ + gallery: this.state.gallery, + dialogMode: this.state.dialogMode, + isDeployingToComMojang: this.props.carto.isDeployingToComMojang, + effect: this.state.effect, + search: this.state.search, + errorMessage: this.state.errorMessage, + newProjectName: this.state.newProjectName, + newProjectCreator: this.state.newProjectCreator, + newProjectDescription: this.state.newProjectDescription, + newProjectPath: this.state.newProjectPath, + newGalleryProject: this.state.newGalleryProject, + contextFocusedProject: this.state.contextFocusedProject, + }); + } + private _onCartoLoaded(source: Carto, target: Carto) { this.forceUpdate(); this._loadSnippets(); @@ -521,6 +601,7 @@ export default class Home extends Component { this.setState({ gallery: this.state.gallery, dialogMode: this.state.dialogMode, + isDeployingToComMojang: this.props.carto.isDeployingToComMojang, newProjectName: this.state.newProjectName, newProjectPath: result, }); @@ -533,8 +614,10 @@ export default class Home extends Component { this.setState({ gallery: this.state?.gallery, dialogMode: HomeDialogMode.newProject, + isDeployingToComMojang: this.props.carto.isDeployingToComMojang, newProjectName: projectName, newProjectCreator: this.props.carto.creator, + newProjectDescription: this.state.newProjectDescription, }); } @@ -542,7 +625,9 @@ export default class Home extends Component { this.setState({ gallery: this.state?.gallery, dialogMode: HomeDialogMode.newProject, + isDeployingToComMojang: this.props.carto.isDeployingToComMojang, newProjectCreator: this.props.carto.creator, + newProjectDescription: this.state.newProjectDescription, }); } @@ -564,11 +649,13 @@ export default class Home extends Component { this.setState({ gallery: this.state.gallery, dialogMode: this.state.dialogMode, + isDeployingToComMojang: this.props.carto.isDeployingToComMojang, effect: this.state.effect, search: this.state.search, errorMessage: this.state.errorMessage, newProjectName: this.state.newProjectName, newProjectCreator: this.state.newProjectCreator, + newProjectDescription: this.state.newProjectDescription, newProjectPath: this.state.newProjectPath, newGalleryProject: this.state.newGalleryProject, contextFocusedProject: curIndex, @@ -597,9 +684,11 @@ export default class Home extends Component { dialogMode: this.state.dialogMode, effect: this.state.effect, search: this.state.search, + isDeployingToComMojang: this.props.carto.isDeployingToComMojang, errorMessage: this.state.errorMessage, newProjectName: this.state.newProjectName, newProjectCreator: this.state.newProjectCreator, + newProjectDescription: this.state.newProjectDescription, newProjectPath: this.state.newProjectPath, newGalleryProject: this.state.newGalleryProject, contextFocusedProject: undefined, @@ -611,6 +700,7 @@ export default class Home extends Component { this.setState({ gallery: this.state?.gallery, dialogMode: HomeDialogMode.none, + isDeployingToComMojang: this.props.carto.isDeployingToComMojang, }); } @@ -622,6 +712,7 @@ export default class Home extends Component { this.setState({ gallery: this.state?.gallery, dialogMode: HomeDialogMode.none, + isDeployingToComMojang: this.props.carto.isDeployingToComMojang, }); } @@ -629,6 +720,7 @@ export default class Home extends Component { this.setState({ gallery: this.state?.gallery, dialogMode: HomeDialogMode.none, + isDeployingToComMojang: this.props.carto.isDeployingToComMojang, }); if ( @@ -641,7 +733,8 @@ export default class Home extends Component { this.state.newGalleryProject, this.state.newProjectName, this.state.newProjectCreator, - this.state.newProjectShortName + this.state.newProjectShortName, + this.state.newProjectDescription ); } else if (this.props.onNewProjectSelected && this.state?.newProjectName !== undefined) { this.props.onNewProjectSelected( @@ -649,7 +742,8 @@ export default class Home extends Component { NewProjectTemplateType.gameTest, this.state.newProjectCreator, this.state.newProjectShortName, - this.state.newProjectPath + this.state.newProjectPath, + this.state.newProjectDescription ); } } @@ -664,6 +758,18 @@ export default class Home extends Component { } } + private async _handleOpenWebLocalDeployClick() { + this.setState({ + gallery: this.state.gallery, + dialogMode: HomeDialogMode.webLocalDeploy, + search: this.state.search, + effect: this.state.effect, + isDeployingToComMojang: this.props.carto.isDeployingToComMojang, + newProjectName: this.state.newProjectName, + newProjectPath: this.state.newProjectPath, + }); + } + private async _handleOpenLocalFolderClick() { await this.openLocalFolder(false); } @@ -688,6 +794,7 @@ export default class Home extends Component { "Folder could not be read - please choose a folder on your device that only has Minecraft files in it (no .exes, .bat files, etc.)\r\n\r\nDetails: " + safeMessage, dialogMode: HomeDialogMode.errorMessage, + isDeployingToComMojang: this.props.carto.isDeployingToComMojang, }); } else { this.props.onNewProjectFromFolderInstanceSelected(storage.rootFolder, result.name, isDocumentationProject); @@ -719,6 +826,7 @@ export default class Home extends Component { this.setState({ errorMessage: "Project at '" + folder.fullPath + "' does not appear to exist. Is it on this device?", dialogMode: HomeDialogMode.errorMessage, + isDeployingToComMojang: this.props.carto.isDeployingToComMojang, }); return; } @@ -748,10 +856,12 @@ export default class Home extends Component { effect: HomeEffect.none, search: this.state.search, errorMessage: undefined, + isDeployingToComMojang: this.props.carto.isDeployingToComMojang, newProjectName: ProjectUtilities.getSuggestedProjectName(project), newProjectCreator: this.props.carto.creator, newProjectPath: this.state.newProjectPath, newGalleryProject: project, + newProjectDescription: this.state.newProjectDescription, }); } else { if (this.props.onGalleryItemCommand !== undefined) { @@ -791,6 +901,7 @@ export default class Home extends Component { this.setState({ gallery: this.state.gallery, dialogMode: HomeDialogMode.confirmProjectDelete, + isDeployingToComMojang: this.props.carto.isDeployingToComMojang, search: this.state.search, effect: this.state.effect, selectedProject: data.tag, @@ -832,6 +943,7 @@ export default class Home extends Component { gallery: this.state.gallery, dialogMode: this.state.dialogMode, search: newSearch, + isDeployingToComMojang: this.props.carto.isDeployingToComMojang, effect: this.state.effect, newProjectName: this.state.newProjectName, newProjectPath: this.state.newProjectPath, @@ -842,7 +954,6 @@ export default class Home extends Component { const projectListItems: ShorthandValue[] = []; let dialogArea = <>; - let localGallery = <>; const webOnlyLinks: any[] = []; const browserWidth = WebUtilities.getWidth(); @@ -896,6 +1007,7 @@ export default class Home extends Component { } let gallery = []; + let mainToolArea = []; let toolBin: any[] = []; gallery.push( @@ -923,7 +1035,7 @@ export default class Home extends Component { ); } - gallery.push( + mainToolArea.push(

Tools

@@ -972,33 +1084,107 @@ export default class Home extends Component {
); - gallery.push( -
+ mainToolArea.push( +
{toolBin}
); - } - if (CartoApp.theme !== CartoThemeStyle.dark) { - webOnlyLinks.push(  /  ); - webOnlyLinks.push( - - Dark Theme - + gallery.push( +
+

Start from a template or code snippet

+
+ +
+
); - } - if (CartoApp.theme !== CartoThemeStyle.light) { - webOnlyLinks.push(  /  ); - webOnlyLinks.push( - - Light Theme - + gallery.push( + ); } + if (!AppServiceProxy.hasAppService) { + if (CartoApp.theme !== CartoThemeStyle.dark) { + webOnlyLinks.push(  /  ); + webOnlyLinks.push( + + Dark Theme + + ); + } + if (CartoApp.theme !== CartoThemeStyle.light) { + webOnlyLinks.push(  /  ); + webOnlyLinks.push( + + Light Theme + + ); + } + } + if (this.state?.dialogMode === HomeDialogMode.newProject) { + const additionalDialogButtons = []; + + if (AppServiceProxy.hasAppServiceOrDebug) { + let path = this.state.newProjectPath; + + if (path === undefined) { + let delimiter = "\\"; + + if (!AppServiceProxy.hasAppService) { + delimiter = "/"; + } + + path = this.carto?.projectsStorage.rootFolder.fullPath + delimiter + this.state.newProjectName; + } + + additionalDialogButtons.push( +
+ Store project at: +
+ ); + + additionalDialogButtons.push( +
+
{path}
+
+ ); + } + const newDialogInnerContent = (
+
Title:
+
+ +
Creator Name:
{ onChange={this._handleNewProjectCreatorChange} />
-
Name:
-
- -
Short Name:
{ onChange={this._handleNewProjectShortNameChange} />
+
Description:
+
+ +
+ {additionalDialogButtons}
); @@ -1106,35 +1293,42 @@ export default class Home extends Component { const recentsArea = []; if (projectListItems.length > 0) { - introArea.push( -

- Projects -

- ); - - if (!this.props.isPersisted) { + if (AppServiceProxy.hasAppServiceOrSim) { introArea.push( -
- (stored in temporary browser storage.){" "} - - Make persistent - +
+ Projects
); } else { introArea.push( -
- (stored in this device's browser storage.) -
+

+ Projects +

); - } + if (!this.props.isPersisted) { + introArea.push( +
+ (stored in temporary browser storage.){" "} + + Make persistent + +
+ ); + } else { + introArea.push( +
+ (stored in this device's browser storage.) +
+ ); + } + } recentsArea.push(
{ let storageAction = <>; let storageMessage = undefined; - storageMessage = "take care: projects are saved locally in your browser's storage on your device."; - storageAction = ( - -    - - Save backups + if (AppServiceProxy.hasAppService) { + storageMessage = "projects are saved in the mctools subfolder of your Documents library."; + } else { + storageMessage = "take care: projects are saved locally in your browser's storage on your device."; + storageAction = ( + +    + + Save backups + + . - . - - ); - + ); + } let effectArea = <>; if (this.state.effect === HomeEffect.dragOver) { @@ -1186,7 +1383,73 @@ export default class Home extends Component { errorMessageContainer =
{this.props.errorMessage}
; } - let toolsArea = <>; + let accessoryToolArea = <>; + + const actionsToolbar = []; + if (AppServiceProxy.hasAppService) { + actionsToolbar.push({ + icon: , + key: "openFolder", + onClick: this._handleOpenFolderClick, + title: "Open folder on this device", + }); + + actionsToolbar.push({ + icon: , + key: "connect", + onClick: this._handleConnectClick, + title: "Connect", + }); + } else { + actionsToolbar.push({ + icon: , + key: "openFolderA", + onClick: this._handleOpenLocalFolderClick, + title: "Open Folder", + }); + } + + actionsToolbar.push({ + icon: , + key: "export", + onClick: this._handleExportAllClick, + title: "Export", + }); + + accessoryToolArea = ( +
+
+
+ + +
+
+
+ ); let termsArea = ( @@ -1334,7 +1597,7 @@ export default class Home extends Component { }} > {introArea} - {toolsArea} + {accessoryToolArea} {recentsArea}
{ height: browserWidth >= 800 ? "calc(100vh - " + (168 + this.props.heightOffset) + "px)" : "", }} > - {localGallery} + {mainToolArea} {gallery}
diff --git a/app/src/UX/JavaScriptEditor.tsx b/app/src/UX/JavaScriptEditor.tsx index f3eecb11..ed6e3935 100644 --- a/app/src/UX/JavaScriptEditor.tsx +++ b/app/src/UX/JavaScriptEditor.tsx @@ -191,6 +191,13 @@ export default class JavaScriptEditor extends Component void; log: (message: string) => void;}; declare var console: GlobalConsole; "; + tslang.javascriptDefaults.addExtraLib(globalContent, globalUri); + tslang.typescriptDefaults.addExtraLib(globalContent, globalUri); + if (typeDefs) { for (let i = 0; i < typeDefs.typeDefs.length; i++) { const td = typeDefs.typeDefs[i]; @@ -592,7 +599,7 @@ export default class JavaScriptEditor extends Component | React.KeyboardEvent | null) { - event?.stopPropagation(); - } - - private _showProjectSettings(event: SyntheticEvent | React.KeyboardEvent | null) { - if (this.props.onActionRequested) { - this.props.onActionRequested(ProjectEditorAction.worldPropertiesDialog); - } - event?.stopPropagation(); - } private _downloadFlatWorld() { ProjectEditorUtilities.launchFlatWorldWithPacksDownload(this.props.carto, this.props.project); @@ -77,15 +67,16 @@ export default class ProjectActions extends Component @@ -109,15 +100,15 @@ export default class ProjectActions extends Component
- + ); exportBin.push( -
@@ -139,7 +130,105 @@ export default class ProjectActions extends Component
Exports this project as a zip file
- + + ); + + exportBin.push( + + ); + + packageBin.push( + + ); + + packageBin.push( + ); const height = "calc(100vh - " + this.props.heightOffset + "px)"; @@ -154,8 +243,12 @@ export default class ProjectActions extends Component -
Inspect and optimize this project
+

Inspect and optimize this project

{inspectBin}
+

Download this project to your device

+
{exportBin}
+

Get packages to run in Minecraft

+
{packageBin}
); } diff --git a/app/src/UX/ProjectEditor.tsx b/app/src/UX/ProjectEditor.tsx index 10e19acc..2b0b04c2 100644 --- a/app/src/UX/ProjectEditor.tsx +++ b/app/src/UX/ProjectEditor.tsx @@ -2,7 +2,7 @@ import React, { Component, SyntheticEvent } from "react"; import IAppProps from "./IAppProps"; import Project, { ProjectErrorState } from "./../app/Project"; import ProjectItem from "./../app/ProjectItem"; -import { ProjectItemType } from "./../app/IProjectItemData"; +import { ProjectItemCreationType, ProjectItemStorageType, ProjectItemType } from "./../app/IProjectItemData"; import ProjectItemList from "./ProjectItemList"; import ProjectItemEditor from "./ProjectItemEditor"; import ProjectExporter from "./../app/ProjectExporter"; @@ -59,11 +59,9 @@ import ProjectInfoDisplay, { InfoItemCommand } from "./ProjectInfoDisplay"; import ProjectInfoItem from "../info/ProjectInfoItem"; import { MinecraftPushWorldType } from "../app/MinecraftPush"; import CartoApp, { HostType, CartoThemeStyle } from "../app/CartoApp"; -import ProjectTools from "../app/ProjectTools"; import { faEdit, faWindowMaximize } from "@fortawesome/free-regular-svg-icons"; import FileExplorer, { FileExplorerMode } from "./FileExplorer"; import ShareProject from "./ShareProject"; -import LocTokenBox from "./LocTokenBox"; import { IProjectUpdaterReference } from "../info/IProjectInfoGeneratorBase"; import { StatusTopic } from "../app/Status"; import { SidePaneMaxWidth, SidePaneMinWidth } from "../app/Carto"; @@ -172,8 +170,9 @@ export default class ProjectEditor extends Component { + this.setState({ + activeProjectItem: this.state.activeProjectItem, + tentativeProjectItem: this.state.tentativeProjectItem, + activeReference: this.state.activeReference, + menuState: this.state.menuState, + mode: this.state.mode, + viewMode: this.state.viewMode, + allInfoSet: this.props.project.infoSet, + allInfoSetGenerated: this.props.project.infoSet.completedGeneration, + displayFileView: this.state.displayFileView, + forceRawView: this.state.forceRawView, + filteredItems: this.state.filteredItems, + searchFilter: this.state.searchFilter, + effectMode: this.state.effectMode, + dialog: ProjectEditorDialog.convertTo, + dialogActiveItem: projectItem, + dialogData: { + name: this.props.project.name + " Java", + }, + statusAreaMode: this.state.statusAreaMode, + lastDeployKey: this.state.lastDeployKey, + lastExportKey: (data.icon as any).key, + lastDeployFunction: this.state.lastDeployFunction, + lastExportFunction: this._handleConvertToClick, + lastDeployData: this.state.lastDeployData, + lastExportData: this.state.lastExportData, + }); + }, 2); + } + + if (data && data.icon && (data.icon as any).key) { + this._setNewExportKey((data.icon as any).key, this._handleConvertToClick, data); + } + } + private async _handleExportZipClick(e: SyntheticEvent | undefined, data: MenuItemProps | undefined) { await this._ensurePersisted(); @@ -1679,46 +1727,53 @@ export default class ProjectEditor extends Component= 0) { + creationType = ProjectItemCreationType.generated; + } else if (relativeFolderPath?.indexOf("/dist/") >= 0) { + creationType = ProjectItemCreationType.dist; + } else if (relativeFolderPath?.indexOf("/build/") >= 0) { + creationType = ProjectItemCreationType.build; + } + + pi = this.props.project.ensureItemByProjectPath( + relativeFolderPath, + ProjectItemStorageType.singleFile, + file.name, + itemType, + undefined, + creationType + ); + } + } + } if (pi) { let newMode = this.state.mode; @@ -2684,7 +2786,7 @@ export default class ProjectEditor extends Component, @@ -2698,9 +2800,9 @@ export default class ProjectEditor extends Component, - content: "MCPack Add-On", - onClick: this._handleExportMCPackClick, - title: "Exports this set of project files as an MCPack Add-On, for use in Minecraft", + content: "Add-On File", + onClick: this._handleExportMCAddonClick, + title: "Exports this set of project files as a MCA, for use in Minecraft", }; exportMenu.push(exportKeys[nextExportKey]); @@ -2803,19 +2905,30 @@ export default class ProjectEditor extends Component, + content: title + " world", + onClick: this._handleExportWorld, + title: "Download " + title, + }; + + exportMenu.push(exportKeys[nextExportKey]); + + if (AppServiceProxy.hasAppServiceOrSim) { + nextExportKey = "convertTo|" + pi.name; + exportKeys[nextExportKey] = { key: nextExportKey, - icon: , - content: title + " world", - onClick: this._handleExportWorld, - title: "Download " + title, + icon: , + content: title + " conversion...", + onClick: this._handleConvertToClick, + title: "Convert and export " + title, }; - exportMenu.push(exportKeys[nextExportKey]); } + const dlsKey = "deploySpecificWorldPack|" + pi.name; deployKeys[dlsKey] = { key: dlsKey + "A", @@ -2835,6 +2948,18 @@ export default class ProjectEditor extends Component, + content: title + " and test assets to Minecraft", + onClick: this._handleDeployWorldAndTestAssetsLocalClick, + title: "Deploys " + title + " and test assets in a zip", + }; + deployMenu.push(deployKeys[miKeyA]); + } } } @@ -2948,10 +3073,27 @@ export default class ProjectEditor extends Component ), onClick: this._handleDownloadFlatWorldWithPacks, - content: "Download flat world with packs", - title: "Get this pack in a sample .mcworld file with packs in this project added", + content: "Flat world with packs", + title: "Get this pack in a sample flat .mcworld file with packs in this project added", }); + const defaultEditorWorldWithPacks = "editorWorld|"; + deployKeys[defaultEditorWorldWithPacks] = { + key: defaultEditorWorldWithPacks + "C", + icon: ( + + ), + onClick: this._handleDeployDownloadEditorWorldWithPacks, + content: "Editor project with packs", + title: "Get this pack in a sample .mcproject file", + }; + deployMenu.push(deployKeys[defaultEditorWorldWithPacks]); + deployMenu.push({ key: "dividerProjectWorld", kind: "divider", @@ -2969,8 +3111,8 @@ export default class ProjectEditor extends Component ), onClick: this._handleDeployDownloadWorldWithPacks, - content: "World with Packs", - title: "Get this pack in a sample .mcworld file, using the sample pack configuration", + content: "Custom world with packs", + title: "Get a custom pack in a sample .mcworld file, using the sample pack configuration", }; deployMenu.push(deployKeys[defaultWorldWithPacks]); @@ -2979,28 +3121,11 @@ export default class ProjectEditor extends Component, onClick: this._handleChangeWorldSettingsClick, - content: "Change world with pack preferences", - title: "Change your preferred world with pack settings", + content: "Change custom world with pack settings", + title: "Change your custom world with pack settings", }; deployMenu.push(deployKeys[configureProjectWorld]); - const defaultEditorWorldWithPacks = "editorWorld|"; - deployKeys[defaultEditorWorldWithPacks] = { - key: defaultEditorWorldWithPacks + "C", - icon: ( - - ), - onClick: this._handleDeployDownloadEditorWorldWithPacks, - content: "Editor Project with Packs", - title: "Get this pack in a sample .mcproject file, using the sample pack configuration", - }; - deployMenu.push(deployKeys[defaultEditorWorldWithPacks]); - let addedItems = 0; for (let i = 0; i < this.props.project.items.length && addedItems < 4; i++) { @@ -3169,6 +3294,25 @@ export default class ProjectEditor extends Component, + title: "Show Toolbox Pane", + onClick: this._toggleMinecraftToolbox, + }); + } + toolbarItems.push({ icon: , key: "more", @@ -3427,7 +3571,7 @@ export default class ProjectEditor extends Component; - - if (!isFullyCompact && !this.props.isHosted && !this.props.hideMainToolbar) { - const title = this.getProjectTitle(); - - metaArea = ( -
-
-
- -
-
-
- ); - } - let effectArea = <>; if (this.state.effectMode === ProjectEditorEffect.dragOver) { @@ -3773,7 +3896,6 @@ export default class ProjectEditor extends Component {toolbarArea} - {metaArea} {column1} {column2} {column3} diff --git a/app/src/UX/ProjectEditorUtilities.ts b/app/src/UX/ProjectEditorUtilities.ts index b288be15..db2e9a4f 100644 --- a/app/src/UX/ProjectEditorUtilities.ts +++ b/app/src/UX/ProjectEditorUtilities.ts @@ -1,5 +1,5 @@ import Carto from "../app/Carto"; -import { ProjectItemStorageType, ProjectItemType } from "../app/IProjectItemData"; +import { ProjectItemCreationType, ProjectItemStorageType, ProjectItemType } from "../app/IProjectItemData"; import Project from "../app/Project"; import ProjectExporter from "../app/ProjectExporter"; import ProjectItemUtilities from "../app/ProjectItemUtilities"; @@ -108,7 +108,7 @@ export default class ProjectEditorUtilities { } public static async launchFlatWorldWithPacksDownload(carto: Carto, project: Project) { - carto.notifyStatusUpdate("Starting export"); + const operId = await carto.notifyOperationStarted("Starting export of flat world with packs."); const projName = await project.loc.getTokenValue(project.name); @@ -121,13 +121,18 @@ export default class ProjectEditorUtilities { const newBytes = await ProjectExporter.generateFlatBetaApisWorldWithPacksZipBytes(carto, project, name); + if (!newBytes) { + carto.notifyOperationEnded(operId); + return; + } + carto.notifyStatusUpdate("Now downloading " + fileName); if (newBytes !== undefined) { saveAs(new Blob([newBytes], { type: "application/octet-stream" }), fileName); } - carto.notifyStatusUpdate("Done with save " + fileName); + carto.notifyOperationEnded(operId, "Done with save " + fileName); } public static async launchWorldWithPacksDownload(carto: Carto, project: Project) { @@ -135,8 +140,6 @@ export default class ProjectEditorUtilities { const fileName = name + ".mcworld"; - carto.notifyStatusUpdate("Packing " + fileName); - const mcworld = await ProjectExporter.generateWorldWithPacks(carto, project, project.ensureWorldSettings()); if (mcworld === undefined) { @@ -189,7 +192,7 @@ export default class ProjectEditorUtilities { folder.name, ProjectItemType.worldFolder, undefined, - false + ProjectItemCreationType.normal ); } @@ -219,7 +222,7 @@ export default class ProjectEditorUtilities { file.name, ProjectItemType.structure, undefined, - false + ProjectItemCreationType.normal ); } @@ -246,7 +249,7 @@ export default class ProjectEditorUtilities { file.name, ProjectItemType.MCWorld, undefined, - false + ProjectItemCreationType.normal ); await project.inferProjectItemsFromZipFile(relPath, contentFile, false); @@ -275,7 +278,7 @@ export default class ProjectEditorUtilities { file.name, ProjectItemType.MCProject, undefined, - false + ProjectItemCreationType.normal ); await project.inferProjectItemsFromZipFile(relPath, contentFile, false); @@ -304,7 +307,7 @@ export default class ProjectEditorUtilities { file.name, ProjectItemType.MCTemplate, undefined, - false + ProjectItemCreationType.normal ); await project.inferProjectItemsFromZipFile(relPath, contentFile, false); @@ -333,7 +336,7 @@ export default class ProjectEditorUtilities { file.name, ProjectItemType.MCAddon, undefined, - false + ProjectItemCreationType.normal ); await project.inferProjectItemsFromZipFile(relPath, contentFile, false); @@ -362,7 +365,7 @@ export default class ProjectEditorUtilities { file.name, ProjectItemType.zip, undefined, - false + ProjectItemCreationType.normal ); await project.inferProjectItemsFromZipFile(relPath, contentFile, false); @@ -391,7 +394,7 @@ export default class ProjectEditorUtilities { file.name, ProjectItemType.MCPack, undefined, - false + ProjectItemCreationType.normal ); await project.inferProjectItemsFromZipFile(relPath, contentFile, false); @@ -420,7 +423,7 @@ export default class ProjectEditorUtilities { file.name, ProjectItemType.structure, undefined, - false + ProjectItemCreationType.normal ); } @@ -447,8 +450,6 @@ export default class ProjectEditorUtilities { const fileName = name + ".mcproject"; - carto.notifyStatusUpdate("Packing " + fileName); - const mcworld = await ProjectExporter.generateWorldWithPacks(carto, project, project.ensureEditorWorldSettings()); if (mcworld === undefined) { diff --git a/app/src/UX/ProjectItemEditor.tsx b/app/src/UX/ProjectItemEditor.tsx index 59f772e2..79acd340 100644 --- a/app/src/UX/ProjectItemEditor.tsx +++ b/app/src/UX/ProjectItemEditor.tsx @@ -8,8 +8,7 @@ import FunctionEditor from "./FunctionEditor"; import Log from "./../core/Log"; import IPersistable from "./IPersistable"; -import { ProjectItemType } from "../app/IProjectItemData"; -import EntityTypeEditor from "./EntityTypeEditor"; +import { ProjectItemCreationType, ProjectItemType } from "../app/IProjectItemData"; import IGitHubInfo from "../app/IGitHubInfo"; import GitHubReferenceEditor from "./GitHubReferenceEditor"; @@ -170,7 +169,7 @@ export default class ProjectItemEditor extends Component ); - } else if ( - file.type === "json" && - projItem.itemType === ProjectItemType.entityTypeBehaviorJson && - !(this.props.forceRawView || ep === ProjectEditPreference.raw) - ) { - Log.verbose("Showing entity type editor for '" + file.storageRelativePath + "'"); - interior = ( - - ); } else if ( file.type === "json" && projItem.itemType === ProjectItemType.scriptTypesJson && diff --git a/app/src/UX/ProjectItemList.tsx b/app/src/UX/ProjectItemList.tsx index 42f81125..df5a1cd2 100644 --- a/app/src/UX/ProjectItemList.tsx +++ b/app/src/UX/ProjectItemList.tsx @@ -1506,7 +1506,7 @@ export default class ProjectItemList extends Component; const additionalButtons = []; let summary = undefined; - let tags = undefined; + let tags = []; const ghurl = "https://github.com/" + proj.gitHubOwner + "/" + proj.gitHubRepoName; @@ -123,7 +123,7 @@ export default class ProjectTile extends Component

{proj.title}

+ {tags}
{description} - {tags}
-

{proj.title}

+
+

{proj.title}

+ {tags} +
diff --git a/app/src/app/Carto.ts b/app/src/app/Carto.ts index 9df248fe..2ba3e8cc 100644 --- a/app/src/app/Carto.ts +++ b/app/src/app/Carto.ts @@ -126,6 +126,7 @@ export default class Carto { private _onPropertyChanged = new EventDispatcher(); private _onLoaded = new EventDispatcher(); private _onStatusAdded = new EventDispatcher(); + private _onOperationCompleted = new EventDispatcher(); private _onStatusAddedAsync: ((carto: Carto, status: IStatus) => Promise)[] = []; private _onGalleryLoaded = new EventDispatcher(); @@ -509,6 +510,10 @@ export default class Carto { return this._onStatusAdded.asEvent(); } + public get onOperationCompleted() { + return this._onOperationCompleted.asEvent(); + } + public get successfullyConnectedWebSocketToMinecraft() { if (this.#data.successfullyConnectedWebSocketToMinecraft === undefined) { return false; @@ -1076,10 +1081,20 @@ export default class Carto { async notifyOperationEnded( endedOperationId: number, - message: string, + message?: string, topic?: StatusTopic, endedWithErrors?: boolean ) { + this.ensureStatusArrayIsTrimmed(); + + this.removeOperation(endedOperationId); + + this._onOperationCompleted.dispatch(this, endedOperationId); + + if (!message) { + return; + } + const status = { message: message, operationId: endedOperationId, @@ -1090,10 +1105,6 @@ export default class Carto { this.status.push(status); - this.ensureStatusArrayIsTrimmed(); - - this.removeOperation(endedOperationId); - await this.callStatusAddedListeners(status); } @@ -1397,7 +1408,6 @@ export default class Carto { const projectPrefs = await this.prefsProjectsFolder.createFile(desiredProjectName + ".json"); - // Log.debugAlert("Creating new project " + messageProjectPath + "|" + desiredProjectName); const newProject = new Project(this, desiredProjectName, projectPrefs); newProject.mainDeployFolderPath = messageProjectPath; newProject.originalFullPath = messageProjectPath; diff --git a/app/src/app/DeploymentStorageMinecraft.ts b/app/src/app/DeploymentStorageMinecraft.ts index 8df21b78..31a6f1cf 100644 --- a/app/src/app/DeploymentStorageMinecraft.ts +++ b/app/src/app/DeploymentStorageMinecraft.ts @@ -10,7 +10,6 @@ import Project from "./Project"; import MinecraftPush from "./MinecraftPush"; import GameStateManager from "../minecraft/GameStateManager"; import Log from "../core/Log"; -import ProjectTools from "./ProjectTools"; import IFolder from "../storage/IFolder"; import { MinecraftGameConnectionMode } from "./ICartoData"; import ProjectExporter from "./ProjectExporter"; @@ -144,7 +143,7 @@ export default class DeploymentStorageMinecraft implements IMinecraft { const deployFolderExists = await this._carto.deployBehaviorPacksFolder.exists(); if (deployFolderExists) { - await ProjectTools.deployProject(this._carto, this._project, this._carto.deploymentStorage.rootFolder); + await ProjectExporter.deployProject(this._carto, this._project, this._carto.deploymentStorage.rootFolder); } } diff --git a/app/src/app/IProjectItemData.ts b/app/src/app/IProjectItemData.ts index 0b6b6426..02bc265f 100644 --- a/app/src/app/IProjectItemData.ts +++ b/app/src/app/IProjectItemData.ts @@ -3,7 +3,7 @@ import IGitHubInfo from "./IGitHubInfo"; -export const MaxItemTypes = 123; +export const MaxItemTypes = 124; export enum ProjectItemCategory { assets, @@ -139,6 +139,7 @@ export enum ProjectItemType { esLintMjs = 120, env = 121, prettierRcJson = 122, + skinCatalogJson = 123, } export enum ProjectItemStorageType { @@ -157,6 +158,13 @@ export enum ProjectItemErrorStatus { unprocessable = 1, } +export enum ProjectItemCreationType { + normal = 0, + generated = 1, + build = 2, + dist = 3, +} + export default interface IProjectItemData { itemType: ProjectItemType; projectPath: string | null | undefined; @@ -167,7 +175,7 @@ export default interface IProjectItemData { isInWorld?: boolean; storageType: ProjectItemStorageType | undefined; gitHubReference?: IGitHubInfo; - isAutogenerated?: boolean; + creationType?: ProjectItemCreationType; editPreference?: ProjectItemEditPreference; errorMessage?: string; errorStatus?: ProjectItemErrorStatus; diff --git a/app/src/app/Project.ts b/app/src/app/Project.ts index 016d0ccc..f88785eb 100644 --- a/app/src/app/Project.ts +++ b/app/src/app/Project.ts @@ -12,7 +12,7 @@ import IProjectData, { } from "./IProjectData"; import { ProjectDataType, ProjectFocus } from "./IProjectData"; import ProjectItem from "./ProjectItem"; -import IProjectItemData, { ProjectItemStorageType, ProjectItemType } from "./IProjectItemData"; +import IProjectItemData, { ProjectItemCreationType, ProjectItemStorageType, ProjectItemType } from "./IProjectItemData"; import Utilities from "./../core/Utilities"; import { EventDispatcher } from "ste-events"; import StorageUtilities from "../storage/StorageUtilities"; @@ -1235,7 +1235,7 @@ export default class Project { StorageUtilities.getLeafName(spath), ProjectItemType.buildProcessedJs, undefined, - false + ProjectItemCreationType.normal ); const file = await item.ensureFileStorage(); @@ -1473,7 +1473,7 @@ export default class Project { for (let i = 0; i < this.#items.length; i++) { const item = this.#items[i]; - if (item.isAutogenerated) { + if (item.creationType) { await item.updateAutogenerated(); } @@ -1518,7 +1518,7 @@ export default class Project { ProjectItemType.catalogIndexJs, StorageUtilities.ensureEndsWithDelimiter(scriptsFolder.storageRelativePath) + "index.js", ProjectItemStorageType.singleFile, - true + ProjectItemCreationType.generated ); } @@ -1535,7 +1535,7 @@ export default class Project { ProjectItemType.behaviorPackManifestJson, StorageUtilities.ensureEndsWithDelimiter(bpFolder.storageRelativePath) + "manifest.json", ProjectItemStorageType.singleFile, - true + ProjectItemCreationType.generated ); } @@ -1858,7 +1858,7 @@ export default class Project { candidateFile.name, newPiType, source, - false, + ProjectItemCreationType.normal, candidateFile, tag, isInWorld @@ -1866,7 +1866,7 @@ export default class Project { } else if (projectPath.endsWith("/scripts/index.js")) { await candidateFile.loadContent(); - let isAutogenerated = false; + let creationType = ProjectItemCreationType.normal; if ( candidateFile.content === undefined || @@ -1874,7 +1874,7 @@ export default class Project { (typeof candidateFile.content === "string" && candidateFile.content.indexOf(AUTOGENERATED_CONTENT_TOKEN) >= 0) ) { - isAutogenerated = true; + creationType = ProjectItemCreationType.generated; } this.ensureItemByTag( @@ -1883,7 +1883,7 @@ export default class Project { ProjectItemType.catalogIndexJs, projectPath, ProjectItemStorageType.singleFile, - isAutogenerated, + creationType, candidateFile, isInWorld ); @@ -1894,7 +1894,7 @@ export default class Project { candidateFile.name, ProjectItemType.vsCodeTasksJson, source, - false, + ProjectItemCreationType.normal, candidateFile, undefined, isInWorld @@ -1906,7 +1906,7 @@ export default class Project { candidateFile.name, ProjectItemType.vsCodeLaunchJson, source, - false, + ProjectItemCreationType.normal, candidateFile, undefined, isInWorld @@ -1918,7 +1918,7 @@ export default class Project { candidateFile.name, ProjectItemType.vsCodeSettingsJson, source, - false, + ProjectItemCreationType.normal, candidateFile, undefined, isInWorld @@ -1930,7 +1930,7 @@ export default class Project { candidateFile.name, ProjectItemType.vsCodeExtensionsJson, source, - false, + ProjectItemCreationType.normal, candidateFile, undefined, isInWorld @@ -1942,7 +1942,7 @@ export default class Project { candidateFile.name, ProjectItemType.tickJson, source, - false, + ProjectItemCreationType.normal, candidateFile, undefined, isInWorld @@ -1954,7 +1954,7 @@ export default class Project { candidateFile.name, ProjectItemType.structure, source, - false, + ProjectItemCreationType.normal, candidateFile, undefined, isInWorld @@ -1966,7 +1966,7 @@ export default class Project { candidateFile.name, ProjectItemType.MCFunction, source, - false, + ProjectItemCreationType.normal, candidateFile, undefined, isInWorld @@ -1978,7 +1978,7 @@ export default class Project { candidateFile.name, ProjectItemType.material, source, - false, + ProjectItemCreationType.normal, candidateFile, undefined, isInWorld @@ -1990,7 +1990,7 @@ export default class Project { candidateFile.name, ProjectItemType.materialVertex, source, - false, + ProjectItemCreationType.normal, candidateFile, undefined, isInWorld @@ -2002,7 +2002,7 @@ export default class Project { candidateFile.name, ProjectItemType.materialFragment, source, - false, + ProjectItemCreationType.normal, candidateFile, undefined, isInWorld @@ -2014,7 +2014,7 @@ export default class Project { candidateFile.name, ProjectItemType.materialGeometry, source, - false, + ProjectItemCreationType.normal, candidateFile, undefined, isInWorld @@ -2032,7 +2032,7 @@ export default class Project { candidateFile.name, ProjectItemType.worldFolder, source, - false, + ProjectItemCreationType.normal, candidateFile, undefined, isInWorld @@ -2044,7 +2044,7 @@ export default class Project { candidateFile.name, ProjectItemType.justConfigTs, source, - false, + ProjectItemCreationType.normal, candidateFile, undefined, isInWorld @@ -2056,7 +2056,7 @@ export default class Project { candidateFile.name, ProjectItemType.esLintMjs, source, - false, + ProjectItemCreationType.normal, candidateFile, undefined, isInWorld @@ -2068,7 +2068,7 @@ export default class Project { candidateFile.name, ProjectItemType.js, source, - false, + ProjectItemCreationType.normal, candidateFile, undefined, isInWorld @@ -2080,7 +2080,7 @@ export default class Project { candidateFile.name, ProjectItemType.ts, source, - false, + ProjectItemCreationType.normal, candidateFile, undefined, isInWorld @@ -2092,7 +2092,7 @@ export default class Project { candidateFile.name, ProjectItemType.MCWorld, source, - false, + ProjectItemCreationType.normal, candidateFile, undefined, isInWorld @@ -2106,7 +2106,7 @@ export default class Project { candidateFile.name, ProjectItemType.MCProject, source, - false, + ProjectItemCreationType.normal, candidateFile, undefined, isInWorld @@ -2120,7 +2120,7 @@ export default class Project { candidateFile.name, ProjectItemType.MCTemplate, source, - false, + ProjectItemCreationType.normal, candidateFile, undefined, isInWorld @@ -2134,7 +2134,7 @@ export default class Project { candidateFile.name, ProjectItemType.MCAddon, source, - false, + ProjectItemCreationType.normal, candidateFile, undefined, isInWorld @@ -2148,7 +2148,7 @@ export default class Project { candidateFile.name, ProjectItemType.MCPack, source, - false, + ProjectItemCreationType.normal, candidateFile, undefined, isInWorld @@ -2162,7 +2162,7 @@ export default class Project { candidateFile.name, ProjectItemType.zip, source, - false, + ProjectItemCreationType.normal, candidateFile, undefined, isInWorld @@ -2196,7 +2196,7 @@ export default class Project { candidateFile.name, imageType, source, - false, + ProjectItemCreationType.normal, candidateFile, undefined, isInWorld @@ -2208,7 +2208,7 @@ export default class Project { candidateFile.name, ProjectItemType.audio, source, - false, + ProjectItemCreationType.normal, candidateFile, undefined, isInWorld @@ -2220,7 +2220,7 @@ export default class Project { candidateFile.name, ProjectItemType.env, source, - false, + ProjectItemCreationType.normal, candidateFile, undefined, isInWorld @@ -2232,7 +2232,7 @@ export default class Project { candidateFile.name, ProjectItemType.lang, source, - false, + ProjectItemCreationType.normal, candidateFile, undefined, isInWorld @@ -2329,6 +2329,8 @@ export default class Project { (projectPath.endsWith("item_texture.json") || projectPath.endsWith("item_textures.json")) ) { newJsonType = ProjectItemType.itemTextureJson; + } else if (folderContext === FolderContext.skinPack && projectPath.endsWith("skins.json")) { + newJsonType = ProjectItemType.skinCatalogJson; } else if (folderContext === FolderContext.resourcePack && folderPathLower.indexOf("/materials/") >= 0) { newJsonType = ProjectItemType.materialSetJson; } else if ( @@ -2457,7 +2459,7 @@ export default class Project { itemName, newJsonType, source, - false, + ProjectItemCreationType.normal, candidateFile, undefined, isInWorld @@ -2647,7 +2649,7 @@ export default class Project { targetFileName, ProjectItemType.structure, undefined, - false + ProjectItemCreationType.normal ); const mcs = new Structure(); @@ -2702,7 +2704,7 @@ export default class Project { ProjectItemType.behaviorPackManifestJson, defaultPath + "manifest.json", ProjectItemStorageType.singleFile, - true + ProjectItemCreationType.generated ); pi = this.ensureItemByTag( @@ -2740,7 +2742,7 @@ export default class Project { ProjectItemType.catalogIndexJs, defaultPath + "scripts/index.js", ProjectItemStorageType.singleFile, - true + ProjectItemCreationType.generated ); } @@ -2946,7 +2948,7 @@ export default class Project { name: string, itemType: ProjectItemType, source?: string, - isAutogenerated?: boolean, + creationType?: ProjectItemCreationType, file?: IFile, tag?: string, isInWorld?: boolean @@ -2971,7 +2973,7 @@ export default class Project { itemType: itemType, projectPath: projectPath, storageType: storageType, - isAutogenerated: isAutogenerated, + creationType: creationType, source: source, tags: tags, name: name, @@ -3010,7 +3012,7 @@ export default class Project { itemType: ProjectItemType, storagePath?: string, storageType?: ProjectItemStorageType, - isAutogenerated?: boolean, + creationType?: ProjectItemCreationType, file?: IFile, isInWorld?: boolean ) { @@ -3024,7 +3026,7 @@ export default class Project { itemType: itemType, projectPath: storagePath, storageType: storageType, - isAutogenerated: isAutogenerated, + creationType: creationType, tags: [tag], name: name, }); @@ -3443,7 +3445,7 @@ export default class Project { file.name, ProjectItemType.projectSummaryMetadata, undefined, - false, + ProjectItemCreationType.normal, file ); } @@ -3870,7 +3872,7 @@ export default class Project { folder.name, itemType, undefined, - false, + ProjectItemCreationType.normal, undefined, undefined, isInWorld diff --git a/app/src/app/ProjectBuild.ts b/app/src/app/ProjectBuild.ts index 20e543d5..8adacb2c 100644 --- a/app/src/app/ProjectBuild.ts +++ b/app/src/app/ProjectBuild.ts @@ -10,6 +10,7 @@ import * as esbuild from "esbuild-wasm"; import ITypeDefCatalog from "../minecraft/ITypeDefCatalog"; import { IErrorMessage, IErrorable } from "../core/IErrorable"; import { StatusTopic } from "./Status"; +import { ProjectItemType } from "./IProjectItemData"; export default class ProjectBuild implements IErrorable { private project: Project; @@ -83,7 +84,17 @@ export default class ProjectBuild implements IErrorable { } get isBuildable() { - return this.project && this.project.projectFolder && this.mainScriptsFolder && this.distScriptsFolder && this.libs; + return this.project && this.project.projectFolder !== undefined; + } + + getHasBuildableElements() { + for (const projectItem of this.project.items) { + if (projectItem.itemType === ProjectItemType.ts) { + return true; + } + } + + return false; } async loadFile(build: esbuild.OnLoadArgs): Promise { @@ -155,6 +166,10 @@ export default class ProjectBuild implements IErrorable { return; } + if (!this.getHasBuildableElements()) { + return; + } + const operId = await this.project.carto.notifyOperationStarted("Script building '" + this.project.name + "'"); const defaultBehaviorPack = await this.project.getDefaultBehaviorPack(); @@ -269,6 +284,10 @@ export default class ProjectBuild implements IErrorable { } async syncToBehaviorPack(bpTargetFolder: IFolder) { + if (!this.getHasBuildableElements()) { + return; + } + const distScriptsFolder = await this.project.ensureDistBuildScriptsFolder(); const scriptsFolder = bpTargetFolder.ensureFolder("scripts"); diff --git a/app/src/app/ProjectContent.ts b/app/src/app/ProjectContent.ts index 604aa826..6b71be74 100644 --- a/app/src/app/ProjectContent.ts +++ b/app/src/app/ProjectContent.ts @@ -5,15 +5,15 @@ import BlockCube from "../minecraft/BlockCube"; import Structure from "../minecraft/Structure"; export default class ProjectContent { - static defaultTestJavaScript = `import * as gt from "@minecraft/server-gametest"; -import * as mc from "@minecraft/server"; + static defaultTestJavaScript = `import { Test } from "@minecraft/server-gametest"; +import { world, system } from "@minecraft/server"; function basicTest(test) { const zoglinEntityType = "zoglin"; const skeletonEntityType = "skeleton"; - test.spawn(zoglinEntityType, new mc.BlockLocation(2, 2, 3)); - test.spawn(skeletonEntityType, new mc.BlockLocation(5, 2, 3)); + test.spawn(zoglinEntityType, { x: 2, y: 2, z: 3}); + test.spawn(skeletonEntityType, { x: 5, y: 2, z: 3}); test.succeedWhen( ()=> { test.assertEntityPresentInArea(skeletonEntityType, false); @@ -24,8 +24,8 @@ function basicTest(test) { gt.register("MyProject", "basicTest", basicTest).structureName("gametests:basic"); `; - static emptyTestJavaScript = `import * as gt from "@minecraft/server-gametest"; -import * as mc from "@minecraft/server"; + static emptyTestJavaScript = `import { Test } from "@minecraft/server-gametest"; +import { world, system } from "@minecraft/server"; function basicTest(test) { @@ -34,7 +34,7 @@ function basicTest(test) { gt.register("MyProject", "basicTest", basicTest).structureName("gametests:basic"); `; - static emptyJavaScript = `import * as mc from "@minecraft/server"; + static emptyJavaScript = `import { world, system } from "@minecraft/server"; function myFunction() { diff --git a/app/src/app/ProjectExporter.ts b/app/src/app/ProjectExporter.ts index b2b9cf6d..2f938b4e 100644 --- a/app/src/app/ProjectExporter.ts +++ b/app/src/app/ProjectExporter.ts @@ -24,6 +24,12 @@ import ProjectBuild from "./ProjectBuild"; import { Generator } from "../minecraft/WorldLevelDat"; import IConversionSettings from "../core/IConversionSettings"; +export const enum FolderDeploy { + retailFolders = 0, + developmentFolders = 1, + noFolders = 2, +} + export default class ProjectExporter { static async generateFlatBetaApisWorldWithPacksZipBytes(carto: Carto, project: Project, name: string) { await Database.loadContent(); @@ -312,6 +318,160 @@ export default class ProjectExporter { return await this.ensureWorldsFolder(carto.deploymentStorage.rootFolder); } + static async prepareProject(project: Project): Promise { + await ProjectExporter.updateProjects(project); + + await project.save(); + + const projectBuild = new ProjectBuild(project); + + await projectBuild.build(); + + if (projectBuild.isInErrorState) { + project.appendErrors(projectBuild); + return undefined; + } + + return projectBuild; + } + + static async deployProject(carto: Carto, project: Project, deployTargetFolder: IFolder) { + const ctProjectBuild = await ProjectExporter.prepareProject(project); + + if (!ctProjectBuild) { + return false; + } + + await ProjectExporter.deployProjectPacks( + project, + ctProjectBuild, + deployTargetFolder, + undefined, + FolderDeploy.developmentFolders + ); + + await deployTargetFolder.saveAll(); + + const targetResourcePacksFolder = deployTargetFolder.ensureFolder("development_resource_packs"); + const rpDeployFolderExists = await targetResourcePacksFolder.exists(); + + if (rpDeployFolderExists) { + await project.ensureProjectFolder(); + + const rpi = await project.getDefaultResourcePackFolder(); + + if (rpi) { + const deployProjectFolder = targetResourcePacksFolder.ensureFolder(project.name); + + await deployProjectFolder.ensureExists(); + + await StorageUtilities.syncFolderTo(rpi, deployProjectFolder, true, true, true, [ + "/mcworlds", + "/minecraftWorlds", + ]); + } + } + + return true; + } + + static async deployProjectPacks( + project: Project, + projectBuild: ProjectBuild, + targetFolder: IFolder, + mcworld?: MCWorld, + useDeveloperFolders?: FolderDeploy + ) { + const bpGroupFolder = + useDeveloperFolders === FolderDeploy.noFolders + ? targetFolder + : targetFolder.ensureFolder( + useDeveloperFolders === FolderDeploy.developmentFolders ? "development_behavior_packs" : "behavior_packs" + ); + + await bpGroupFolder.ensureExists(); + + const activeBehaviorPackFolder = await project.getDefaultBehaviorPackFolder(); + const scriptsFolder = await project.getMainScriptsFolder(); + + if (activeBehaviorPackFolder) { + const bpTargetFolder = bpGroupFolder.ensureFolder( + activeBehaviorPackFolder.ensuredName + (useDeveloperFolders === FolderDeploy.noFolders ? "_bp" : "") + ); + + await bpTargetFolder.ensureExists(); + + await StorageUtilities.syncFolderTo(activeBehaviorPackFolder, bpTargetFolder, true, true, false, [ + "mcworlds", + "db", + "level.dat", + "level.dat_old", + "levelname.txt", + "behavior_packs", + "resource_packs", + ]); + + await projectBuild.syncToBehaviorPack(bpTargetFolder); + + if (scriptsFolder && scriptsFolder.parentFolder !== activeBehaviorPackFolder) { + const scriptsTargetFolder = bpTargetFolder.ensureFolder("scripts"); + + await scriptsTargetFolder.ensureExists(); + + await StorageUtilities.syncFolderTo(scriptsFolder, scriptsTargetFolder, true, true, false, ["*.ts"]); + } + + if (mcworld) { + mcworld.ensureBehaviorPack( + project.defaultBehaviorPackUniqueId, + project.defaultBehaviorPackVersion, + activeBehaviorPackFolder.name + ); + } + + await bpTargetFolder.saveAll(); + } + + const activeResourcePackFolder = await project.getDefaultResourcePackFolder(); + + if (activeResourcePackFolder) { + const rpGroupFolder = + useDeveloperFolders === FolderDeploy.noFolders + ? targetFolder + : targetFolder.ensureFolder( + useDeveloperFolders === FolderDeploy.developmentFolders ? "development_resource_packs" : "resource_packs" + ); + + await rpGroupFolder.ensureExists(); + + const rpTargetFolder = rpGroupFolder.ensureFolder( + activeResourcePackFolder.ensuredName + (useDeveloperFolders === FolderDeploy.noFolders ? "_rp" : "") + ); + + await rpTargetFolder.ensureExists(); + + await StorageUtilities.syncFolderTo(activeResourcePackFolder, rpTargetFolder, true, true, false, [ + "mcworlds", + "db", + "level.dat", + "level.dat_old", + "levelname.txt", + "behavior_packs", + "resource_packs", + ]); + + if (mcworld) { + mcworld.ensureResourcePack( + project.defaultResourcePackUniqueId, + project.defaultResourcePackVersion, + activeResourcePackFolder.name + ); + + await rpTargetFolder.saveAll(); + } + } + } + static async deployAsWorldAndTestAssets( carto: Carto, project: Project, @@ -320,9 +480,11 @@ export default class ProjectExporter { deployFolder?: IFolder ) { let mcworld: MCWorld | undefined; + const operId = await carto.notifyOperationStarted( "Deploying world '" + worldProjectItem.name + "' and test assets." ); + await worldProjectItem.load(); if (!worldProjectItem.file && !worldProjectItem.folder) { @@ -341,18 +503,10 @@ export default class ProjectExporter { return; } - await ProjectExporter.updateProjects(project); - - await project.save(); - - const projectBuild = new ProjectBuild(project); + const projectBuild = await ProjectExporter.prepareProject(project); - await projectBuild.build(); - - if (projectBuild.isInErrorState) { - project.appendErrors(projectBuild); + if (!projectBuild) { await carto.notifyOperationEnded(operId, "Packaging the world not be completed.", undefined, true); - return; } const dateNow = new Date(); @@ -392,28 +546,20 @@ export default class ProjectExporter { await mcworld.syncFolderTo(targetFolder); - const bpGroupFolder = targetFolder.ensureFolder("behavior_packs"); - - await bpGroupFolder.ensureExists(); - - const bpFolder = await project.getDefaultBehaviorPackFolder(); + if (projectBuild) { + await ProjectExporter.deployProjectPacks(project, projectBuild, targetFolder, mcworld); + } - if (bpFolder) { - const bpTargetFolder = bpGroupFolder.ensureFolder(bpFolder.name); + const creatorToolsProject = await Database.ensureCreatorToolsIngameProject(); - await bpTargetFolder.ensureExists(); + if (creatorToolsProject) { + const ctProjectBuild = await ProjectExporter.prepareProject(creatorToolsProject); - await StorageUtilities.syncFolderTo(bpFolder, bpTargetFolder, true, true, false, [ - "mcworlds", - "db", - "level.dat", - "level.dat_old", - "levelname.txt", - "behavior_packs", - "resource_packs", - ]); + if (ctProjectBuild) { + await ProjectExporter.deployProjectPacks(creatorToolsProject, ctProjectBuild, targetFolder, mcworld); + } - await projectBuild.syncToBehaviorPack(bpTargetFolder); + await mcworld.save(); } await targetFolder.saveAll(); @@ -425,21 +571,13 @@ export default class ProjectExporter { return; } - if (bpFolder) { - newMcWorld.ensureBehaviorPack( - project.defaultBehaviorPackUniqueId, - project.defaultBehaviorPackVersion, - bpFolder.name - ); - } - - newMcWorld.betaApisExperiment = true; + // newMcWorld.betaApisExperiment = true; await targetFolder.saveAll(); await newMcWorld.save(); - await carto.notifyOperationEnded(operId, "World + local assets deploy completed."); + await carto.notifyOperationEnded(operId, "World + local test assets deploy completed."); if (zipStorage) { const zipBytes = await zipStorage.generateUint8ArrayAsync(); @@ -477,18 +615,10 @@ export default class ProjectExporter { return; } - await ProjectExporter.updateProjects(project); - - await project.save(); + const projectBuild = await ProjectExporter.prepareProject(project); - const projectBuild = new ProjectBuild(project); - - await projectBuild.build(); - - if (projectBuild.isInErrorState) { - project.appendErrors(projectBuild); - await carto.notifyOperationEnded(operId, "World could not be packaged.", undefined, true); - return; + if (!projectBuild) { + await carto.notifyOperationEnded(operId, "Packaging the world not be completed.", undefined, true); } const dateNow = new Date(); @@ -554,17 +684,10 @@ export default class ProjectExporter { ) { const operId = await carto.notifyOperationStarted("Generating world and packs for '" + project.name + "'."); - await ProjectExporter.updateProjects(project); - - await project.save(); - - const projectBuild = new ProjectBuild(project); - - await projectBuild.build(); + const projectBuild = await ProjectExporter.prepareProject(project); - if (projectBuild.isInErrorState) { - project.appendErrors(projectBuild); - await carto.notifyOperationEnded(operId, "Packaging the world could not be completed.", undefined, true); + if (projectBuild === undefined) { + await carto.notifyOperationEnded(operId); return; } @@ -594,71 +717,8 @@ export default class ProjectExporter { await mcworld.applyWorldSettings(worldSettings); - const behaviorPackFolder = await project.getDefaultBehaviorPackFolder(); - const scriptsFolder = await project.getMainScriptsFolder(); - - if (behaviorPackFolder) { - const bpGroupFolder = targetFolder.ensureFolder("behavior_packs"); - - await bpGroupFolder.ensureExists(); - - const bpTargetFolder = bpGroupFolder.ensureFolder(behaviorPackFolder.name); - - await bpTargetFolder.ensureExists(); - - await StorageUtilities.syncFolderTo(behaviorPackFolder, bpTargetFolder, true, true, false, [ - "mcworlds", - "db", - "level.dat", - "level.dat_old", - "levelname.txt", - "behavior_packs", - "resource_packs", - ]); - - await projectBuild.syncToBehaviorPack(bpTargetFolder); - - if (scriptsFolder && scriptsFolder.parentFolder !== behaviorPackFolder) { - const scriptsTargetFolder = bpTargetFolder.ensureFolder("scripts"); - - await scriptsTargetFolder.ensureExists(); - - await StorageUtilities.syncFolderTo(scriptsFolder, scriptsTargetFolder, true, true, false, ["*.ts"]); - } - - mcworld.ensureBehaviorPack( - project.defaultBehaviorPackUniqueId, - project.defaultBehaviorPackVersion, - behaviorPackFolder.name - ); - } - - const resourcePackFolder = await project.getDefaultResourcePackFolder(); - - if (resourcePackFolder) { - const rpGroupFolder = targetFolder.ensureFolder("resource_packs"); - - await rpGroupFolder.ensureExists(); - - const rpTargetFolder = rpGroupFolder.ensureFolder(resourcePackFolder.name); - - await rpTargetFolder.ensureExists(); - - await StorageUtilities.syncFolderTo(resourcePackFolder, rpTargetFolder, true, true, false, [ - "mcworlds", - "db", - "level.dat", - "level.dat_old", - "levelname.txt", - "behavior_packs", - "resource_packs", - ]); - - mcworld.ensureResourcePack( - project.defaultResourcePackUniqueId, - project.defaultResourcePackVersion, - resourcePackFolder.name - ); + if (projectBuild) { + await ProjectExporter.deployProjectPacks(project, projectBuild, targetFolder, mcworld); } mcworld.betaApisExperiment = true; @@ -877,47 +937,28 @@ export default class ProjectExporter { return undefined; } - static async generatePackAsZip(carto: Carto, project: Project, returnAsBlob: boolean): Promise { + static async generateMCAddonAsZip( + carto: Carto, + project: Project, + returnAsBlob: boolean + ): Promise { const operId = await carto.notifyOperationStarted("Exporting '" + project.name + "' as MCPack"); const zipStorage = new ZipStorage(); - const bpFolder = await project.getDefaultBehaviorPackFolder(); - - if (bpFolder) { - const childFolder = zipStorage.rootFolder.ensureFolder(bpFolder.name); - - await StorageUtilities.syncFolderTo(bpFolder, childFolder, true, true, false, [ - "/mcworlds", - "/minecraftWorlds", - "*.ts", - ]); - - const scriptsFolder = await project.ensureDefaultScriptsFolder(); + const projectBuild = await ProjectExporter.prepareProject(project); - if ( - !scriptsFolder.storageRelativePath.startsWith(bpFolder.storageRelativePath) && - scriptsFolder.storageRelativePath !== "/" - ) { - await StorageUtilities.syncFolderTo(scriptsFolder, childFolder.ensureFolder("scripts"), true, false, false, [ - ".ts", - ]); - } + if (!projectBuild) { + return undefined; } - const rpFolder = await project.getDefaultResourcePackFolder(); - - if (rpFolder) { - let rpFolderName = rpFolder.name; - - if (bpFolder && bpFolder.name === rpFolderName) { - rpFolderName += "rp"; - } - - const childFolder = zipStorage.rootFolder.ensureFolder(rpFolderName); - - await StorageUtilities.syncFolderTo(rpFolder, childFolder, true, true, false, ["/mcworlds", "/minecraftWorlds"]); - } + await ProjectExporter.deployProjectPacks( + project, + projectBuild, + zipStorage.rootFolder, + undefined, + FolderDeploy.noFolders + ); await zipStorage.rootFolder.saveAll(); @@ -957,64 +998,16 @@ export default class ProjectExporter { mcworld.project = project; - await ProjectExporter.updateProjects(project); - - await project.save(); - - const projectBuild = new ProjectBuild(project); - - await projectBuild.build(); + const projectBuild = await ProjectExporter.prepareProject(project); - if (projectBuild.isInErrorState) { - project.appendErrors(projectBuild); + if (!projectBuild) { return undefined; } mcworld.betaApisExperiment = true; mcworld.name = worldName; - const rootFolder = mcworld.storage.rootFolder; - - const sourceBpf = await project.ensureDefaultBehaviorPackFolder(); - - const bp = rootFolder.ensureFolder("behavior_packs"); - - const bpf = bp.ensureFolder(project.name); - - if (sourceBpf !== null) { - await bpf.ensureExists(); - mcworld.ensureBehaviorPack(project.defaultBehaviorPackUniqueId, project.defaultBehaviorPackVersion, project.name); - - await StorageUtilities.syncFolderTo(sourceBpf, bpf, true, false, false, ["/mcworlds", "/minecraftWorlds", ".ts"]); - - const scriptsFolder = await project.ensureDefaultScriptsFolder(); - - if ( - !scriptsFolder.storageRelativePath.startsWith(sourceBpf.storageRelativePath) && - scriptsFolder.storageRelativePath !== "/" - ) { - await StorageUtilities.syncFolderTo(scriptsFolder, bpf.ensureFolder("scripts"), true, false, false, [".ts"]); - } - - await projectBuild.syncToBehaviorPack(bpf); - - await bpf.saveAll(); - } - - const sourceRpf = await project.ensureDefaultResourcePackFolder(); - - const rp = rootFolder.ensureFolder("resource_packs"); - - const rpf = rp.ensureFolder(project.name); - - if (sourceRpf !== null) { - await rpf.ensureExists(); - mcworld.ensureResourcePack(project.defaultResourcePackUniqueId, project.defaultResourcePackVersion, project.name); - - await StorageUtilities.syncFolderTo(sourceRpf, rpf, true, false, false, ["/mcworlds", "/minecraftWorlds", ".ts"]); - - await rpf.saveAll(); - } + await ProjectExporter.deployProjectPacks(project, projectBuild, mcworld.storage.rootFolder, mcworld); return mcworld; } diff --git a/app/src/app/ProjectItem.ts b/app/src/app/ProjectItem.ts index ea19c3e4..a4441971 100644 --- a/app/src/app/ProjectItem.ts +++ b/app/src/app/ProjectItem.ts @@ -2,6 +2,7 @@ // Licensed under the MIT License. import IProjectItemData, { + ProjectItemCreationType, ProjectItemEditPreference, ProjectItemErrorStatus, ProjectItemStorageType, @@ -419,8 +420,8 @@ export default class ProjectItem { this._data.storageType = newStorageType; } - get isAutogenerated() { - return this._data.isAutogenerated; + get creationType() { + return this._data.creationType; } get itemType() { @@ -503,7 +504,7 @@ export default class ProjectItem { } get needsSave() { - if (this._file === null && this.isAutogenerated && this.storageType === ProjectItemStorageType.singleFile) { + if (this._file === null && this.creationType && this.storageType === ProjectItemStorageType.singleFile) { return true; } @@ -813,7 +814,7 @@ export default class ProjectItem { } if (!this._isFileContentProcessed && this._file) { - if (this._data.isAutogenerated === true) { + if (this._data.creationType === ProjectItemCreationType.generated) { await this.updateAutogenerated(true); } else { await this._file.loadContent(); @@ -925,7 +926,7 @@ export default class ProjectItem { await this.load(); } - if (this._file == null || !this._data.isAutogenerated) { + if (this._file == null || this._data.creationType !== ProjectItemCreationType.generated) { return; } diff --git a/app/src/app/ProjectItemManager.ts b/app/src/app/ProjectItemManager.ts index 1337b817..14315c3d 100644 --- a/app/src/app/ProjectItemManager.ts +++ b/app/src/app/ProjectItemManager.ts @@ -4,7 +4,7 @@ import Project from "./Project"; import ProjectContent from "./ProjectContent"; import { ProjectScriptLanguage } from "./IProjectData"; -import { ProjectItemStorageType, ProjectItemType } from "./IProjectItemData"; +import { ProjectItemCreationType, ProjectItemStorageType, ProjectItemType } from "./IProjectItemData"; import StorageUtilities from "./../storage/StorageUtilities"; import ZipStorage from "../storage/ZipStorage"; import IProjectItemSeed from "./IProjectItemSeed"; @@ -81,7 +81,7 @@ export default class ProjectItemManager { StorageUtilities.getLeafName(candidateFilePath), itemType === ProjectItemType.js ? ProjectItemType.js : ProjectItemType.ts, undefined, - false + ProjectItemCreationType.normal ); const file = await pi.ensureFileStorage(); @@ -270,7 +270,7 @@ export default class ProjectItemManager { StorageUtilities.getLeafName(candidateFilePath), ProjectItemType.testJs, undefined, - false + ProjectItemCreationType.normal ); const file = await pi.ensureFileStorage(); @@ -321,7 +321,7 @@ export default class ProjectItemManager { StorageUtilities.getLeafName(candidateFilePath), ProjectItemType.MCFunction, undefined, - false + ProjectItemCreationType.normal ); const file = await pi.ensureFileStorage(); @@ -359,7 +359,7 @@ export default class ProjectItemManager { StorageUtilities.getLeafName(candidateFilePath), ProjectItemType.structure, undefined, - false + ProjectItemCreationType.normal ); const file = await pi.ensureFileStorage(); @@ -399,7 +399,7 @@ export default class ProjectItemManager { StorageUtilities.getLeafName(candidateFilePath), ProjectItemType.actionSetJson, undefined, - false + ProjectItemCreationType.normal ); const file = await pi.ensureFileStorage(); @@ -438,7 +438,7 @@ export default class ProjectItemManager { candidateFolderPath, ProjectItemType.documentedTypeFolder, undefined, - false + ProjectItemCreationType.normal ); await pi.ensureFolderStorage(); @@ -472,7 +472,7 @@ export default class ProjectItemManager { StorageUtilities.getLeafName(candidateFilePath), ProjectItemType.worldTest, undefined, - false + ProjectItemCreationType.normal ); const file = await pi.ensureFileStorage(); @@ -512,7 +512,7 @@ export default class ProjectItemManager { StorageUtilities.getLeafName(candidateFilePath), ProjectItemType.worldTest, undefined, - false + ProjectItemCreationType.normal ); const file = await pi.ensureFileStorage(); diff --git a/app/src/app/ProjectTools.ts b/app/src/app/ProjectTools.ts index 9aae5210..24e4a07b 100644 --- a/app/src/app/ProjectTools.ts +++ b/app/src/app/ProjectTools.ts @@ -5,11 +5,7 @@ import Project from "./Project"; import ITool, { ToolType, ToolScope } from "./ITool"; import { ProjectItemType } from "./IProjectItemData"; import Carto from "./Carto"; -import IFolder from "../storage/IFolder"; -import StorageUtilities from "../storage/StorageUtilities"; -import Log from "../core/Log"; import CommandRunner from "./CommandRunner"; -import ProjectBuild from "./ProjectBuild"; export default class ProjectTools { static async addGlobalTools(tools: ITool[]) { @@ -92,80 +88,6 @@ export default class ProjectTools { } } - static async deployProject(carto: Carto, project: Project, deployTargetFolder: IFolder) { - const targetBehaviorPacksFolder = deployTargetFolder.ensureFolder("development_behavior_packs"); - - const bpDeployFolderExists = await targetBehaviorPacksFolder.exists(); - - if (bpDeployFolderExists) { - await project.ensureProjectFolder(); - - const bpi = await project.ensureDefaultBehaviorPackFolder(); - - const deployProjectFolder = targetBehaviorPacksFolder.ensureFolder(project.name); - - await deployProjectFolder.ensureExists(); - - await StorageUtilities.syncFolderTo(bpi, deployProjectFolder, true, true, true, [ - "/mcworlds", - "/minecraftWorlds", - ]); - - const projectBuild = new ProjectBuild(project); - - await projectBuild.build(); - - if (projectBuild.isInErrorState) { - project.appendErrors(projectBuild); - - return; - } - - const scriptsFolder = project.getDistBuildScriptsFolder(); - - if ( - scriptsFolder && - !scriptsFolder.storageRelativePath.startsWith(bpi.storageRelativePath) && - scriptsFolder.storageRelativePath !== "/" - ) { - await StorageUtilities.syncFolderTo( - scriptsFolder, - deployProjectFolder.ensureFolder("scripts"), - true, - true, - true, - [".ts"], - undefined, - async (message: string) => { - Log.verbose(message); - } - ); - } - - await deployProjectFolder.saveAll(); - } - - const targetResourcePacksFolder = deployTargetFolder.ensureFolder("development_resource_packs"); - const rpDeployFolderExists = await targetResourcePacksFolder.exists(); - - if (rpDeployFolderExists) { - await project.ensureProjectFolder(); - - const rpi = await project.getDefaultResourcePackFolder(); - - if (rpi) { - const deployProjectFolder = targetResourcePacksFolder.ensureFolder(project.name); - - await deployProjectFolder.ensureExists(); - - await StorageUtilities.syncFolderTo(rpi, deployProjectFolder, true, true, true, [ - "/mcworlds", - "/minecraftWorlds", - ]); - } - } - } - static async reload(carto: Carto) { await carto.runMinecraftCommand("reload"); } diff --git a/app/src/app/ProjectUtilities.ts b/app/src/app/ProjectUtilities.ts index 19507c23..699b3bc6 100644 --- a/app/src/app/ProjectUtilities.ts +++ b/app/src/app/ProjectUtilities.ts @@ -4,7 +4,7 @@ import StorageUtilities from "../storage/StorageUtilities"; import MinecraftUtilities from "../minecraft/MinecraftUtilities"; import Project from "./Project"; -import { ProjectItemType, ProjectItemStorageType } from "./IProjectItemData"; +import { ProjectItemType, ProjectItemStorageType, ProjectItemCreationType } from "./IProjectItemData"; import Database from "../minecraft/Database"; import Log from "../core/Log"; import Utilities from "../core/Utilities"; @@ -82,7 +82,7 @@ export default class ProjectUtilities { fileName, typeInfo.itemType, undefined, - false + ProjectItemCreationType.normal ); } @@ -335,7 +335,7 @@ export default class ProjectUtilities { ".env", ProjectItemType.env, undefined, - false, + ProjectItemCreationType.normal, undefined, undefined, false @@ -458,7 +458,7 @@ export default class ProjectUtilities { } static getSuggestedProjectNameFromElements(id?: string, gitHubFolder?: string, gitHubRepoName?: string) { - let projName = "my-"; + let projName = "my"; if (id) { projName += id; @@ -583,7 +583,7 @@ export default class ProjectUtilities { StorageUtilities.getLeafName(candidateJsFilePath), ProjectItemType.entityTypeBaseJs, undefined, - true + ProjectItemCreationType.generated ); piGenJs.updateAutogenerated(); @@ -604,7 +604,7 @@ export default class ProjectUtilities { StorageUtilities.getLeafName(candidateJsFilePath), ProjectItemType.entityTypeBaseTs, undefined, - true + ProjectItemCreationType.generated ); piGenJs.updateAutogenerated(); @@ -796,7 +796,8 @@ export default class ProjectUtilities { if (file) { const snipSet = StorageUtilities.getJsonObject(file) as { [snippetName: string]: ISnippet }; - if (snipSet[snippetId]) { + + if (snipSet && snipSet[snippetId]) { return snipSet[snippetId]; } } @@ -808,25 +809,175 @@ export default class ProjectUtilities { static CodeReplaceTokens = ["say Hello", 'sendMessage("Hello world']; - static adaptSample(sampleContent: string, fileContent: string) { - const result = { - sampleContent: sampleContent, - newIntroLines: "", - }; + static ImportTypes = { + vanilla: ["MinecraftDimensionTypes", "MinecraftBlockTypes", "MinecraftItemTypes", "MinecraftEntityTypes"], + math: ["Vector3Utils"], + mcui: [ + "MessageFormResponse", + "MessageFormData", + "ActionFormData", + "ActionFormResponse", + "ModalFormData", + "ModalFormResponse", + ], + mc: [ + "world", + "system", + "BlockPermutation", + "BlockSignComponent", + "SignSide", + "DyeColor", + "EntityQueryOptions", + "ButtonPushAfterEvent", + "ItemStack", + "MolangVariableMap", + "EntityInventoryComponent", + "Enchantment", + "ItemEnchantsComponent", + "EntityHealthComponent", + "EntityOnFireComponent", + "EntityEquippableComponent", + "EquipmentSlot", + "EntityItemComponent", + "EntitySpawnAfterEvent", + "PistonActivateBeforeEvent", + "PistonActivateAfterEvent", + "MusicOptions", + "WorldSoundOptions", + "PlayerSoundOptions", + "DisplaySlotId", + "ObjectiveSortOrder", + "TripWireAfterEvent", + "LeverActionAfterEvent", + "Vector3", + "DimensionLocation", + ], + }; + static adaptSample(sampleContent: string, fileContent: string) { if (sampleContent.indexOf(" mc.") >= 0 && fileContent.indexOf(" as mc") <= 0) { - result.sampleContent = result.sampleContent.replace(/mc./gi, ""); + sampleContent = sampleContent.replace(/mc./gi, ""); } - /*if (sampleContent.indexOf("targetLocation") >= 0 && fileContent.indexOf("targetLocation") <= 0) { - result.sampleContent = result.sampleContent.replace(/targetLocation/gi, "{ x: 0, y: 64, z: 0 }"); - }*/ + if (sampleContent.indexOf(" mcui.") >= 0 && fileContent.indexOf(" as mcui") <= 0) { + sampleContent = sampleContent.replace(/mcui./gi, ""); + } - return result; + return sampleContent; + } + + static modifyImports(fileContent: string) { + let startOfCode = fileContent.indexOf("("); + let nextStartOfCode = fileContent.indexOf("function"); + + if (nextStartOfCode >= 0 && nextStartOfCode < startOfCode) { + startOfCode = nextStartOfCode; + } + + nextStartOfCode = fileContent.indexOf("class"); + + if (nextStartOfCode >= 0 && nextStartOfCode < startOfCode) { + startOfCode = nextStartOfCode; + } + + const previousNewLine = fileContent.lastIndexOf("\n", startOfCode); + + if (previousNewLine >= 0) { + startOfCode = previousNewLine; + } + + if (startOfCode > 0) { + let introContent = fileContent.substring(0, startOfCode); + const restOfContent = fileContent.substring(startOfCode); + + introContent = ProjectUtilities.ensureImportLines( + introContent, + restOfContent, + "@minecraft/server", + this.ImportTypes.mc + ); + + introContent = ProjectUtilities.ensureImportLines( + introContent, + restOfContent, + "@minecraft/server-ui", + this.ImportTypes.mcui + ); + + introContent = ProjectUtilities.ensureImportLines( + introContent, + restOfContent, + "@minecraft/vanilla-data", + this.ImportTypes.vanilla + ); + + introContent = ProjectUtilities.ensureImportLines( + introContent, + restOfContent, + "@minecraft/math", + this.ImportTypes.math + ); + + fileContent = introContent + restOfContent; + } + + return fileContent; + } + + static ensureImportLines( + introSection: string, + restOfContent: string, + moduleName: string, + importCollection: string[] + ) { + for (const importType of importCollection) { + if (restOfContent.indexOf(importType) >= 0) { + let importLineIndex = introSection.indexOf('from "' + moduleName + '";'); + + if (importLineIndex < 0) { + introSection = 'import {} from "' + moduleName + '";\r\n' + introSection; + importLineIndex = 10; + } + + let previousNewLine = introSection.lastIndexOf("\n", importLineIndex); + + if (previousNewLine < 0) { + previousNewLine = 0; + } + + let endNewLine = introSection.indexOf("\n", importLineIndex); + + if (endNewLine > previousNewLine) { + let importLine = introSection.substring(previousNewLine, endNewLine); + + const leftBracket = importLine.indexOf("{"); + const rightBracket = importLine.indexOf("}"); + + if (leftBracket > 0 && rightBracket > leftBracket) { + const interior = importLine.substring(leftBracket + 1, rightBracket).trim(); + + if (interior.indexOf(importType) < 0) { + let injectToken = importType; + + // is there one token already in the import linte + if (interior.length > 0) { + injectToken = ", " + injectToken; + } + + importLine = importLine.substring(0, rightBracket) + injectToken + importLine.substring(rightBracket); + } + } + + introSection = introSection.substring(0, previousNewLine) + importLine + introSection.substring(endNewLine); + } + } + } + + return introSection; } static async injectSnippet(project: Project, snippet: ISnippet, fullScriptBoxReplace: boolean) { - const replaceContent = "\r\n" + snippet.body.join("\n") + "\r\n"; + let snippetInjectContent = "\r\n" + snippet.body.join("\n") + "\r\n"; const folder = await project.ensureDefaultScriptsFolder(); @@ -838,7 +989,7 @@ export default class ProjectUtilities { if (file !== undefined) { if (fullScriptBoxReplace && fileName === "ScriptBox.ts") { - file.setContent(replaceContent); + file.setContent(snippetInjectContent); } else { const type = StorageUtilities.getTypeFromName(file.name); @@ -856,66 +1007,14 @@ export default class ProjectUtilities { const previousNewLine = content.lastIndexOf("\n", token); const nextNewLine = content.indexOf("\n", token); if (previousNewLine >= 0 && nextNewLine > previousNewLine) { - const replacer = ProjectUtilities.adaptSample(replaceContent, content); + snippetInjectContent = ProjectUtilities.adaptSample(snippetInjectContent, content); content = - replacer.newIntroLines + - content.substring(0, previousNewLine) + - replacer.sampleContent + - content.substring(nextNewLine + 1); - - if (content.indexOf("mcui.") >= 0) { - content = content.replace( - 'from "@minecraft/server";', - 'from "@minecraft/server";\r\nimport * as mcui from "@minecraft/server-ui";' - ); - } - - if (content.indexOf("MinecraftEntityTypes") >= 0) { - content = content.replace( - 'from "@minecraft/server";', - 'from "@minecraft/server";\r\nimport { MinecraftEntityTypes } from "@minecraft/vanilla-data";' - ); - } - - if (content.indexOf("MinecraftBlockTypes") >= 0) { - content = content.replace( - 'from "@minecraft/server";', - 'from "@minecraft/server";\r\nimport { MinecraftBlockTypes } from "@minecraft/vanilla-data";' - ); - } - - if (content.indexOf("MinecraftItemTypes") >= 0) { - content = content.replace( - 'from "@minecraft/server";', - 'from "@minecraft/server";\r\nimport { MinecraftItemTypes } from "@minecraft/vanilla-data";' - ); - } - - if (content.indexOf("MinecraftEffectTypes") >= 0) { - content = content.replace( - 'from "@minecraft/server";', - 'from "@minecraft/server";\r\nimport { MinecraftEffectTypes } from "@minecraft/vanilla-data";' - ); - } - - if (content.indexOf("MinecraftDimensionTypes") >= 0) { - content = content.replace( - 'from "@minecraft/server";', - 'from "@minecraft/server";\r\nimport { MinecraftDimensionTypes } from "@minecraft/vanilla-data";' - ); - } - - if (content.indexOf("Vector3Utils") >= 0) { - content = content.replace( - 'from "@minecraft/server";', - 'from "@minecraft/server";\r\nimport { Vector3Utils } from "@minecraft/math";' - ); - } + content.substring(0, previousNewLine) + snippetInjectContent + content.substring(nextNewLine + 1); if ( - replacer.sampleContent.indexOf("overworld") >= 0 && - replacer.sampleContent.indexOf("const overworld") <= 0 + snippetInjectContent.indexOf("overworld") >= 0 && + snippetInjectContent.indexOf("const overworld") <= 0 ) { let firstComment = content.indexOf("//"); if (firstComment >= 0) { @@ -925,6 +1024,9 @@ export default class ProjectUtilities { content.substring(firstComment, content.length); } } + + content = ProjectUtilities.modifyImports(content); + file.setContent(content); } } @@ -987,7 +1089,7 @@ export default class ProjectUtilities { nextBlockTypeName, ProjectItemType.blockTypeBehaviorJson, undefined, - false + ProjectItemCreationType.normal ); const file = await pi.ensureFileStorage(); @@ -1027,7 +1129,7 @@ export default class ProjectUtilities { StorageUtilities.getLeafName(candidateJsFilePath), ProjectItemType.blockTypeBaseJs, undefined, - true + ProjectItemCreationType.generated ); piGenJs.updateAutogenerated(); @@ -1048,7 +1150,7 @@ export default class ProjectUtilities { StorageUtilities.getLeafName(candidateJsFilePath), ProjectItemType.blockTypeBaseTs, undefined, - true + ProjectItemCreationType.normal ); piGenJs.updateAutogenerated(); diff --git a/app/src/cli/ClUtils.ts b/app/src/cli/ClUtils.ts index 488d9c8a..a1eb667f 100644 --- a/app/src/cli/ClUtils.ts +++ b/app/src/cli/ClUtils.ts @@ -12,9 +12,13 @@ import IProjectStartInfo from "./IProjectStartInfo"; export enum TaskType { noCommand = 0, - validate = 1, - version = 2, - aggregateReports = 3, + info = 7, + add = 8, + create = 9, + validate = 10, + version = 12, + world = 18, + aggregateReports = 22, } export enum OutputType { @@ -99,7 +103,7 @@ export default class ClUtils { } static getIsWriteCommand(taskType: TaskType) { - return false; + return taskType === TaskType.create || taskType === TaskType.add; } static async getMainWorkFolder(taskType: TaskType, inputFolder?: string, outputFolder?: string) { @@ -124,7 +128,7 @@ export default class ClUtils { const exists = await workFolder.exists(); if (!exists) { - throw new Error("Specified folder path '" + workFolder.fullPath + "' does not exist from '" + __dirname + "'."); + throw new Error("Specified folder path '" + workFolder.fullPath + "' does not exist within '" + __dirname + "'."); } await workFolder.load(); diff --git a/app/src/cli/index.ts b/app/src/cli/index.ts index 79dd1b8e..bfc8acd9 100644 --- a/app/src/cli/index.ts +++ b/app/src/cli/index.ts @@ -20,6 +20,11 @@ import ClUtils, { OutputType, TaskType } from "./ClUtils.js"; import { spawn, Pool, Worker } from "threads"; import ContentIndex from "../core/ContentIndex.js"; import IIndexJson from "../storage/IIndexJson.js"; +import inquirer from "inquirer"; +import IGalleryItem, { GalleryItemType } from "../app/IGalleryItem.js"; +import ProjectUtilities, { NewEntityTypeAddMode } from "../app/ProjectUtilities.js"; +import Project, { ProjectAutoDeploymentMode } from "../app/Project.js"; +import ProjectExporter from "../app/ProjectExporter.js"; if (typeof btoa === "undefined") { // @ts-ignore @@ -39,6 +44,7 @@ CartoApp.hostType = HostType.toolsNodejs; const MAX_LINES_PER_CSV_FILE = 500000; +const ERROR_INIT_ERROR = 44; const ERROR_VALIDATION_INTERNALPROCESSINGERROR = 53; const ERROR_VALIDATION_TESTFAIL = 56; const ERROR_VALIDATION_ERROR = 57; @@ -49,6 +55,11 @@ let carto: Carto | undefined; const projectStarts: (IProjectStartInfo | undefined)[] = []; let localEnv: LocalEnvironment | undefined; let mode: string | undefined; +let type: string | undefined; +let newName: string | undefined; +let newDescription: string | undefined; +let template: string | undefined; +let creator: string | undefined; let suite: string | undefined; let outputType: OutputType | undefined; let aggregateReportsAfterValidation: boolean | undefined = false; @@ -76,7 +87,19 @@ program ) .option("-of, --output-file [path to file]", "Path to the export file, if applicable for the command you are using.") .option("-ot, --output-type [output type]", "Type of output, if applicable for the command you are using.") + .option( + "-bp, --behavior-pack ", + "Adds a set of behavior pack UUIDs as references for any worlds that are updated." + ) + .option( + "-rp, --resource-pack ", + "Adds a set of resources pack UUIDs as references for any worlds that are updated." + ) + .option("-betaapis, --beta-apis", "Ensures that the Beta APIs experiment is set for any worlds that are updated.") + .option("-no-betaapis, --no-beta-apis", "Removes the Beta APIs experiment if set.") .option("-f, --force", "Force any updates.") + .option("-editor", "Ensures that the world is an Editor world.") + .option("-no-editor", "Removes that the world is an editor.") .option("--threads [thread count]", "Targeted number of threads to use.") .option("-show, --display-only", "Whether to only show messages, vs. output report files.") .option("-lv, --log-verbose", "Whether to show verbose log messages."); @@ -87,6 +110,52 @@ program.addHelpText("before", "\x1b[32m│ ┏▀┓ │\x1b[0m See " + constant program.addHelpText("before", "\x1b[32m└─────┘\x1b[0m"); program.addHelpText("before", " "); +program + .command("world") + .alias("w") + .description("Displays/sets world settings within a folder.") + .addArgument( + new Argument("[mode]", "If set to 'set', will update the world with a set of properties that are specified.") + ) + .action((modeIn) => { + mode = modeIn; + executionTaskType = TaskType.world; + }); + +program + .command("add") + .alias("a") + .description("Adds new content into this Minecraft project") + .addArgument(new Argument("[type]", "Type of item to add")) + .action((typeIn) => { + type = typeIn; + executionTaskType = TaskType.add; + }); + +program + .command("create") + .alias("c") + .description("Creates a new Minecraft project") + .addArgument(new Argument("[name]", "Desired project name")) + .addArgument(new Argument("[template]", "Template name")) + .addArgument(new Argument("[creator]", "Creator name")) + .addArgument(new Argument("[description]", "Project description")) + .action((nameIn, templateIn, creatorIn, descriptionIn) => { + newName = nameIn; + template = templateIn; + creator = creatorIn; + newDescription = descriptionIn; + executionTaskType = TaskType.create; + }); + +program + .command("info") + .alias("i") + .description("Displays information about the current project.") + .action(() => { + executionTaskType = TaskType.info; + }); + program .command("validate") .alias("val") @@ -193,6 +262,10 @@ if (options.logVerbose) { await loadProjects(); switch (executionTaskType as TaskType) { + case TaskType.info: + await displayInfo(); + break; + case TaskType.version: await displayVersion(); break; @@ -204,6 +277,35 @@ if (options.logVerbose) { case TaskType.aggregateReports: await aggregateReports(); break; + + case TaskType.add: + try { + for (const projectStart of projectStarts) { + if (projectStart) { + await add(ClUtils.createProject(carto, projectStart)); + } + } + } catch (e) { + errorLevel = ERROR_INIT_ERROR; + console.error("Error adding to a project. " + e.toString()); + } + break; + + case TaskType.create: + try { + for (const projectStart of projectStarts) { + if (projectStart) { + await create(ClUtils.createProject(carto, projectStart), projectStarts.length <= 1); + } + } + } catch (e) { + errorLevel = ERROR_INIT_ERROR; + console.error("Error creating a project. " + e.toString()); + } + break; + case TaskType.world: + await setAndDisplayAllWorlds(); + break; } })(); @@ -562,7 +664,7 @@ async function setAndDisplayAllWorlds() { // if only an output folder is specified, put the world there // if an input and an output folder is specified, put the world at a subfolder of the input folder. - if (options.inputFolder) { + if (options.outputFolder) { destF = await wcf.ensureFolderFromRelativePath(StorageUtilities.ensureEndsDelimited(options.outputFolder)); } @@ -947,3 +1049,399 @@ async function saveAggregatedReports(projectList: IProjectMetaState[]) { await projectsCsvFile.saveContent(); } } + +async function create(project: Project, isSingleFolder: boolean) { + outputLogo("Minecraft Creator Tools (preview)"); + + if (!carto) { + errorLevel = ERROR_INIT_ERROR; + console.error("Not configured correctly to create a project (no mctools core)."); + return; + } + + await carto.loadGallery(); + + if (!carto.gallery) { + errorLevel = ERROR_INIT_ERROR; + console.error("Not configured correctly to create a project (no gallery)."); + return; + } + + let title = newName; + + if (!newName) { + const titleQuestions: inquirer.DistinctQuestion[] = []; + titleQuestions.push({ + type: "input", + name: "title", + default: "My Project", + message: "What's your preferred project title?", + }); + const titleAnswer = await inquirer.prompt(titleQuestions); + + if (titleAnswer["title"]) { + title = titleAnswer["title"]; + } + } + + if (!title) { + errorLevel = ERROR_INIT_ERROR; + console.error("No title for your project was selected."); + return; + } + + let applyDescription = newDescription; + + if (applyDescription === undefined) { + applyDescription = title; + + const descriptionQuestions: inquirer.DistinctQuestion[] = []; + descriptionQuestions.push({ + type: "input", + name: "description", + default: applyDescription, + message: "What's your preferred project description?", + }); + + const descriptionAnswer = await inquirer.prompt(descriptionQuestions); + + if (descriptionAnswer["description"]) { + applyDescription = descriptionAnswer["description"]; + } + + if (applyDescription === undefined) { + applyDescription = title; + } + } + + if (!creator) { + const creatorQuestions: inquirer.DistinctQuestion[] = []; + creatorQuestions.push({ + type: "input", + name: "creator", + default: "Creator", + message: "What's your creator name?", + }); + const creatorAnswer = await inquirer.prompt(creatorQuestions); + + if (creatorAnswer["creator"]) { + creator = creatorAnswer["creator"]; + } + } + + const questions: inquirer.DistinctQuestion[] = []; + if (!newName) { + newName = title?.replace(/ /gi, "-").toLowerCase(); + + questions.push({ + type: "input", + name: "name", + default: newName, + message: "What's your preferred project short name? (<20 chars, no spaces)", + }); + } + + if (!options.inputFolder && (!options.outputFolder || options.outputFolder === "out") && isSingleFolder) { + const folderNameQuestions: inquirer.DistinctQuestion[] = []; + + folderNameQuestions.push({ + type: "input", + name: "folderName", + default: newName, + message: "What's your preferred folder name?", + }); + + const folderNameAnswer = await inquirer.prompt(folderNameQuestions); + + if (folderNameAnswer["folderName"]) { + const folderName = folderNameAnswer["folderName"]; + + if (folderName && project.mainDeployFolderPath) { + const path = + NodeStorage.ensureEndsWithDelimiter(process.cwd()) + NodeStorage.ensureEndsWithDelimiter(folderName); + + const outputStorage = new NodeStorage(path, ""); + const outFolder = outputStorage.rootFolder; + await outFolder.ensureExists(); + + project = new Project(carto, project.name, null); + + project.localFolderPath = path; + + project.autoDeploymentMode = ProjectAutoDeploymentMode.noAutoDeployment; + } + } + } + + const galProjects = carto.gallery.items; + let galProject: IGalleryItem | undefined; + + if (template) { + for (let i = 0; i < galProjects.length; i++) { + const galProjectCand = galProjects[i]; + if (galProjectCand && galProjectCand.id && galProjectCand.id.toLowerCase() === template.toLowerCase()) { + galProject = galProjectCand; + } + } + } + + if (!galProject) { + const projectTypeChoices: inquirer.DistinctChoice[] = []; + + for (let i = 0; i < galProjects.length; i++) { + const galProjectCand = galProjects[i]; + + if (galProjectCand.type === GalleryItemType.project) + projectTypeChoices.push({ + name: galProjectCand.id + ": " + galProjectCand.title, + value: i, + }); + } + + questions.push({ + type: "list", + name: "projectSource", + message: "What template should we use?", + choices: projectTypeChoices, + }); + } + + if (!galProject || !newName) { + const answers = await inquirer.prompt(questions); + + if (answers) { + if (answers["name"]) { + newName = answers["name"]; + } + + if (!galProject) { + galProject = galProjects[answers["projectSource"]]; + } + } + } + + if (!newName) { + errorLevel = ERROR_INIT_ERROR; + console.error("Not configured correctly to create a project."); + return; + } + + if (!galProject) { + errorLevel = ERROR_INIT_ERROR; + console.error("No project was selected."); + return; + } + + project = await ProjectExporter.syncProjectFromGitHub( + true, + carto, + galProject.gitHubRepoName, + galProject.gitHubOwner, + galProject.gitHubBranch, + galProject.gitHubFolder, + newName, + project, + galProject.fileList + ); + + let suggestedShortName: string | undefined = undefined; + + if (newName && creator) { + suggestedShortName = ProjectUtilities.getSuggestedProjectShortName(creator, newName); + } + + if (creator) { + await ProjectUtilities.applyCreator(project, creator); + } + + await ProjectUtilities.processNewProject(project, title, applyDescription, suggestedShortName); + + console.log( + "\nAll done! Now run \x1b[47m\x1b[30mnpm i\x1b[37m\x1b[40m in the \x1b[47m\x1b[30m" + + project.projectFolder?.fullPath + + "\x1b[37m\x1b[40m folder to install dependencies, if any, from npm." + ); +} + +async function add(project: Project) { + let typeDesc = "Item"; + if (type) { + switch (type) { + case "entity": + typeDesc = "Entity"; + break; + case "item": + typeDesc = "Item"; + break; + case "block": + typeDesc = "Block"; + break; + default: + console.log("Unknown item type '" + typeDesc + "' specified."); + type = undefined; + break; + } + } + outputLogo("Minecraft Add " + typeDesc); + + if (!carto) { + errorLevel = ERROR_INIT_ERROR; + console.error("Not configured correctly to add an item (no mctools core)."); + return; + } + + await carto.loadGallery(); + + if (!carto.gallery) { + errorLevel = ERROR_INIT_ERROR; + console.error("Not configured correctly to add an item (no gallery)."); + return; + } + + const typeQuestions: inquirer.DistinctQuestion[] = []; + const questions: inquirer.DistinctQuestion[] = []; + + const galProjects = carto.gallery.items; + let galProject: IGalleryItem | undefined; + + if (template) { + for (let i = 0; i < galProjects.length; i++) { + const galProjectCand = galProjects[i]; + if (galProjectCand && galProjectCand.id && galProjectCand.id.toLowerCase() === template.toLowerCase()) { + galProject = galProjectCand; + } + } + } + + if (type === undefined) { + typeQuestions.push({ + type: "list", + name: "type", + message: "What type of item should we add?", + choices: [ + { name: "Entity Type", value: "entity" }, + { name: "Block Type", value: "block" }, + { name: "Item Type", value: "item" }, + ], + }); + + const typeAnswers = await inquirer.prompt(typeQuestions); + + type = typeAnswers["type"]; + } + + if (type === "entity") { + const gallery = await carto.loadGallery(); + + if (gallery) { + const entityTypeChoices: inquirer.DistinctChoice[] = []; + + for (const proj of gallery.items) { + if (proj.type === GalleryItemType.entityType) { + entityTypeChoices.push({ + name: proj.id, + value: proj.title, + }); + } + } + + questions.push({ + type: "list", + name: "entityType", + message: "Based on which entity type?", + choices: entityTypeChoices, + }); + + if (!newName) { + questions.push({ + type: "input", + name: "name", + message: "What's your preferred new item name? (<20 chars, no spaces)", + }); + } + + const answers = await inquirer.prompt(questions); + + if (!newName) { + newName = answers["name"]; + } + + const entityType = answers["entityType"]; + + if (entityType) { + for (const proj of gallery.items) { + if (proj.id === entityType) { + await ProjectUtilities.addEntityTypeFromGallery(project, proj, newName, NewEntityTypeAddMode.baseId); + } + } + } + } else { + errorLevel = ERROR_INIT_ERROR; + console.error("Could not find any entity types."); + } + } else { + if (!galProject) { + const projectTypeChoices: inquirer.DistinctChoice[] = []; + + for (let i = 0; i < galProjects.length; i++) { + const galProjectCand = galProjects[i]; + + if (galProjectCand.type === GalleryItemType.chunk) { + projectTypeChoices.push({ + name: galProjectCand.id + ": " + galProjectCand.title, + value: i, + }); + } + } + + questions.push({ + type: "list", + name: "projectSource", + message: "What type of item should we add?", + choices: projectTypeChoices, + }); + } + + if (!newName) { + questions.push({ + type: "input", + name: "name", + message: "What's your preferred new item name? (<20 chars, no spaces)", + }); + } + + const answers = await inquirer.prompt(questions); + + if (!newName) { + newName = answers["name"]; + } + + if (!galProject) { + galProject = galProjects[answers["projectSource"]]; + } + + await project.ensureDefaultBehaviorPackFolder(); + + project = await ProjectExporter.syncProjectFromGitHub( + false, + carto, + galProject.gitHubRepoName, + galProject.gitHubOwner, + galProject.gitHubBranch, + galProject.gitHubFolder, + project.name, + project, + galProject.fileList + ); + } + + await project.save(); +} + +function outputLogo(message: string) { + console.log("\x1b[32m┌─────┐\x1b[0m"); + console.log("\x1b[32m│ ▄ ▄ │\x1b[0m " + message); + console.log("\x1b[32m│ ┏▀┓ │\x1b[0m"); + console.log("\x1b[32m└─────┘\x1b[0m"); + console.log(""); +} diff --git a/app/src/info/AddOnItemRequirementsGenerator.ts b/app/src/info/AddOnItemRequirementsGenerator.ts index f4bb1672..bbcdd5af 100644 --- a/app/src/info/AddOnItemRequirementsGenerator.ts +++ b/app/src/info/AddOnItemRequirementsGenerator.ts @@ -7,18 +7,18 @@ import IProjectInfoItemGenerator from "./IProjectItemInfoGenerator"; import ProjectInfoSet from "./ProjectInfoSet"; import { ProjectItemType } from "../app/IProjectItemData"; -import BehaviorAnimationController from "../minecraft/BehaviorAnimationController"; import { InfoItemType } from "./IInfoItemData"; import AddOnRequirementsGenerator from "./AddOnRequirementsGenerator"; -import BehaviorAnimation from "../minecraft/BehaviorAnimation"; -import ResourceAnimationController from "../minecraft/ResourceAnimationController"; -import ResourceAnimation from "../minecraft/ResourceAnimation"; import ResourceRenderController from "../minecraft/ResourceRenderController"; import ResourceManifestDefinition from "../minecraft/ResourceManifestDefinition"; import BehaviorManifestDefinition from "../minecraft/BehaviorManifestDefinition"; import ModelGeometryDefinition from "../minecraft/ModelGeometryDefinition"; import Material from "../minecraft/Material"; import ContentIndex from "../core/ContentIndex"; +import AnimationResourceDefinition from "../minecraft/AnimationResourceDefinition"; +import AnimationBehaviorDefinition from "../minecraft/AnimationBehaviorDefinition"; +import AnimationControllerBehaviorDefinition from "../minecraft/AnimationControllerBehaviorDefinition"; +import AnimationControllerResourceDefinition from "../minecraft/AnimationControllerResourceDefinition"; export default class AddOnItemRequirementsGenerator implements IProjectInfoItemGenerator { id = "ADDONIREQ"; @@ -124,10 +124,10 @@ export default class AddOnItemRequirementsGenerator implements IProjectInfoItemG await projectItem.ensureFileStorage(); if (projectItem.file) { - const bacManifest = await BehaviorAnimationController.ensureOnFile(projectItem.file); + const bacManifest = await AnimationControllerBehaviorDefinition.ensureOnFile(projectItem.file); - if (bacManifest && bacManifest.wrapper && bacManifest.wrapper.animation_controllers) { - for (let bacName in bacManifest.wrapper.animation_controllers) { + if (bacManifest && bacManifest.data && bacManifest.data.animation_controllers) { + for (let bacName in bacManifest.data.animation_controllers) { let bacNameBreak = bacName.split("."); if (bacNameBreak.length < 3 || bacNameBreak[0] !== "controller" || bacNameBreak[1] !== "animation") { @@ -160,10 +160,10 @@ export default class AddOnItemRequirementsGenerator implements IProjectInfoItemG await projectItem.ensureFileStorage(); if (projectItem.file) { - const baManifest = await BehaviorAnimation.ensureOnFile(projectItem.file); + const baManifest = await AnimationBehaviorDefinition.ensureOnFile(projectItem.file); - if (baManifest && baManifest.wrapper && baManifest.wrapper.animations) { - for (let aName in baManifest.wrapper.animations) { + if (baManifest && baManifest.data && baManifest.data.animations) { + for (let aName in baManifest.data.animations) { let baNameBreak = aName.split("."); if (baNameBreak.length < 2 || baNameBreak[0] !== "animation") { @@ -196,10 +196,10 @@ export default class AddOnItemRequirementsGenerator implements IProjectInfoItemG await projectItem.ensureFileStorage(); if (projectItem.file) { - const racManifest = await ResourceAnimationController.ensureOnFile(projectItem.file); + const racManifest = await AnimationControllerResourceDefinition.ensureOnFile(projectItem.file); - if (racManifest && racManifest.definition && racManifest.definition.animation_controllers) { - for (let racName in racManifest.definition.animation_controllers) { + if (racManifest && racManifest.data && racManifest.data.animation_controllers) { + for (let racName in racManifest.data.animation_controllers) { let racNameBreak = racName.split("."); if (racNameBreak.length < 3 || racNameBreak[0] !== "controller" || racNameBreak[1] !== "animation") { @@ -232,10 +232,10 @@ export default class AddOnItemRequirementsGenerator implements IProjectInfoItemG await projectItem.ensureFileStorage(); if (projectItem.file) { - const raManifest = await ResourceAnimation.ensureOnFile(projectItem.file); + const raManifest = await AnimationResourceDefinition.ensureOnFile(projectItem.file); - if (raManifest && raManifest.wrapper && raManifest.wrapper.animations) { - for (let aName in raManifest.wrapper.animations) { + if (raManifest && raManifest.animations) { + for (let aName in raManifest.animations) { let raNameBreak = aName.split("."); if (raNameBreak.length < 2 || raNameBreak[0] !== "animation") { diff --git a/app/src/info/AnimationResourceInfoGenerator.ts b/app/src/info/AnimationResourceInfoGenerator.ts new file mode 100644 index 00000000..7b7f0ae0 --- /dev/null +++ b/app/src/info/AnimationResourceInfoGenerator.ts @@ -0,0 +1,135 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import ProjectInfoItem from "./ProjectInfoItem"; +import { ProjectItemType } from "../app/IProjectItemData"; +import { InfoItemType } from "./IInfoItemData"; +import ProjectInfoSet from "./ProjectInfoSet"; +import IProjectInfoGenerator from "./IProjectInfoGenerator"; +import Project from "../app/Project"; +import ContentIndex from "../core/ContentIndex"; +import AnimationResourceDefinition from "../minecraft/AnimationResourceDefinition"; + +export default class AnimationResourceInfoGenerator implements IProjectInfoGenerator { + id = "RESOURCEANIMATION"; + title = "Resource Animation"; + + performAddOnValidations = false; + + getTopicData(topicId: number) { + switch (topicId) { + case 1: + return { title: "Animations" }; + + case 2: + return { title: "Bones" }; + + default: + return { title: topicId.toString() }; + } + } + + summarize(info: any, infoSet: ProjectInfoSet) { + info.animationCount = infoSet.getSummedNumberValue("RESOURCEANIMATION", 1); + } + + async generate(project: Project, contentIndex: ContentIndex): Promise { + const items: ProjectInfoItem[] = []; + + const animationCountPi = new ProjectInfoItem(InfoItemType.featureAggregate, this.id, 1, "Animations"); + items.push(animationCountPi); + + const boneCountPi = new ProjectInfoItem(InfoItemType.featureAggregate, this.id, 2, "Bones"); + items.push(boneCountPi); + + for (const projectItem of project.items) { + if (projectItem.itemType === ProjectItemType.animationResourceJson) { + await projectItem.ensureFileStorage(); + + if (projectItem.file) { + const ra = await AnimationResourceDefinition.ensureOnFile(projectItem.file); + + if (ra && ra.animations) { + for (const animationName in ra.animations) { + const animation = ra.animations[animationName]; + + animationCountPi.incrementFeature("Resource", "Count", 1); + + if (animation.bones) { + for (const boneName in animation.bones) { + const bone = animation.bones[boneName]; + + if (bone) { + boneCountPi.incrementFeature("Resource Animation Bone", "Count", 1); + + if (bone.position) { + this.processAnimationValue(boneCountPi, bone.position, "Position"); + } + + if (bone.rotation) { + this.processAnimationValue(boneCountPi, bone.rotation, "Rotation"); + } + + if (bone.scale) { + this.processAnimationValue(boneCountPi, bone.scale, "Scale"); + } + } + } + } + } + } + } + } + } + + return items; + } + + processAnimationValue(boneCountPi: ProjectInfoItem, value: any, type: string) { + let isKeyframedBoneAnimation = false; + + if (typeof value === "string") { + boneCountPi.incrementFeature("Resource Animation Bone " + type + " Expression", "Count", 1); + return; + } + + for (const key in value) { + const val = value[key]; + + if ((val as any).constructor === Array) { + isKeyframedBoneAnimation = true; + break; + } + } + + if (isKeyframedBoneAnimation) { + boneCountPi.incrementFeature("Resource Animation Bone " + type + " Keyframe", "Count", 1); + + for (const key in value) { + const val = value[key]; + + if ((val as any).constructor === Array) { + for (const valAtom of val) { + if (typeof valAtom === "string") { + boneCountPi.incrementFeature("Resource Animation Bone " + type + " Keyframe with Molang", "Count", 1); + } else { + boneCountPi.incrementFeature("Resource Animation Bone " + type + " Keyframe", "Count", 1); + } + } + } + } + } else { + boneCountPi.incrementFeature("Resource Animation Bone " + type + " Continuous", "Count", 1); + + if ((value as any).constructor === Array) { + for (const val of value) { + if (typeof val.position === "string") { + boneCountPi.incrementFeature("Resource Animation Bone " + type + " Continuous with Molang", "Count", 1); + } else { + boneCountPi.incrementFeature("Resource Animation Bone " + type + " Continuous", "Count", 1); + } + } + } + } + } +} diff --git a/app/src/info/GeneratorRegistrations.ts b/app/src/info/GeneratorRegistrations.ts index 4ac63f91..3718d337 100644 --- a/app/src/info/GeneratorRegistrations.ts +++ b/app/src/info/GeneratorRegistrations.ts @@ -30,6 +30,7 @@ import PackSizeInfoGenerator from "./PackSizeInfoGenerator"; import BehaviorPackItemTypeManager from "../manager/BehaviorPackItemTypeManager"; import TextureImageInfoGenerator from "./TextureImageInfoGenerator"; import FormatVersionManager from "../manager/FormatVersionManager"; +import AnimationResourceInfoGenerator from "./AnimationResourceInfoGenerator"; export default class GeneratorRegistrations { static projectGenerators = [ @@ -43,6 +44,7 @@ export default class GeneratorRegistrations { new MinEngineVersionManager(), new BaseGameVersionManager(), new FormatVersionManager(), + new AnimationResourceInfoGenerator(), new BehaviorPackEntityTypeManager(), new BehaviorPackItemTypeManager(), new AddOnRequirementsGenerator(), diff --git a/app/src/info/ProjectInfoSet.ts b/app/src/info/ProjectInfoSet.ts index 6c6cc731..f263a573 100644 --- a/app/src/info/ProjectInfoSet.ts +++ b/app/src/info/ProjectInfoSet.ts @@ -233,6 +233,7 @@ export default class ProjectInfoSet { } } catch (e: any) { genItems.push(new ProjectInfoItem(InfoItemType.internalProcessingError, gen.id, 500, e)); + Log.debugAlert(e); } } } diff --git a/app/src/info/TextureInfoGenerator.ts b/app/src/info/TextureInfoGenerator.ts index 8e7ee876..d204984d 100644 --- a/app/src/info/TextureInfoGenerator.ts +++ b/app/src/info/TextureInfoGenerator.ts @@ -315,17 +315,39 @@ export default class TextureInfoGenerator implements IProjectInfoGenerator { itemTextureVanillaPaths.push(itemTexture.textures); } } else if (itemTexture.textures) { - for (let str of itemTexture.textures) { - /*if (!allTexturesLeaf.includes(str)) { + if (typeof itemTexture.textures === "string") { + const matchesVanillaPath = await TextureInfoGenerator.matchesVanillaPath( + itemTexture.textures, + rpFolder + ); + + if (!matchesVanillaPath && !itemTexturePaths.includes(itemTexture.textures)) { + itemTexturePaths.push(itemTexture.textures); + } else if (matchesVanillaPath && !itemTextureVanillaPaths.includes(itemTexture.textures)) { + itemTextureVanillaPaths.push(itemTexture.textures); + } + } else if (itemTexture.textures.constructor === Array) { + for (let str of itemTexture.textures) { + /*if (!allTexturesLeaf.includes(str)) { allTexturesLeaf.push(str); }*/ - const matchesVanillaPath = await TextureInfoGenerator.matchesVanillaPath(str, rpFolder); + const matchesVanillaPath = await TextureInfoGenerator.matchesVanillaPath(str, rpFolder); - if (!matchesVanillaPath && !itemTexturePaths.includes(str)) { - itemTexturePaths.push(str); - } else if (matchesVanillaPath && !itemTextureVanillaPaths.includes(str)) { - itemTextureVanillaPaths.push(str); + if (!matchesVanillaPath && !itemTexturePaths.includes(str)) { + itemTexturePaths.push(str); + } else if (matchesVanillaPath && !itemTextureVanillaPaths.includes(str)) { + itemTextureVanillaPaths.push(str); + } + } + } else if ((itemTexture.textures as any).path) { + const texturePath = (itemTexture.textures as any).path; + const matchesVanillaPath = await TextureInfoGenerator.matchesVanillaPath(texturePath, rpFolder); + + if (!matchesVanillaPath && !itemTexturePaths.includes(texturePath)) { + itemTexturePaths.push(texturePath); + } else if (matchesVanillaPath && !itemTextureVanillaPaths.includes(texturePath)) { + itemTextureVanillaPaths.push(texturePath); } } } diff --git a/app/src/info/WorldDataInfoGenerator.ts b/app/src/info/WorldDataInfoGenerator.ts index 1a34c8bd..2ed1b7ad 100644 --- a/app/src/info/WorldDataInfoGenerator.ts +++ b/app/src/info/WorldDataInfoGenerator.ts @@ -13,12 +13,12 @@ import { StatusTopic } from "../app/Status"; import CommandStructure from "../app/CommandStructure"; import ProjectInfoSet from "./ProjectInfoSet"; import CommandRegistry from "../app/CommandRegistry"; -import BehaviorAnimationController from "../minecraft/BehaviorAnimationController"; -import BehaviorAnimation from "../minecraft/BehaviorAnimation"; import Dialogue from "../minecraft/Dialogue"; import ProjectItemUtilities from "../app/ProjectItemUtilities"; import ContentIndex, { AnnotationCategories } from "../core/ContentIndex"; import { NbtTagType } from "../minecraft/NbtBinaryTag"; +import AnimationControllerBehaviorDefinition from "../minecraft/AnimationControllerBehaviorDefinition"; +import AnimationBehaviorDefinition from "../minecraft/AnimationBehaviorDefinition"; export default class WorldDataInfoGenerator implements IProjectInfoItemGenerator { id = "WORLDDATA"; @@ -201,9 +201,9 @@ export default class WorldDataInfoGenerator implements IProjectInfoItemGenerator await projectItem.ensureFileStorage(); if (projectItem.file) { - const acManifest = await BehaviorAnimationController.ensureOnFile(projectItem.file); + const acManifest = await AnimationControllerBehaviorDefinition.ensureOnFile(projectItem.file); - if (acManifest && acManifest.wrapper && acManifest.wrapper.animation_controllers) { + if (acManifest && acManifest.data && acManifest.data.animation_controllers) { let states = acManifest.getAllStates(); for (const state of states) { @@ -221,9 +221,9 @@ export default class WorldDataInfoGenerator implements IProjectInfoItemGenerator await projectItem.ensureFileStorage(); if (projectItem.file) { - const animManifest = await BehaviorAnimation.ensureOnFile(projectItem.file); + const animManifest = await AnimationBehaviorDefinition.ensureOnFile(projectItem.file); - if (animManifest && animManifest.wrapper && animManifest.wrapper.animations) { + if (animManifest && animManifest.data && animManifest.data.animations) { let timelines = animManifest.getAllTimeline(); for (const timeline of timelines) { @@ -472,6 +472,8 @@ export default class WorldDataInfoGenerator implements IProjectInfoItemGenerator } } } + + chunk.clearCachedData(); } } } diff --git a/app/src/local/LocalTools.ts b/app/src/local/LocalTools.ts index e25f3225..676d437a 100644 --- a/app/src/local/LocalTools.ts +++ b/app/src/local/LocalTools.ts @@ -7,8 +7,8 @@ import Project from "../app/Project"; import IFolder from "../storage/IFolder"; import * as fs from "fs"; import * as open from "open"; -import ProjectTools from "../app/ProjectTools"; import IStorage from "../storage/IStorage"; +import IFile from "../storage/IFile"; export default class LocalTools { static async exportWorld(carto: Carto, project: Project, path: string) { @@ -27,6 +27,8 @@ export default class LocalTools { } } + static async convertFromJavaWorld(carto: Carto, javaWorldFile: IFile) {} + static async launchWorld(carto: Carto, worldFolderName: string) { const commandLine = "minecraft://mode/?load=" + worldFolderName; console.log("Running " + commandLine); @@ -44,7 +46,7 @@ export default class LocalTools { } static async deploy(carto: Carto, project: Project, storage: IStorage, rootFolder: IFolder, name: string) { - await ProjectTools.deployProject(carto, project, rootFolder); + await ProjectExporter.deployProject(carto, project, rootFolder); await rootFolder.saveAll(); } diff --git a/app/src/manager/BaseGameVersionManager.ts b/app/src/manager/BaseGameVersionManager.ts index 0ddbd59f..dc642aa1 100644 --- a/app/src/manager/BaseGameVersionManager.ts +++ b/app/src/manager/BaseGameVersionManager.ts @@ -11,7 +11,7 @@ import IProjectUpdater from "../updates/IProjectUpdater"; import ProjectUpdateResult from "../updates/ProjectUpdateResult"; import { UpdateResultType } from "../updates/IUpdateResult"; import { IProjectInfoTopicData } from "../info/IProjectInfoGeneratorBase"; -import WorldTemplateManifestJson from "../minecraft/WorldTemplateManifestJson"; +import WorldTemplateManifestDefinition from "../minecraft/WorldTemplateManifestDefinition"; import ProjectInfoSet from "../info/ProjectInfoSet"; import ContentIndex from "../core/ContentIndex"; @@ -131,7 +131,7 @@ export default class BaseGameVersionManager implements IProjectInfoGenerator, IP if (pi.file) { foundWorldTemplate = true; - const bpManifest = await WorldTemplateManifestJson.ensureOnFile(pi.file); + const bpManifest = await WorldTemplateManifestDefinition.ensureOnFile(pi.file); if (bpManifest) { if ( @@ -325,7 +325,7 @@ export default class BaseGameVersionManager implements IProjectInfoGenerator, IP await pi.ensureFileStorage(); if (pi.file) { - const wtManifest = await WorldTemplateManifestJson.ensureOnFile(pi.file); + const wtManifest = await WorldTemplateManifestDefinition.ensureOnFile(pi.file); if (wtManifest) { const mev = wtManifest.baseGameVersion; diff --git a/app/src/manager/FormatVersionManager.ts b/app/src/manager/FormatVersionManager.ts index 5459d43a..4203695e 100644 --- a/app/src/manager/FormatVersionManager.ts +++ b/app/src/manager/FormatVersionManager.ts @@ -11,7 +11,6 @@ import IProjectUpdater from "../updates/IProjectUpdater"; import ProjectUpdateResult from "../updates/ProjectUpdateResult"; import { UpdateResultType } from "../updates/IUpdateResult"; import { IProjectInfoTopicData, IProjectUpdaterReference } from "../info/IProjectInfoGeneratorBase"; -import WorldTemplateManifestJson from "../minecraft/WorldTemplateManifestJson"; import ProjectInfoSet from "../info/ProjectInfoSet"; import ContentIndex from "../core/ContentIndex"; import BlockTypeBehaviorDefinition from "../minecraft/BlockTypeBehaviorDefinition"; @@ -25,6 +24,7 @@ import AnimationResourceDefinition from "../minecraft/AnimationResourceDefinitio import AttachableResourceDefinition from "../minecraft/AttachableResourceDefinition"; import EntityTypeResourceDefinition from "../minecraft/EntityTypeResourceDefinition"; import FogResourceDefinition from "../minecraft/FogResourceDefinition"; +import WorldTemplateManifestDefinition from "../minecraft/WorldTemplateManifestDefinition"; export default class FormatVersionManager implements IProjectInfoGenerator, IProjectUpdater { id = "FORMATVER"; @@ -545,7 +545,7 @@ export default class FormatVersionManager implements IProjectInfoGenerator, IPro await pi.ensureFileStorage(); if (pi.file) { - const wtManifest = await WorldTemplateManifestJson.ensureOnFile(pi.file); + const wtManifest = await WorldTemplateManifestDefinition.ensureOnFile(pi.file); if (wtManifest) { const mev = wtManifest.baseGameVersion; diff --git a/app/src/minecraft/AnimationBehaviorDefinition.ts b/app/src/minecraft/AnimationBehaviorDefinition.ts index f4596518..8e97b62b 100644 --- a/app/src/minecraft/AnimationBehaviorDefinition.ts +++ b/app/src/minecraft/AnimationBehaviorDefinition.ts @@ -6,14 +6,14 @@ import { EventDispatcher, IEventHandler } from "ste-events"; import StorageUtilities from "../storage/StorageUtilities"; import Database from "./Database"; import MinecraftUtilities from "./MinecraftUtilities"; -import IAnimationBehavior from "./IAnimationBehavior"; +import IAnimationBehaviorWrapper, { IAnimationBehaviorTimelineWrapper } from "./IAnimationBehavior"; export default class AnimationBehaviorDefinition { private _file?: IFile; private _id?: string; private _isLoaded: boolean = false; - public data?: IAnimationBehavior; + public data?: IAnimationBehaviorWrapper; private _onLoaded = new EventDispatcher(); @@ -53,6 +53,31 @@ export default class AnimationBehaviorDefinition { return undefined; } + getAllTimeline() { + const timelines: IAnimationBehaviorTimelineWrapper[] = []; + + if (this.data && this.data.animations) { + for (const aName in this.data.animations) { + const anim = this.data.animations[aName]; + + if (anim && anim.timeline) { + for (const timestamp in anim.timeline) { + const timeline = anim.timeline[timestamp]; + if (timeline) { + timelines.push({ + animationId: aName, + timestamp: timestamp, + timeline: timeline, + }); + } + } + } + } + } + + return timelines; + } + public async getFormatVersionIsCurrent() { const fv = this.getFormatVersion(); @@ -81,7 +106,10 @@ export default class AnimationBehaviorDefinition { _ensureDataInitialized() { if (this.data === undefined) { - this.data = {}; + this.data = { + format_version: "1.12.0", + animations: {}, + }; } } diff --git a/app/src/minecraft/AnimationControllerBehaviorDefinition.ts b/app/src/minecraft/AnimationControllerBehaviorDefinition.ts index f455c046..e88da99c 100644 --- a/app/src/minecraft/AnimationControllerBehaviorDefinition.ts +++ b/app/src/minecraft/AnimationControllerBehaviorDefinition.ts @@ -6,14 +6,16 @@ import { EventDispatcher, IEventHandler } from "ste-events"; import StorageUtilities from "../storage/StorageUtilities"; import Database from "./Database"; import MinecraftUtilities from "./MinecraftUtilities"; -import IAnimationControllerBehavior from "./IAnimationControllerBehavior"; +import IAnimationControllerBehaviorWrapper, { + IAnimationControllerBehaviorStateWrapper, +} from "./IAnimationControllerBehavior"; export default class AnimationControllerBehaviorDefinition { private _file?: IFile; private _id?: string; private _isLoaded: boolean = false; - public data?: IAnimationControllerBehavior; + public data?: IAnimationControllerBehaviorWrapper; private _onLoaded = new EventDispatcher< AnimationControllerBehaviorDefinition, @@ -66,6 +68,31 @@ export default class AnimationControllerBehaviorDefinition { return await Database.isRecentVersionFromVersionArray(fv); } + getAllStates() { + const states: IAnimationControllerBehaviorStateWrapper[] = []; + + if (this.data && this.data.animation_controllers) { + for (const acName in this.data.animation_controllers) { + const ac = this.data.animation_controllers[acName]; + + if (ac && ac.states) { + for (const stateName in ac.states) { + const state = ac.states[stateName]; + + if (state) { + states.push({ + id: stateName, + animationControllerId: acName, + state: state, + }); + } + } + } + } + } + + return states; + } public getFormatVersion(): number[] | undefined { if (!this.data || !this.data.format_version) { return undefined; @@ -84,7 +111,10 @@ export default class AnimationControllerBehaviorDefinition { _ensureDataInitialized() { if (this.data === undefined) { - this.data = {}; + this.data = { + format_version: "1.12.0", + animation_controllers: {}, + }; } } diff --git a/app/src/minecraft/AnimationControllerResourceDefinition.ts b/app/src/minecraft/AnimationControllerResourceDefinition.ts index 8157e423..d69de4b5 100644 --- a/app/src/minecraft/AnimationControllerResourceDefinition.ts +++ b/app/src/minecraft/AnimationControllerResourceDefinition.ts @@ -6,14 +6,14 @@ import { EventDispatcher, IEventHandler } from "ste-events"; import StorageUtilities from "../storage/StorageUtilities"; import Database from "./Database"; import MinecraftUtilities from "./MinecraftUtilities"; -import IAnimationControllerResource from "./IAnimationControllerResource"; +import IResourceAnimationControllerDefinition from "./IAnimationControllerResource"; export default class AnimationControllerResourceDefinition { private _file?: IFile; private _id?: string; private _isLoaded: boolean = false; - public data?: IAnimationControllerResource; + public data?: IResourceAnimationControllerDefinition; private _onLoaded = new EventDispatcher< AnimationControllerResourceDefinition, @@ -84,7 +84,10 @@ export default class AnimationControllerResourceDefinition { _ensureDataInitialized() { if (this.data === undefined) { - this.data = {}; + this.data = { + format_version: "1.12.0", + animation_controllers: {}, + }; } } diff --git a/app/src/minecraft/AnimationResourceDefinition.ts b/app/src/minecraft/AnimationResourceDefinition.ts index 0d71ba31..9625dba7 100644 --- a/app/src/minecraft/AnimationResourceDefinition.ts +++ b/app/src/minecraft/AnimationResourceDefinition.ts @@ -6,14 +6,14 @@ import { EventDispatcher, IEventHandler } from "ste-events"; import StorageUtilities from "../storage/StorageUtilities"; import Database from "./Database"; import MinecraftUtilities from "./MinecraftUtilities"; -import IAnimationResource from "./IAnimationResource"; +import IResourceAnimationWrapper from "./IAnimationResource"; export default class AnimationResourceDefinition { private _file?: IFile; private _id?: string; private _isLoaded: boolean = false; - public data?: IAnimationResource; + public data?: IResourceAnimationWrapper; private _onLoaded = new EventDispatcher(); @@ -53,6 +53,13 @@ export default class AnimationResourceDefinition { return undefined; } + public get animations() { + if (this.data && this.data.animations) { + return this.data.animations; + } + + return undefined; + } public async getFormatVersionIsCurrent() { const fv = this.getFormatVersion(); @@ -81,7 +88,10 @@ export default class AnimationResourceDefinition { _ensureDataInitialized() { if (this.data === undefined) { - this.data = {}; + this.data = { + format_version: "1.12.0", + animations: {}, + }; } } diff --git a/app/src/minecraft/BehaviorAnimation.ts b/app/src/minecraft/BehaviorAnimation.ts deleted file mode 100644 index 42fd1b5a..00000000 --- a/app/src/minecraft/BehaviorAnimation.ts +++ /dev/null @@ -1,146 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -import IFile from "../storage/IFile"; -import { EventDispatcher, IEventHandler } from "ste-events"; -import StorageUtilities from "../storage/StorageUtilities"; -import IBehaviorAnimationWrapper, { IBehaviorAnimationTimelineWrapper } from "./IBehaviorAnimation"; -import MinecraftUtilities from "./MinecraftUtilities"; - -export default class BehaviorAnimation { - private _file?: IFile; - private _id?: string; - private _isLoaded: boolean = false; - - public wrapper?: IBehaviorAnimationWrapper; - - private _onLoaded = new EventDispatcher(); - - public get isLoaded() { - return this._isLoaded; - } - - public get file() { - return this._file; - } - - public set file(newFile: IFile | undefined) { - this._file = newFile; - } - - public get onLoaded() { - return this._onLoaded.asEvent(); - } - - public async getFormatVersionIsCurrent() { - const fv = this.getFormatVersion(); - - if (fv === undefined || fv.length !== 3) { - return false; - } - - return fv[0] > 1 || fv[1] >= 10; - } - - public getFormatVersion(): number[] | undefined { - if (!this.wrapper) { - return undefined; - } - - return MinecraftUtilities.getVersionArrayFrom(this.wrapper.format_version); - } - - static async ensureOnFile(file: IFile, loadHandler?: IEventHandler) { - let ac: BehaviorAnimation | undefined; - - if (file.manager === undefined) { - ac = new BehaviorAnimation(); - - ac.file = file; - - file.manager = ac; - } - - if (file.manager !== undefined && file.manager instanceof BehaviorAnimation) { - ac = file.manager as BehaviorAnimation; - - if (!ac.isLoaded && loadHandler) { - ac.onLoaded.subscribe(loadHandler); - } - - await ac.load(); - } - - return ac; - } - - getAllTimeline() { - const timelines: IBehaviorAnimationTimelineWrapper[] = []; - - if (this.wrapper && this.wrapper.animations) { - for (const aName in this.wrapper.animations) { - const anim = this.wrapper.animations[aName]; - - if (anim && anim.timeline) { - for (const timestamp in anim.timeline) { - const timeline = anim.timeline[timestamp]; - if (timeline) { - timelines.push({ - animationId: aName, - timestamp: timestamp, - timeline: timeline, - }); - } - } - } - } - } - - return timelines; - } - - persist() { - if (this._file === undefined) { - return; - } - - const pjString = JSON.stringify(this.wrapper, null, 2); - - this._file.setContent(pjString); - } - - public ensureDefinition(name: string, description: string) { - if (!this.wrapper) { - this.wrapper = { - format_version: "1.12.0", - animations: {}, - }; - } - } - - async save() { - if (this._file === undefined) { - return; - } - - this.persist(); - - await this._file.saveContent(false); - } - - async load() { - if (this._file === undefined || this._isLoaded) { - return; - } - - await this._file.loadContent(); - - if (this._file.content === null || this._file.content instanceof Uint8Array) { - return; - } - - this.wrapper = StorageUtilities.getJsonObject(this._file); - - this._isLoaded = true; - } -} diff --git a/app/src/minecraft/BehaviorAnimationController.ts b/app/src/minecraft/BehaviorAnimationController.ts deleted file mode 100644 index bade2946..00000000 --- a/app/src/minecraft/BehaviorAnimationController.ts +++ /dev/null @@ -1,152 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -import IFile from "../storage/IFile"; -import { EventDispatcher, IEventHandler } from "ste-events"; -import StorageUtilities from "../storage/StorageUtilities"; -import IBehaviorAnimationControllerWrapper, { - IBehaviorAnimationControllerStateWrapper, -} from "./IBehaviorAnimationController"; -import MinecraftUtilities from "./MinecraftUtilities"; - -export default class BehaviorAnimationController { - private _file?: IFile; - private _id?: string; - private _isLoaded: boolean = false; - - public wrapper?: IBehaviorAnimationControllerWrapper; - - private _onLoaded = new EventDispatcher(); - - public get isLoaded() { - return this._isLoaded; - } - - public get file() { - return this._file; - } - - public set file(newFile: IFile | undefined) { - this._file = newFile; - } - - public get onLoaded() { - return this._onLoaded.asEvent(); - } - - public async getFormatVersionIsCurrent() { - const fv = this.getFormatVersion(); - - if (fv === undefined || fv.length !== 3) { - return false; - } - - return fv[0] > 1 || fv[1] >= 10; - } - - public getFormatVersion(): number[] | undefined { - if (!this.wrapper) { - return undefined; - } - - return MinecraftUtilities.getVersionArrayFrom(this.wrapper.format_version); - } - - static async ensureOnFile( - file: IFile, - loadHandler?: IEventHandler - ) { - let ac: BehaviorAnimationController | undefined; - - if (file.manager === undefined) { - ac = new BehaviorAnimationController(); - - ac.file = file; - - file.manager = ac; - } - - if (file.manager !== undefined && file.manager instanceof BehaviorAnimationController) { - ac = file.manager as BehaviorAnimationController; - - if (!ac.isLoaded && loadHandler) { - ac.onLoaded.subscribe(loadHandler); - } - - await ac.load(); - } - - return ac; - } - - getAllStates() { - const states: IBehaviorAnimationControllerStateWrapper[] = []; - - if (this.wrapper && this.wrapper.animation_controllers) { - for (const acName in this.wrapper.animation_controllers) { - const ac = this.wrapper.animation_controllers[acName]; - - if (ac && ac.states) { - for (const stateName in ac.states) { - const state = ac.states[stateName]; - - if (state) { - states.push({ - id: stateName, - animationControllerId: acName, - state: state, - }); - } - } - } - } - } - - return states; - } - - persist() { - if (this._file === undefined) { - return; - } - - const pjString = JSON.stringify(this.wrapper, null, 2); - - this._file.setContent(pjString); - } - - public ensureDefinition(name: string, description: string) { - if (!this.wrapper) { - this.wrapper = { - format_version: "1.12.0", - animation_controllers: {}, - }; - } - } - - async save() { - if (this._file === undefined) { - return; - } - - this.persist(); - - await this._file.saveContent(false); - } - - async load() { - if (this._file === undefined || this._isLoaded) { - return; - } - - await this._file.loadContent(); - - if (this._file.content === null || this._file.content instanceof Uint8Array) { - return; - } - - this.wrapper = StorageUtilities.getJsonObject(this._file); - - this._isLoaded = true; - } -} diff --git a/app/src/minecraft/Database.ts b/app/src/minecraft/Database.ts index f1314399..bef8c2be 100644 --- a/app/src/minecraft/Database.ts +++ b/app/src/minecraft/Database.ts @@ -21,12 +21,15 @@ import IMainInfoVersions from "./IMainInfoVersions"; import IFormDefinition from "../dataform/IFormDefinition"; import ContentIndex from "../core/ContentIndex"; import IProjectInfoData from "../info/IProjectInfoData"; +import Project from "../app/Project"; +import { ProjectItemCreationType, ProjectItemStorageType, ProjectItemType } from "../app/IProjectItemData"; export default class Database { static isLoaded = false; static isScriptTypesLoaded = false; static catalog: Catalog | null = null; static loadedFormCount = 0; + static _creatorToolsIngameProject: Project | null = null; static uxCatalog: { [formName: string]: IFormDefinition } = {}; static betaTypeDefs: ITypeDefCatalog | null = null; static libs: ITypeDefCatalog | null = null; @@ -186,6 +189,56 @@ export default class Database { return true; } + static async ensureCreatorToolsIngameProject() { + if (Database._creatorToolsIngameProject) { + return Database._creatorToolsIngameProject; + } + + await Database.loadContent(); + + if (Database.contentFolder === null || !CartoApp.carto) { + Log.unexpectedContentState(); + return undefined; + } + + const file = Database.contentFolder.ensureFile("creator_tools_ingame.mcaddon"); + + await file.loadContent(); + + if (file.content instanceof Uint8Array) { + Database._creatorToolsIngameProject = new Project(CartoApp.carto, "Creator Tools", null); + + const projectFolder = await Database._creatorToolsIngameProject.ensureProjectFolder(); + + const folder = projectFolder.ensureFolder("addons"); + + const contentFile = folder.ensureFile(file.name); + + contentFile.setContent(file.content); + + contentFile.saveContent(); + + const relPath = contentFile.getFolderRelativePath(Database._creatorToolsIngameProject.projectFolder as IFolder); + + if (relPath !== undefined) { + Database._creatorToolsIngameProject.ensureItemByProjectPath( + relPath, + ProjectItemStorageType.singleFile, + file.name, + ProjectItemType.MCAddon, + undefined, + ProjectItemCreationType.normal + ); + + await Database._creatorToolsIngameProject.inferProjectItemsFromZipFile(relPath, contentFile, false); + } + + return Database._creatorToolsIngameProject; + } + + return undefined; + } + static async getLatestVersionInfo(preview: boolean, force?: boolean) { if (preview && Database.latestPreviewVersion && !force) { return Database.latestPreviewVersion; diff --git a/app/src/minecraft/IAnimationBehavior.ts b/app/src/minecraft/IAnimationBehavior.ts index 34f68896..dc251c70 100644 --- a/app/src/minecraft/IAnimationBehavior.ts +++ b/app/src/minecraft/IAnimationBehavior.ts @@ -1,6 +1,28 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -export default interface IAnimationBehavior { - format_version?: string; +export default interface IAnimationBehaviorWrapper { + format_version: string; + __comment__?: string; + animations: IAnimationBehaviorSet; +} + +export interface IAnimationBehaviorSet { + [identifier: string]: IAnimationBehavior; +} + +export interface IAnimationBehavior { + animation_length: number; + loop?: boolean; + timeline?: IAnimationBehaviorTimeline; +} + +export interface IAnimationBehaviorTimeline { + [timeStamp: string]: string[]; +} + +export interface IAnimationBehaviorTimelineWrapper { + animationId: string; + timestamp: string; + timeline: string[]; } diff --git a/app/src/minecraft/IAnimationControllerBehavior.ts b/app/src/minecraft/IAnimationControllerBehavior.ts index bf4347c5..36122240 100644 --- a/app/src/minecraft/IAnimationControllerBehavior.ts +++ b/app/src/minecraft/IAnimationControllerBehavior.ts @@ -1,6 +1,42 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -export default interface IAnimationControllerBehavior { - format_version?: string; +export default interface IAnimationControllerBehaviorWrapper { + format_version: string; + __comment__?: string; + animation_controllers: IAnimationControllerBehaviorSet; +} + +export interface IAnimationControllerBehaviorSet { + [identifier: string]: IAnimationControllerBehavior; +} + +export interface IAnimationControllerBehavior { + initial_state: string; + states: IAnimationControllerBehaviorStateSet; +} + +export interface IAnimationControllerBehaviorStateSet { + [identifier: string]: IAnimationControllerBehaviorState; +} + +export interface IAnimationControllerBehaviorState { + animations: string[]; + transitions: IAnimationControllerBehaviorStateTransitionSet[]; + on_entry?: string[]; + on_exit?: string[]; +} + +export interface IAnimationControllerBehaviorStateWrapper { + id: string; + animationControllerId: string; + state: IAnimationControllerBehaviorState; +} + +export interface IAnimationControllerBehaviorStateTransitionSet { + [identifier: string]: IAnimationControllerBehaviorStateTransition; +} + +export interface IAnimationControllerBehaviorStateTransition { + [identifier: string]: string; } diff --git a/app/src/minecraft/IAnimationControllerResource.ts b/app/src/minecraft/IAnimationControllerResource.ts index bf1a2958..3d4ab9ae 100644 --- a/app/src/minecraft/IAnimationControllerResource.ts +++ b/app/src/minecraft/IAnimationControllerResource.ts @@ -1,6 +1,35 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -export default interface IAnimationControllerResource { - format_version?: string; +export default interface IAnimationControllerResourceDefinition { + format_version: string; + __comment__?: string; + animation_controllers: IAnimationControllerResourceSet; +} + +export interface IAnimationControllerResourceSet { + [identifier: string]: IAnimationControllerResource; +} + +export interface IAnimationControllerResource { + initial_state: string; + states: IAnimationControllerResourceStateSet; +} + +export interface IAnimationControllerResourceStateSet { + [identifier: string]: IAnimationControllerResourceState; +} + +export interface IAnimationControllerResourceState { + animations: string[]; + transitions: IAnimationControllerResourceStateTransitionSet[]; + blend_transition: number; +} + +export interface IAnimationControllerResourceStateTransitionSet { + [identifier: string]: IAnimationControllerResourceStateTransition; +} + +export interface IAnimationControllerResourceStateTransition { + [identifier: string]: string; } diff --git a/app/src/minecraft/IAnimationResource.ts b/app/src/minecraft/IAnimationResource.ts index d9dbae8f..edcb59c8 100644 --- a/app/src/minecraft/IAnimationResource.ts +++ b/app/src/minecraft/IAnimationResource.ts @@ -1,6 +1,27 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -export default interface IAnimationResource { - format_version?: string; +export default interface IAnimationResourceWrapper { + format_version: string; + __comment__?: string; + animations: IAnimationResourceSet; +} + +export interface IAnimationResourceSet { + [identifier: string]: IAnimationResource; +} + +export interface IAnimationResource { + animation_length: number; + bones: IAnimationResourceBoneSet; +} + +export interface IAnimationResourceBoneSet { + [identifier: string]: IAnimationResourceBone; +} + +export interface IAnimationResourceBone { + rotation: number[] | string; + position: number[] | string; + scale: number[] | string; } diff --git a/app/src/minecraft/IBehaviorAnimation.ts b/app/src/minecraft/IBehaviorAnimation.ts deleted file mode 100644 index e3d5565b..00000000 --- a/app/src/minecraft/IBehaviorAnimation.ts +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -export default interface IBehaviorAnimationWrapper { - format_version: string; - __comment__?: string; - animations: IBehaviorAnimationSet; -} - -export interface IBehaviorAnimationSet { - [identifier: string]: IBehaviorAnimation; -} - -export interface IBehaviorAnimation { - animation_length: number; - loop?: boolean; - timeline?: IBehaviorAnimationTimeline; -} - -export interface IBehaviorAnimationTimeline { - [timeStamp: string]: string[]; -} - -export interface IBehaviorAnimationTimelineWrapper { - animationId: string; - timestamp: string; - timeline: string[]; -} diff --git a/app/src/minecraft/IBehaviorAnimationController.ts b/app/src/minecraft/IBehaviorAnimationController.ts deleted file mode 100644 index bee0a57b..00000000 --- a/app/src/minecraft/IBehaviorAnimationController.ts +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -export default interface IBehaviorAnimationControllerWrapper { - format_version: string; - __comment__?: string; - animation_controllers: IBehaviorAnimationControllerSet; -} - -export interface IBehaviorAnimationControllerSet { - [identifier: string]: IBehaviorAnimationController; -} - -export interface IBehaviorAnimationController { - initial_state: string; - states: IBehaviorAnimationControllerStateSet; -} - -export interface IBehaviorAnimationControllerStateSet { - [identifier: string]: IBehaviorAnimationControllerState; -} - -export interface IBehaviorAnimationControllerState { - animations: string[]; - transitions: IBehaviorAnimationControllerStateTransitionSet[]; - on_entry?: string[]; - on_exit?: string[]; -} - -export interface IBehaviorAnimationControllerStateWrapper { - id: string; - animationControllerId: string; - state: IBehaviorAnimationControllerState; -} - -export interface IBehaviorAnimationControllerStateTransitionSet { - [identifier: string]: IBehaviorAnimationControllerStateTransition; -} - -export interface IBehaviorAnimationControllerStateTransition { - [identifier: string]: string; -} diff --git a/app/src/minecraft/IResourceAnimation.ts b/app/src/minecraft/IResourceAnimation.ts deleted file mode 100644 index 735c65df..00000000 --- a/app/src/minecraft/IResourceAnimation.ts +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -export default interface IResourceAnimationWrapper { - format_version: string; - __comment__?: string; - animations: IResourceAnimationSet; -} - -export interface IResourceAnimationSet { - [identifier: string]: IResourceAnimation; -} - -export interface IResourceAnimation { - animation_length: number; - bones: IResourceAnimationBoneSet; -} - -export interface IResourceAnimationBoneSet { - [identifier: string]: IResourceAnimationBone; -} - -export interface IResourceAnimationBone { - rotation: number[]; - position: number[]; -} diff --git a/app/src/minecraft/IResourceAnimationController.ts b/app/src/minecraft/IResourceAnimationController.ts deleted file mode 100644 index 43df6e65..00000000 --- a/app/src/minecraft/IResourceAnimationController.ts +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -export default interface IResourceAnimationControllerDefinition { - format_version: string; - __comment__?: string; - animation_controllers: IResourceAnimationControllerSet; -} - -export interface IResourceAnimationControllerSet { - [identifier: string]: IResourceAnimationController; -} - -export interface IResourceAnimationController { - initial_state: string; - states: IResourceAnimationControllerStateSet; -} - -export interface IResourceAnimationControllerStateSet { - [identifier: string]: IResourceAnimationControllerState; -} - -export interface IResourceAnimationControllerState { - animations: string[]; - transitions: IResourceAnimationControllerStateTransitionSet[]; - blend_transition: number; -} - -export interface IResourceAnimationControllerStateTransitionSet { - [identifier: string]: IResourceAnimationControllerStateTransition; -} - -export interface IResourceAnimationControllerStateTransition { - [identifier: string]: string; -} diff --git a/app/src/minecraft/IWorldManifest.ts b/app/src/minecraft/IWorldManifest.ts index 82d62eac..de35f4a3 100644 --- a/app/src/minecraft/IWorldManifest.ts +++ b/app/src/minecraft/IWorldManifest.ts @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +// supports both world and world template manifests. + export default interface IWorldManifest { format_version: number; __comment__?: string; @@ -11,9 +13,9 @@ export default interface IWorldManifest { export interface IWorldManifestHeader { base_game_version: number[]; description: string; - lock_template_options: boolean; + lock_template_options?: boolean; name: string; - platform_locked: boolean; + platform_locked?: boolean; uuid: string; version: number[]; } diff --git a/app/src/minecraft/IWorldTemplateManifest.ts b/app/src/minecraft/IWorldTemplateManifest.ts deleted file mode 100644 index f27920bd..00000000 --- a/app/src/minecraft/IWorldTemplateManifest.ts +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -export default interface IWorldTemplateManifest { - __comment__?: string; - format_version?: number; - header: IWorldTemplateManifestHeader; - modules: IWorldTemplateModule[]; -} - -export interface IWorldTemplateManifestHeader { - description: string; - name: string; - uuid: string; - lock_template_options?: boolean; - version: number[]; - base_game_version: number[]; -} - -export interface IWorldTemplateModule { - description?: string; - type: string; - language?: string; - uuid: string; - version: number[]; - entry?: string; -} diff --git a/app/src/minecraft/MCWorld.ts b/app/src/minecraft/MCWorld.ts index 709b7fb9..e7231742 100644 --- a/app/src/minecraft/MCWorld.ts +++ b/app/src/minecraft/MCWorld.ts @@ -28,7 +28,7 @@ import NbtBinary from "./NbtBinary"; import { NbtTagType } from "./NbtBinaryTag"; import AnchorSet from "./AnchorSet"; import Project from "../app/Project"; -import { ProjectItemStorageType, ProjectItemType } from "../app/IProjectItemData"; +import { ProjectItemCreationType, ProjectItemStorageType, ProjectItemType } from "../app/IProjectItemData"; import ActorItem from "./ActorItem"; import { StatusTopic } from "../app/Status"; import { IErrorMessage, IErrorable } from "../core/IErrorable"; @@ -1388,9 +1388,9 @@ export default class MCWorld implements IGetSetPropertyObject, IDimension, IErro this.levelDb = new LevelDb(ldbFileArr, logFileArr, manifestFileArr, this.name); - await this.levelDb.init(/*async (message: string): Promise => { + await this.levelDb.init(async (message: string): Promise => { await this._project?.carto.notifyStatusUpdate(message, StatusTopic.worldLoad); - }*/); + }); Utilities.appendErrors(this, this.levelDb); @@ -1591,7 +1591,11 @@ export default class MCWorld implements IGetSetPropertyObject, IDimension, IErro const z = DataUtilities.getSignedInteger(keyBytes[8], keyBytes[9], keyBytes[10], keyBytes[11], true); Log.assert( - keyBytes.length === 16 || keyBytes.length === 24 || keyBytes.length === 20 || keyBytes.length === 12, + keyBytes.length === 16 || + keyBytes.length === 24 || + keyBytes.length === 20 || + keyBytes.length === 13 || + keyBytes.length === 12, "Unexpected digp key size (" + keyBytes.length + ")" ); @@ -1869,9 +1873,9 @@ export default class MCWorld implements IGetSetPropertyObject, IDimension, IErro const scriptFolder = await this._project.ensureDefaultScriptsFolder(); - const genFolder = scriptFolder.ensureFolder("generated"); - if (scriptFolder) { + const genFolder = scriptFolder.ensureFolder("generated"); + this._autogenJsFile = genFolder.ensureFile(newFileName); this._project.ensureItemByProjectPath( @@ -1880,7 +1884,7 @@ export default class MCWorld implements IGetSetPropertyObject, IDimension, IErro this._autogenJsFile.name, ProjectItemType.js, undefined, - true + ProjectItemCreationType.generated ); } } @@ -1896,7 +1900,7 @@ export default class MCWorld implements IGetSetPropertyObject, IDimension, IErro private getAutoGenScript() { const content: string[] = []; - content.push("export const " + this.name + " = {"); + content.push("export const " + MinecraftUtilities.makeNameScriptSafe(this.name) + " = {"); if (this.anchors) { const anchorKeys = this.anchors.getKeys(); @@ -1907,7 +1911,7 @@ export default class MCWorld implements IGetSetPropertyObject, IDimension, IErro if (anchor) { content.push( " " + - anchor.name + + MinecraftUtilities.makeNameScriptSafe(anchor.name) + ": { from: { x: " + anchor.from.x + ", y: " + diff --git a/app/src/minecraft/MinecraftDefinitions.ts b/app/src/minecraft/MinecraftDefinitions.ts index 0e30a27e..cef5c7c4 100644 --- a/app/src/minecraft/MinecraftDefinitions.ts +++ b/app/src/minecraft/MinecraftDefinitions.ts @@ -1,14 +1,14 @@ import { ProjectItemType } from "../app/IProjectItemData"; import ProjectItem from "../app/ProjectItem"; -import BehaviorAnimation from "./BehaviorAnimation"; -import BehaviorAnimationController from "./BehaviorAnimationController"; +import AnimationBehaviorDefinition from "./AnimationBehaviorDefinition"; +import AnimationControllerBehaviorDefinition from "./AnimationControllerBehaviorDefinition"; +import AnimationControllerResourceDefinition from "./AnimationControllerResourceDefinition"; +import AnimationResourceDefinition from "./AnimationResourceDefinition"; import BehaviorManifestDefinition from "./BehaviorManifestDefinition"; import BlockTypeBehaviorDefinition from "./BlockTypeBehaviorDefinition"; import EntityTypeDefinition from "./EntityTypeDefinition"; import FlipbookTextureCatalogDefinition from "./FlipbookTextureCatalogDefinition"; import ItemTypeBehaviorDefinition from "./ItemTypeBehaviorDefinition"; -import ResourceAnimation from "./ResourceAnimation"; -import ResourceAnimationController from "./ResourceAnimationController"; import ResourceManifestDefinition from "./ResourceManifestDefinition"; export default class MinecraftDefinitions { @@ -31,13 +31,13 @@ export default class MinecraftDefinitions { case ProjectItemType.resourcePackManifestJson: return await ResourceManifestDefinition.ensureOnFile(projectItem.file); case ProjectItemType.animationControllerBehaviorJson: - return await BehaviorAnimationController.ensureOnFile(projectItem.file); + return await AnimationControllerBehaviorDefinition.ensureOnFile(projectItem.file); case ProjectItemType.animationControllerResourceJson: - return await ResourceAnimationController.ensureOnFile(projectItem.file); + return await AnimationControllerResourceDefinition.ensureOnFile(projectItem.file); case ProjectItemType.animationBehaviorJson: - return await BehaviorAnimation.ensureOnFile(projectItem.file); + return await AnimationBehaviorDefinition.ensureOnFile(projectItem.file); case ProjectItemType.animationResourceJson: - return await ResourceAnimation.ensureOnFile(projectItem.file); + return await AnimationResourceDefinition.ensureOnFile(projectItem.file); } return undefined; diff --git a/app/src/minecraft/MinecraftUtilities.ts b/app/src/minecraft/MinecraftUtilities.ts index ac636ab6..c28beadb 100644 --- a/app/src/minecraft/MinecraftUtilities.ts +++ b/app/src/minecraft/MinecraftUtilities.ts @@ -20,6 +20,20 @@ export default class MinecraftUtilities { return path; } + static makeNameScriptSafe(tokenName: string) { + tokenName = tokenName.replace(/[^a-z0-9]/gi, "-").replace(/\s+/g, "-"); + + while (tokenName.length > 1 && !Utilities.isAlpha(tokenName.substring(0, 1))) { + tokenName = tokenName.substring(1); + } + + if (!Utilities.isAlpha(tokenName.substring(0, 1))) { + tokenName = "a" + tokenName; + } + + return tokenName; + } + static makeNameFolderSafe(tokenName: string) { tokenName = Utilities.replaceAll(tokenName, " ", "-").toLowerCase(); diff --git a/app/src/minecraft/NbtBinary.ts b/app/src/minecraft/NbtBinary.ts index 89d23318..88fecbec 100644 --- a/app/src/minecraft/NbtBinary.ts +++ b/app/src/minecraft/NbtBinary.ts @@ -18,8 +18,12 @@ export default class NbtBinary implements IErrorable { return null; } + if (this.roots.length === 0) { + return null; + } + if (this.roots.length !== 1) { - throw new Error("Unexpectedly did not find a single root."); + this._pushError("Unexpectedly did not find a single root (" + this.roots.length + ")"); } return this.roots[0]; diff --git a/app/src/minecraft/ResourceAnimation.ts b/app/src/minecraft/ResourceAnimation.ts deleted file mode 100644 index 7071dc19..00000000 --- a/app/src/minecraft/ResourceAnimation.ts +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -import IFile from "../storage/IFile"; -import { EventDispatcher, IEventHandler } from "ste-events"; -import StorageUtilities from "../storage/StorageUtilities"; -import IResourceAnimationWrapper from "./IResourceAnimation"; -import MinecraftUtilities from "./MinecraftUtilities"; - -export default class ResourceAnimation { - private _file?: IFile; - private _isLoaded: boolean = false; - - public wrapper?: IResourceAnimationWrapper; - - private _onLoaded = new EventDispatcher(); - - public get isLoaded() { - return this._isLoaded; - } - - public get file() { - return this._file; - } - - public set file(newFile: IFile | undefined) { - this._file = newFile; - } - - public get onLoaded() { - return this._onLoaded.asEvent(); - } - - public async getFormatVersionIsCurrent() { - const fv = this.getFormatVersion(); - - if (fv === undefined || fv.length !== 3) { - return false; - } - - return fv[0] > 1 || fv[1] >= 10; - } - - public getFormatVersion(): number[] | undefined { - if (!this.wrapper) { - return undefined; - } - - return MinecraftUtilities.getVersionArrayFrom(this.wrapper.format_version); - } - - static async ensureOnFile(file: IFile, loadHandler?: IEventHandler) { - let ac: ResourceAnimation | undefined; - - if (file.manager === undefined) { - ac = new ResourceAnimation(); - - ac.file = file; - - file.manager = ac; - } - - if (file.manager !== undefined && file.manager instanceof ResourceAnimation) { - ac = file.manager as ResourceAnimation; - - if (!ac.isLoaded && loadHandler) { - ac.onLoaded.subscribe(loadHandler); - } - - await ac.load(); - } - - return ac; - } - - persist() { - if (this._file === undefined) { - return; - } - - const pjString = JSON.stringify(this.wrapper, null, 2); - - this._file.setContent(pjString); - } - - public ensureDefinition(name: string, description: string) { - if (!this.wrapper) { - this.wrapper = { - format_version: "1.12.0", - animations: {}, - }; - } - } - - async save() { - if (this._file === undefined) { - return; - } - - this.persist(); - - await this._file.saveContent(false); - } - - async load() { - if (this._file === undefined || this._isLoaded) { - return; - } - - await this._file.loadContent(); - - if (this._file.content === null || this._file.content instanceof Uint8Array) { - return; - } - - this.wrapper = StorageUtilities.getJsonObject(this._file); - - this._isLoaded = true; - } -} diff --git a/app/src/minecraft/ResourceAnimationController.ts b/app/src/minecraft/ResourceAnimationController.ts deleted file mode 100644 index 1c9b6611..00000000 --- a/app/src/minecraft/ResourceAnimationController.ts +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -import IFile from "../storage/IFile"; -import { EventDispatcher, IEventHandler } from "ste-events"; -import StorageUtilities from "../storage/StorageUtilities"; -import IResourceAnimationControllerDefinition from "./IResourceAnimationController"; -import MinecraftUtilities from "./MinecraftUtilities"; - -export default class ResourceAnimationController { - private _file?: IFile; - private _isLoaded: boolean = false; - - public definition?: IResourceAnimationControllerDefinition; - - private _onLoaded = new EventDispatcher(); - - public get isLoaded() { - return this._isLoaded; - } - - public get file() { - return this._file; - } - - public set file(newFile: IFile | undefined) { - this._file = newFile; - } - - public get onLoaded() { - return this._onLoaded.asEvent(); - } - - public async getFormatVersionIsCurrent() { - const fv = this.getFormatVersion(); - - if (fv === undefined || fv.length !== 3) { - return false; - } - - return fv[0] > 1 || fv[1] >= 10; - } - - public getFormatVersion(): number[] | undefined { - if (!this.definition) { - return undefined; - } - - return MinecraftUtilities.getVersionArrayFrom(this.definition.format_version); - } - - static async ensureOnFile( - file: IFile, - loadHandler?: IEventHandler - ) { - let ac: ResourceAnimationController | undefined; - - if (file.manager === undefined) { - ac = new ResourceAnimationController(); - - ac.file = file; - - file.manager = ac; - } - - if (file.manager !== undefined && file.manager instanceof ResourceAnimationController) { - ac = file.manager as ResourceAnimationController; - - if (!ac.isLoaded && loadHandler) { - ac.onLoaded.subscribe(loadHandler); - } - - await ac.load(); - } - - return ac; - } - - persist() { - if (this._file === undefined) { - return; - } - - const pjString = JSON.stringify(this.definition, null, 2); - - this._file.setContent(pjString); - } - - public ensureDefinition(name: string, description: string) { - if (!this.definition) { - this.definition = { - format_version: "1.12.0", - animation_controllers: {}, - }; - } - } - - async save() { - if (this._file === undefined) { - return; - } - - this.persist(); - - await this._file.saveContent(false); - } - - async load() { - if (this._file === undefined || this._isLoaded) { - return; - } - - await this._file.loadContent(); - - if (this._file.content === null || this._file.content instanceof Uint8Array) { - return; - } - - this.definition = StorageUtilities.getJsonObject(this._file); - - this._isLoaded = true; - } -} diff --git a/app/src/minecraft/WorldChunk.ts b/app/src/minecraft/WorldChunk.ts index 0f676264..885208ef 100644 --- a/app/src/minecraft/WorldChunk.ts +++ b/app/src/minecraft/WorldChunk.ts @@ -49,7 +49,7 @@ export default class WorldChunk { bitsPerBlock: number[]; blockDataStart: number[]; - blockPalettes: BlockPalette[]; + blockPalettes: (BlockPalette | undefined)[]; subChunkFormatType: SubChunkFormatType[]; actorDigests: string[]; @@ -109,6 +109,24 @@ export default class WorldChunk { this.z = inZ; } + clearCachedData() { + for (let i = 0; i < 64; i++) { + if (this.subChunks[i] !== undefined) { + this.blockDataStart[i] = -1; + this.bitsPerBlock[i] = -1; + this.blockPalettes[i] = undefined; + + this.pendingSubChunksToProcess[i] = true; + } + } + + this.blockTops = undefined; + this.blockActorsEnsured = false; + + this._blockActorsRelLoc = []; + this._blockActors = []; + } + addActorDigest(digest: string) { this.actorDigests.push(digest); } @@ -169,14 +187,19 @@ export default class WorldChunk { break; case 115: // not sure what chunk #115 is, or if this is a parsing bug. observed to be one byte with a value of 0 - Log.assert(false, "Unexpected type 115 record."); + // Log.assert(false, "Unexpected type 115 record."); break; case 118: // 118 = legacy version - Log.assert(keyValue.value !== undefined && keyValue.value.length === 1, "Unexpected type 118 record."); + Log.assert( + keyValue.value !== undefined && (keyValue.value.length === 0 || keyValue.value.length === 1), + "Unexpected type 118 record." + ); - if (keyValue.value) { + if (keyValue.value && keyValue.value.length === 1) { this.legacyVersion = keyValue.value[0]; + } else if (keyValue.value && keyValue.value.length === 0) { + this.legacyVersion = undefined; } break; @@ -189,7 +212,7 @@ export default class WorldChunk { break; case 46: // data2d legacy - Log.assert(false, "Unexpected data 2D legacy."); + // Log.assert(false, "Data 2D legacy (NYI)."); break; case 47: // subchunk prefix @@ -205,7 +228,7 @@ export default class WorldChunk { } if (!keyValue.value || keyValue.value.length <= 0) { - Log.fail("Empty subchunk defined."); + Log.assert(this.subChunks[subChunkIndex] === undefined, "Empty subchunk defined."); return; } @@ -217,7 +240,6 @@ export default class WorldChunk { case 48: // legacy terrain const bytes = keyValue.value; - // Log.assert(!this.legacyTerrainBytes); if (bytes && bytes.length > 0) { Log.assert(bytes.length === 83200, "LegacyTerrain record should be 83,200 bytes"); @@ -241,7 +263,7 @@ export default class WorldChunk { break; case 52: // legacy block extra data - Log.assert(false, "Unexpected legacy block extra data."); + // Log.assert(false, "Legacy block extra data - NYI"); break; case 53: // biome state @@ -1169,7 +1191,6 @@ export default class WorldChunk { bytes[byteStart + 3], true ); - // Log.assert(x !== 15 || y !== 80 || z !== 15); word >>>= subChunkBitsPerBlock * blocksIn; diff --git a/app/src/minecraft/WorldTemplateManifestJson.ts b/app/src/minecraft/WorldTemplateManifestDefinition.ts similarity index 86% rename from app/src/minecraft/WorldTemplateManifestJson.ts rename to app/src/minecraft/WorldTemplateManifestDefinition.ts index 85139b06..dce6b1cb 100644 --- a/app/src/minecraft/WorldTemplateManifestJson.ts +++ b/app/src/minecraft/WorldTemplateManifestDefinition.ts @@ -5,17 +5,17 @@ import IFile from "../storage/IFile"; import { EventDispatcher, IEventHandler } from "ste-events"; import Utilities from "../core/Utilities"; import Project from "../app/Project"; -import IWorldTemplateManifest, { IWorldTemplateManifestHeader } from "./IWorldTemplateManifest"; import StorageUtilities from "../storage/StorageUtilities"; +import IWorldManifest, { IWorldManifestHeader } from "./IWorldManifest"; -export default class WorldTemplateManifestJson { +export default class WorldTemplateManifestDefinition { private _file?: IFile; private _id?: string; private _isLoaded: boolean = false; - public definition?: IWorldTemplateManifest; + public definition?: IWorldManifest; - private _onLoaded = new EventDispatcher(); + private _onLoaded = new EventDispatcher(); public get isLoaded() { return this._isLoaded; @@ -79,20 +79,20 @@ export default class WorldTemplateManifestJson { static async ensureOnFile( file: IFile, - loadHandler?: IEventHandler + loadHandler?: IEventHandler ) { - let bmj: WorldTemplateManifestJson | undefined; + let bmj: WorldTemplateManifestDefinition | undefined; if (file.manager === undefined) { - bmj = new WorldTemplateManifestJson(); + bmj = new WorldTemplateManifestDefinition(); bmj.file = file; file.manager = bmj; } - if (file.manager !== undefined && file.manager instanceof WorldTemplateManifestJson) { - bmj = file.manager as WorldTemplateManifestJson; + if (file.manager !== undefined && file.manager instanceof WorldTemplateManifestDefinition) { + bmj = file.manager as WorldTemplateManifestDefinition; if (!bmj.isLoaded && loadHandler) { bmj.onLoaded.subscribe(loadHandler); @@ -145,11 +145,11 @@ export default class WorldTemplateManifestJson { } } - public ensureHeaderForProject(project: Project): IWorldTemplateManifestHeader { + public ensureHeaderForProject(project: Project): IWorldManifestHeader { return this.ensureHeader(project.title, project.description); } - public ensureHeader(name: string, description: string): IWorldTemplateManifestHeader { + public ensureHeader(name: string, description: string): IWorldManifestHeader { this.ensureDefinition(name, description); if (!this.definition) { diff --git a/app/src/monaco/MonacoEditor.tsx b/app/src/monaco/MonacoEditor.tsx deleted file mode 100644 index e7ab292a..00000000 --- a/app/src/monaco/MonacoEditor.tsx +++ /dev/null @@ -1,266 +0,0 @@ -import React, { Component } from "react"; -import * as monaco from "monaco-editor"; -/* -(window as any).MonacoEnvironment = { - getWorkerUrl: function (workerId, label) { - return `data:text/javascript;charset=utf-8,${encodeURIComponent(` - self.MonacoEnvironment = { baseUrl: '${window.location.origin}/' }; - importScripts('${window.location.origin}/vs/base/worker/workerMain.js'); - `)}`; - } - window.self.MonacoEnvironment = { - baseUrl: encodeURIComponent(window.location.origin), - getWorkerUrl: function (_moduleId: any, label: string) { - if (label === 'json') { - return './json.worker.bundle.js'; - } - if (label === 'css' || label === 'scss' || label === 'less') { - return './css.worker.bundle.js'; - } - if (label === 'html' || label === 'handlebars' || label === 'razor') { - return './html.worker.bundle.js'; - } - if (label === 'typescript' || label === 'javascript') { - return './ts.worker.bundle.js'; - } - return './editor.worker.bundle.js'; - } -}; - -window.self.MonacoEnvironment = { - baseUrl: encodeURIComponent(window.location.origin + "/dist/vs/"), - getWorkerUrl: function (_moduleId: any, label: string) { - if (label === 'json') { - return '/dist/vs/language/tsWorker.js'; - } - if (label === 'css' || label === 'scss' || label === 'less') { - return './css.worker.bundle.js'; - } - if (label === 'html' || label === 'handlebars' || label === 'razor') { - return './html.worker.bundle.js'; - } - if (label === 'typescript' || label === 'javascript') { - return '/dist/vs/language/tsWorker.js'; - } - return './editor.worker.bundle.js'; - } - -}; - -};*/ - -// @ts-ignore -window.self.MonacoEnvironment = { - baseUrl: encodeURIComponent(window.location.origin), - getWorkerUrl: function (_moduleId: any, label: string) { - if (label === "json") { - return "./json.worker.bundle.js"; - } - if (label === "css" || label === "scss" || label === "less") { - return "./css.worker.bundle.js"; - } - if (label === "html" || label === "handlebars" || label === "razor") { - return "./html.worker.bundle.js"; - } - if (label === "typescript" || label === "javascript") { - return "./ts.worker.bundle.js"; - } - return "./editor.worker.bundle.js"; - }, -}; - -interface IMonacoEditorProps { - contentId: string; - initialContent: string; - onContentUpdated?: (newContent: string) => void; -} - -interface IMonacoEditorState { - contentId: string; - content: string; - updateEditorValueNext: boolean; -} - -export default class MonacoEditor extends Component { - _editorOuterDiv: HTMLDivElement | null; - _editorDiv: HTMLDivElement | null; - _editor: monaco.editor.IStandaloneCodeEditor | null; - _lastContentId: string; - _viewStates: { [id: string]: monaco.editor.ICodeEditorViewState }; - - constructor(props: IMonacoEditorProps) { - super(props); - - this._doResize = this._doResize.bind(this); - this._handleContentChange = this._handleContentChange.bind(this); - - this._editorOuterDiv = null; - this._editorDiv = null; - this._editor = null; - - this._viewStates = {}; - - window.addEventListener("resize", this._doResize); - - this.state = { - contentId: "____", - content: "", - updateEditorValueNext: false, - }; - - this._lastContentId = this.state.contentId; - } - - private _doResize() { - if (this._editor != null && this._editorDiv != null) { - let elt: HTMLElement = this._editorDiv; - - if (elt.parentElement != null && elt.parentElement != null) { - elt = elt.parentElement.parentElement as HTMLElement; - - this._editor.layout({ - width: elt.clientWidth, - height: elt.clientHeight, - } as monaco.editor.IDimension); - } - } - } - - static getDerivedStateFromProps(props: IMonacoEditorProps, state: IMonacoEditorState) { - if ( - props.initialContent !== null && - props.initialContent !== state.content && - props.contentId !== state.contentId - ) { - state.contentId = props.contentId; - state.content = props.initialContent; - state.updateEditorValueNext = true; - - return state; - } - - return null; // No change to state - } - - componentWillUnmount() { - if (this._editor != null) { - this._editor.dispose(); - this._editor = null; - } - - this._editorDiv = null; - this._editorOuterDiv = null; - } - - componentDidUpdate(prevProps: IMonacoEditorProps, prevState: IMonacoEditorState) { - if (this._editor !== null && this.state.updateEditorValueNext) { - if (this._lastContentId !== this.state.contentId) { - this._preserveViewState(this._lastContentId); - } - - this._lastContentId = this.state.contentId; - - this._editor.setValue(this.state.content); - - const viewState = this._viewStates[this.state.contentId]; - - if (viewState != null) { - this._editor.restoreViewState(viewState); - } - } - } - - _handleContentChange(event: monaco.editor.IModelContentChangedEvent) { - this._save(); - } - - _save() { - if (this._editor !== null) { - const val = this._editor.getValue(); - - if (val !== this.state.content) { - this._preserveViewState(this.state.contentId); - - if (this.props.onContentUpdated != null) { - this.props.onContentUpdated(val); - } - - this.setState({ - contentId: this.state.contentId, - content: val, - updateEditorValueNext: false, - }); - } - } - } - - _preserveViewState(contentId: string) { - if (this._editor != null) { - const viewState = this._editor.saveViewState(); - - if (viewState != null) { - this._viewStates[contentId] = viewState; - } - } - } - - _setEditor(elt: HTMLDivElement) { - if (elt !== null && elt !== this._editorOuterDiv) { - if (this._editorDiv == null) { - this._editorDiv = document.createElement("DIV") as HTMLDivElement; - - // this._editorDiv.addEventListener("resize", this._doResize); - /* - const eltParent = elt.parentElement; - - if (eltParent != null) - { - eltParent = elt.parentElement; - if (eltParent != null) - { - eltParent.addEventListener("resize", this._doResize); - } - } -*/ - this._editorDiv.setAttribute( - "style", - "width: 100%; height: 100%; min-width: 100%; min-height: 100%; background-color: purple" - ); - } else if (this._editorOuterDiv != null) { - this._editorOuterDiv.removeChild(this._editorDiv); - } - - elt.appendChild(this._editorDiv); - - this._editorOuterDiv = elt; - - if (this._editor == null) { - this._editor = monaco.editor.create(this._editorDiv, { - value: this.state.content, - theme: "vs-dark", - automaticLayout: false, - language: "javascript", - }); - - this._editor.onDidChangeModelContent(this._handleContentChange); - } - - this._doResize(); - } - } - - render() { - return ( -
this._setEditor(c)} - /> - ); - } -} diff --git a/app/src/storage/FolderBase.ts b/app/src/storage/FolderBase.ts index 6d63c87c..71984403 100644 --- a/app/src/storage/FolderBase.ts +++ b/app/src/storage/FolderBase.ts @@ -14,6 +14,10 @@ import StorageBase from "./StorageBase"; export default abstract class FolderBase implements IFolder { abstract get name(): string; + get ensuredName(): string { + return this.name; + } + isDisposed: boolean = false; #lastLoadedOrSaved: Date | null; @@ -467,6 +471,10 @@ export default abstract class FolderBase implements IFolder { return this; } + if (path.startsWith("./")) { + path = path.substring(1); + } + path = this.canonicalizePath(path); if (path[path.length - 1] !== "/") { diff --git a/app/src/storage/IFolder.ts b/app/src/storage/IFolder.ts index 13f2d331..82621827 100644 --- a/app/src/storage/IFolder.ts +++ b/app/src/storage/IFolder.ts @@ -16,6 +16,8 @@ export default interface IFolder extends IStorageObject { parentFolder: IFolder | null; storage: IStorage; + ensuredName: string; + extendedPath: string; fileCount: number; diff --git a/app/src/storage/StorageUtilities.ts b/app/src/storage/StorageUtilities.ts index e6bcbfc6..ff79c62c 100644 --- a/app/src/storage/StorageUtilities.ts +++ b/app/src/storage/StorageUtilities.ts @@ -182,7 +182,9 @@ export default class StorageUtilities { path = path + StorageUtilities.standardFolderDelimiter; } - if (!path.startsWith(StorageUtilities.standardFolderDelimiter)) { + if (path.startsWith("." + StorageUtilities.standardFolderDelimiter)) { + path = path.substring(1); + } else if (!path.startsWith(StorageUtilities.standardFolderDelimiter)) { path = StorageUtilities.standardFolderDelimiter + path; } diff --git a/app/src/storage/ZipFile.ts b/app/src/storage/ZipFile.ts index 4a39c870..25d19c4b 100644 --- a/app/src/storage/ZipFile.ts +++ b/app/src/storage/ZipFile.ts @@ -105,7 +105,7 @@ export default class ZipFile extends FileBase implements IFile { // Log.debug("Saving '" + this.content.length + "' content to '" + this.name + "' within zip"); this._parentFolder.storage.modified = this.modified; - this._parentFolder.zip = await this._parentFolder.zip.file(this.name, this.content); + this._parentFolder.zip = this._parentFolder.zip.file(this.name, this.content); } } diff --git a/app/src/storage/ZipFolder.ts b/app/src/storage/ZipFolder.ts index 3fb64b15..df9c1a27 100644 --- a/app/src/storage/ZipFolder.ts +++ b/app/src/storage/ZipFolder.ts @@ -23,6 +23,26 @@ export default class ZipFolder extends FolderBase implements IFolder { private _jsz: JSZip; + get ensuredName(): string { + if (this.name.length > 0) { + return this.name; + } + + if (this.storage.name) { + let name = this.storage.name; + + const lastPeriod = name.lastIndexOf("."); + + if (lastPeriod > 0) { + name = name.substring(0, lastPeriod); + } + + return name; + } + + return "folder"; + } + get zip() { return this._jsz; } diff --git a/app/src/test/CommandLineTest.ts b/app/src/test/CommandLineTest.ts index 795456a7..a025b4d9 100644 --- a/app/src/test/CommandLineTest.ts +++ b/app/src/test/CommandLineTest.ts @@ -1,5 +1,6 @@ import { assert } from "chai"; import Carto from "../app/Carto"; +import Project, { ProjectAutoDeploymentMode } from "../app/Project"; import CartoApp, { HostType } from "../app/CartoApp"; import NodeStorage from "../local/NodeStorage"; import Database from "../minecraft/Database"; @@ -17,8 +18,8 @@ let carto: Carto | undefined = undefined; let localEnv: LocalEnvironment | undefined = undefined; let scenariosFolder: IFolder | undefined = undefined; - let resultsFolder: IFolder | undefined = undefined; +let sampleFolder: IFolder | undefined = undefined; localEnv = new LocalEnvironment(false); @@ -27,6 +28,7 @@ localEnv = new LocalEnvironment(false); CartoApp.ensureLocalFolder = _ensureLocalFolder; const testRootPath = NodeStorage.ensureEndsWithDelimiter(__dirname) + "/../../test/"; + const sampleContentRootPath = NodeStorage.ensureEndsWithDelimiter(__dirname) + "/../../../"; const scenariosStorage = new NodeStorage(testRootPath, "scenarios"); @@ -40,6 +42,12 @@ localEnv = new LocalEnvironment(false); await resultsFolder.ensureExists(); + const sampleContentStorage = new NodeStorage(sampleContentRootPath, "samplecontent"); + + sampleFolder = sampleContentStorage.rootFolder; + + await sampleFolder.ensureExists(); + CartoApp.prefsStorage = new NodeStorage( localEnv.utilities.testWorkingPath + "prefs" + NodeStorage.folderDelimiter, "" @@ -94,7 +102,6 @@ function removeResultFolder(scenarioName: string) { const path = StorageUtilities.ensureEndsWithDelimiter(resultsFolder.fullPath) + StorageUtilities.ensureEndsWithDelimiter(scenarioName); - if (fs.existsSync(path)) // @ts-ignore fs.rmSync(path, { @@ -103,6 +110,90 @@ function removeResultFolder(scenarioName: string) { } } +describe("worldCommand", async () => { + let exitCode: number | null = null; + const stdoutLines: string[] = []; + const stderrLines: string[] = []; + + before(function (done) { + this.timeout(10000); + + removeResultFolder("worldCommand"); + + const process = spawn("node", [ + " ./../toolbuild/jsn/cli", + "world", + "set", + "-betaapis", + "-o", + "./test/results/worldCommand/", + ]); + + collectLines(process.stdout, stdoutLines); + collectLines(process.stderr, stderrLines); + + process.on("exit", (code) => { + exitCode = code; + done(); + }); + }); + + it("should have no stderr lines", async () => { + assert.equal(stderrLines.length, 0, "Error: |" + stderrLines.join("\n") + "|"); + }).timeout(10000); + + it("exit code should be zero", async () => { + assert.equal(exitCode, 0); + }).timeout(10000); + + it("output matches", async () => { + await folderMatches("worldCommand"); + }); +}); + +describe("createCommandAddonStarter", async () => { + let exitCode: number | null = null; + const stdoutLines: string[] = []; + const stderrLines: string[] = []; + + before(function (done) { + this.timeout(10000); + + removeResultFolder("createCommandAddonStarter"); + + const process = spawn("node", [ + " ./../toolbuild/jsn/cli", + "create", + "testerName", + "addonStarter", + "testerCreatorName", + "testerDescription", + "-o", + "./test/results/createCommandAddonStarter/", + ]); + + collectLines(process.stdout, stdoutLines); + collectLines(process.stderr, stderrLines); + + process.on("exit", (code) => { + exitCode = code; + done(); + }); + }); + + it("should have no stderr lines", async () => { + assert.equal(stderrLines.length, 0, "Error: |" + stderrLines.join("\n") + "|"); + }).timeout(10000); + + it("exit code should be zero", async () => { + assert.equal(exitCode, 0); + }).timeout(10000); + + it("output matches", async () => { + await folderMatches("createCommandAddonStarter"); + }); +}); + describe("validateAddons1WellFormedCommand", async () => { let exitCode: number | null = null; const stdoutLines: string[] = []; @@ -285,9 +376,9 @@ async function collectLines(readable: Readable, data: string[]) { let lineUp = line.replace(/\\n/g, ""); lineUp = lineUp.replace(/\\r/g, ""); - if (lineUp.indexOf("ebugger") === -1) { + if (lineUp.indexOf("ebugger") <= 0) { // ignore any lines about the debugger. - console.log(lineUp); + // console.log(lineUp); data.push(lineUp); } } @@ -306,6 +397,7 @@ async function folderMatches(scenarioName: string, excludeFileList?: string[]) { const isEqual = await StorageUtilities.folderContentsEqual(scenarioFolder, scenarioOutFolder, excludeFileList, true, [ "generatorVersion", + "uuid", ]); assert( @@ -335,7 +427,7 @@ async function ensureJsonMatchesScenario(obj: object, scenarioName: string) { assert(exists, "report.json file for scenario '" + scenarioName + "' does not exist."); - const isEqual = await StorageUtilities.fileContentsEqual(scenarioFile, outFile, true, ["generatorVersion"]); + const isEqual = await StorageUtilities.fileContentsEqual(scenarioFile, outFile, true, ["generatorVersion", "uuid"]); assert( isEqual, diff --git a/app/test/scenarios/createCommandAddonStarter/.env b/app/test/scenarios/createCommandAddonStarter/.env new file mode 100644 index 00000000..bafce30d --- /dev/null +++ b/app/test/scenarios/createCommandAddonStarter/.env @@ -0,0 +1,3 @@ +PROJECT_NAME="aop_mobs" +MINECRAFT_PRODUCT="BedrockUWP" +CUSTOM_DEPLOYMENT_PATH="" \ No newline at end of file diff --git a/app/test/scenarios/createCommandAddonStarter/.prettierrc.json b/app/test/scenarios/createCommandAddonStarter/.prettierrc.json new file mode 100644 index 00000000..8856048e --- /dev/null +++ b/app/test/scenarios/createCommandAddonStarter/.prettierrc.json @@ -0,0 +1,10 @@ +{ + "trailingComma": "es5", + "tabWidth": 2, + "semi": true, + "singleQuote": false, + "bracketSpacing": true, + "arrowParens": "always", + "printWidth": 120, + "endOfLine": "auto" +} \ No newline at end of file diff --git a/app/test/scenarios/createCommandAddonStarter/.vscode/extensions.json b/app/test/scenarios/createCommandAddonStarter/.vscode/extensions.json new file mode 100644 index 00000000..674ee0b6 --- /dev/null +++ b/app/test/scenarios/createCommandAddonStarter/.vscode/extensions.json @@ -0,0 +1,7 @@ +{ + "recommendations": [ + "esbenp.prettier-vscode", + "blockceptionltd.blockceptionvscodeminecraftbedrockdevelopmentextension", + "mojang-studios.minecraft-debugger" + ] +} \ No newline at end of file diff --git a/app/test/scenarios/createCommandAddonStarter/.vscode/launch.json b/app/test/scenarios/createCommandAddonStarter/.vscode/launch.json new file mode 100644 index 00000000..d2c6b191 --- /dev/null +++ b/app/test/scenarios/createCommandAddonStarter/.vscode/launch.json @@ -0,0 +1,14 @@ +{ + "version": "0.3.0", + "configurations": [ + { + "type": "minecraft-js", + "request": "attach", + "name": "Debug with Minecraft", + "preLaunchTask": "build", + "sourceMapRoot": "${workspaceFolder}/dist/debug/", + "generatedSourceRoot": "${workspaceFolder}/dist/scripts/", + "port": 19144 + } + ] +} \ No newline at end of file diff --git a/app/test/scenarios/createCommandAddonStarter/.vscode/settings.json b/app/test/scenarios/createCommandAddonStarter/.vscode/settings.json new file mode 100644 index 00000000..78f445f4 --- /dev/null +++ b/app/test/scenarios/createCommandAddonStarter/.vscode/settings.json @@ -0,0 +1,39 @@ +{ + "[javascript]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[typescript]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[typescriptreact]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[json]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "git.ignoreLimitWarning": true, + "editor.formatOnSave": true, + "search.exclude": { + "**/.git": true, + "**/node_modules": true, + "**/build": true + }, + "files.exclude": { + "**/.git": true, + "**/.DS_Store": true, + "**/node_modules": true, + "**/build": true + }, + "cSpell.words": [ + "boomfly", + "gametest", + "gametests", + "minecart", + "sheepomelon", + "shulker", + "spawnable", + "summonable", + "zoglin" + ], + "editor.tabSize": 2 +} \ No newline at end of file diff --git a/app/test/scenarios/createCommandAddonStarter/.vscode/tasks.json b/app/test/scenarios/createCommandAddonStarter/.vscode/tasks.json new file mode 100644 index 00000000..96078336 --- /dev/null +++ b/app/test/scenarios/createCommandAddonStarter/.vscode/tasks.json @@ -0,0 +1,18 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "build", + "type": "shell", + "command": "npm run build", + "dependsOn": [ + "minecraft: deploy" + ] + }, + { + "label": "deploy", + "type": "shell", + "command": "npm run local-deploy" + } + ] +} \ No newline at end of file diff --git a/app/test/scenarios/createCommandAddonStarter/behavior_packs/cn_test/manifest.json b/app/test/scenarios/createCommandAddonStarter/behavior_packs/cn_test/manifest.json new file mode 100644 index 00000000..683da7d9 --- /dev/null +++ b/app/test/scenarios/createCommandAddonStarter/behavior_packs/cn_test/manifest.json @@ -0,0 +1,68 @@ +{ + "format_version": 2, + "header": { + "name": "testerName", + "description": "testerDescription", + "uuid": "25ae3291-9d7a-4a21-a1f5-2c70e39ede34", + "version": [ + 1, + 0, + 0 + ], + "min_engine_version": [ + 1, + 21, + 20 + ] + }, + "modules": [ + { + "description": "Behavior", + "version": [ + 1, + 0, + 0 + ], + "uuid": "8e67648f-9b4d-42cd-aa5c-9f1681c74b1e", + "type": "data" + }, + { + "description": "Script resources", + "language": "javascript", + "type": "script", + "uuid": "e1bb6ca5-2ed5-4e7a-8a75-248c7f31383a", + "version": [ + 0, + 0, + 1 + ], + "entry": "scripts/main.js" + } + ], + "dependencies": [ + { + "uuid": "9d6dad89-6e29-46ba-83d5-490a4901caef", + "version": [ + 1, + 0, + 0 + ] + }, + { + "module_name": "@minecraft/server", + "version": [ + 1, + 13, + 0 + ] + }, + { + "module_name": "@minecraft/server-ui", + "version": [ + 1, + 2, + 0 + ] + } + ] +} \ No newline at end of file diff --git a/app/test/scenarios/createCommandAddonStarter/behavior_packs/cn_test/pack_icon.png b/app/test/scenarios/createCommandAddonStarter/behavior_packs/cn_test/pack_icon.png new file mode 100644 index 00000000..a28f3eaa Binary files /dev/null and b/app/test/scenarios/createCommandAddonStarter/behavior_packs/cn_test/pack_icon.png differ diff --git a/app/test/scenarios/createCommandAddonStarter/eslint.config.mjs b/app/test/scenarios/createCommandAddonStarter/eslint.config.mjs new file mode 100644 index 00000000..0c863ca9 --- /dev/null +++ b/app/test/scenarios/createCommandAddonStarter/eslint.config.mjs @@ -0,0 +1,20 @@ +import minecraftLinting from "eslint-plugin-minecraft-linting"; +import tsParser from "@typescript-eslint/parser"; +import ts from "@typescript-eslint/eslint-plugin"; + +export default [ + { + files: ["scripts/**/*.ts"], + languageOptions: { + parser: tsParser, + ecmaVersion: "latest", + }, + plugins: { + ts, + "minecraft-linting": minecraftLinting, + }, + rules: { + "minecraft-linting/avoid-unnecessary-command": "error", + }, + }, +]; diff --git a/app/test/scenarios/createCommandAddonStarter/just.config.ts b/app/test/scenarios/createCommandAddonStarter/just.config.ts new file mode 100644 index 00000000..543c5694 --- /dev/null +++ b/app/test/scenarios/createCommandAddonStarter/just.config.ts @@ -0,0 +1,72 @@ +import { argv, parallel, series, task, tscTask } from "just-scripts"; +import { + BundleTaskParameters, + CopyTaskParameters, + bundleTask, + cleanTask, + cleanCollateralTask, + copyTask, + coreLint, + mcaddonTask, + setupEnvironment, + ZipTaskParameters, + STANDARD_CLEAN_PATHS, + DEFAULT_CLEAN_DIRECTORIES, + getOrThrowFromProcess, + watchTask, +} from "@minecraft/core-build-tasks"; +import path from "path"; + +// Setup env variables +setupEnvironment(path.resolve(__dirname, ".env")); +const projectName = getOrThrowFromProcess("PROJECT_NAME"); + +const bundleTaskOptions: BundleTaskParameters = { + entryPoint: path.join(__dirname, "./scripts/main.ts"), + external: ["@minecraft/server", "@minecraft/server-ui"], + outfile: path.resolve(__dirname, "./dist/scripts/main.js"), + minifyWhitespace: false, + sourcemap: true, + outputSourcemapPath: path.resolve(__dirname, "./dist/debug"), +}; + +const copyTaskOptions: CopyTaskParameters = { + copyToBehaviorPacks: [`./behavior_packs/${projectName}`], + copyToScripts: ["./dist/scripts"], + copyToResourcePacks: [`./resource_packs/${projectName}`], +}; + +const mcaddonTaskOptions: ZipTaskParameters = { + ...copyTaskOptions, + outputFile: `./dist/packages/${projectName}.mcaddon`, +}; + +// Lint +task("lint", coreLint(["scripts/**/*.ts"], argv().fix)); + +// Build +task("typescript", tscTask()); +task("bundle", bundleTask(bundleTaskOptions)); +task("build", series("typescript", "bundle")); + +// Clean +task("clean-local", cleanTask(DEFAULT_CLEAN_DIRECTORIES)); +task("clean-collateral", cleanCollateralTask(STANDARD_CLEAN_PATHS)); +task("clean", parallel("clean-local", "clean-collateral")); + +// Package +task("copyArtifacts", copyTask(copyTaskOptions)); +task("package", series("clean-collateral", "copyArtifacts")); + +// Local Deploy used for deploying local changes directly to output via the bundler. It does a full build and package first just in case. +task( + "local-deploy", + watchTask( + ["scripts/**/*.ts", "behavior_packs/**/*.{json,lang,png}", "resource_packs/**/*.{json,lang,png}"], + series("clean-local", "build", "package") + ) +); + +// Mcaddon +task("createMcaddonFile", mcaddonTask(mcaddonTaskOptions)); +task("mcaddon", series("clean-local", "build", "createMcaddonFile")); diff --git a/app/test/scenarios/createCommandAddonStarter/package-lock.json b/app/test/scenarios/createCommandAddonStarter/package-lock.json new file mode 100644 index 00000000..5391d075 --- /dev/null +++ b/app/test/scenarios/createCommandAddonStarter/package-lock.json @@ -0,0 +1,4633 @@ +{ + "name": "addon_starter", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "addon_starter", + "version": "0.1.0", + "dependencies": { + "@minecraft/math": "^1.1.0", + "@minecraft/server": "^1.8.0", + "@minecraft/server-ui": "^1.1.0", + "@minecraft/vanilla-data": "^1.20.60" + }, + "devDependencies": { + "@minecraft/core-build-tasks": "^1.1.3", + "eslint-plugin-minecraft-linting": "^1.2.1", + "source-map": "^0.7.4", + "ts-node": "^10.9.1", + "typescript": "^5.0.2" + } + }, + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz", + "integrity": "sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.2.tgz", + "integrity": "sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.2.tgz", + "integrity": "sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.2.tgz", + "integrity": "sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz", + "integrity": "sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.2.tgz", + "integrity": "sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.2.tgz", + "integrity": "sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.2.tgz", + "integrity": "sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.2.tgz", + "integrity": "sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.2.tgz", + "integrity": "sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.2.tgz", + "integrity": "sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.2.tgz", + "integrity": "sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.2.tgz", + "integrity": "sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.2.tgz", + "integrity": "sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.2.tgz", + "integrity": "sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.2.tgz", + "integrity": "sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.2.tgz", + "integrity": "sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.2.tgz", + "integrity": "sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.2.tgz", + "integrity": "sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.2.tgz", + "integrity": "sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.2.tgz", + "integrity": "sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.2.tgz", + "integrity": "sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz", + "integrity": "sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", + "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/js": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", + "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.14", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", + "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz", + "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==", + "dev": true + }, + "node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@microsoft/api-extractor": { + "version": "7.42.3", + "resolved": "https://registry.npmjs.org/@microsoft/api-extractor/-/api-extractor-7.42.3.tgz", + "integrity": "sha512-JNLJFpGHz6ekjS6bvYXxUBeRGnSHeCMFNvRbCQ+7XXB/ZFrgLSMPwWtEq40AiWAy+oyG5a4RSNwdJTp0B2USvQ==", + "dev": true, + "dependencies": { + "@microsoft/api-extractor-model": "7.28.13", + "@microsoft/tsdoc": "0.14.2", + "@microsoft/tsdoc-config": "~0.16.1", + "@rushstack/node-core-library": "4.0.2", + "@rushstack/rig-package": "0.5.2", + "@rushstack/terminal": "0.10.0", + "@rushstack/ts-command-line": "4.19.1", + "lodash": "~4.17.15", + "minimatch": "~3.0.3", + "resolve": "~1.22.1", + "semver": "~7.5.4", + "source-map": "~0.6.1", + "typescript": "5.3.3" + }, + "bin": { + "api-extractor": "bin/api-extractor" + } + }, + "node_modules/@microsoft/api-extractor-model": { + "version": "7.28.13", + "resolved": "https://registry.npmjs.org/@microsoft/api-extractor-model/-/api-extractor-model-7.28.13.tgz", + "integrity": "sha512-39v/JyldX4MS9uzHcdfmjjfS6cYGAoXV+io8B5a338pkHiSt+gy2eXQ0Q7cGFJ7quSa1VqqlMdlPrB6sLR/cAw==", + "dev": true, + "dependencies": { + "@microsoft/tsdoc": "0.14.2", + "@microsoft/tsdoc-config": "~0.16.1", + "@rushstack/node-core-library": "4.0.2" + } + }, + "node_modules/@microsoft/api-extractor-model/node_modules/@rushstack/node-core-library": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-4.0.2.tgz", + "integrity": "sha512-hyES82QVpkfQMeBMteQUnrhASL/KHPhd7iJ8euduwNJG4mu2GSOKybf0rOEjOm1Wz7CwJEUm9y0yD7jg2C1bfg==", + "dev": true, + "dependencies": { + "fs-extra": "~7.0.1", + "import-lazy": "~4.0.0", + "jju": "~1.4.0", + "resolve": "~1.22.1", + "semver": "~7.5.4", + "z-schema": "~5.0.2" + }, + "peerDependencies": { + "@types/node": "*" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@microsoft/api-extractor/node_modules/@rushstack/node-core-library": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-4.0.2.tgz", + "integrity": "sha512-hyES82QVpkfQMeBMteQUnrhASL/KHPhd7iJ8euduwNJG4mu2GSOKybf0rOEjOm1Wz7CwJEUm9y0yD7jg2C1bfg==", + "dev": true, + "dependencies": { + "fs-extra": "~7.0.1", + "import-lazy": "~4.0.0", + "jju": "~1.4.0", + "resolve": "~1.22.1", + "semver": "~7.5.4", + "z-schema": "~5.0.2" + }, + "peerDependencies": { + "@types/node": "*" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@microsoft/api-extractor/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@microsoft/api-extractor/node_modules/typescript": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", + "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/@microsoft/tsdoc": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.14.2.tgz", + "integrity": "sha512-9b8mPpKrfeGRuhFH5iO1iwCLeIIsV6+H1sRfxbkoGXIyQE2BTsPd9zqSqQJ+pv5sJ/hT5M1zvOFL02MnEezFug==", + "dev": true + }, + "node_modules/@microsoft/tsdoc-config": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/@microsoft/tsdoc-config/-/tsdoc-config-0.16.2.tgz", + "integrity": "sha512-OGiIzzoBLgWWR0UdRJX98oYO+XKGf7tiK4Zk6tQ/E4IJqGCe7dvkTvgDZV5cFJUzLGDOjeAXrnZoA6QkVySuxw==", + "dev": true, + "dependencies": { + "@microsoft/tsdoc": "0.14.2", + "ajv": "~6.12.6", + "jju": "~1.4.0", + "resolve": "~1.19.0" + } + }, + "node_modules/@microsoft/tsdoc-config/node_modules/resolve": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz", + "integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==", + "dev": true, + "dependencies": { + "is-core-module": "^2.1.0", + "path-parse": "^1.0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/@minecraft/common": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@minecraft/common/-/common-1.2.0.tgz", + "integrity": "sha512-JdmEq4P3Z/FtoBzhLijFgMSVFnFRrUoLwY8DHHrgtFo0mfLTOLTB1RErYjLMsA6b7BGVNxkX/pfFRiH7QZ0XwQ==" + }, + "node_modules/@minecraft/core-build-tasks": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@minecraft/core-build-tasks/-/core-build-tasks-1.1.3.tgz", + "integrity": "sha512-gjNYm9XNYP0eAirUuo3LfKLpZKQG+PLaFbpwXIvi/lCiN0rctOlC450POV8GdyOP4vkJKbKE0iwjhVpD+03XVw==", + "dev": true, + "dependencies": { + "@microsoft/api-extractor": "^7.38.3", + "@rushstack/node-core-library": "^3.59.6", + "dotenv": "^16.0.2", + "esbuild": "^0.20.1", + "just-scripts": "^2.2.1", + "prettier": "^2.8.2", + "rimraf": "^3.0.2", + "vitest": "^0.34.6", + "zip-lib": "^0.7.3" + } + }, + "node_modules/@minecraft/math": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@minecraft/math/-/math-1.3.4.tgz", + "integrity": "sha512-QoVkHVoA8oAsTmQoGnFpm7n4UHx+t9o2D7O4Tiy4xMokv38HczwRT9x/LzUyvFu0felF1nRVBTH/d8QxW1GhoA==", + "peerDependencies": { + "@minecraft/server": "^1.6.0" + } + }, + "node_modules/@minecraft/server": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@minecraft/server/-/server-1.9.0.tgz", + "integrity": "sha512-PhOLfCYM83t24TY3+8WA5zCRGCyG/89VC6ZSi4Ye92QZORC/0Td5JIh2ctJtUhAiYCbct/Ph/Of3BCi8/itr6A==", + "dependencies": { + "@minecraft/common": "^1.1.0" + } + }, + "node_modules/@minecraft/server-ui": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@minecraft/server-ui/-/server-ui-1.1.0.tgz", + "integrity": "sha512-Gnf+GHjjT4VFoXEt7qjrfDRipDgc93YcXbgTmdPTQ5Og3DIRD003ahH97tGMZmeNdsB+ymvAquf+o2o9W2pDjw==", + "dependencies": { + "@minecraft/server": "^1.2.0" + } + }, + "node_modules/@minecraft/vanilla-data": { + "version": "1.20.70", + "resolved": "https://registry.npmjs.org/@minecraft/vanilla-data/-/vanilla-data-1.20.70.tgz", + "integrity": "sha512-t6NGlfaI7d/HyQFrHe2rvqPujdlRkTz7futtKoFilC7bh/9ZjA8Hu4LTPI597zJd3SdR1I9Rp8dwooK2apDLSg==" + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.13.0.tgz", + "integrity": "sha512-5ZYPOuaAqEH/W3gYsRkxQATBW3Ii1MfaT4EQstTnLKViLi2gLSQmlmtTpGucNP3sXEpOiI5tdGhjdE111ekyEg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.13.0.tgz", + "integrity": "sha512-BSbaCmn8ZadK3UAQdlauSvtaJjhlDEjS5hEVVIN3A4bbl3X+otyf/kOJV08bYiRxfejP3DXFzO2jz3G20107+Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.13.0.tgz", + "integrity": "sha512-Ovf2evVaP6sW5Ut0GHyUSOqA6tVKfrTHddtmxGQc1CTQa1Cw3/KMCDEEICZBbyppcwnhMwcDce9ZRxdWRpVd6g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.13.0.tgz", + "integrity": "sha512-U+Jcxm89UTK592vZ2J9st9ajRv/hrwHdnvyuJpa5A2ngGSVHypigidkQJP+YiGL6JODiUeMzkqQzbCG3At81Gg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.13.0.tgz", + "integrity": "sha512-8wZidaUJUTIR5T4vRS22VkSMOVooG0F4N+JSwQXWSRiC6yfEsFMLTYRFHvby5mFFuExHa/yAp9juSphQQJAijQ==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.13.0.tgz", + "integrity": "sha512-Iu0Kno1vrD7zHQDxOmvweqLkAzjxEVqNhUIXBsZ8hu8Oak7/5VTPrxOEZXYC1nmrBVJp0ZcL2E7lSuuOVaE3+w==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.13.0.tgz", + "integrity": "sha512-C31QrW47llgVyrRjIwiOwsHFcaIwmkKi3PCroQY5aVq4H0A5v/vVVAtFsI1nfBngtoRpeREvZOkIhmRwUKkAdw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.13.0.tgz", + "integrity": "sha512-Oq90dtMHvthFOPMl7pt7KmxzX7E71AfyIhh+cPhLY9oko97Zf2C9tt/XJD4RgxhaGeAraAXDtqxvKE1y/j35lA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.13.0.tgz", + "integrity": "sha512-yUD/8wMffnTKuiIsl6xU+4IA8UNhQ/f1sAnQebmE/lyQ8abjsVyDkyRkWop0kdMhKMprpNIhPmYlCxgHrPoXoA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.13.0.tgz", + "integrity": "sha512-9RyNqoFNdF0vu/qqX63fKotBh43fJQeYC98hCaf89DYQpv+xu0D8QFSOS0biA7cGuqJFOc1bJ+m2rhhsKcw1hw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.13.0.tgz", + "integrity": "sha512-46ue8ymtm/5PUU6pCvjlic0z82qWkxv54GTJZgHrQUuZnVH+tvvSP0LsozIDsCBFO4VjJ13N68wqrKSeScUKdA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.13.0.tgz", + "integrity": "sha512-P5/MqLdLSlqxbeuJ3YDeX37srC8mCflSyTrUsgbU1c/U9j6l2g2GiIdYaGD9QjdMQPMSgYm7hgg0551wHyIluw==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.13.0.tgz", + "integrity": "sha512-UKXUQNbO3DOhzLRwHSpa0HnhhCgNODvfoPWv2FCXme8N/ANFfhIPMGuOT+QuKd16+B5yxZ0HdpNlqPvTMS1qfw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rushstack/node-core-library": { + "version": "3.66.1", + "resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-3.66.1.tgz", + "integrity": "sha512-ker69cVKAoar7MMtDFZC4CzcDxjwqIhFzqEnYI5NRN/8M3om6saWCVx/A7vL2t/jFCJsnzQplRDqA7c78pytng==", + "dev": true, + "dependencies": { + "colors": "~1.2.1", + "fs-extra": "~7.0.1", + "import-lazy": "~4.0.0", + "jju": "~1.4.0", + "resolve": "~1.22.1", + "semver": "~7.5.4", + "z-schema": "~5.0.2" + }, + "peerDependencies": { + "@types/node": "*" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@rushstack/package-deps-hash": { + "version": "4.1.39", + "resolved": "https://registry.npmjs.org/@rushstack/package-deps-hash/-/package-deps-hash-4.1.39.tgz", + "integrity": "sha512-uIP1drAVJk/njhACBnD/kPI7vyM8mVbSBs+igiRiedeR9cf5Dp7ChLOfaBq5pJFHOHrLVtXVIjECZxrX5WeQRQ==", + "dev": true, + "dependencies": { + "@rushstack/node-core-library": "4.0.2" + } + }, + "node_modules/@rushstack/package-deps-hash/node_modules/@rushstack/node-core-library": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-4.0.2.tgz", + "integrity": "sha512-hyES82QVpkfQMeBMteQUnrhASL/KHPhd7iJ8euduwNJG4mu2GSOKybf0rOEjOm1Wz7CwJEUm9y0yD7jg2C1bfg==", + "dev": true, + "dependencies": { + "fs-extra": "~7.0.1", + "import-lazy": "~4.0.0", + "jju": "~1.4.0", + "resolve": "~1.22.1", + "semver": "~7.5.4", + "z-schema": "~5.0.2" + }, + "peerDependencies": { + "@types/node": "*" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@rushstack/rig-package": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@rushstack/rig-package/-/rig-package-0.5.2.tgz", + "integrity": "sha512-mUDecIJeH3yYGZs2a48k+pbhM6JYwWlgjs2Ca5f2n1G2/kgdgP9D/07oglEGf6mRyXEnazhEENeYTSNDRCwdqA==", + "dev": true, + "dependencies": { + "resolve": "~1.22.1", + "strip-json-comments": "~3.1.1" + } + }, + "node_modules/@rushstack/terminal": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@rushstack/terminal/-/terminal-0.10.0.tgz", + "integrity": "sha512-UbELbXnUdc7EKwfH2sb8ChqNgapUOdqcCIdQP4NGxBpTZV2sQyeekuK3zmfQSa/MN+/7b4kBogl2wq0vpkpYGw==", + "dev": true, + "dependencies": { + "@rushstack/node-core-library": "4.0.2", + "supports-color": "~8.1.1" + }, + "peerDependencies": { + "@types/node": "*" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@rushstack/terminal/node_modules/@rushstack/node-core-library": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-4.0.2.tgz", + "integrity": "sha512-hyES82QVpkfQMeBMteQUnrhASL/KHPhd7iJ8euduwNJG4mu2GSOKybf0rOEjOm1Wz7CwJEUm9y0yD7jg2C1bfg==", + "dev": true, + "dependencies": { + "fs-extra": "~7.0.1", + "import-lazy": "~4.0.0", + "jju": "~1.4.0", + "resolve": "~1.22.1", + "semver": "~7.5.4", + "z-schema": "~5.0.2" + }, + "peerDependencies": { + "@types/node": "*" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@rushstack/ts-command-line": { + "version": "4.19.1", + "resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-4.19.1.tgz", + "integrity": "sha512-J7H768dgcpG60d7skZ5uSSwyCZs/S2HrWP1Ds8d1qYAyaaeJmpmmLr9BVw97RjFzmQPOYnoXcKA4GkqDCkduQg==", + "dev": true, + "dependencies": { + "@rushstack/terminal": "0.10.0", + "@types/argparse": "1.0.38", + "argparse": "~1.0.9", + "string-argv": "~0.3.1" + } + }, + "node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", + "dev": true + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true + }, + "node_modules/@types/argparse": { + "version": "1.0.38", + "resolved": "https://registry.npmjs.org/@types/argparse/-/argparse-1.0.38.tgz", + "integrity": "sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA==", + "dev": true + }, + "node_modules/@types/chai": { + "version": "4.3.12", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.12.tgz", + "integrity": "sha512-zNKDHG/1yxm8Il6uCCVsm+dRdEsJlFoDu73X17y09bId6UwoYww+vFBsAcRzl8knM1sab3Dp1VRikFQwDOtDDw==", + "dev": true + }, + "node_modules/@types/chai-subset": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/chai-subset/-/chai-subset-1.3.5.tgz", + "integrity": "sha512-c2mPnw+xHtXDoHmdtcCXGwyLMiauiAyxWMzhGpqHC4nqI/Y5G2XhTampslK2rb59kpcuHon03UH8W6iYUzw88A==", + "dev": true, + "dependencies": { + "@types/chai": "*" + } + }, + "node_modules/@types/chokidar": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@types/chokidar/-/chokidar-2.1.3.tgz", + "integrity": "sha512-6qK3xoLLAhQVTucQGHTySwOVA1crHRXnJeLwqK6KIFkkKa2aoMFXh+WEi8PotxDtvN6MQJLyYN9ag9P6NLV81w==", + "deprecated": "This is a stub types definition. chokidar provides its own type definitions, so you do not need this installed.", + "dev": true, + "dependencies": { + "chokidar": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "dev": true + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true + }, + "node_modules/@types/node": { + "version": "20.11.28", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.28.tgz", + "integrity": "sha512-M/GPWVS2wLkSkNHVeLkrF2fD5Lx5UC4PxA0uZcKc6QqbIQUJyW1jVjueJYi1z8n0I5PxYrtpnPnWglE+y9A0KA==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/semver": { + "version": "7.5.8", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", + "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", + "dev": true + }, + "node_modules/@types/undertaker": { + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/@types/undertaker/-/undertaker-1.2.11.tgz", + "integrity": "sha512-j1Z0V2ByRHr8ZK7eOeGq0LGkkdthNFW0uAZGY22iRkNQNL9/vAV0yFPr1QN3FM/peY5bxs9P+1f0PYJTQVa5iA==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/undertaker-registry": "*", + "async-done": "~1.3.2" + } + }, + "node_modules/@types/undertaker-registry": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@types/undertaker-registry/-/undertaker-registry-1.0.4.tgz", + "integrity": "sha512-tW77pHh2TU4uebWXWeEM5laiw8BuJ7pyJYDh6xenOs75nhny2kVgwYbegJ4BoLMYsIrXaBpKYaPdYO3/udG+hg==", + "dev": true + }, + "node_modules/@types/yargs-parser": { + "version": "20.2.5", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.5.tgz", + "integrity": "sha512-pAJfNtUhU/xDwMKb3rR8MnEUSqHIfsmo3vw09baYY0rEp6AzM6Mb5ZzTuZbe/YXiYL04E6coxe+3qhVOVG98dA==", + "dev": true + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.3.0.tgz", + "integrity": "sha512-e65ii0Y/jkqX3GXSBM7v9qt9ufxd4omcWyPVVC/msq/hP+hYC6CddLRvlvclni+u7UcaNYT/QhBYlaMHaR2ixw==", + "dev": true, + "dependencies": { + "@eslint-community/regexpp": "^4.5.1", + "@typescript-eslint/scope-manager": "7.3.0", + "@typescript-eslint/type-utils": "7.3.0", + "@typescript-eslint/utils": "7.3.0", + "@typescript-eslint/visitor-keys": "7.3.0", + "debug": "^4.3.4", + "graphemer": "^1.4.0", + "ignore": "^5.2.4", + "natural-compare": "^1.4.0", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^7.0.0", + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.3.0.tgz", + "integrity": "sha512-OZcvH8zipGILuxJmtFgzjAJ+bOpWidzEppIRsT2P4ZUrizU0EsPt4hhzDn3lNfM1Hv7slZPTEQGKjUEn/ftQYA==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "7.3.0", + "@typescript-eslint/types": "7.3.0", + "@typescript-eslint/typescript-estree": "7.3.0", + "@typescript-eslint/visitor-keys": "7.3.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.3.0.tgz", + "integrity": "sha512-KlG7xH3J/+nHpZRcYeskO5QVJCnnssxYKBlrj3MoyMONihn3P4xu5jIelrS5YWvBjbytgHmFkzjDApranoYkNA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.3.0", + "@typescript-eslint/visitor-keys": "7.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.3.0.tgz", + "integrity": "sha512-TyQ19ydo248eFjTfHFSvZbxalFUOxU9o2M6SUk3wOA0yRF1ZiB2VP5iaoLrGKcg7TyUxS4knYIHnE55ih82Cfg==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "7.3.0", + "@typescript-eslint/utils": "7.3.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.3.0.tgz", + "integrity": "sha512-oYCBkD0xVxzmZZmYiIWVewyy/q/ugq7PPm4pHhE1IgcT062i96G0Ww3gd8BvUYpk2yvg95q00Hj2CHRLjAuZBA==", + "dev": true, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.3.0.tgz", + "integrity": "sha512-UF85+bInQZ3olhI/zxv0c2b2SMuymn3t6/lkRkSB239HHxFmPSlmcggOKAjYzqRCdtqhPDftpsV1LlDH66AXrA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.3.0", + "@typescript-eslint/visitor-keys": "7.3.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "9.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.3.0.tgz", + "integrity": "sha512-7PKIDoe2ppR1SK56TLv7WQXrdHqEiueVwLVIjdSR4ROY2LprmJenf4+tT8iJIfxrsPzjSJGNeQ7GVmfoYbqrhw==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "7.3.0", + "@typescript-eslint/types": "7.3.0", + "@typescript-eslint/typescript-estree": "7.3.0", + "semver": "^7.5.4" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.3.0.tgz", + "integrity": "sha512-Gz8Su+QjOI5qP8UQ74VqKaTt/BLy23IhCCHLbYxhmNzHCGFHrvfgq4hISZvuqQ690ubkD0746qLcWC647nScuQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.3.0", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "dev": true + }, + "node_modules/@vitest/expect": { + "version": "0.34.6", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-0.34.6.tgz", + "integrity": "sha512-QUzKpUQRc1qC7qdGo7rMK3AkETI7w18gTCUrsNnyjjJKYiuUB9+TQK3QnR1unhCnWRC0AbKv2omLGQDF/mIjOw==", + "dev": true, + "dependencies": { + "@vitest/spy": "0.34.6", + "@vitest/utils": "0.34.6", + "chai": "^4.3.10" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "0.34.6", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-0.34.6.tgz", + "integrity": "sha512-1CUQgtJSLF47NnhN+F9X2ycxUP0kLHQ/JWvNHbeBfwW8CzEGgeskzNnHDyv1ieKTltuR6sdIHV+nmR6kPxQqzQ==", + "dev": true, + "dependencies": { + "@vitest/utils": "0.34.6", + "p-limit": "^4.0.0", + "pathe": "^1.1.1" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner/node_modules/p-limit": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", + "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^1.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@vitest/runner/node_modules/yocto-queue": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz", + "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==", + "dev": true, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@vitest/snapshot": { + "version": "0.34.6", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-0.34.6.tgz", + "integrity": "sha512-B3OZqYn6k4VaN011D+ve+AA4whM4QkcwcrwaKwAbyyvS/NB1hCWjFIBQxAQQSQir9/RtyAAGuq+4RJmbn2dH4w==", + "dev": true, + "dependencies": { + "magic-string": "^0.30.1", + "pathe": "^1.1.1", + "pretty-format": "^29.5.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "0.34.6", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-0.34.6.tgz", + "integrity": "sha512-xaCvneSaeBw/cz8ySmF7ZwGvL0lBjfvqc1LpQ/vcdHEvpLn3Ff1vAvjw+CoGn0802l++5L/pxb7whwcWAw+DUQ==", + "dev": true, + "dependencies": { + "tinyspy": "^2.1.1" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "0.34.6", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-0.34.6.tgz", + "integrity": "sha512-IG5aDD8S6zlvloDsnzHw0Ut5xczlF+kv2BOTo+iXfPr54Yhi5qbVOgGB1hZaVq4iJ4C/MZ2J0y15IlsV/ZcI0A==", + "dev": true, + "dependencies": { + "diff-sequences": "^29.4.3", + "loupe": "^2.3.6", + "pretty-format": "^29.5.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/acorn": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz", + "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/arr-filter": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/arr-filter/-/arr-filter-1.1.2.tgz", + "integrity": "sha512-A2BETWCqhsecSvCkWAeVBFLH6sXEUGASuzkpjL3GR1SlL/PWL6M3J8EAAld2Uubmh39tvkJTqC9LeLHCUKmFXA==", + "dev": true, + "dependencies": { + "make-iterator": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/arr-map": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/arr-map/-/arr-map-2.0.2.tgz", + "integrity": "sha512-tVqVTHt+Q5Xb09qRkbu+DidW1yYzz5izWS2Xm2yFm7qJnmUfz4HPzNxbHkdRJbz2lrqI7S+z17xNYdFcBBO8Hw==", + "dev": true, + "dependencies": { + "make-iterator": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-each": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz", + "integrity": "sha512-zHjL5SZa68hkKHBFBK6DJCTtr9sfTCPCaph/L7tMSLcTFgy+zX7E+6q5UArbtOtMBCtxdICpfTCspRse+ywyXA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-initial": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/array-initial/-/array-initial-1.1.0.tgz", + "integrity": "sha512-BC4Yl89vneCYfpLrs5JU2aAu9/a+xWbeKhvISg9PT7eWFB9UlRvI+rKEtk6mgxWr3dSkk9gQ8hCrdqt06NXPdw==", + "dev": true, + "dependencies": { + "array-slice": "^1.0.0", + "is-number": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-initial/node_modules/is-number": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", + "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-last": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/array-last/-/array-last-1.3.0.tgz", + "integrity": "sha512-eOCut5rXlI6aCOS7Z7kCplKRKyiFQ6dHFBem4PwlwKeNFk2/XxTrhRh5T9PyaEWGy/NHTZWbY+nsZlNFJu9rYg==", + "dev": true, + "dependencies": { + "is-number": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-last/node_modules/is-number": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", + "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-slice": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz", + "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/async-done": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/async-done/-/async-done-1.3.2.tgz", + "integrity": "sha512-uYkTP8dw2og1tu1nmza1n1CMW0qb8gWWlwqMmLb7MhBVs4BXrFziT6HXUd+/RlRA/i4H9AkofYloUbs1fwMqlw==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.2", + "process-nextick-args": "^2.0.0", + "stream-exhaust": "^1.0.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/async-settle": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/async-settle/-/async-settle-2.0.0.tgz", + "integrity": "sha512-Obu/KE8FurfQRN6ODdHN9LuXqwC+JFIM9NRyZqJJ4ZfLJmIYN9Rg0/kb+wF70VV5+fJusTMQlJ1t5rF7J/ETdg==", + "dev": true, + "dependencies": { + "async-done": "^2.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/async-settle/node_modules/async-done": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/async-done/-/async-done-2.0.0.tgz", + "integrity": "sha512-j0s3bzYq9yKIVLKGE/tWlCpa3PfFLcrDZLTSVdnnCTGagXuXBJO4SsY9Xdk/fQBirCkH4evW5xOeJXqlAQFdsw==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.4.4", + "once": "^1.4.0", + "stream-exhaust": "^1.0.2" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/bach": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/bach/-/bach-2.0.1.tgz", + "integrity": "sha512-A7bvGMGiTOxGMpNupYl9HQTf0FFDNF4VCmks4PJpFyN1AX2pdKuxuwdvUz2Hu388wcgp+OvGFNsumBfFNkR7eg==", + "dev": true, + "dependencies": { + "async-done": "^2.0.0", + "async-settle": "^2.0.0", + "now-and-later": "^3.0.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/bach/node_modules/async-done": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/async-done/-/async-done-2.0.0.tgz", + "integrity": "sha512-j0s3bzYq9yKIVLKGE/tWlCpa3PfFLcrDZLTSVdnnCTGagXuXBJO4SsY9Xdk/fQBirCkH4evW5xOeJXqlAQFdsw==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.4.4", + "once": "^1.4.0", + "stream-exhaust": "^1.0.2" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/chai": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.4.1.tgz", + "integrity": "sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==", + "dev": true, + "dependencies": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.3", + "deep-eql": "^4.1.3", + "get-func-name": "^2.0.2", + "loupe": "^2.3.6", + "pathval": "^1.1.1", + "type-detect": "^4.0.8" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/check-error": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", + "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", + "dev": true, + "dependencies": { + "get-func-name": "^2.0.2" + }, + "engines": { + "node": "*" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/collection-map": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-map/-/collection-map-1.0.0.tgz", + "integrity": "sha512-5D2XXSpkOnleOI21TG7p3T0bGAsZ/XknZpKBmGYyluO8pw4zA3K8ZlrBIbC4FXg3m6z/RNFiUFfT2sQK01+UHA==", + "dev": true, + "dependencies": { + "arr-map": "^2.0.2", + "for-own": "^1.0.0", + "make-iterator": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/colors": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.2.5.tgz", + "integrity": "sha512-erNRLao/Y3Fv54qUa0LBB+//Uf3YwMUmdJinN20yMXm9zdKKqH9wt7R9IIVZ+K7ShzfpLV/Zg8+VyrBJYB4lpg==", + "dev": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/commander": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", + "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", + "dev": true, + "optional": true, + "engines": { + "node": "^12.20.0 || >=14" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/d": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.2.tgz", + "integrity": "sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==", + "dev": true, + "dependencies": { + "es5-ext": "^0.10.64", + "type": "^2.7.2" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-eql": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", + "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", + "dev": true, + "dependencies": { + "type-detect": "^4.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/default-resolution": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/default-resolution/-/default-resolution-2.0.0.tgz", + "integrity": "sha512-2xaP6GiwVwOEbXCGoJ4ufgC76m8cj805jrghScewJC2ZDsb9U0b4BIrba+xt/Uytyd0HvQ6+WymSRTfnYj59GQ==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/diff-match-patch": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/diff-match-patch/-/diff-match-patch-1.0.5.tgz", + "integrity": "sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw==", + "dev": true + }, + "node_modules/diff-sequences": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/dotenv": { + "version": "16.4.5", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", + "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/es5-ext": { + "version": "0.10.64", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.64.tgz", + "integrity": "sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.3", + "esniff": "^2.0.1", + "next-tick": "^1.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", + "dev": true, + "dependencies": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "node_modules/es6-symbol": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.4.tgz", + "integrity": "sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==", + "dev": true, + "dependencies": { + "d": "^1.0.2", + "ext": "^1.7.0" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/es6-weak-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", + "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", + "dev": true, + "dependencies": { + "d": "1", + "es5-ext": "^0.10.46", + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.1" + } + }, + "node_modules/esbuild": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.2.tgz", + "integrity": "sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.20.2", + "@esbuild/android-arm": "0.20.2", + "@esbuild/android-arm64": "0.20.2", + "@esbuild/android-x64": "0.20.2", + "@esbuild/darwin-arm64": "0.20.2", + "@esbuild/darwin-x64": "0.20.2", + "@esbuild/freebsd-arm64": "0.20.2", + "@esbuild/freebsd-x64": "0.20.2", + "@esbuild/linux-arm": "0.20.2", + "@esbuild/linux-arm64": "0.20.2", + "@esbuild/linux-ia32": "0.20.2", + "@esbuild/linux-loong64": "0.20.2", + "@esbuild/linux-mips64el": "0.20.2", + "@esbuild/linux-ppc64": "0.20.2", + "@esbuild/linux-riscv64": "0.20.2", + "@esbuild/linux-s390x": "0.20.2", + "@esbuild/linux-x64": "0.20.2", + "@esbuild/netbsd-x64": "0.20.2", + "@esbuild/openbsd-x64": "0.20.2", + "@esbuild/sunos-x64": "0.20.2", + "@esbuild/win32-arm64": "0.20.2", + "@esbuild/win32-ia32": "0.20.2", + "@esbuild/win32-x64": "0.20.2" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", + "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.0", + "@humanwhocodes/config-array": "^0.11.14", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-plugin-minecraft-linting": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-minecraft-linting/-/eslint-plugin-minecraft-linting-1.2.1.tgz", + "integrity": "sha512-BhWQmo3MHA7/wn0Jl8C8Qexb20ug7xNWqZpFdWIk9FlbMPkUZZsNsf81F0QBU6Ng7Cy+K+OG4R4fqCoG4Zk2eQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/eslint-plugin": "^7.2.0", + "@typescript-eslint/parser": "^7.2.0", + "@typescript-eslint/utils": "^7.2.0", + "eslint": "^8.53.0" + } + }, + "node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/esniff": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/esniff/-/esniff-2.0.1.tgz", + "integrity": "sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==", + "dev": true, + "dependencies": { + "d": "^1.0.1", + "es5-ext": "^0.10.62", + "event-emitter": "^0.3.5", + "type": "^2.7.2" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/event-emitter": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", + "integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==", + "dev": true, + "dependencies": { + "d": "1", + "es5-ext": "~0.10.14" + } + }, + "node_modules/ext": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz", + "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==", + "dev": true, + "dependencies": { + "type": "^2.7.2" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", + "dev": true, + "dependencies": { + "pend": "~1.2.0" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "bin": { + "flat": "cli.js" + } + }, + "node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dev": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", + "dev": true + }, + "node_modules/for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/for-own": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", + "integrity": "sha512-0OABksIGrxKK8K4kynWkQ7y1zounQxP+CWnyclVwj81KW3vlLlGUx57DKGcP/LH216GzqnstnPocF16Nxs0Ycg==", + "dev": true, + "dependencies": { + "for-in": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-func-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", + "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ignore": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-lazy": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-4.0.0.tgz", + "integrity": "sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-core-module": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "dev": true, + "dependencies": { + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jju": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/jju/-/jju-1.4.0.tgz", + "integrity": "sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/js-yaml/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/jsonc-parser": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.1.tgz", + "integrity": "sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==", + "dev": true + }, + "node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/just-scripts": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/just-scripts/-/just-scripts-2.2.3.tgz", + "integrity": "sha512-hL/Xx5zuQRWBWwlFFBZfjKCzhG/gPs3s8HWFPbwa56ieGdvbANkLE0XPpqV1lTDgftg6qKc8mfPGeaCibKwskA==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "diff-match-patch": "1.0.5", + "fs-extra": "^11.0.0", + "glob": "^7.1.3", + "just-scripts-utils": "^2.0.1", + "just-task": ">=1.9.0 <2.0.0", + "prompts": "^2.4.0", + "run-parallel-limit": "^1.0.6", + "semver": "^7.0.0", + "supports-color": "^8.1.0", + "webpack-merge": "^5.7.3" + }, + "bin": { + "just-scripts": "bin/just-scripts.js" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/just-scripts-utils": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/just-scripts-utils/-/just-scripts-utils-2.0.1.tgz", + "integrity": "sha512-1w/XxLA/m90Dx7xZu1+TnBm16wZxOe55Izsi/fH3EIaNOutAYMPwmZiKUrjEAk9qgZUj3t+QMU0Geap0zaM4/g==", + "dev": true, + "dependencies": { + "fs-extra": "^11.0.0", + "just-task-logger": ">=1.2.1 <2.0.0", + "semver": "^7.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/just-scripts-utils/node_modules/fs-extra": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", + "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/just-scripts-utils/node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/just-scripts-utils/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/just-scripts/node_modules/fs-extra": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", + "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/just-scripts/node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/just-scripts/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/just-task": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/just-task/-/just-task-1.9.0.tgz", + "integrity": "sha512-L04cusZ4XAoCRTwARF1CksFM07geurx2M6ccOtxROc9D/OiXsoOXyV2KMsMHmxVIPbFP8wRRVGf2z68UsrBX0g==", + "dev": true, + "dependencies": { + "@rushstack/package-deps-hash": "^4.0.0", + "@types/chokidar": "^2.1.3", + "@types/undertaker": "^1.2.8", + "@types/yargs-parser": "^20.2.2", + "bach": "^2.0.0", + "chalk": "^4.0.0", + "chokidar": "^3.5.2", + "fs-extra": "^11.0.0", + "just-task-logger": ">=1.2.1 <2.0.0", + "resolve": "^1.19.0", + "undertaker": "^1.3.0", + "undertaker-registry": "^2.0.0", + "yargs-parser": "^20.2.3" + }, + "bin": { + "just": "bin/just.js" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/just-task-logger": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/just-task-logger/-/just-task-logger-1.2.1.tgz", + "integrity": "sha512-OnVvMTqOC44cDzIrQ3F43FCYY3OyBscanV6GzKvm3SlaUj0Pvc2F39jNMARrstg7ILIdWkeNg1+iWRxsOfKxeA==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "yargs-parser": "^20.2.3" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/just-task/node_modules/fs-extra": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", + "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/just-task/node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/just-task/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/last-run": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/last-run/-/last-run-1.1.1.tgz", + "integrity": "sha512-U/VxvpX4N/rFvPzr3qG5EtLKEnNI0emvIQB3/ecEwv+8GHaUKbIB8vxv1Oai5FAF0d0r7LXHhLLe5K/yChm5GQ==", + "dev": true, + "dependencies": { + "default-resolution": "^2.0.0", + "es6-weak-map": "^2.0.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/local-pkg": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.4.3.tgz", + "integrity": "sha512-SFppqq5p42fe2qcZQqqEOiVRXl+WCP1MdT6k7BDEW1j++sp5fIY+/fdRQitvKgB5BrBcmrs5m/L0v2FrU5MY1g==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", + "dev": true + }, + "node_modules/lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==", + "dev": true + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/loupe": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", + "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", + "dev": true, + "dependencies": { + "get-func-name": "^2.0.1" + } + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/magic-string": { + "version": "0.30.8", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.8.tgz", + "integrity": "sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ==", + "dev": true, + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.15" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "node_modules/make-iterator": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz", + "integrity": "sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/minimatch": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.8.tgz", + "integrity": "sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/mlly": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.6.1.tgz", + "integrity": "sha512-vLgaHvaeunuOXHSmEbZ9izxPx3USsk8KCQ8iC+aTlp5sKRSoZvwhHh5L9VbKSaVC6sJDqbyohIS76E2VmHIPAA==", + "dev": true, + "dependencies": { + "acorn": "^8.11.3", + "pathe": "^1.1.2", + "pkg-types": "^1.0.3", + "ufo": "^1.3.2" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/next-tick": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", + "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==", + "dev": true + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/now-and-later": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/now-and-later/-/now-and-later-3.0.0.tgz", + "integrity": "sha512-pGO4pzSdaxhWTGkfSfHx3hVzJVslFPwBp2Myq9MYN/ChfJZF87ochMAXnvz6/58RJSf5ik2q9tXprBBrk2cpcg==", + "dev": true, + "dependencies": { + "once": "^1.4.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/object.defaults": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object.defaults/-/object.defaults-1.1.0.tgz", + "integrity": "sha512-c/K0mw/F11k4dEUBMW8naXUuBuhxRCfG7W+yFy8EcijU/rSmazOUd1XAEEe6bC0OuXY4HUKjTJv7xbxIMqdxrA==", + "dev": true, + "dependencies": { + "array-each": "^1.0.1", + "array-slice": "^1.0.0", + "for-own": "^1.0.0", + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object.reduce": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object.reduce/-/object.reduce-1.0.1.tgz", + "integrity": "sha512-naLhxxpUESbNkRqc35oQ2scZSJueHGQNUfMW/0U37IgN6tE2dgDWg3whf+NEliy3F/QysrO48XKUz/nGPe+AQw==", + "dev": true, + "dependencies": { + "for-own": "^1.0.0", + "make-iterator": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/optionator": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "dev": true, + "dependencies": { + "@aashutoshrathi/word-wrap": "^1.2.3", + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/pathe": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", + "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", + "dev": true + }, + "node_modules/pathval": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "dev": true + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pkg-types": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.0.3.tgz", + "integrity": "sha512-nN7pYi0AQqJnoLPC9eHFQ8AcyaixBUOwvqc5TDnIKCMEE6I0y8P7OKA7fPexsXGCGxQDl/cmrLAp26LhcwxZ4A==", + "dev": true, + "dependencies": { + "jsonc-parser": "^3.2.0", + "mlly": "^1.2.0", + "pathe": "^1.1.0" + } + }, + "node_modules/postcss": { + "version": "8.4.38", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz", + "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.0.0", + "source-map-js": "^1.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "dev": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rollup": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.13.0.tgz", + "integrity": "sha512-3YegKemjoQnYKmsBlOHfMLVPPA5xLkQ8MHLLSw/fBrFaVkEayL51DilPpNNLq1exr98F2B1TzrV0FUlN3gWRPg==", + "dev": true, + "dependencies": { + "@types/estree": "1.0.5" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.13.0", + "@rollup/rollup-android-arm64": "4.13.0", + "@rollup/rollup-darwin-arm64": "4.13.0", + "@rollup/rollup-darwin-x64": "4.13.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.13.0", + "@rollup/rollup-linux-arm64-gnu": "4.13.0", + "@rollup/rollup-linux-arm64-musl": "4.13.0", + "@rollup/rollup-linux-riscv64-gnu": "4.13.0", + "@rollup/rollup-linux-x64-gnu": "4.13.0", + "@rollup/rollup-linux-x64-musl": "4.13.0", + "@rollup/rollup-win32-arm64-msvc": "4.13.0", + "@rollup/rollup-win32-ia32-msvc": "4.13.0", + "@rollup/rollup-win32-x64-msvc": "4.13.0", + "fsevents": "~2.3.2" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/run-parallel-limit": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/run-parallel-limit/-/run-parallel-limit-1.1.0.tgz", + "integrity": "sha512-jJA7irRNM91jaKc3Hcl1npHsFLOXOoTkPCUL1JEa1R82O2miplXXRaGdjW/KM/98YQWDhJLiSs793CnXfblJUw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/source-map-js": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", + "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true + }, + "node_modules/std-env": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.7.0.tgz", + "integrity": "sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==", + "dev": true + }, + "node_modules/stream-exhaust": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/stream-exhaust/-/stream-exhaust-1.0.2.tgz", + "integrity": "sha512-b/qaq/GlBK5xaq1yrK9/zFcyRSTNxmcZwFLGSTG0mXgZl/4Z6GgiyYOXOvY7N3eEvFRAG1bkDRz5EPGSvPYQlw==", + "dev": true + }, + "node_modules/string-argv": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", + "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==", + "dev": true, + "engines": { + "node": ">=0.6.19" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-literal": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-1.3.0.tgz", + "integrity": "sha512-PugKzOsyXpArk0yWmUwqOZecSO0GH0bPoctLcqNDH9J04pVW3lflYE0ujElBGTloevcxF5MofAOZ7C5l2b+wLg==", + "dev": true, + "dependencies": { + "acorn": "^8.10.0" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "node_modules/tinybench": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.6.0.tgz", + "integrity": "sha512-N8hW3PG/3aOoZAN5V/NSAEDz0ZixDSSt5b/a05iqtpgfLWMSVuCo7w0k2vVvEjdrIoeGqZzweX2WlyioNIHchA==", + "dev": true + }, + "node_modules/tinypool": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.7.0.tgz", + "integrity": "sha512-zSYNUlYSMhJ6Zdou4cJwo/p7w5nmAH17GRfU/ui3ctvjXFErXXkruT4MWW6poDeXgCaIBlGLrfU6TbTXxyGMww==", + "dev": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tinyspy": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-2.2.1.tgz", + "integrity": "sha512-KYad6Vy5VDWV4GH3fjpseMQ/XU2BhIYP7Vzd0LG44qRWm/Yt2WCOTicFdvmgo6gWaqooMQCawTtILVQJupKu7A==", + "dev": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/ts-api-utils": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", + "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", + "dev": true, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dev": true, + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/type": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", + "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==", + "dev": true + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript": { + "version": "5.4.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.2.tgz", + "integrity": "sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/ufo": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.5.2.tgz", + "integrity": "sha512-eiutMaL0J2MKdhcOM1tUy13pIrYnyR87fEd8STJQFrrAwImwvlXkxlZEjaKah8r2viPohld08lt73QfLG1NxMg==", + "dev": true + }, + "node_modules/undertaker": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/undertaker/-/undertaker-1.3.0.tgz", + "integrity": "sha512-/RXwi5m/Mu3H6IHQGww3GNt1PNXlbeCuclF2QYR14L/2CHPz3DFZkvB5hZ0N/QUkiXWCACML2jXViIQEQc2MLg==", + "dev": true, + "dependencies": { + "arr-flatten": "^1.0.1", + "arr-map": "^2.0.0", + "bach": "^1.0.0", + "collection-map": "^1.0.0", + "es6-weak-map": "^2.0.1", + "fast-levenshtein": "^1.0.0", + "last-run": "^1.1.0", + "object.defaults": "^1.0.0", + "object.reduce": "^1.0.0", + "undertaker-registry": "^1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/undertaker-registry": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/undertaker-registry/-/undertaker-registry-2.0.0.tgz", + "integrity": "sha512-+hhVICbnp+rlzZMgxXenpvTxpuvA67Bfgtt+O9WOE5jo7w/dyiF1VmoZVIHvP2EkUjsyKyTwYKlLhA+j47m1Ew==", + "dev": true, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/undertaker/node_modules/async-settle": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-settle/-/async-settle-1.0.0.tgz", + "integrity": "sha512-VPXfB4Vk49z1LHHodrEQ6Xf7W4gg1w0dAPROHngx7qgDjqmIQ+fXmwgGXTW/ITLai0YLSvWepJOP9EVpMnEAcw==", + "dev": true, + "dependencies": { + "async-done": "^1.2.2" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/undertaker/node_modules/bach": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/bach/-/bach-1.2.0.tgz", + "integrity": "sha512-bZOOfCb3gXBXbTFXq3OZtGR88LwGeJvzu6szttaIzymOTS4ZttBNOWSv7aLZja2EMycKtRYV0Oa8SNKH/zkxvg==", + "dev": true, + "dependencies": { + "arr-filter": "^1.1.1", + "arr-flatten": "^1.0.1", + "arr-map": "^2.0.0", + "array-each": "^1.0.0", + "array-initial": "^1.0.0", + "array-last": "^1.1.1", + "async-done": "^1.2.2", + "async-settle": "^1.0.0", + "now-and-later": "^2.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/undertaker/node_modules/fast-levenshtein": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-1.1.4.tgz", + "integrity": "sha512-Ia0sQNrMPXXkqVFt6w6M1n1oKo3NfKs+mvaV811Jwir7vAk9a6PVV9VPYf6X3BU97QiLEmuW3uXH9u87zDFfdw==", + "dev": true + }, + "node_modules/undertaker/node_modules/now-and-later": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/now-and-later/-/now-and-later-2.0.1.tgz", + "integrity": "sha512-KGvQ0cB70AQfg107Xvs/Fbu+dGmZoTRJp2TaPwcwQm3/7PteUyN2BCgk8KBMPGBUXZdVwyWS8fDCGFygBm19UQ==", + "dev": true, + "dependencies": { + "once": "^1.3.2" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/undertaker/node_modules/undertaker-registry": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/undertaker-registry/-/undertaker-registry-1.0.1.tgz", + "integrity": "sha512-UR1khWeAjugW3548EfQmL9Z7pGMlBgXteQpr1IZeZBtnkCJQJIJ1Scj0mb9wQaPvUZ9Q17XqW6TIaPchJkyfqw==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "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==", + "dev": true + }, + "node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true + }, + "node_modules/validator": { + "version": "13.11.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.11.0.tgz", + "integrity": "sha512-Ii+sehpSfZy+At5nPdnyMhx78fEoPDkR2XW/zimHEL3MyGJQOCQ7WeP20jPYRz7ZCpcKLB21NxuXHF3bxjStBQ==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/vite": { + "version": "5.2.10", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.10.tgz", + "integrity": "sha512-PAzgUZbP7msvQvqdSD+ErD5qGnSFiGOoWmV5yAKUEI0kdhjbH6nMWVyZQC/hSc4aXwc0oJ9aEdIiF9Oje0JFCw==", + "dev": true, + "dependencies": { + "esbuild": "^0.20.1", + "postcss": "^8.4.38", + "rollup": "^4.13.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/vite-node": { + "version": "0.34.6", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-0.34.6.tgz", + "integrity": "sha512-nlBMJ9x6n7/Amaz6F3zJ97EBwR2FkzhBRxF5e+jE6LA3yi6Wtc2lyTij1OnDMIr34v5g/tVQtsVAzhT0jc5ygA==", + "dev": true, + "dependencies": { + "cac": "^6.7.14", + "debug": "^4.3.4", + "mlly": "^1.4.0", + "pathe": "^1.1.1", + "picocolors": "^1.0.0", + "vite": "^3.0.0 || ^4.0.0 || ^5.0.0-0" + }, + "bin": { + "vite-node": "vite-node.mjs" + }, + "engines": { + "node": ">=v14.18.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/vitest": { + "version": "0.34.6", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-0.34.6.tgz", + "integrity": "sha512-+5CALsOvbNKnS+ZHMXtuUC7nL8/7F1F2DnHGjSsszX8zCjWSSviphCb/NuS9Nzf4Q03KyyDRBAXhF/8lffME4Q==", + "dev": true, + "dependencies": { + "@types/chai": "^4.3.5", + "@types/chai-subset": "^1.3.3", + "@types/node": "*", + "@vitest/expect": "0.34.6", + "@vitest/runner": "0.34.6", + "@vitest/snapshot": "0.34.6", + "@vitest/spy": "0.34.6", + "@vitest/utils": "0.34.6", + "acorn": "^8.9.0", + "acorn-walk": "^8.2.0", + "cac": "^6.7.14", + "chai": "^4.3.10", + "debug": "^4.3.4", + "local-pkg": "^0.4.3", + "magic-string": "^0.30.1", + "pathe": "^1.1.1", + "picocolors": "^1.0.0", + "std-env": "^3.3.3", + "strip-literal": "^1.0.1", + "tinybench": "^2.5.0", + "tinypool": "^0.7.0", + "vite": "^3.1.0 || ^4.0.0 || ^5.0.0-0", + "vite-node": "0.34.6", + "why-is-node-running": "^2.2.2" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": ">=v14.18.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@vitest/browser": "*", + "@vitest/ui": "*", + "happy-dom": "*", + "jsdom": "*", + "playwright": "*", + "safaridriver": "*", + "webdriverio": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@vitest/browser": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + }, + "playwright": { + "optional": true + }, + "safaridriver": { + "optional": true + }, + "webdriverio": { + "optional": true + } + } + }, + "node_modules/webpack-merge": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", + "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "dev": true, + "dependencies": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/why-is-node-running": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.2.2.tgz", + "integrity": "sha512-6tSwToZxTOcotxHeA+qGCq1mVzKR3CwcJGmVcY+QE8SHy6TnpFnh8PAvPNHYr7EcuVeG0QSMxtYCuO1ta/G/oA==", + "dev": true, + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wildcard": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", + "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", + "dev": true + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "dev": true, + "dependencies": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, + "node_modules/yazl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/yazl/-/yazl-2.5.1.tgz", + "integrity": "sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw==", + "dev": true, + "dependencies": { + "buffer-crc32": "~0.2.3" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/z-schema": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/z-schema/-/z-schema-5.0.5.tgz", + "integrity": "sha512-D7eujBWkLa3p2sIpJA0d1pr7es+a7m0vFAnZLlCEKq/Ij2k0MLi9Br2UPxoxdYystm5K1yeBGzub0FlYUEWj2Q==", + "dev": true, + "dependencies": { + "lodash.get": "^4.4.2", + "lodash.isequal": "^4.5.0", + "validator": "^13.7.0" + }, + "bin": { + "z-schema": "bin/z-schema" + }, + "engines": { + "node": ">=8.0.0" + }, + "optionalDependencies": { + "commander": "^9.4.1" + } + }, + "node_modules/zip-lib": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/zip-lib/-/zip-lib-0.7.3.tgz", + "integrity": "sha512-hp40KYzTJvoaCRr2t6hztlPnVmHYqDUDiIn0hlfAFwVBs3/jwkLy8aZ7NVGHECeWH2Tv8WPwWyR6QuWYarIjJQ==", + "dev": true, + "dependencies": { + "yauzl": "^2.10.0", + "yazl": "^2.5.1" + }, + "engines": { + "node": ">=8" + } + } + } +} \ No newline at end of file diff --git a/app/test/scenarios/createCommandAddonStarter/package.json b/app/test/scenarios/createCommandAddonStarter/package.json new file mode 100644 index 00000000..ad87ae84 --- /dev/null +++ b/app/test/scenarios/createCommandAddonStarter/package.json @@ -0,0 +1,29 @@ +{ + "name": "testerName", + "version": "0.1.0", + "productName": "Minecraft Add-On Starter Project", + "description": "testerDescription", + "private": true, + "devDependencies": { + "@minecraft/core-build-tasks": "^1.1.3", + "eslint-plugin-minecraft-linting": "^1.2.1", + "source-map": "^0.7.4", + "ts-node": "^10.9.1", + "typescript": "^5.0.2" + }, + "scripts": { + "lint": "just-scripts lint", + "build": "just-scripts build", + "clean": "just-scripts clean", + "local-deploy": "just-scripts local-deploy", + "mcaddon": "just-scripts mcaddon", + "enablemcloopback": "CheckNetIsolation.exe LoopbackExempt -a -p=S-1-15-2-1958404141-86561845-1752920682-3514627264-368642714-62675701-733520436", + "enablemcpreviewloopback": "CheckNetIsolation.exe LoopbackExempt -a -p=S-1-15-2-424268864-5579737-879501358-346833251-474568803-887069379-4040235476" + }, + "dependencies": { + "@minecraft/math": "^1.1.0", + "@minecraft/server": "^1.8.0", + "@minecraft/server-ui": "^1.1.0", + "@minecraft/vanilla-data": "^1.20.60" + } +} \ No newline at end of file diff --git a/app/test/scenarios/createCommandAddonStarter/resource_packs/cn_test/manifest.json b/app/test/scenarios/createCommandAddonStarter/resource_packs/cn_test/manifest.json new file mode 100644 index 00000000..b6107c20 --- /dev/null +++ b/app/test/scenarios/createCommandAddonStarter/resource_packs/cn_test/manifest.json @@ -0,0 +1,40 @@ +{ + "format_version": 2, + "header": { + "name": "testerName", + "description": "testerDescription", + "uuid": "1d728d92-dfd8-4f90-8aac-176d6d0e00dc", + "version": [ + 1, + 0, + 0 + ], + "min_engine_version": [ + 1, + 21, + 20 + ] + }, + "modules": [ + { + "description": "Add-on Pack Resources", + "type": "resources", + "uuid": "523d72d2-3ba9-498a-bc63-8beb5fe268cb", + "version": [ + 1, + 0, + 0 + ] + } + ], + "dependencies": [ + { + "uuid": "9ec8af93-4b38-429f-a4bd-7e277a50d238", + "version": [ + 1, + 0, + 0 + ] + } + ] +} \ No newline at end of file diff --git a/app/test/scenarios/createCommandAddonStarter/resource_packs/cn_test/pack_icon.png b/app/test/scenarios/createCommandAddonStarter/resource_packs/cn_test/pack_icon.png new file mode 100644 index 00000000..a28f3eaa Binary files /dev/null and b/app/test/scenarios/createCommandAddonStarter/resource_packs/cn_test/pack_icon.png differ diff --git a/app/test/scenarios/createCommandAddonStarter/scripts/main.ts b/app/test/scenarios/createCommandAddonStarter/scripts/main.ts new file mode 100644 index 00000000..ffe13b36 --- /dev/null +++ b/app/test/scenarios/createCommandAddonStarter/scripts/main.ts @@ -0,0 +1,10 @@ +import { world, system } from "@minecraft/server"; + +function mainTick() { + + // add main loop code here. + system.run(mainTick); +} + +// Uncomment the line below to ensure your main tick code is called from the start. +// system.run(mainTick); diff --git a/app/test/scenarios/createCommandAddonStarter/tsconfig.json b/app/test/scenarios/createCommandAddonStarter/tsconfig.json new file mode 100644 index 00000000..94214dac --- /dev/null +++ b/app/test/scenarios/createCommandAddonStarter/tsconfig.json @@ -0,0 +1,35 @@ +{ + "compilerOptions": { + "target": "es6", + "moduleResolution": "Node", + "module": "ES2020", + "declaration": false, + "noLib": false, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "sourceMap": true, + "pretty": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "allowUnreachableCode": true, + "allowUnusedLabels": true, + "noImplicitAny": true, + "noImplicitReturns": false, + "noImplicitUseStrict": false, + "outDir": "lib", + "rootDir": ".", + "baseUrl": "behavior_packs/", + "listFiles": false, + "noEmitHelpers": true, + "skipLibCheck": true + }, + "include": [ + "scripts/**/*" + ], + "exclude": [ + "lib", + "dist", + "node_modules" + ], + "compileOnSave": false +} \ No newline at end of file diff --git a/app/test/scenarios/simple/report.json b/app/test/scenarios/simple/report.json index 7dbbf9e3..7710ec9b 100644 --- a/app/test/scenarios/simple/report.json +++ b/app/test/scenarios/simple/report.json @@ -21,6 +21,7 @@ "defaultBehaviorPackMinEngineVersion": "1.20.10", "defaultBehaviorPackName": "Starter Hello World Tests", "defaultBehaviorPackDescription": "Introductory tests for Minecraft GameTest Framework.", + "animationCount": 0, "textureCount": 0, "chunkCount": 0, "subchunkLessChunkCount": 0, @@ -211,6 +212,14 @@ "testCompleteSuccesses": 1 } }, + "RESOURCEANIMATION": { + "1": { + "title": "Animations" + }, + "2": { + "title": "Bones" + } + }, "BPENTITYTYPE": { "2": { "title": "Entity Type Runtime Identifier" @@ -579,6 +588,16 @@ "gId": "BASEGAMEVER", "gIx": 260 }, + { + "iTp": 7, + "gId": "RESOURCEANIMATION", + "gIx": 1 + }, + { + "iTp": 7, + "gId": "RESOURCEANIMATION", + "gIx": 2 + }, { "iTp": 7, "gId": "BPENTITYTYPE", diff --git a/app/test/scenarios/validateAddons1WellFormedCommand/content1.mcr.json b/app/test/scenarios/validateAddons1WellFormedCommand/content1.mcr.json index 79ec49de..b502a1c7 100644 --- a/app/test/scenarios/validateAddons1WellFormedCommand/content1.mcr.json +++ b/app/test/scenarios/validateAddons1WellFormedCommand/content1.mcr.json @@ -16,6 +16,7 @@ "contentSize": 54260, "contentFileCounts": 37, "contentFolderCounts": 18, + "animationCount": 0, "textureCount": 0, "chunkCount": 0, "subchunkLessChunkCount": 0, diff --git a/app/test/scenarios/validateAddons1WellFormedCommand/content1.report.html b/app/test/scenarios/validateAddons1WellFormedCommand/content1.report.html index 42afff48..eb2e32af 100644 --- a/app/test/scenarios/validateAddons1WellFormedCommand/content1.report.html +++ b/app/test/scenarios/validateAddons1WellFormedCommand/content1.report.html @@ -6,7 +6,7 @@ _reportObjects.push(data); } -_addReportJson({"info":{"behaviorPackManifestCount":0,"unknownJsonCount":0,"entityTypeManifestCount":0,"itemTypeManifestCount":0,"blockTypeManifestCount":0,"resourcePackManifestCount":0,"worldCount":0,"entityTypeResourceCount":0,"behaviorPackAnimationCount":0,"behaviorPackAnimationControllerCount":0,"overallSize":54260,"fileCounts":37,"folderCounts":23,"contentSize":54260,"contentFileCounts":37,"contentFolderCounts":18,"textureCount":0,"chunkCount":0,"subchunkLessChunkCount":0,"worldLoadErrors":0,"featureSets":{"Textures Entity Resource Count":{"Count":3},"Textures Texture References":{"Count":3},"Textures Entity References":{"Count":3},"Textures File Count":{"Count":4},"Textures Unique Texture Handles (estimated)":{"Count":3},"Textures Unique Texture Paths":{"Count":3},"Textures Unique Particle Texture Paths":{"Count":0},"Textures Unique Particle Texture Vanilla Paths":{"Count":1},"Textures Unique Entity Texture Paths":{"Count":3},"Command say":{"Count":1},"Command summon":{"Count":1}},"summary":{"PACKSIZE":{"1":{"title":"Overall Size"},"2":{"title":"Overall File Count","defaultMessage":"File Counts"},"3":{"title":"Overall Folder Count","defaultMessage":"Folder Counts"},"4":{"title":"Content Size"},"5":{"title":"Content File Count","defaultMessage":"Content File Counts"},"6":{"title":"Content Folder Count","defaultMessage":"Content Folder Counts"}},"ADDONREQ":{"102":{"title":"102","defaultMessage":"Found an add-on-blocked folder 'entities' in a parent folder pack\\loot_tables. Should be named 'creatorshortname' and not a common term","testCompleteFails":1},"104":{"title":"104","defaultMessage":"Found a loose file 'sheepomelon.json' in loot_tables\\entities. Files should only be in the folder loot_tables\\entities\\","testCompleteFails":2}},"TEXTURE":{"1":{"title":"Textures"}},"WORLDDATA":{"1":{"defaultMessage":"Blocks","testCompleteSuccesses":1},"2":{"defaultMessage":"Block Data"},"3":{"defaultMessage":"Commands"},"4":{"defaultMessage":"Execute Sub Commands"},"5":{"defaultMessage":"NBT Tags"},"6":{"defaultMessage":"NBT Experiment Tags"}},"ADDONIREQ":{"1":{"defaultMessage":"Test Addon Item Requirements Generator completed successfully.","testCompleteSuccesses":1}}}},"items":[{"iTp":7,"gId":"PACKSIZE","gIx":1,"d":54260},{"iTp":7,"gId":"PACKSIZE","gIx":2,"d":37},{"iTp":7,"gId":"PACKSIZE","gIx":3,"d":23},{"iTp":7,"gId":"PACKSIZE","gIx":4,"d":54260},{"iTp":7,"gId":"PACKSIZE","gIx":5,"d":37},{"iTp":7,"gId":"PACKSIZE","gIx":6,"d":18},{"iTp":1,"gId":"ADDONREQ","gIx":102,"d":"entities"},{"iTp":1,"gId":"ADDONREQ","gIx":104,"d":"sheepomelon.json"},{"iTp":1,"gId":"ADDONREQ","gIx":104,"m":"Found a loose file 'sheepomelon_shear.json' in loot_tables\\entities. Files should only be in the folder loot_tables\\entities\\","d":"sheepomelon_shear.json"},{"iTp":7,"gId":"TEXTURE","gIx":1,"fs":{"Entity Resource Count":{"Count":3},"Texture References":{"Count":3},"Entity References":{"Count":3},"File Count":{"Count":4},"Unique Texture Handles (estimated)":{"Count":3},"Unique Texture Paths":{"Count":3},"Unique Particle Texture Paths":{"Count":0},"Unique Particle Texture Vanilla Paths":{"Count":1},"Unique Entity Texture Paths":{"Count":3}}},{"iTp":7,"gId":"WORLDDATA","gIx":1,"p":"/Content/behavior_packs/aop_mobsbp/"},{"iTp":7,"gId":"WORLDDATA","gIx":2,"p":"/Content/behavior_packs/aop_mobsbp/"},{"iTp":7,"gId":"WORLDDATA","gIx":3,"p":"/Content/behavior_packs/aop_mobsbp/"},{"iTp":7,"gId":"WORLDDATA","gIx":4,"p":"/Content/behavior_packs/aop_mobsbp/"},{"iTp":7,"gId":"WORLDDATA","gIx":5,"p":"/Content/behavior_packs/aop_mobsbp/"},{"iTp":7,"gId":"WORLDDATA","gIx":6,"p":"/Content/behavior_packs/aop_mobsbp/"},{"iTp":7,"gId":"WORLDDATA","gIx":1,"p":"/Content/behavior_packs/aop_mobsbp/manifest.json"},{"iTp":7,"gId":"WORLDDATA","gIx":2,"p":"/Content/behavior_packs/aop_mobsbp/manifest.json"},{"iTp":7,"gId":"WORLDDATA","gIx":3,"p":"/Content/behavior_packs/aop_mobsbp/manifest.json"},{"iTp":7,"gId":"WORLDDATA","gIx":4,"p":"/Content/behavior_packs/aop_mobsbp/manifest.json"},{"iTp":7,"gId":"WORLDDATA","gIx":5,"p":"/Content/behavior_packs/aop_mobsbp/manifest.json"},{"iTp":7,"gId":"WORLDDATA","gIx":6,"p":"/Content/behavior_packs/aop_mobsbp/manifest.json"},{"iTp":7,"gId":"WORLDDATA","gIx":1,"p":"/Content/behavior_packs/aop_mobsbp/animations/sheepomelon.bp_anims.json"},{"iTp":7,"gId":"WORLDDATA","gIx":2,"p":"/Content/behavior_packs/aop_mobsbp/animations/sheepomelon.bp_anims.json"},{"iTp":7,"gId":"WORLDDATA","gIx":3,"p":"/Content/behavior_packs/aop_mobsbp/animations/sheepomelon.bp_anims.json","fs":{"say":{"Count":1},"summon":{"Count":1}}},{"iTp":7,"gId":"WORLDDATA","gIx":4,"p":"/Content/behavior_packs/aop_mobsbp/animations/sheepomelon.bp_anims.json"},{"iTp":7,"gId":"WORLDDATA","gIx":5,"p":"/Content/behavior_packs/aop_mobsbp/animations/sheepomelon.bp_anims.json"},{"iTp":7,"gId":"WORLDDATA","gIx":6,"p":"/Content/behavior_packs/aop_mobsbp/animations/sheepomelon.bp_anims.json"},{"iTp":7,"gId":"WORLDDATA","gIx":1,"p":"/Content/behavior_packs/aop_mobsbp/animation_controllers/sheepomelon.bp_ac.json"},{"iTp":7,"gId":"WORLDDATA","gIx":2,"p":"/Content/behavior_packs/aop_mobsbp/animation_controllers/sheepomelon.bp_ac.json"},{"iTp":7,"gId":"WORLDDATA","gIx":3,"p":"/Content/behavior_packs/aop_mobsbp/animation_controllers/sheepomelon.bp_ac.json"},{"iTp":7,"gId":"WORLDDATA","gIx":4,"p":"/Content/behavior_packs/aop_mobsbp/animation_controllers/sheepomelon.bp_ac.json"},{"iTp":7,"gId":"WORLDDATA","gIx":5,"p":"/Content/behavior_packs/aop_mobsbp/animation_controllers/sheepomelon.bp_ac.json"},{"iTp":7,"gId":"WORLDDATA","gIx":6,"p":"/Content/behavior_packs/aop_mobsbp/animation_controllers/sheepomelon.bp_ac.json"},{"iTp":7,"gId":"WORLDDATA","gIx":1,"p":"/Content/behavior_packs/aop_mobsbp/entities/biceson.behavior.json"},{"iTp":7,"gId":"WORLDDATA","gIx":2,"p":"/Content/behavior_packs/aop_mobsbp/entities/biceson.behavior.json"},{"iTp":7,"gId":"WORLDDATA","gIx":3,"p":"/Content/behavior_packs/aop_mobsbp/entities/biceson.behavior.json"},{"iTp":7,"gId":"WORLDDATA","gIx":4,"p":"/Content/behavior_packs/aop_mobsbp/entities/biceson.behavior.json"},{"iTp":7,"gId":"WORLDDATA","gIx":5,"p":"/Content/behavior_packs/aop_mobsbp/entities/biceson.behavior.json"},{"iTp":7,"gId":"WORLDDATA","gIx":6,"p":"/Content/behavior_packs/aop_mobsbp/entities/biceson.behavior.json"},{"iTp":7,"gId":"WORLDDATA","gIx":1,"p":"/Content/behavior_packs/aop_mobsbp/entities/nardolphle.behavior.json"},{"iTp":7,"gId":"WORLDDATA","gIx":2,"p":"/Content/behavior_packs/aop_mobsbp/entities/nardolphle.behavior.json"},{"iTp":7,"gId":"WORLDDATA","gIx":3,"p":"/Content/behavior_packs/aop_mobsbp/entities/nardolphle.behavior.json"},{"iTp":7,"gId":"WORLDDATA","gIx":4,"p":"/Content/behavior_packs/aop_mobsbp/entities/nardolphle.behavior.json"},{"iTp":7,"gId":"WORLDDATA","gIx":5,"p":"/Content/behavior_packs/aop_mobsbp/entities/nardolphle.behavior.json"},{"iTp":7,"gId":"WORLDDATA","gIx":6,"p":"/Content/behavior_packs/aop_mobsbp/entities/nardolphle.behavior.json"},{"iTp":7,"gId":"WORLDDATA","gIx":1,"p":"/Content/behavior_packs/aop_mobsbp/entities/sheepomelon.behavior.json"},{"iTp":7,"gId":"WORLDDATA","gIx":2,"p":"/Content/behavior_packs/aop_mobsbp/entities/sheepomelon.behavior.json"},{"iTp":7,"gId":"WORLDDATA","gIx":3,"p":"/Content/behavior_packs/aop_mobsbp/entities/sheepomelon.behavior.json"},{"iTp":7,"gId":"WORLDDATA","gIx":4,"p":"/Content/behavior_packs/aop_mobsbp/entities/sheepomelon.behavior.json"},{"iTp":7,"gId":"WORLDDATA","gIx":5,"p":"/Content/behavior_packs/aop_mobsbp/entities/sheepomelon.behavior.json"},{"iTp":7,"gId":"WORLDDATA","gIx":6,"p":"/Content/behavior_packs/aop_mobsbp/entities/sheepomelon.behavior.json"},{"iTp":7,"gId":"WORLDDATA","gIx":1,"p":"/Content/behavior_packs/aop_mobsbp/loot_tables/entities/sheepomelon.json"},{"iTp":7,"gId":"WORLDDATA","gIx":2,"p":"/Content/behavior_packs/aop_mobsbp/loot_tables/entities/sheepomelon.json"},{"iTp":7,"gId":"WORLDDATA","gIx":3,"p":"/Content/behavior_packs/aop_mobsbp/loot_tables/entities/sheepomelon.json"},{"iTp":7,"gId":"WORLDDATA","gIx":4,"p":"/Content/behavior_packs/aop_mobsbp/loot_tables/entities/sheepomelon.json"},{"iTp":7,"gId":"WORLDDATA","gIx":5,"p":"/Content/behavior_packs/aop_mobsbp/loot_tables/entities/sheepomelon.json"},{"iTp":7,"gId":"WORLDDATA","gIx":6,"p":"/Content/behavior_packs/aop_mobsbp/loot_tables/entities/sheepomelon.json"},{"iTp":7,"gId":"WORLDDATA","gIx":1,"p":"/Content/behavior_packs/aop_mobsbp/loot_tables/entities/sheepomelon_shear.json"},{"iTp":7,"gId":"WORLDDATA","gIx":2,"p":"/Content/behavior_packs/aop_mobsbp/loot_tables/entities/sheepomelon_shear.json"},{"iTp":7,"gId":"WORLDDATA","gIx":3,"p":"/Content/behavior_packs/aop_mobsbp/loot_tables/entities/sheepomelon_shear.json"},{"iTp":7,"gId":"WORLDDATA","gIx":4,"p":"/Content/behavior_packs/aop_mobsbp/loot_tables/entities/sheepomelon_shear.json"},{"iTp":7,"gId":"WORLDDATA","gIx":5,"p":"/Content/behavior_packs/aop_mobsbp/loot_tables/entities/sheepomelon_shear.json"},{"iTp":7,"gId":"WORLDDATA","gIx":6,"p":"/Content/behavior_packs/aop_mobsbp/loot_tables/entities/sheepomelon_shear.json"},{"iTp":7,"gId":"WORLDDATA","gIx":1,"p":"/Content/behavior_packs/aop_mobsbp/spawn_rules/biceson.json"},{"iTp":7,"gId":"WORLDDATA","gIx":2,"p":"/Content/behavior_packs/aop_mobsbp/spawn_rules/biceson.json"},{"iTp":7,"gId":"WORLDDATA","gIx":3,"p":"/Content/behavior_packs/aop_mobsbp/spawn_rules/biceson.json"},{"iTp":7,"gId":"WORLDDATA","gIx":4,"p":"/Content/behavior_packs/aop_mobsbp/spawn_rules/biceson.json"},{"iTp":7,"gId":"WORLDDATA","gIx":5,"p":"/Content/behavior_packs/aop_mobsbp/spawn_rules/biceson.json"},{"iTp":7,"gId":"WORLDDATA","gIx":6,"p":"/Content/behavior_packs/aop_mobsbp/spawn_rules/biceson.json"},{"iTp":7,"gId":"WORLDDATA","gIx":1,"p":"/Content/behavior_packs/aop_mobsbp/spawn_rules/nardolphle.json"},{"iTp":7,"gId":"WORLDDATA","gIx":2,"p":"/Content/behavior_packs/aop_mobsbp/spawn_rules/nardolphle.json"},{"iTp":7,"gId":"WORLDDATA","gIx":3,"p":"/Content/behavior_packs/aop_mobsbp/spawn_rules/nardolphle.json"},{"iTp":7,"gId":"WORLDDATA","gIx":4,"p":"/Content/behavior_packs/aop_mobsbp/spawn_rules/nardolphle.json"},{"iTp":7,"gId":"WORLDDATA","gIx":5,"p":"/Content/behavior_packs/aop_mobsbp/spawn_rules/nardolphle.json"},{"iTp":7,"gId":"WORLDDATA","gIx":6,"p":"/Content/behavior_packs/aop_mobsbp/spawn_rules/nardolphle.json"},{"iTp":7,"gId":"WORLDDATA","gIx":1,"p":"/Content/behavior_packs/aop_mobsbp/spawn_rules/sheepomelon.json"},{"iTp":7,"gId":"WORLDDATA","gIx":2,"p":"/Content/behavior_packs/aop_mobsbp/spawn_rules/sheepomelon.json"},{"iTp":7,"gId":"WORLDDATA","gIx":3,"p":"/Content/behavior_packs/aop_mobsbp/spawn_rules/sheepomelon.json"},{"iTp":7,"gId":"WORLDDATA","gIx":4,"p":"/Content/behavior_packs/aop_mobsbp/spawn_rules/sheepomelon.json"},{"iTp":7,"gId":"WORLDDATA","gIx":5,"p":"/Content/behavior_packs/aop_mobsbp/spawn_rules/sheepomelon.json"},{"iTp":7,"gId":"WORLDDATA","gIx":6,"p":"/Content/behavior_packs/aop_mobsbp/spawn_rules/sheepomelon.json"},{"iTp":7,"gId":"WORLDDATA","gIx":1,"p":"/Content/behavior_packs/aop_mobsbp/texts/en_US.lang"},{"iTp":7,"gId":"WORLDDATA","gIx":2,"p":"/Content/behavior_packs/aop_mobsbp/texts/en_US.lang"},{"iTp":7,"gId":"WORLDDATA","gIx":3,"p":"/Content/behavior_packs/aop_mobsbp/texts/en_US.lang"},{"iTp":7,"gId":"WORLDDATA","gIx":4,"p":"/Content/behavior_packs/aop_mobsbp/texts/en_US.lang"},{"iTp":7,"gId":"WORLDDATA","gIx":5,"p":"/Content/behavior_packs/aop_mobsbp/texts/en_US.lang"},{"iTp":7,"gId":"WORLDDATA","gIx":6,"p":"/Content/behavior_packs/aop_mobsbp/texts/en_US.lang"},{"iTp":7,"gId":"WORLDDATA","gIx":1,"p":"/Content/behavior_packs/aop_mobsbp/texts/languages.json"},{"iTp":7,"gId":"WORLDDATA","gIx":2,"p":"/Content/behavior_packs/aop_mobsbp/texts/languages.json"},{"iTp":7,"gId":"WORLDDATA","gIx":3,"p":"/Content/behavior_packs/aop_mobsbp/texts/languages.json"},{"iTp":7,"gId":"WORLDDATA","gIx":4,"p":"/Content/behavior_packs/aop_mobsbp/texts/languages.json"},{"iTp":7,"gId":"WORLDDATA","gIx":5,"p":"/Content/behavior_packs/aop_mobsbp/texts/languages.json"},{"iTp":7,"gId":"WORLDDATA","gIx":6,"p":"/Content/behavior_packs/aop_mobsbp/texts/languages.json"},{"iTp":7,"gId":"WORLDDATA","gIx":1,"p":"/Content/resource_packs/aop_mobsrp/"},{"iTp":7,"gId":"WORLDDATA","gIx":2,"p":"/Content/resource_packs/aop_mobsrp/"},{"iTp":7,"gId":"WORLDDATA","gIx":3,"p":"/Content/resource_packs/aop_mobsrp/"},{"iTp":7,"gId":"WORLDDATA","gIx":4,"p":"/Content/resource_packs/aop_mobsrp/"},{"iTp":7,"gId":"WORLDDATA","gIx":5,"p":"/Content/resource_packs/aop_mobsrp/"},{"iTp":7,"gId":"WORLDDATA","gIx":6,"p":"/Content/resource_packs/aop_mobsrp/"},{"iTp":7,"gId":"WORLDDATA","gIx":1,"p":"/Content/resource_packs/aop_mobsrp/manifest.json"},{"iTp":7,"gId":"WORLDDATA","gIx":2,"p":"/Content/resource_packs/aop_mobsrp/manifest.json"},{"iTp":7,"gId":"WORLDDATA","gIx":3,"p":"/Content/resource_packs/aop_mobsrp/manifest.json"},{"iTp":7,"gId":"WORLDDATA","gIx":4,"p":"/Content/resource_packs/aop_mobsrp/manifest.json"},{"iTp":7,"gId":"WORLDDATA","gIx":5,"p":"/Content/resource_packs/aop_mobsrp/manifest.json"},{"iTp":7,"gId":"WORLDDATA","gIx":6,"p":"/Content/resource_packs/aop_mobsrp/manifest.json"},{"iTp":7,"gId":"WORLDDATA","gIx":1,"p":"/Content/resource_packs/aop_mobsrp/sounds.json"},{"iTp":7,"gId":"WORLDDATA","gIx":2,"p":"/Content/resource_packs/aop_mobsrp/sounds.json"},{"iTp":7,"gId":"WORLDDATA","gIx":3,"p":"/Content/resource_packs/aop_mobsrp/sounds.json"},{"iTp":7,"gId":"WORLDDATA","gIx":4,"p":"/Content/resource_packs/aop_mobsrp/sounds.json"},{"iTp":7,"gId":"WORLDDATA","gIx":5,"p":"/Content/resource_packs/aop_mobsrp/sounds.json"},{"iTp":7,"gId":"WORLDDATA","gIx":6,"p":"/Content/resource_packs/aop_mobsrp/sounds.json"},{"iTp":7,"gId":"WORLDDATA","gIx":1,"p":"/Content/resource_packs/aop_mobsrp/animations/biceson.animation.json"},{"iTp":7,"gId":"WORLDDATA","gIx":2,"p":"/Content/resource_packs/aop_mobsrp/animations/biceson.animation.json"},{"iTp":7,"gId":"WORLDDATA","gIx":3,"p":"/Content/resource_packs/aop_mobsrp/animations/biceson.animation.json"},{"iTp":7,"gId":"WORLDDATA","gIx":4,"p":"/Content/resource_packs/aop_mobsrp/animations/biceson.animation.json"},{"iTp":7,"gId":"WORLDDATA","gIx":5,"p":"/Content/resource_packs/aop_mobsrp/animations/biceson.animation.json"},{"iTp":7,"gId":"WORLDDATA","gIx":6,"p":"/Content/resource_packs/aop_mobsrp/animations/biceson.animation.json"},{"iTp":7,"gId":"WORLDDATA","gIx":1,"p":"/Content/resource_packs/aop_mobsrp/animations/nardolphle.animation.json"},{"iTp":7,"gId":"WORLDDATA","gIx":2,"p":"/Content/resource_packs/aop_mobsrp/animations/nardolphle.animation.json"},{"iTp":7,"gId":"WORLDDATA","gIx":3,"p":"/Content/resource_packs/aop_mobsrp/animations/nardolphle.animation.json"},{"iTp":7,"gId":"WORLDDATA","gIx":4,"p":"/Content/resource_packs/aop_mobsrp/animations/nardolphle.animation.json"},{"iTp":7,"gId":"WORLDDATA","gIx":5,"p":"/Content/resource_packs/aop_mobsrp/animations/nardolphle.animation.json"},{"iTp":7,"gId":"WORLDDATA","gIx":6,"p":"/Content/resource_packs/aop_mobsrp/animations/nardolphle.animation.json"},{"iTp":7,"gId":"WORLDDATA","gIx":1,"p":"/Content/resource_packs/aop_mobsrp/animations/sheepomelon.animation.json"},{"iTp":7,"gId":"WORLDDATA","gIx":2,"p":"/Content/resource_packs/aop_mobsrp/animations/sheepomelon.animation.json"},{"iTp":7,"gId":"WORLDDATA","gIx":3,"p":"/Content/resource_packs/aop_mobsrp/animations/sheepomelon.animation.json"},{"iTp":7,"gId":"WORLDDATA","gIx":4,"p":"/Content/resource_packs/aop_mobsrp/animations/sheepomelon.animation.json"},{"iTp":7,"gId":"WORLDDATA","gIx":5,"p":"/Content/resource_packs/aop_mobsrp/animations/sheepomelon.animation.json"},{"iTp":7,"gId":"WORLDDATA","gIx":6,"p":"/Content/resource_packs/aop_mobsrp/animations/sheepomelon.animation.json"},{"iTp":7,"gId":"WORLDDATA","gIx":1,"p":"/Content/resource_packs/aop_mobsrp/entity/biceson.entity.json"},{"iTp":7,"gId":"WORLDDATA","gIx":2,"p":"/Content/resource_packs/aop_mobsrp/entity/biceson.entity.json"},{"iTp":7,"gId":"WORLDDATA","gIx":3,"p":"/Content/resource_packs/aop_mobsrp/entity/biceson.entity.json"},{"iTp":7,"gId":"WORLDDATA","gIx":4,"p":"/Content/resource_packs/aop_mobsrp/entity/biceson.entity.json"},{"iTp":7,"gId":"WORLDDATA","gIx":5,"p":"/Content/resource_packs/aop_mobsrp/entity/biceson.entity.json"},{"iTp":7,"gId":"WORLDDATA","gIx":6,"p":"/Content/resource_packs/aop_mobsrp/entity/biceson.entity.json"},{"iTp":7,"gId":"WORLDDATA","gIx":1,"p":"/Content/resource_packs/aop_mobsrp/entity/nardolphle.entity.json"},{"iTp":7,"gId":"WORLDDATA","gIx":2,"p":"/Content/resource_packs/aop_mobsrp/entity/nardolphle.entity.json"},{"iTp":7,"gId":"WORLDDATA","gIx":3,"p":"/Content/resource_packs/aop_mobsrp/entity/nardolphle.entity.json"},{"iTp":7,"gId":"WORLDDATA","gIx":4,"p":"/Content/resource_packs/aop_mobsrp/entity/nardolphle.entity.json"},{"iTp":7,"gId":"WORLDDATA","gIx":5,"p":"/Content/resource_packs/aop_mobsrp/entity/nardolphle.entity.json"},{"iTp":7,"gId":"WORLDDATA","gIx":6,"p":"/Content/resource_packs/aop_mobsrp/entity/nardolphle.entity.json"},{"iTp":7,"gId":"WORLDDATA","gIx":1,"p":"/Content/resource_packs/aop_mobsrp/entity/sheepomelon.entity.json"},{"iTp":7,"gId":"WORLDDATA","gIx":2,"p":"/Content/resource_packs/aop_mobsrp/entity/sheepomelon.entity.json"},{"iTp":7,"gId":"WORLDDATA","gIx":3,"p":"/Content/resource_packs/aop_mobsrp/entity/sheepomelon.entity.json"},{"iTp":7,"gId":"WORLDDATA","gIx":4,"p":"/Content/resource_packs/aop_mobsrp/entity/sheepomelon.entity.json"},{"iTp":7,"gId":"WORLDDATA","gIx":5,"p":"/Content/resource_packs/aop_mobsrp/entity/sheepomelon.entity.json"},{"iTp":7,"gId":"WORLDDATA","gIx":6,"p":"/Content/resource_packs/aop_mobsrp/entity/sheepomelon.entity.json"},{"iTp":7,"gId":"WORLDDATA","gIx":1,"p":"/Content/resource_packs/aop_mobsrp/materials/entity.material"},{"iTp":7,"gId":"WORLDDATA","gIx":2,"p":"/Content/resource_packs/aop_mobsrp/materials/entity.material"},{"iTp":7,"gId":"WORLDDATA","gIx":3,"p":"/Content/resource_packs/aop_mobsrp/materials/entity.material"},{"iTp":7,"gId":"WORLDDATA","gIx":4,"p":"/Content/resource_packs/aop_mobsrp/materials/entity.material"},{"iTp":7,"gId":"WORLDDATA","gIx":5,"p":"/Content/resource_packs/aop_mobsrp/materials/entity.material"},{"iTp":7,"gId":"WORLDDATA","gIx":6,"p":"/Content/resource_packs/aop_mobsrp/materials/entity.material"},{"iTp":7,"gId":"WORLDDATA","gIx":1,"p":"/Content/resource_packs/aop_mobsrp/models/entity/biceson.geometry.json"},{"iTp":7,"gId":"WORLDDATA","gIx":2,"p":"/Content/resource_packs/aop_mobsrp/models/entity/biceson.geometry.json"},{"iTp":7,"gId":"WORLDDATA","gIx":3,"p":"/Content/resource_packs/aop_mobsrp/models/entity/biceson.geometry.json"},{"iTp":7,"gId":"WORLDDATA","gIx":4,"p":"/Content/resource_packs/aop_mobsrp/models/entity/biceson.geometry.json"},{"iTp":7,"gId":"WORLDDATA","gIx":5,"p":"/Content/resource_packs/aop_mobsrp/models/entity/biceson.geometry.json"},{"iTp":7,"gId":"WORLDDATA","gIx":6,"p":"/Content/resource_packs/aop_mobsrp/models/entity/biceson.geometry.json"},{"iTp":7,"gId":"WORLDDATA","gIx":1,"p":"/Content/resource_packs/aop_mobsrp/models/entity/nardolphle.geometry.json"},{"iTp":7,"gId":"WORLDDATA","gIx":2,"p":"/Content/resource_packs/aop_mobsrp/models/entity/nardolphle.geometry.json"},{"iTp":7,"gId":"WORLDDATA","gIx":3,"p":"/Content/resource_packs/aop_mobsrp/models/entity/nardolphle.geometry.json"},{"iTp":7,"gId":"WORLDDATA","gIx":4,"p":"/Content/resource_packs/aop_mobsrp/models/entity/nardolphle.geometry.json"},{"iTp":7,"gId":"WORLDDATA","gIx":5,"p":"/Content/resource_packs/aop_mobsrp/models/entity/nardolphle.geometry.json"},{"iTp":7,"gId":"WORLDDATA","gIx":6,"p":"/Content/resource_packs/aop_mobsrp/models/entity/nardolphle.geometry.json"},{"iTp":7,"gId":"WORLDDATA","gIx":1,"p":"/Content/resource_packs/aop_mobsrp/models/entity/sheepomelon.geometry.json"},{"iTp":7,"gId":"WORLDDATA","gIx":2,"p":"/Content/resource_packs/aop_mobsrp/models/entity/sheepomelon.geometry.json"},{"iTp":7,"gId":"WORLDDATA","gIx":3,"p":"/Content/resource_packs/aop_mobsrp/models/entity/sheepomelon.geometry.json"},{"iTp":7,"gId":"WORLDDATA","gIx":4,"p":"/Content/resource_packs/aop_mobsrp/models/entity/sheepomelon.geometry.json"},{"iTp":7,"gId":"WORLDDATA","gIx":5,"p":"/Content/resource_packs/aop_mobsrp/models/entity/sheepomelon.geometry.json"},{"iTp":7,"gId":"WORLDDATA","gIx":6,"p":"/Content/resource_packs/aop_mobsrp/models/entity/sheepomelon.geometry.json"},{"iTp":7,"gId":"WORLDDATA","gIx":1,"p":"/Content/resource_packs/aop_mobsrp/particles/fireworks_pop.json"},{"iTp":7,"gId":"WORLDDATA","gIx":2,"p":"/Content/resource_packs/aop_mobsrp/particles/fireworks_pop.json"},{"iTp":7,"gId":"WORLDDATA","gIx":3,"p":"/Content/resource_packs/aop_mobsrp/particles/fireworks_pop.json"},{"iTp":7,"gId":"WORLDDATA","gIx":4,"p":"/Content/resource_packs/aop_mobsrp/particles/fireworks_pop.json"},{"iTp":7,"gId":"WORLDDATA","gIx":5,"p":"/Content/resource_packs/aop_mobsrp/particles/fireworks_pop.json"},{"iTp":7,"gId":"WORLDDATA","gIx":6,"p":"/Content/resource_packs/aop_mobsrp/particles/fireworks_pop.json"},{"iTp":7,"gId":"WORLDDATA","gIx":1,"p":"/Content/resource_packs/aop_mobsrp/particles/smoke_puff.json"},{"iTp":7,"gId":"WORLDDATA","gIx":2,"p":"/Content/resource_packs/aop_mobsrp/particles/smoke_puff.json"},{"iTp":7,"gId":"WORLDDATA","gIx":3,"p":"/Content/resource_packs/aop_mobsrp/particles/smoke_puff.json"},{"iTp":7,"gId":"WORLDDATA","gIx":4,"p":"/Content/resource_packs/aop_mobsrp/particles/smoke_puff.json"},{"iTp":7,"gId":"WORLDDATA","gIx":5,"p":"/Content/resource_packs/aop_mobsrp/particles/smoke_puff.json"},{"iTp":7,"gId":"WORLDDATA","gIx":6,"p":"/Content/resource_packs/aop_mobsrp/particles/smoke_puff.json"},{"iTp":7,"gId":"WORLDDATA","gIx":1,"p":"/Content/resource_packs/aop_mobsrp/texts/en_US.lang"},{"iTp":7,"gId":"WORLDDATA","gIx":2,"p":"/Content/resource_packs/aop_mobsrp/texts/en_US.lang"},{"iTp":7,"gId":"WORLDDATA","gIx":3,"p":"/Content/resource_packs/aop_mobsrp/texts/en_US.lang"},{"iTp":7,"gId":"WORLDDATA","gIx":4,"p":"/Content/resource_packs/aop_mobsrp/texts/en_US.lang"},{"iTp":7,"gId":"WORLDDATA","gIx":5,"p":"/Content/resource_packs/aop_mobsrp/texts/en_US.lang"},{"iTp":7,"gId":"WORLDDATA","gIx":6,"p":"/Content/resource_packs/aop_mobsrp/texts/en_US.lang"},{"iTp":7,"gId":"WORLDDATA","gIx":1,"p":"/Content/resource_packs/aop_mobsrp/texts/languages.json"},{"iTp":7,"gId":"WORLDDATA","gIx":2,"p":"/Content/resource_packs/aop_mobsrp/texts/languages.json"},{"iTp":7,"gId":"WORLDDATA","gIx":3,"p":"/Content/resource_packs/aop_mobsrp/texts/languages.json"},{"iTp":7,"gId":"WORLDDATA","gIx":4,"p":"/Content/resource_packs/aop_mobsrp/texts/languages.json"},{"iTp":7,"gId":"WORLDDATA","gIx":5,"p":"/Content/resource_packs/aop_mobsrp/texts/languages.json"},{"iTp":7,"gId":"WORLDDATA","gIx":6,"p":"/Content/resource_packs/aop_mobsrp/texts/languages.json"},{"iTp":0,"gId":"WORLDDATA","gIx":1,"m":"Test World Data Validation completed successfully."},{"iTp":0,"gId":"ADDONIREQ","gIx":1}],"generatorName":"Minecraft Creator Tools","suite":2,"generatorVersion":"0.2.9","sourceName":"content1","sourcePath":"/"}); +_addReportJson({"info":{"behaviorPackManifestCount":0,"unknownJsonCount":0,"entityTypeManifestCount":0,"itemTypeManifestCount":0,"blockTypeManifestCount":0,"resourcePackManifestCount":0,"worldCount":0,"entityTypeResourceCount":0,"behaviorPackAnimationCount":0,"behaviorPackAnimationControllerCount":0,"overallSize":54260,"fileCounts":37,"folderCounts":23,"contentSize":54260,"contentFileCounts":37,"contentFolderCounts":18,"animationCount":0,"textureCount":0,"chunkCount":0,"subchunkLessChunkCount":0,"worldLoadErrors":0,"featureSets":{"Textures Entity Resource Count":{"Count":3},"Textures Texture References":{"Count":3},"Textures Entity References":{"Count":3},"Textures File Count":{"Count":4},"Textures Unique Texture Handles (estimated)":{"Count":3},"Textures Unique Texture Paths":{"Count":3},"Textures Unique Particle Texture Paths":{"Count":0},"Textures Unique Particle Texture Vanilla Paths":{"Count":1},"Textures Unique Entity Texture Paths":{"Count":3},"Command say":{"Count":1},"Command summon":{"Count":1}},"summary":{"PACKSIZE":{"1":{"title":"Overall Size"},"2":{"title":"Overall File Count","defaultMessage":"File Counts"},"3":{"title":"Overall Folder Count","defaultMessage":"Folder Counts"},"4":{"title":"Content Size"},"5":{"title":"Content File Count","defaultMessage":"Content File Counts"},"6":{"title":"Content Folder Count","defaultMessage":"Content Folder Counts"}},"ADDONREQ":{"102":{"title":"102","defaultMessage":"Found an add-on-blocked folder 'entities' in a parent folder pack\\loot_tables. Should be named 'creatorshortname' and not a common term","testCompleteFails":1},"104":{"title":"104","defaultMessage":"Found a loose file 'sheepomelon.json' in loot_tables\\entities. Files should only be in the folder loot_tables\\entities\\","testCompleteFails":2}},"TEXTURE":{"1":{"title":"Textures"}},"WORLDDATA":{"1":{"defaultMessage":"Blocks","testCompleteSuccesses":1},"2":{"defaultMessage":"Block Data"},"3":{"defaultMessage":"Commands"},"4":{"defaultMessage":"Execute Sub Commands"},"5":{"defaultMessage":"NBT Tags"},"6":{"defaultMessage":"NBT Experiment Tags"}},"ADDONIREQ":{"1":{"defaultMessage":"Test Addon Item Requirements Generator completed successfully.","testCompleteSuccesses":1}}}},"items":[{"iTp":7,"gId":"PACKSIZE","gIx":1,"d":54260},{"iTp":7,"gId":"PACKSIZE","gIx":2,"d":37},{"iTp":7,"gId":"PACKSIZE","gIx":3,"d":23},{"iTp":7,"gId":"PACKSIZE","gIx":4,"d":54260},{"iTp":7,"gId":"PACKSIZE","gIx":5,"d":37},{"iTp":7,"gId":"PACKSIZE","gIx":6,"d":18},{"iTp":1,"gId":"ADDONREQ","gIx":102,"d":"entities"},{"iTp":1,"gId":"ADDONREQ","gIx":104,"d":"sheepomelon.json"},{"iTp":1,"gId":"ADDONREQ","gIx":104,"m":"Found a loose file 'sheepomelon_shear.json' in loot_tables\\entities. Files should only be in the folder loot_tables\\entities\\","d":"sheepomelon_shear.json"},{"iTp":7,"gId":"TEXTURE","gIx":1,"fs":{"Entity Resource Count":{"Count":3},"Texture References":{"Count":3},"Entity References":{"Count":3},"File Count":{"Count":4},"Unique Texture Handles (estimated)":{"Count":3},"Unique Texture Paths":{"Count":3},"Unique Particle Texture Paths":{"Count":0},"Unique Particle Texture Vanilla Paths":{"Count":1},"Unique Entity Texture Paths":{"Count":3}}},{"iTp":7,"gId":"WORLDDATA","gIx":1,"p":"/Content/behavior_packs/aop_mobsbp/"},{"iTp":7,"gId":"WORLDDATA","gIx":2,"p":"/Content/behavior_packs/aop_mobsbp/"},{"iTp":7,"gId":"WORLDDATA","gIx":3,"p":"/Content/behavior_packs/aop_mobsbp/"},{"iTp":7,"gId":"WORLDDATA","gIx":4,"p":"/Content/behavior_packs/aop_mobsbp/"},{"iTp":7,"gId":"WORLDDATA","gIx":5,"p":"/Content/behavior_packs/aop_mobsbp/"},{"iTp":7,"gId":"WORLDDATA","gIx":6,"p":"/Content/behavior_packs/aop_mobsbp/"},{"iTp":7,"gId":"WORLDDATA","gIx":1,"p":"/Content/behavior_packs/aop_mobsbp/manifest.json"},{"iTp":7,"gId":"WORLDDATA","gIx":2,"p":"/Content/behavior_packs/aop_mobsbp/manifest.json"},{"iTp":7,"gId":"WORLDDATA","gIx":3,"p":"/Content/behavior_packs/aop_mobsbp/manifest.json"},{"iTp":7,"gId":"WORLDDATA","gIx":4,"p":"/Content/behavior_packs/aop_mobsbp/manifest.json"},{"iTp":7,"gId":"WORLDDATA","gIx":5,"p":"/Content/behavior_packs/aop_mobsbp/manifest.json"},{"iTp":7,"gId":"WORLDDATA","gIx":6,"p":"/Content/behavior_packs/aop_mobsbp/manifest.json"},{"iTp":7,"gId":"WORLDDATA","gIx":1,"p":"/Content/behavior_packs/aop_mobsbp/animations/sheepomelon.bp_anims.json"},{"iTp":7,"gId":"WORLDDATA","gIx":2,"p":"/Content/behavior_packs/aop_mobsbp/animations/sheepomelon.bp_anims.json"},{"iTp":7,"gId":"WORLDDATA","gIx":3,"p":"/Content/behavior_packs/aop_mobsbp/animations/sheepomelon.bp_anims.json","fs":{"say":{"Count":1},"summon":{"Count":1}}},{"iTp":7,"gId":"WORLDDATA","gIx":4,"p":"/Content/behavior_packs/aop_mobsbp/animations/sheepomelon.bp_anims.json"},{"iTp":7,"gId":"WORLDDATA","gIx":5,"p":"/Content/behavior_packs/aop_mobsbp/animations/sheepomelon.bp_anims.json"},{"iTp":7,"gId":"WORLDDATA","gIx":6,"p":"/Content/behavior_packs/aop_mobsbp/animations/sheepomelon.bp_anims.json"},{"iTp":7,"gId":"WORLDDATA","gIx":1,"p":"/Content/behavior_packs/aop_mobsbp/animation_controllers/sheepomelon.bp_ac.json"},{"iTp":7,"gId":"WORLDDATA","gIx":2,"p":"/Content/behavior_packs/aop_mobsbp/animation_controllers/sheepomelon.bp_ac.json"},{"iTp":7,"gId":"WORLDDATA","gIx":3,"p":"/Content/behavior_packs/aop_mobsbp/animation_controllers/sheepomelon.bp_ac.json"},{"iTp":7,"gId":"WORLDDATA","gIx":4,"p":"/Content/behavior_packs/aop_mobsbp/animation_controllers/sheepomelon.bp_ac.json"},{"iTp":7,"gId":"WORLDDATA","gIx":5,"p":"/Content/behavior_packs/aop_mobsbp/animation_controllers/sheepomelon.bp_ac.json"},{"iTp":7,"gId":"WORLDDATA","gIx":6,"p":"/Content/behavior_packs/aop_mobsbp/animation_controllers/sheepomelon.bp_ac.json"},{"iTp":7,"gId":"WORLDDATA","gIx":1,"p":"/Content/behavior_packs/aop_mobsbp/entities/biceson.behavior.json"},{"iTp":7,"gId":"WORLDDATA","gIx":2,"p":"/Content/behavior_packs/aop_mobsbp/entities/biceson.behavior.json"},{"iTp":7,"gId":"WORLDDATA","gIx":3,"p":"/Content/behavior_packs/aop_mobsbp/entities/biceson.behavior.json"},{"iTp":7,"gId":"WORLDDATA","gIx":4,"p":"/Content/behavior_packs/aop_mobsbp/entities/biceson.behavior.json"},{"iTp":7,"gId":"WORLDDATA","gIx":5,"p":"/Content/behavior_packs/aop_mobsbp/entities/biceson.behavior.json"},{"iTp":7,"gId":"WORLDDATA","gIx":6,"p":"/Content/behavior_packs/aop_mobsbp/entities/biceson.behavior.json"},{"iTp":7,"gId":"WORLDDATA","gIx":1,"p":"/Content/behavior_packs/aop_mobsbp/entities/nardolphle.behavior.json"},{"iTp":7,"gId":"WORLDDATA","gIx":2,"p":"/Content/behavior_packs/aop_mobsbp/entities/nardolphle.behavior.json"},{"iTp":7,"gId":"WORLDDATA","gIx":3,"p":"/Content/behavior_packs/aop_mobsbp/entities/nardolphle.behavior.json"},{"iTp":7,"gId":"WORLDDATA","gIx":4,"p":"/Content/behavior_packs/aop_mobsbp/entities/nardolphle.behavior.json"},{"iTp":7,"gId":"WORLDDATA","gIx":5,"p":"/Content/behavior_packs/aop_mobsbp/entities/nardolphle.behavior.json"},{"iTp":7,"gId":"WORLDDATA","gIx":6,"p":"/Content/behavior_packs/aop_mobsbp/entities/nardolphle.behavior.json"},{"iTp":7,"gId":"WORLDDATA","gIx":1,"p":"/Content/behavior_packs/aop_mobsbp/entities/sheepomelon.behavior.json"},{"iTp":7,"gId":"WORLDDATA","gIx":2,"p":"/Content/behavior_packs/aop_mobsbp/entities/sheepomelon.behavior.json"},{"iTp":7,"gId":"WORLDDATA","gIx":3,"p":"/Content/behavior_packs/aop_mobsbp/entities/sheepomelon.behavior.json"},{"iTp":7,"gId":"WORLDDATA","gIx":4,"p":"/Content/behavior_packs/aop_mobsbp/entities/sheepomelon.behavior.json"},{"iTp":7,"gId":"WORLDDATA","gIx":5,"p":"/Content/behavior_packs/aop_mobsbp/entities/sheepomelon.behavior.json"},{"iTp":7,"gId":"WORLDDATA","gIx":6,"p":"/Content/behavior_packs/aop_mobsbp/entities/sheepomelon.behavior.json"},{"iTp":7,"gId":"WORLDDATA","gIx":1,"p":"/Content/behavior_packs/aop_mobsbp/loot_tables/entities/sheepomelon.json"},{"iTp":7,"gId":"WORLDDATA","gIx":2,"p":"/Content/behavior_packs/aop_mobsbp/loot_tables/entities/sheepomelon.json"},{"iTp":7,"gId":"WORLDDATA","gIx":3,"p":"/Content/behavior_packs/aop_mobsbp/loot_tables/entities/sheepomelon.json"},{"iTp":7,"gId":"WORLDDATA","gIx":4,"p":"/Content/behavior_packs/aop_mobsbp/loot_tables/entities/sheepomelon.json"},{"iTp":7,"gId":"WORLDDATA","gIx":5,"p":"/Content/behavior_packs/aop_mobsbp/loot_tables/entities/sheepomelon.json"},{"iTp":7,"gId":"WORLDDATA","gIx":6,"p":"/Content/behavior_packs/aop_mobsbp/loot_tables/entities/sheepomelon.json"},{"iTp":7,"gId":"WORLDDATA","gIx":1,"p":"/Content/behavior_packs/aop_mobsbp/loot_tables/entities/sheepomelon_shear.json"},{"iTp":7,"gId":"WORLDDATA","gIx":2,"p":"/Content/behavior_packs/aop_mobsbp/loot_tables/entities/sheepomelon_shear.json"},{"iTp":7,"gId":"WORLDDATA","gIx":3,"p":"/Content/behavior_packs/aop_mobsbp/loot_tables/entities/sheepomelon_shear.json"},{"iTp":7,"gId":"WORLDDATA","gIx":4,"p":"/Content/behavior_packs/aop_mobsbp/loot_tables/entities/sheepomelon_shear.json"},{"iTp":7,"gId":"WORLDDATA","gIx":5,"p":"/Content/behavior_packs/aop_mobsbp/loot_tables/entities/sheepomelon_shear.json"},{"iTp":7,"gId":"WORLDDATA","gIx":6,"p":"/Content/behavior_packs/aop_mobsbp/loot_tables/entities/sheepomelon_shear.json"},{"iTp":7,"gId":"WORLDDATA","gIx":1,"p":"/Content/behavior_packs/aop_mobsbp/spawn_rules/biceson.json"},{"iTp":7,"gId":"WORLDDATA","gIx":2,"p":"/Content/behavior_packs/aop_mobsbp/spawn_rules/biceson.json"},{"iTp":7,"gId":"WORLDDATA","gIx":3,"p":"/Content/behavior_packs/aop_mobsbp/spawn_rules/biceson.json"},{"iTp":7,"gId":"WORLDDATA","gIx":4,"p":"/Content/behavior_packs/aop_mobsbp/spawn_rules/biceson.json"},{"iTp":7,"gId":"WORLDDATA","gIx":5,"p":"/Content/behavior_packs/aop_mobsbp/spawn_rules/biceson.json"},{"iTp":7,"gId":"WORLDDATA","gIx":6,"p":"/Content/behavior_packs/aop_mobsbp/spawn_rules/biceson.json"},{"iTp":7,"gId":"WORLDDATA","gIx":1,"p":"/Content/behavior_packs/aop_mobsbp/spawn_rules/nardolphle.json"},{"iTp":7,"gId":"WORLDDATA","gIx":2,"p":"/Content/behavior_packs/aop_mobsbp/spawn_rules/nardolphle.json"},{"iTp":7,"gId":"WORLDDATA","gIx":3,"p":"/Content/behavior_packs/aop_mobsbp/spawn_rules/nardolphle.json"},{"iTp":7,"gId":"WORLDDATA","gIx":4,"p":"/Content/behavior_packs/aop_mobsbp/spawn_rules/nardolphle.json"},{"iTp":7,"gId":"WORLDDATA","gIx":5,"p":"/Content/behavior_packs/aop_mobsbp/spawn_rules/nardolphle.json"},{"iTp":7,"gId":"WORLDDATA","gIx":6,"p":"/Content/behavior_packs/aop_mobsbp/spawn_rules/nardolphle.json"},{"iTp":7,"gId":"WORLDDATA","gIx":1,"p":"/Content/behavior_packs/aop_mobsbp/spawn_rules/sheepomelon.json"},{"iTp":7,"gId":"WORLDDATA","gIx":2,"p":"/Content/behavior_packs/aop_mobsbp/spawn_rules/sheepomelon.json"},{"iTp":7,"gId":"WORLDDATA","gIx":3,"p":"/Content/behavior_packs/aop_mobsbp/spawn_rules/sheepomelon.json"},{"iTp":7,"gId":"WORLDDATA","gIx":4,"p":"/Content/behavior_packs/aop_mobsbp/spawn_rules/sheepomelon.json"},{"iTp":7,"gId":"WORLDDATA","gIx":5,"p":"/Content/behavior_packs/aop_mobsbp/spawn_rules/sheepomelon.json"},{"iTp":7,"gId":"WORLDDATA","gIx":6,"p":"/Content/behavior_packs/aop_mobsbp/spawn_rules/sheepomelon.json"},{"iTp":7,"gId":"WORLDDATA","gIx":1,"p":"/Content/behavior_packs/aop_mobsbp/texts/en_US.lang"},{"iTp":7,"gId":"WORLDDATA","gIx":2,"p":"/Content/behavior_packs/aop_mobsbp/texts/en_US.lang"},{"iTp":7,"gId":"WORLDDATA","gIx":3,"p":"/Content/behavior_packs/aop_mobsbp/texts/en_US.lang"},{"iTp":7,"gId":"WORLDDATA","gIx":4,"p":"/Content/behavior_packs/aop_mobsbp/texts/en_US.lang"},{"iTp":7,"gId":"WORLDDATA","gIx":5,"p":"/Content/behavior_packs/aop_mobsbp/texts/en_US.lang"},{"iTp":7,"gId":"WORLDDATA","gIx":6,"p":"/Content/behavior_packs/aop_mobsbp/texts/en_US.lang"},{"iTp":7,"gId":"WORLDDATA","gIx":1,"p":"/Content/behavior_packs/aop_mobsbp/texts/languages.json"},{"iTp":7,"gId":"WORLDDATA","gIx":2,"p":"/Content/behavior_packs/aop_mobsbp/texts/languages.json"},{"iTp":7,"gId":"WORLDDATA","gIx":3,"p":"/Content/behavior_packs/aop_mobsbp/texts/languages.json"},{"iTp":7,"gId":"WORLDDATA","gIx":4,"p":"/Content/behavior_packs/aop_mobsbp/texts/languages.json"},{"iTp":7,"gId":"WORLDDATA","gIx":5,"p":"/Content/behavior_packs/aop_mobsbp/texts/languages.json"},{"iTp":7,"gId":"WORLDDATA","gIx":6,"p":"/Content/behavior_packs/aop_mobsbp/texts/languages.json"},{"iTp":7,"gId":"WORLDDATA","gIx":1,"p":"/Content/resource_packs/aop_mobsrp/"},{"iTp":7,"gId":"WORLDDATA","gIx":2,"p":"/Content/resource_packs/aop_mobsrp/"},{"iTp":7,"gId":"WORLDDATA","gIx":3,"p":"/Content/resource_packs/aop_mobsrp/"},{"iTp":7,"gId":"WORLDDATA","gIx":4,"p":"/Content/resource_packs/aop_mobsrp/"},{"iTp":7,"gId":"WORLDDATA","gIx":5,"p":"/Content/resource_packs/aop_mobsrp/"},{"iTp":7,"gId":"WORLDDATA","gIx":6,"p":"/Content/resource_packs/aop_mobsrp/"},{"iTp":7,"gId":"WORLDDATA","gIx":1,"p":"/Content/resource_packs/aop_mobsrp/manifest.json"},{"iTp":7,"gId":"WORLDDATA","gIx":2,"p":"/Content/resource_packs/aop_mobsrp/manifest.json"},{"iTp":7,"gId":"WORLDDATA","gIx":3,"p":"/Content/resource_packs/aop_mobsrp/manifest.json"},{"iTp":7,"gId":"WORLDDATA","gIx":4,"p":"/Content/resource_packs/aop_mobsrp/manifest.json"},{"iTp":7,"gId":"WORLDDATA","gIx":5,"p":"/Content/resource_packs/aop_mobsrp/manifest.json"},{"iTp":7,"gId":"WORLDDATA","gIx":6,"p":"/Content/resource_packs/aop_mobsrp/manifest.json"},{"iTp":7,"gId":"WORLDDATA","gIx":1,"p":"/Content/resource_packs/aop_mobsrp/sounds.json"},{"iTp":7,"gId":"WORLDDATA","gIx":2,"p":"/Content/resource_packs/aop_mobsrp/sounds.json"},{"iTp":7,"gId":"WORLDDATA","gIx":3,"p":"/Content/resource_packs/aop_mobsrp/sounds.json"},{"iTp":7,"gId":"WORLDDATA","gIx":4,"p":"/Content/resource_packs/aop_mobsrp/sounds.json"},{"iTp":7,"gId":"WORLDDATA","gIx":5,"p":"/Content/resource_packs/aop_mobsrp/sounds.json"},{"iTp":7,"gId":"WORLDDATA","gIx":6,"p":"/Content/resource_packs/aop_mobsrp/sounds.json"},{"iTp":7,"gId":"WORLDDATA","gIx":1,"p":"/Content/resource_packs/aop_mobsrp/animations/biceson.animation.json"},{"iTp":7,"gId":"WORLDDATA","gIx":2,"p":"/Content/resource_packs/aop_mobsrp/animations/biceson.animation.json"},{"iTp":7,"gId":"WORLDDATA","gIx":3,"p":"/Content/resource_packs/aop_mobsrp/animations/biceson.animation.json"},{"iTp":7,"gId":"WORLDDATA","gIx":4,"p":"/Content/resource_packs/aop_mobsrp/animations/biceson.animation.json"},{"iTp":7,"gId":"WORLDDATA","gIx":5,"p":"/Content/resource_packs/aop_mobsrp/animations/biceson.animation.json"},{"iTp":7,"gId":"WORLDDATA","gIx":6,"p":"/Content/resource_packs/aop_mobsrp/animations/biceson.animation.json"},{"iTp":7,"gId":"WORLDDATA","gIx":1,"p":"/Content/resource_packs/aop_mobsrp/animations/nardolphle.animation.json"},{"iTp":7,"gId":"WORLDDATA","gIx":2,"p":"/Content/resource_packs/aop_mobsrp/animations/nardolphle.animation.json"},{"iTp":7,"gId":"WORLDDATA","gIx":3,"p":"/Content/resource_packs/aop_mobsrp/animations/nardolphle.animation.json"},{"iTp":7,"gId":"WORLDDATA","gIx":4,"p":"/Content/resource_packs/aop_mobsrp/animations/nardolphle.animation.json"},{"iTp":7,"gId":"WORLDDATA","gIx":5,"p":"/Content/resource_packs/aop_mobsrp/animations/nardolphle.animation.json"},{"iTp":7,"gId":"WORLDDATA","gIx":6,"p":"/Content/resource_packs/aop_mobsrp/animations/nardolphle.animation.json"},{"iTp":7,"gId":"WORLDDATA","gIx":1,"p":"/Content/resource_packs/aop_mobsrp/animations/sheepomelon.animation.json"},{"iTp":7,"gId":"WORLDDATA","gIx":2,"p":"/Content/resource_packs/aop_mobsrp/animations/sheepomelon.animation.json"},{"iTp":7,"gId":"WORLDDATA","gIx":3,"p":"/Content/resource_packs/aop_mobsrp/animations/sheepomelon.animation.json"},{"iTp":7,"gId":"WORLDDATA","gIx":4,"p":"/Content/resource_packs/aop_mobsrp/animations/sheepomelon.animation.json"},{"iTp":7,"gId":"WORLDDATA","gIx":5,"p":"/Content/resource_packs/aop_mobsrp/animations/sheepomelon.animation.json"},{"iTp":7,"gId":"WORLDDATA","gIx":6,"p":"/Content/resource_packs/aop_mobsrp/animations/sheepomelon.animation.json"},{"iTp":7,"gId":"WORLDDATA","gIx":1,"p":"/Content/resource_packs/aop_mobsrp/entity/biceson.entity.json"},{"iTp":7,"gId":"WORLDDATA","gIx":2,"p":"/Content/resource_packs/aop_mobsrp/entity/biceson.entity.json"},{"iTp":7,"gId":"WORLDDATA","gIx":3,"p":"/Content/resource_packs/aop_mobsrp/entity/biceson.entity.json"},{"iTp":7,"gId":"WORLDDATA","gIx":4,"p":"/Content/resource_packs/aop_mobsrp/entity/biceson.entity.json"},{"iTp":7,"gId":"WORLDDATA","gIx":5,"p":"/Content/resource_packs/aop_mobsrp/entity/biceson.entity.json"},{"iTp":7,"gId":"WORLDDATA","gIx":6,"p":"/Content/resource_packs/aop_mobsrp/entity/biceson.entity.json"},{"iTp":7,"gId":"WORLDDATA","gIx":1,"p":"/Content/resource_packs/aop_mobsrp/entity/nardolphle.entity.json"},{"iTp":7,"gId":"WORLDDATA","gIx":2,"p":"/Content/resource_packs/aop_mobsrp/entity/nardolphle.entity.json"},{"iTp":7,"gId":"WORLDDATA","gIx":3,"p":"/Content/resource_packs/aop_mobsrp/entity/nardolphle.entity.json"},{"iTp":7,"gId":"WORLDDATA","gIx":4,"p":"/Content/resource_packs/aop_mobsrp/entity/nardolphle.entity.json"},{"iTp":7,"gId":"WORLDDATA","gIx":5,"p":"/Content/resource_packs/aop_mobsrp/entity/nardolphle.entity.json"},{"iTp":7,"gId":"WORLDDATA","gIx":6,"p":"/Content/resource_packs/aop_mobsrp/entity/nardolphle.entity.json"},{"iTp":7,"gId":"WORLDDATA","gIx":1,"p":"/Content/resource_packs/aop_mobsrp/entity/sheepomelon.entity.json"},{"iTp":7,"gId":"WORLDDATA","gIx":2,"p":"/Content/resource_packs/aop_mobsrp/entity/sheepomelon.entity.json"},{"iTp":7,"gId":"WORLDDATA","gIx":3,"p":"/Content/resource_packs/aop_mobsrp/entity/sheepomelon.entity.json"},{"iTp":7,"gId":"WORLDDATA","gIx":4,"p":"/Content/resource_packs/aop_mobsrp/entity/sheepomelon.entity.json"},{"iTp":7,"gId":"WORLDDATA","gIx":5,"p":"/Content/resource_packs/aop_mobsrp/entity/sheepomelon.entity.json"},{"iTp":7,"gId":"WORLDDATA","gIx":6,"p":"/Content/resource_packs/aop_mobsrp/entity/sheepomelon.entity.json"},{"iTp":7,"gId":"WORLDDATA","gIx":1,"p":"/Content/resource_packs/aop_mobsrp/materials/entity.material"},{"iTp":7,"gId":"WORLDDATA","gIx":2,"p":"/Content/resource_packs/aop_mobsrp/materials/entity.material"},{"iTp":7,"gId":"WORLDDATA","gIx":3,"p":"/Content/resource_packs/aop_mobsrp/materials/entity.material"},{"iTp":7,"gId":"WORLDDATA","gIx":4,"p":"/Content/resource_packs/aop_mobsrp/materials/entity.material"},{"iTp":7,"gId":"WORLDDATA","gIx":5,"p":"/Content/resource_packs/aop_mobsrp/materials/entity.material"},{"iTp":7,"gId":"WORLDDATA","gIx":6,"p":"/Content/resource_packs/aop_mobsrp/materials/entity.material"},{"iTp":7,"gId":"WORLDDATA","gIx":1,"p":"/Content/resource_packs/aop_mobsrp/models/entity/biceson.geometry.json"},{"iTp":7,"gId":"WORLDDATA","gIx":2,"p":"/Content/resource_packs/aop_mobsrp/models/entity/biceson.geometry.json"},{"iTp":7,"gId":"WORLDDATA","gIx":3,"p":"/Content/resource_packs/aop_mobsrp/models/entity/biceson.geometry.json"},{"iTp":7,"gId":"WORLDDATA","gIx":4,"p":"/Content/resource_packs/aop_mobsrp/models/entity/biceson.geometry.json"},{"iTp":7,"gId":"WORLDDATA","gIx":5,"p":"/Content/resource_packs/aop_mobsrp/models/entity/biceson.geometry.json"},{"iTp":7,"gId":"WORLDDATA","gIx":6,"p":"/Content/resource_packs/aop_mobsrp/models/entity/biceson.geometry.json"},{"iTp":7,"gId":"WORLDDATA","gIx":1,"p":"/Content/resource_packs/aop_mobsrp/models/entity/nardolphle.geometry.json"},{"iTp":7,"gId":"WORLDDATA","gIx":2,"p":"/Content/resource_packs/aop_mobsrp/models/entity/nardolphle.geometry.json"},{"iTp":7,"gId":"WORLDDATA","gIx":3,"p":"/Content/resource_packs/aop_mobsrp/models/entity/nardolphle.geometry.json"},{"iTp":7,"gId":"WORLDDATA","gIx":4,"p":"/Content/resource_packs/aop_mobsrp/models/entity/nardolphle.geometry.json"},{"iTp":7,"gId":"WORLDDATA","gIx":5,"p":"/Content/resource_packs/aop_mobsrp/models/entity/nardolphle.geometry.json"},{"iTp":7,"gId":"WORLDDATA","gIx":6,"p":"/Content/resource_packs/aop_mobsrp/models/entity/nardolphle.geometry.json"},{"iTp":7,"gId":"WORLDDATA","gIx":1,"p":"/Content/resource_packs/aop_mobsrp/models/entity/sheepomelon.geometry.json"},{"iTp":7,"gId":"WORLDDATA","gIx":2,"p":"/Content/resource_packs/aop_mobsrp/models/entity/sheepomelon.geometry.json"},{"iTp":7,"gId":"WORLDDATA","gIx":3,"p":"/Content/resource_packs/aop_mobsrp/models/entity/sheepomelon.geometry.json"},{"iTp":7,"gId":"WORLDDATA","gIx":4,"p":"/Content/resource_packs/aop_mobsrp/models/entity/sheepomelon.geometry.json"},{"iTp":7,"gId":"WORLDDATA","gIx":5,"p":"/Content/resource_packs/aop_mobsrp/models/entity/sheepomelon.geometry.json"},{"iTp":7,"gId":"WORLDDATA","gIx":6,"p":"/Content/resource_packs/aop_mobsrp/models/entity/sheepomelon.geometry.json"},{"iTp":7,"gId":"WORLDDATA","gIx":1,"p":"/Content/resource_packs/aop_mobsrp/particles/fireworks_pop.json"},{"iTp":7,"gId":"WORLDDATA","gIx":2,"p":"/Content/resource_packs/aop_mobsrp/particles/fireworks_pop.json"},{"iTp":7,"gId":"WORLDDATA","gIx":3,"p":"/Content/resource_packs/aop_mobsrp/particles/fireworks_pop.json"},{"iTp":7,"gId":"WORLDDATA","gIx":4,"p":"/Content/resource_packs/aop_mobsrp/particles/fireworks_pop.json"},{"iTp":7,"gId":"WORLDDATA","gIx":5,"p":"/Content/resource_packs/aop_mobsrp/particles/fireworks_pop.json"},{"iTp":7,"gId":"WORLDDATA","gIx":6,"p":"/Content/resource_packs/aop_mobsrp/particles/fireworks_pop.json"},{"iTp":7,"gId":"WORLDDATA","gIx":1,"p":"/Content/resource_packs/aop_mobsrp/particles/smoke_puff.json"},{"iTp":7,"gId":"WORLDDATA","gIx":2,"p":"/Content/resource_packs/aop_mobsrp/particles/smoke_puff.json"},{"iTp":7,"gId":"WORLDDATA","gIx":3,"p":"/Content/resource_packs/aop_mobsrp/particles/smoke_puff.json"},{"iTp":7,"gId":"WORLDDATA","gIx":4,"p":"/Content/resource_packs/aop_mobsrp/particles/smoke_puff.json"},{"iTp":7,"gId":"WORLDDATA","gIx":5,"p":"/Content/resource_packs/aop_mobsrp/particles/smoke_puff.json"},{"iTp":7,"gId":"WORLDDATA","gIx":6,"p":"/Content/resource_packs/aop_mobsrp/particles/smoke_puff.json"},{"iTp":7,"gId":"WORLDDATA","gIx":1,"p":"/Content/resource_packs/aop_mobsrp/texts/en_US.lang"},{"iTp":7,"gId":"WORLDDATA","gIx":2,"p":"/Content/resource_packs/aop_mobsrp/texts/en_US.lang"},{"iTp":7,"gId":"WORLDDATA","gIx":3,"p":"/Content/resource_packs/aop_mobsrp/texts/en_US.lang"},{"iTp":7,"gId":"WORLDDATA","gIx":4,"p":"/Content/resource_packs/aop_mobsrp/texts/en_US.lang"},{"iTp":7,"gId":"WORLDDATA","gIx":5,"p":"/Content/resource_packs/aop_mobsrp/texts/en_US.lang"},{"iTp":7,"gId":"WORLDDATA","gIx":6,"p":"/Content/resource_packs/aop_mobsrp/texts/en_US.lang"},{"iTp":7,"gId":"WORLDDATA","gIx":1,"p":"/Content/resource_packs/aop_mobsrp/texts/languages.json"},{"iTp":7,"gId":"WORLDDATA","gIx":2,"p":"/Content/resource_packs/aop_mobsrp/texts/languages.json"},{"iTp":7,"gId":"WORLDDATA","gIx":3,"p":"/Content/resource_packs/aop_mobsrp/texts/languages.json"},{"iTp":7,"gId":"WORLDDATA","gIx":4,"p":"/Content/resource_packs/aop_mobsrp/texts/languages.json"},{"iTp":7,"gId":"WORLDDATA","gIx":5,"p":"/Content/resource_packs/aop_mobsrp/texts/languages.json"},{"iTp":7,"gId":"WORLDDATA","gIx":6,"p":"/Content/resource_packs/aop_mobsrp/texts/languages.json"},{"iTp":0,"gId":"WORLDDATA","gIx":1,"m":"Test World Data Validation completed successfully."},{"iTp":0,"gId":"ADDONIREQ","gIx":1}],"generatorName":"Minecraft Creator Tools","suite":2,"generatorVersion":"0.2.9","sourceName":"content1","sourcePath":"/"});