From 9fa131beab6eea5248cb09bc148906ecbefe56e3 Mon Sep 17 00:00:00 2001 From: SnaveSutit Date: Sun, 26 Apr 2026 13:38:56 -0400 Subject: [PATCH 01/17] =?UTF-8?q?=F0=9F=90=9B=20Fix=20#491=20-=201.21.4=20?= =?UTF-8?q?export=20being=20used=20for=201.21.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/systems/resourcepackCompiler/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/systems/resourcepackCompiler/index.ts b/src/systems/resourcepackCompiler/index.ts index 05eb68de..3b69684f 100644 --- a/src/systems/resourcepackCompiler/index.ts +++ b/src/systems/resourcepackCompiler/index.ts @@ -22,7 +22,7 @@ function getResourcePackCompilerForVersion(version: string): ResourcePackCompile case VersionUtil.compare(version, '>=', '1.21.2'): return EXPORT_1_21_2 case VersionUtil.compare(version, '>=', '1.21.0'): - return EXPORT_1_21_2 + return EXPORT_1_20_4 case VersionUtil.compare(version, '>=', '1.20.5'): return EXPORT_1_20_4 case VersionUtil.compare(version, '>=', '1.20.4'): From de6ac71a2e957d8e1e124259d90d2016b6528a2c Mon Sep 17 00:00:00 2001 From: SnaveSutit Date: Sun, 26 Apr 2026 13:42:18 -0400 Subject: [PATCH 02/17] =?UTF-8?q?=F0=9F=90=9B=20Fix=20#490=20-=20Scientifi?= =?UTF-8?q?c=20notation=20used=20for=20locator=20transform=20update=20comm?= =?UTF-8?q?ands?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/systems/datapackCompiler/1.20.4/animation.mcb | 10 +++++----- src/systems/datapackCompiler/1.20.5/animation.mcb | 10 +++++----- src/systems/datapackCompiler/1.21.0/animation.mcb | 10 +++++----- src/systems/datapackCompiler/1.21.2/animation.mcb | 10 +++++----- src/systems/datapackCompiler/1.21.4/animation.mcb | 10 +++++----- src/systems/datapackCompiler/1.21.5/animation.mcb | 10 +++++----- 6 files changed, 30 insertions(+), 30 deletions(-) diff --git a/src/systems/datapackCompiler/1.20.4/animation.mcb b/src/systems/datapackCompiler/1.20.4/animation.mcb index 2885f197..77f9b92a 100644 --- a/src/systems/datapackCompiler/1.20.4/animation.mcb +++ b/src/systems/datapackCompiler/1.20.4/animation.mcb @@ -442,11 +442,11 @@ dir animations { lastActiveFrame[node.uuid] = transform ;if (!lastFrame || matrixToNbtFloatArray(transform.matrix).toString() !== matrixToNbtFloatArray(lastFrame.matrix).toString()) { to_merge.locators[node.storage_name] = { - px: transform.pos[0], - py: transform.pos[1], - pz: transform.pos[2], - ry: transform.head_rot[1], - rx: transform.head_rot[0] + px: roundTo(transform.pos[0], 10), + py: roundTo(transform.pos[1], 10), + pz: roundTo(transform.pos[2], 10), + ry: roundTo(transform.head_rot[1], 10), + rx: roundTo(transform.head_rot[0], 10) }; } diff --git a/src/systems/datapackCompiler/1.20.5/animation.mcb b/src/systems/datapackCompiler/1.20.5/animation.mcb index 2f9667f2..b5be4fce 100644 --- a/src/systems/datapackCompiler/1.20.5/animation.mcb +++ b/src/systems/datapackCompiler/1.20.5/animation.mcb @@ -445,11 +445,11 @@ dir animations { lastActiveFrame[node.uuid] = transform ;if (!lastFrame || matrixToNbtFloatArray(transform.matrix).toString() !== matrixToNbtFloatArray(lastFrame.matrix).toString()) { to_merge.locators[node.storage_name] = { - px: transform.pos[0], - py: transform.pos[1], - pz: transform.pos[2], - ry: transform.head_rot[1], - rx: transform.head_rot[0] + px: roundTo(transform.pos[0], 10), + py: roundTo(transform.pos[1], 10), + pz: roundTo(transform.pos[2], 10), + ry: roundTo(transform.head_rot[1], 10), + rx: roundTo(transform.head_rot[0], 10) }; } diff --git a/src/systems/datapackCompiler/1.21.0/animation.mcb b/src/systems/datapackCompiler/1.21.0/animation.mcb index 56f91f43..fdecf1e2 100644 --- a/src/systems/datapackCompiler/1.21.0/animation.mcb +++ b/src/systems/datapackCompiler/1.21.0/animation.mcb @@ -446,11 +446,11 @@ dir animations { lastActiveFrame[node.uuid] = transform ;if (!lastFrame || matrixToNbtFloatArray(transform.matrix).toString() !== matrixToNbtFloatArray(lastFrame.matrix).toString()) { to_merge.locators[node.storage_name] = { - px: transform.pos[0], - py: transform.pos[1], - pz: transform.pos[2], - ry: transform.head_rot[1], - rx: transform.head_rot[0] + px: roundTo(transform.pos[0], 10), + py: roundTo(transform.pos[1], 10), + pz: roundTo(transform.pos[2], 10), + ry: roundTo(transform.head_rot[1], 10), + rx: roundTo(transform.head_rot[0], 10) }; } diff --git a/src/systems/datapackCompiler/1.21.2/animation.mcb b/src/systems/datapackCompiler/1.21.2/animation.mcb index f79875ca..bf9445c7 100644 --- a/src/systems/datapackCompiler/1.21.2/animation.mcb +++ b/src/systems/datapackCompiler/1.21.2/animation.mcb @@ -445,11 +445,11 @@ dir animations { lastActiveFrame[node.uuid] = transform ;if (!lastFrame || matrixToNbtFloatArray(transform.matrix).toString() !== matrixToNbtFloatArray(lastFrame.matrix).toString()) { to_merge.locators[node.storage_name] = { - px: transform.pos[0], - py: transform.pos[1], - pz: transform.pos[2], - ry: transform.head_rot[1], - rx: transform.head_rot[0] + px: roundTo(transform.pos[0], 10), + py: roundTo(transform.pos[1], 10), + pz: roundTo(transform.pos[2], 10), + ry: roundTo(transform.head_rot[1], 10), + rx: roundTo(transform.head_rot[0], 10) }; } diff --git a/src/systems/datapackCompiler/1.21.4/animation.mcb b/src/systems/datapackCompiler/1.21.4/animation.mcb index 72e66cd2..c20c7ad4 100644 --- a/src/systems/datapackCompiler/1.21.4/animation.mcb +++ b/src/systems/datapackCompiler/1.21.4/animation.mcb @@ -510,11 +510,11 @@ dir animations { lastActiveFrame[node.uuid] = transform ;if (!lastFrame || matrixToNbtFloatArray(transform.matrix).toString() !== matrixToNbtFloatArray(lastFrame.matrix).toString()) { to_merge.locators[node.storage_name] = { - px: transform.pos[0], - py: transform.pos[1], - pz: transform.pos[2], - ry: transform.head_rot[1], - rx: transform.head_rot[0] + px: roundTo(transform.pos[0], 10), + py: roundTo(transform.pos[1], 10), + pz: roundTo(transform.pos[2], 10), + ry: roundTo(transform.head_rot[1], 10), + rx: roundTo(transform.head_rot[0], 10) }; } diff --git a/src/systems/datapackCompiler/1.21.5/animation.mcb b/src/systems/datapackCompiler/1.21.5/animation.mcb index edaeff96..3673d381 100644 --- a/src/systems/datapackCompiler/1.21.5/animation.mcb +++ b/src/systems/datapackCompiler/1.21.5/animation.mcb @@ -509,11 +509,11 @@ dir animations { lastActiveFrame[node.uuid] = transform ;if (!lastFrame || matrixToNbtFloatArray(transform.matrix).toString() !== matrixToNbtFloatArray(lastFrame.matrix).toString()) { to_merge.locators[node.storage_name] = { - px: transform.pos[0], - py: transform.pos[1], - pz: transform.pos[2], - ry: transform.head_rot[1], - rx: transform.head_rot[0] + px: roundTo(transform.pos[0], 10), + py: roundTo(transform.pos[1], 10), + pz: roundTo(transform.pos[2], 10), + ry: roundTo(transform.head_rot[1], 10), + rx: roundTo(transform.head_rot[0], 10) }; } From ee50bb3de3ac10e31c0fd8bd3d4e3cb213bf8621 Mon Sep 17 00:00:00 2001 From: SnaveSutit Date: Sun, 26 Apr 2026 13:47:41 -0400 Subject: [PATCH 03/17] =?UTF-8?q?=E2=9C=A8=20Implement=20#476=20-=20Add=20?= =?UTF-8?q?`exportAll`=20to=20global=20API.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/index.ts | 4 ++-- src/interface/animatedJavaBarItem.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/index.ts b/src/index.ts index 1dcfd0e9..68129adf 100644 --- a/src/index.ts +++ b/src/index.ts @@ -28,6 +28,7 @@ import { openExportProgressDialog } from './dialogs/exportProgress/exportProgres import { openUnexpectedErrorDialog } from './dialogs/unexpectedError/unexpectedError' import { BLUEPRINT_FORMAT } from './formats/blueprint' import { BLUEPRINT_CODEC } from './formats/blueprint/codec' +import { exportAll } from './interface/animatedJavaBarItem' import { TextDisplay } from './outliner/textDisplay' import { VanillaBlockDisplay, debugBlockState } from './outliner/vanillaBlockDisplay' import { VanillaItemDisplay } from './outliner/vanillaItemDisplay' @@ -82,6 +83,7 @@ const AnimatedJavaApi = { BLOCKSTATE_REGISTRY, exportProject, openInstallPopup, + exportAll, removeCubesAssociatedWithTexture(texture: Texture) { const cubes = Cube.all.filter(cube => Object.values(cube.faces).some(face => face.texture === texture.uuid) @@ -127,5 +129,3 @@ EVENTS.PLUGIN_FINISHED_LOADING.subscribe(() => { openChangelogDialog() } }) - -import './plugin' diff --git a/src/interface/animatedJavaBarItem.ts b/src/interface/animatedJavaBarItem.ts index d51afb38..01011fa0 100644 --- a/src/interface/animatedJavaBarItem.ts +++ b/src/interface/animatedJavaBarItem.ts @@ -74,7 +74,7 @@ function areMultipleBlueprintsOpen() { return Blockbench.ModelProject.all.filter(p => p.format.id === BLUEPRINT_FORMAT_ID).length > 1 } -async function exportAll(debugMode: boolean) { +export async function exportAll(debugMode: boolean) { const selectedProject = Project const blueprints = Blockbench.ModelProject.all.filter(p => p.format.id === BLUEPRINT_FORMAT_ID) let success = true From a13a8bdadb81b2310710b33f9e868f5cd6ef821f Mon Sep 17 00:00:00 2001 From: SnaveSutit Date: Tue, 28 Apr 2026 22:16:54 -0400 Subject: [PATCH 04/17] =?UTF-8?q?=F0=9F=90=9B=20Fix=20blueprint=20format?= =?UTF-8?q?=20failing=20to=20save?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/formats/blueprint/codec.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/formats/blueprint/codec.ts b/src/formats/blueprint/codec.ts index 1e484ca2..7401d470 100644 --- a/src/formats/blueprint/codec.ts +++ b/src/formats/blueprint/codec.ts @@ -395,7 +395,8 @@ export const BLUEPRINT_CODEC = registerDeletableHandlerPatch({ content: this.compile!(), // eslint-disable-next-line @typescript-eslint/naming-convention custom_writer: (content: string, path: string) => { - if (fs.existsSync(PathModule.dirname(path))) { + const { existsSync } = getFsModule() + if (existsSync(PathModule.dirname(path))) { Project!.save_path = path this.write!(content, path) } else { From 912f52bb5a4ee80cc6ca7bd6f7bde4b3712d4f1a Mon Sep 17 00:00:00 2001 From: SnaveSutit Date: Tue, 28 Apr 2026 22:17:31 -0400 Subject: [PATCH 05/17] =?UTF-8?q?=F0=9F=90=9B=20Fix=20keyframe=20panel=20m?= =?UTF-8?q?ods?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/index.ts | 2 + src/interface/keyframeEasings.ts | 42 +++++++--- src/panels/customKeyframe/customKeyframe.ts | 93 ++++++++++++--------- src/svelteComponents/keyframeEasings.svelte | 2 + 4 files changed, 87 insertions(+), 52 deletions(-) diff --git a/src/index.ts b/src/index.ts index 68129adf..a3b75830 100644 --- a/src/index.ts +++ b/src/index.ts @@ -129,3 +129,5 @@ EVENTS.PLUGIN_FINISHED_LOADING.subscribe(() => { openChangelogDialog() } }) + +import './plugin' diff --git a/src/interface/keyframeEasings.ts b/src/interface/keyframeEasings.ts index b21f88a9..4560ee12 100644 --- a/src/interface/keyframeEasings.ts +++ b/src/interface/keyframeEasings.ts @@ -1,5 +1,6 @@ import { registerPatch } from 'blockbench-patch-manager' import { injectComponent } from 'svelte-patching-tools' +import { activeProjectIsBlueprintFormat } from '../formats/blueprint' import KeyframeEasingsSvelte from '../svelteComponents/keyframeEasings.svelte' import EVENTS from '../util/events' @@ -12,24 +13,43 @@ function isFirstKeyframe(kf: _Keyframe) { } let unmountCallback: (() => Promise) | null = null -let selectedKeyframe: _Keyframe | undefined +let currentUpdatePromise: Promise | null = null -registerPatch({ - id: 'animated_java:mounted-svelte/keyframe-easings', - apply() { - const unsub = EVENTS.UPDATE_KEYFRAME_SELECTION.subscribe(async () => { - selectedKeyframe = Timeline.selected.at(0) - await unmountCallback?.() - if (!selectedKeyframe || isFirstKeyframe(selectedKeyframe)) return +const updatePanel = () => { + if (currentUpdatePromise) { + return currentUpdatePromise.then(() => { + void updatePanel() + }) + } + currentUpdatePromise = new Promise(async resolve => { + await unmountCallback?.() + if (!activeProjectIsBlueprintFormat()) return + + const selectedKeyframe = Timeline.selected.at(0) + if (selectedKeyframe && !isFirstKeyframe(selectedKeyframe)) { unmountCallback = injectComponent({ component: KeyframeEasingsSvelte, props: { selectedKeyframe }, - elementSelector(): HTMLElement | null { - return document.querySelector('#panel_keyframe') + elementSelector() { + return Panels.keyframe.node + }, + postMount() { + currentUpdatePromise = null + resolve() }, }) - }) + } else { + currentUpdatePromise = null + resolve() + } + }) +} + +registerPatch({ + id: 'animated_java:mounted-svelte/keyframe-easings', + apply() { + const unsub = EVENTS.UPDATE_KEYFRAME_SELECTION.subscribe(() => void updatePanel()) return { unsub } }, diff --git a/src/panels/customKeyframe/customKeyframe.ts b/src/panels/customKeyframe/customKeyframe.ts index 8e493aa8..dd467f72 100644 --- a/src/panels/customKeyframe/customKeyframe.ts +++ b/src/panels/customKeyframe/customKeyframe.ts @@ -1,12 +1,61 @@ import { registerPatch } from 'blockbench-patch-manager' import { injectComponent } from 'svelte-patching-tools' -import { EFFECT_ANIMATOR_CHANNELS, isCustomKeyframeChannel } from '../../mods/customKeyframes' +import { EFFECT_ANIMATOR_CHANNELS } from '../../mods/customKeyframes' import EVENTS from '../../util/events' import { localize as translate } from '../../util/lang' import CommandsKeyframePanel from './commandsKeyframe.svelte' import VariantKeyframePanel from './variantKeyframe.svelte' let unmountCallback: (() => Promise) | null = null +let currentUpdatePromise: Promise | null = null + +const updatePanel = () => { + if (currentUpdatePromise) { + return currentUpdatePromise.then(() => { + void updatePanel() + }) + } + + currentUpdatePromise = new Promise(async resolve => { + await unmountCallback?.() + + // if (!activeProjectIsBlueprintFormat()) return + + const keyframe = Timeline.selected.at(0) + if (keyframe) { + let component: any + switch (keyframe.channel) { + case EFFECT_ANIMATOR_CHANNELS.VARIANT: + component = VariantKeyframePanel + break + + case EFFECT_ANIMATOR_CHANNELS.FUNCTION: + component = CommandsKeyframePanel + break + + default: + currentUpdatePromise = null + resolve() + return + } + + unmountCallback = injectComponent({ + component, + props: { keyframe }, + elementSelector() { + return Panels.keyframe.node + }, + postMount() { + currentUpdatePromise = null + resolve() + }, + }) + } else { + currentUpdatePromise = null + resolve() + } + }) +} registerPatch({ id: 'animated_java:panel/custom-keyframe-data-points', @@ -18,46 +67,8 @@ registerPatch({ Language.data['timeline.function'] = translate('effect_animator.timeline.function') const unsubs = [ - EVENTS.UPDATE_KEYFRAME_SELECTION.subscribe(async () => { - await unmountCallback?.() - unmountCallback = null - - const keyframe = Timeline.selected.at(0) - const isCustomKeyframe = isCustomKeyframeChannel(keyframe?.channel ?? '') - - if (keyframe && isCustomKeyframe) { - let component: any - switch (keyframe.channel) { - case EFFECT_ANIMATOR_CHANNELS.VARIANT: - component = VariantKeyframePanel - break - - case EFFECT_ANIMATOR_CHANNELS.FUNCTION: - component = CommandsKeyframePanel - break - - default: - console.error(`Unknown custom keyframe channel: '${keyframe.channel}'`) - return - } - - unmountCallback = injectComponent({ - component, - props: { keyframe }, - elementSelector(): HTMLElement | null { - return document.querySelector( - '#panel_keyframe .panel_vue_wrapper .keyframe_data_point' - ) - }, - // hideTargetChildren: true, - }) - } - }), - - EVENTS.UNSELECT_AJ_PROJECT.subscribe(async () => { - await unmountCallback?.() - unmountCallback = null - }), + EVENTS.UPDATE_KEYFRAME_SELECTION.subscribe(() => void updatePanel()), + EVENTS.UNSELECT_AJ_PROJECT.subscribe(() => void updatePanel()), ] return { unsubs } diff --git a/src/svelteComponents/keyframeEasings.svelte b/src/svelteComponents/keyframeEasings.svelte index 3011174e..dce3b8ff 100644 --- a/src/svelteComponents/keyframeEasings.svelte +++ b/src/svelteComponents/keyframeEasings.svelte @@ -58,6 +58,7 @@ } else { kf.easing = getEasingFunctionName(type, mode) } + Project.saved = false } function setKeyframeEasingArg(kf: _Keyframe, arg: number | undefined) { @@ -66,6 +67,7 @@ } else { kf.easingArgs = [arg] } + Project.saved = false } function getEasingFunctionName(type: string, mode = 'inout') { From adcc0e240068e6e7b61e528450a55404786d2458 Mon Sep 17 00:00:00 2001 From: SnaveSutit Date: Tue, 28 Apr 2026 22:18:13 -0400 Subject: [PATCH 06/17] =?UTF-8?q?=E2=9C=A8=20Update=20CONTRIBUTING.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CONTRIBUTING.md | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 560d0f37..eb6c1ac8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -11,21 +11,18 @@ Contributions are always welcome, however, please consult @SnaveSutit before sta ### 🛠️ Prerequisites -- #### Required +- #### Required + - [Bun](https://bun.sh/) + - [Git](https://git-scm.com/) - - [Node.js](https://nodejs.org/en/) - - [Yarn](https://classic.yarnpkg.com/lang/en/docs/install/#windows-stable) - - [Git](https://git-scm.com/) - -- #### Recommended - - - [VSCode](https://code.visualstudio.com/) +- #### Recommended + - [VSCode](https://code.visualstudio.com/) > (or any other code editor, but this project has configurations for VSCode) - - [Blockbench](https://www.blockbench.net/) + - [Blockbench](https://www.blockbench.net/) > The repository includes [Envbench](https://github.com/SnaveSutit/envbench) to create and manage a dev instance of Blockbench, So installing Blockbench separately is not strictly required. - - [SnaveSutit's Blockbench Types](https://github.com/SnaveSutit/blockbench-types) - > Bleeding edge types for Blockbench plugins.
Install via `yarn add -D https://github.com/SnaveSutit/blockbench-types.git` - - [GitButler](https://gitbutler.com/) + - [SnaveSutit's Blockbench Types](https://github.com/SnaveSutit/blockbench-types) + > Bleeding edge types for Blockbench plugins.
Install via `bun add -D https://github.com/SnaveSutit/blockbench-types.git` + - [GitButler](https://gitbutler.com/) > A Git client for simultaneous branches on top of your existing workflow. ## 🖇️ Cloning the Repository @@ -34,7 +31,7 @@ Contributions are always welcome, however, please consult @SnaveSutit before sta > [How do I clone a repository?](https://docs.github.com/en/repositories/creating-and-managing-repositories/cloning-a-repository) -2. Run `yarn install` to install dependencies. +2. Run `bun install` to install dependencies. 3. Open up `src/blockbenchTypes.d.ts` and replace the first line with the following: @@ -44,9 +41,9 @@ Contributions are always welcome, however, please consult @SnaveSutit before sta > By default this references my local fork of the Blockbench types to quickly add / adjust types as needed. So you need to adjust this to the official Blockbench types, or your own fork, if you're not me. -4. Run `yarn dev` to start the development environment, which will watch for changes and recompile the plugin. +4. Run `bun run dev` to start the development environment, which will watch for changes and recompile the plugin. -5. Open a new terminal, or click `Split` if you're in VSCode's terminal, and run `yarn start` to start the development instance of Blockbench. +5. Open a new terminal, or click `Split` if you're in VSCode's terminal, and run `bun run start` to start the development instance of Blockbench. 6. That's it! You're ready to start developing. From 33b9fe0327cb28c736778db567d1419a40a525e0 Mon Sep 17 00:00:00 2001 From: SnaveSutit Date: Tue, 28 Apr 2026 22:18:54 -0400 Subject: [PATCH 07/17] =?UTF-8?q?=E2=9C=82=EF=B8=8F=20Remove=20debug=20log?= =?UTF-8?q?s?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/systems/minecraft/fontManager.ts | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/systems/minecraft/fontManager.ts b/src/systems/minecraft/fontManager.ts index d0292f9b..da516002 100644 --- a/src/systems/minecraft/fontManager.ts +++ b/src/systems/minecraft/fontManager.ts @@ -179,7 +179,7 @@ class BitmapFontProvider extends FontProvider { this.ascent = providerJSON.ascent for (const row of providerJSON.chars) { const str = new UnicodeString(row) - console.log({ row, str }) + // console.log({ row, str }) this.chars.push(str) } } @@ -196,15 +196,15 @@ class BitmapFontProvider extends FontProvider { this.charHeight = texture.image.height / this.chars.length this.charWidth = texture.image.width / this.chars[0].length if (!Number.isFinite(this.charWidth)) { - console.log({ - providerJSON: this.providerJSON, - bitmapPath: this.bitmapPath, - imageWidth: texture.image.width, - charsPerRow: this.chars[0].length, - calculatedCharWidth: this.charWidth, - chars: this.chars, - texture, - }) + // console.log({ + // providerJSON: this.providerJSON, + // bitmapPath: this.bitmapPath, + // imageWidth: texture.image.width, + // charsPerRow: this.chars[0].length, + // calculatedCharWidth: this.charWidth, + // chars: this.chars, + // texture, + // }) throw new Error( `Invalid character width calculated from bitmap font atlas: ${this.charWidth}` ) @@ -325,7 +325,7 @@ export class MinecraftFont { throw error } - console.log(this.assetPath, fontJSON) + // console.log(this.assetPath, fontJSON) for (const providerJSON of fontJSON.providers) { switch (providerJSON.type) { From 04710f930f162bbf3199056cdca6437f2387ddf4 Mon Sep 17 00:00:00 2001 From: SnaveSutit Date: Tue, 28 Apr 2026 22:19:29 -0400 Subject: [PATCH 08/17] =?UTF-8?q?=F0=9F=9A=A7=20Interaction=20Nodes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 1 - .../interactionConfig.svelte | 79 +++++++++ .../interactionConfig/interactionConfig.ts | 138 +++++++++++++++ src/dialogs/locatorConfig/locatorConfig.ts | 1 + src/formats/blueprint/index.ts | 15 +- src/lang/en.yml | 56 ++++++ src/mods/boundingBox.ts | 165 ++++++++++++++++++ src/mods/locatorAnimatorMod.ts | 2 +- src/nodeConfigs.ts | 116 ++++++++++++ src/systems/animationRenderer.ts | 17 +- src/systems/rigRenderer.ts | 43 +++++ 11 files changed, 617 insertions(+), 16 deletions(-) create mode 100644 src/dialogs/interactionConfig/interactionConfig.svelte create mode 100644 src/dialogs/interactionConfig/interactionConfig.ts create mode 100644 src/mods/boundingBox.ts diff --git a/package.json b/package.json index 8dc2b5e7..2423e259 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,6 @@ "description": "Effortlessly craft complex animations for Minecraft: Java Edition", "version": "1.10.0-beta.5", "min_blockbench_version": "5.1.4", - "max_blockbench_version": "5.1.4", "variant": "desktop", "tags": [ "Minecraft: Java Edition", diff --git a/src/dialogs/interactionConfig/interactionConfig.svelte b/src/dialogs/interactionConfig/interactionConfig.svelte new file mode 100644 index 00000000..1f9ba930 --- /dev/null +++ b/src/dialogs/interactionConfig/interactionConfig.svelte @@ -0,0 +1,79 @@ + + + + +
+ {#if PLUGIN_MODE} + {#each localize('dialog.interaction_config.plugin_mode_warning').split('\n') as line} +

{line}

+ {/each} + {:else} + + + + + + + + + + + + {/if} +
+ + diff --git a/src/dialogs/interactionConfig/interactionConfig.ts b/src/dialogs/interactionConfig/interactionConfig.ts new file mode 100644 index 00000000..95ade895 --- /dev/null +++ b/src/dialogs/interactionConfig/interactionConfig.ts @@ -0,0 +1,138 @@ +import { + registerDeletableHandlerPatch, + registerPropertyOverridePatch, +} from 'blockbench-patch-manager' +import { observable } from 'svelte-observable-store' +import { SvelteDialog } from 'svelte-patching-tools/blockbench' +import { PACKAGE } from '../../constants' +import { activeProjectIsBlueprintFormat } from '../../formats/blueprint' +import { InteractionConfig } from '../../nodeConfigs' +import { localize } from '../../util/lang' +import LocatorConfigDialog from './interactionConfig.svelte' + +// TODO - Make on-tick function work without requiring use-entity. + +export function openInteractionConfigDialog(interaction: BoundingBox) { + // Blockbench's JSON stringifier doesn't handle custom toJSON functions, so I'm storing the config JSON in the bounding box instead of the actual BoundingBoxConfig object + const boundingBoxConfig = InteractionConfig.fromJSON( + // @ts-expect-error - Broken BB types + (interaction.config ??= new InteractionConfig().toJSON()) + ) + + const response = observable(boundingBoxConfig.response) + const onSummonFunction = observable(boundingBoxConfig.onSummonFunction) + const onInteractionFunction = observable(boundingBoxConfig.onInteractionFunction) + const onAttackFunction = observable(boundingBoxConfig.onAttackFunction) + const onRemoveFunction = observable(boundingBoxConfig.onRemoveFunction) + const onTickFunction = observable(boundingBoxConfig.onTickFunction) + + new SvelteDialog({ + id: `${PACKAGE.name}:interactionConfig`, + title: localize('dialog.interaction_config.title'), + width: 800, + component: LocatorConfigDialog, + props: { + response, + onSummonFunction, + onInteractionFunction, + onAttackFunction, + onRemoveFunction, + onTickFunction, + }, + disableKeybinds: true, + onConfirm() { + boundingBoxConfig.response = response.get() + boundingBoxConfig.onSummonFunction = onSummonFunction.get() + boundingBoxConfig.onInteractionFunction = onInteractionFunction.get() + boundingBoxConfig.onAttackFunction = onAttackFunction.get() + boundingBoxConfig.onRemoveFunction = onRemoveFunction.get() + boundingBoxConfig.onTickFunction = onTickFunction.get() + + // @ts-expect-error - Broken BB types + interaction.config = boundingBoxConfig.toJSON() + }, + }).show() +} + +const OPEN_INTERACTION_CONFIG = registerDeletableHandlerPatch({ + id: `animated_java:action/interaction-config`, + create() { + // @ts-expect-error - Broken BB types + const action = new Blockbench.Action(`animated_java:action/interaction-config`, { + icon: 'settings', + name: localize('action.open_interaction_config.name'), + condition: () => activeProjectIsBlueprintFormat(), + click: () => { + const interaction = BoundingBox.selected.at(0) + if (!interaction) return + // @ts-expect-error - Broken BB types + openInteractionConfigDialog(interaction) + }, + }) + return action + }, +}) + +registerPropertyOverridePatch({ + id: `animated_java:bounding-box/extend`, + target: BoundingBox.prototype, + key: 'extend', + + get: function (this, value) { + if (activeProjectIsBlueprintFormat()) { + return function (this: BoundingBox, ...args) { + const result = value.apply(this, args) + this.menu = BoundingBox.prototype.menu + return result + } + } + return value + }, +}) + +registerPropertyOverridePatch({ + id: `animated_java:bounding-box/menu`, + dependencies: [`animated_java:action/interaction-config`], + target: BoundingBox.prototype, + key: 'menu', + + get: function (this, value) { + if (activeProjectIsBlueprintFormat()) { + return new Menu([ + ...Outliner.control_menu_group, + new MenuSeparator('export'), + 'generate_bedrock_block_box', + 'generate_bedrock_entity_box', + new MenuSeparator('interaction'), + OPEN_INTERACTION_CONFIG.get(), + new MenuSeparator('settings'), + { + name: 'menu.cube.color', + icon: 'color_lens', + children() { + return markerColors.map((color, i) => { + return { + icon: 'bubble_chart', + color: color.standard, + // @ts-expect-error - Broken BB types + name: color.name ?? 'cube.color.' + color.id, + click(element: BoundingBox) { + // @ts-expect-error - Broken BB types + element.forSelected((obj: BoundingBox) => { + obj.setColor(i) + }, 'Change color') + }, + } + }) + }, + }, + 'randomize_marker_colors', + new MenuSeparator('manage'), + 'rename', + 'toggle_visibility', + 'delete', + ]) + } + return value + }, +}) diff --git a/src/dialogs/locatorConfig/locatorConfig.ts b/src/dialogs/locatorConfig/locatorConfig.ts index 792f2564..69548342 100644 --- a/src/dialogs/locatorConfig/locatorConfig.ts +++ b/src/dialogs/locatorConfig/locatorConfig.ts @@ -50,6 +50,7 @@ export function openLocatorConfigDialog(locator: Locator) { registerDeletableHandlerPatch({ id: `animated_java:action/locator-config`, create() { + // @ts-expect-error - Broken BB types const action = new Blockbench.Action(`animated_java:action/locator-config`, { icon: 'settings', name: translate('action.open_locator_config.name'), diff --git a/src/formats/blueprint/index.ts b/src/formats/blueprint/index.ts index d5897792..85ac29d4 100644 --- a/src/formats/blueprint/index.ts +++ b/src/formats/blueprint/index.ts @@ -5,7 +5,7 @@ import { mount, unmount } from 'svelte' import { observable, type Observable } from 'svelte-observable-store' import { injectComponent } from 'svelte-patching-tools' import AnimatedJavaIcon from '../../assets/icons/animated_java_fancy_icon_centered.svg' -import { DisplayEntityConfig, LocatorConfig } from '../../nodeConfigs' +import { DisplayEntityConfig, InteractionConfig, LocatorConfig } from '../../nodeConfigs' import { type TextDisplay } from '../../outliner/textDisplay' import { type VanillaBlockDisplay } from '../../outliner/vanillaBlockDisplay' import { type VanillaItemDisplay } from '../../outliner/vanillaItemDisplay' @@ -65,6 +65,18 @@ export interface IBlueprintLocatorConfigJSON { on_tick_function?: LocatorConfig['__onTickFunction'] } +/** + * The serialized Variant Interaction Config + */ +export interface IBlueprintInteractionConfigJSON { + response?: InteractionConfig['__response'] + on_summon_function?: InteractionConfig['__onSummonFunction'] + on_interaction_function?: InteractionConfig['__onInteractionFunction'] + on_attack_function?: InteractionConfig['__onAttackFunction'] + on_remove_function?: InteractionConfig['__onRemoveFunction'] + on_tick_function?: InteractionConfig['__onTickFunction'] +} + /** * The serialized Variant */ @@ -361,6 +373,7 @@ export const BLUEPRINT_FORMAT = registerDeletableHandlerPatch({ single_texture: false, texture_folder: false, texture_meshes: false, + bounding_boxes: true, uv_rotation: true, vertex_color_ambient_occlusion: true, java_cube_shading_properties: true, diff --git a/src/lang/en.yml b/src/lang/en.yml index 9c6211bd..b6ca849b 100644 --- a/src/lang/en.yml +++ b/src/lang/en.yml @@ -26,6 +26,8 @@ animated_java: name: Display Entity Config open_locator_config: name: Locator Config + open_interaction_config: + name: Interaction Config export: name: Export export_debug: @@ -506,7 +508,61 @@ animated_java: [Markdown] Commands to run `as` and `at` the Locator's entity every tick. + interaction_config: + title: Interaction Config + plugin_mode_warning: |- + Plugin Mode is enabled! Interaction have no configuration in Plugin Mode. + Instead, use the Plugin API to add custom functionality to your Interaction. + For more information, see the Official Plugin API documentation for more information. + + response: + title: Response + description: Whether interacting with this Interaction should trigger a response (hand animation / attack sound). + + on_summon_function: + title: On-Summon Function + description: |- + [Markdown] + Commands to run `as` and `at` this Interaction when summoned. + + Supports [MC-Build](https://mcbuild.dev) syntax. + + on_interaction_function: + title: On-Interaction Function + description: |- + [Markdown] + Commands to run `as` and `at` this Interaction when a player interacts with it. + + You can use `execute on target` to select the player who initiated the interaction. + + Supports [MC-Build](https://mcbuild.dev) syntax. + + on_attack_function: + title: On-Attack Function + description: |- + [Markdown] + Commands to run `as` and `at` this Interaction when a player attacks it. + + You can use `execute on attacker` to select the player who initiated the attack. + + Supports [MC-Build](https://mcbuild.dev) syntax. + + on_remove_function: + title: On-Remove Function + description: |- + [Markdown] + Commands to run `as` and `at` this Interaction when removed. + Supports [MC-Build](https://mcbuild.dev) syntax. + + on_tick_function: + title: On-Tick Function + description: |- + [Markdown] + Commands to run `as` and `at` this Interaction every tick. + + Supports [MC-Build](https://mcbuild.dev) syntax. + text_display_config: title: Text Display Config use_nbt: diff --git a/src/mods/boundingBox.ts b/src/mods/boundingBox.ts new file mode 100644 index 00000000..7cc5fdab --- /dev/null +++ b/src/mods/boundingBox.ts @@ -0,0 +1,165 @@ +import { registerPatch, registerPropertyOverridePatch } from 'blockbench-patch-manager' +import { + activeProjectIsBlueprintFormat, + type IBlueprintInteractionConfigJSON, +} from '../formats/blueprint' +import { DisplayEntityConfig } from '../nodeConfigs' +import { sanitizeOutlinerElementName } from '../outliner/util' +import { DeepClonedObjectProperty } from '../util/property' + +declare global { + // @ts-expect-error - Broken BB Types + interface BoundingBox { + onSummonFunction: string + config: IBlueprintInteractionConfigJSON + } +} + +registerPropertyOverridePatch({ + id: 'animated_java:bounding_box/square_horizontal_size/resize', + target: BoundingBox.prototype, + key: 'resize', + + get: function (this, value) { + if (activeProjectIsBlueprintFormat()) { + return function ( + this: BoundingBox, + val: number | ((offset: number) => number), + axis: axisNumber, + negative?: boolean, + allowNegative?: boolean, + bidirectional?: boolean + ) { + const result = value.call(this, val, axis, negative, allowNegative, bidirectional) + + if (axis === 0) { + this.from = [this.from[0], this.from[1], this.from[0]] + this.to = [this.to[0], this.to[1], this.to[0]] + } else if (axis === 2) { + this.from = [this.from[2], this.from[1], this.from[2]] + this.to = [this.to[2], this.to[1], this.to[2]] + } + + this.preview_controller.updateGeometry(this) + TickUpdates.selection = true + + return result + } + } + return value + }, +}) + +registerPropertyOverridePatch({ + id: 'animated_java:bounding_box/preview_controller/update_transform', + target: BoundingBox.prototype.preview_controller, + key: 'updateTransform', + + get: function (this, value) { + if (activeProjectIsBlueprintFormat()) { + console.log('Applying bounding box preview controller patch') + return function (this: NodePreviewController, el: BoundingBox) { + const mesh = el.mesh + if (el.getTypeBehavior('movable')) { + mesh.position.set(el.origin[0], el.origin[1], el.origin[2]) + } + if (mesh.parent !== Project.model_3d) { + Project.model_3d.add(mesh) + } + + if (el.mesh.fix_position) { + el.mesh.fix_position.set(...el.origin) + if (el.parent instanceof Group) { + el.mesh.fix_position.x -= el.parent.mesh.position.x + el.mesh.fix_position.y -= el.parent.mesh.position.y + el.mesh.fix_position.z -= el.parent.mesh.position.z + } + } + if (el.mesh.fix_rotation) { + el.mesh.fix_rotation.copy(el.mesh.rotation) + } + + mesh.updateMatrixWorld() + this.dispatchEvent('update_transform', { element: el }) + return + } + } + return value + }, +}) + +registerPropertyOverridePatch({ + id: 'animated_java:bounding_box/preview_controller/setup', + target: BoundingBox.prototype.preview_controller, + key: 'setup', + + get: function (this, value) { + if (activeProjectIsBlueprintFormat()) { + return function (this: NodePreviewController, el: BoundingBox) { + const result = value.call(this, el) + + const mesh = el.mesh + mesh.fix_rotation = new THREE.Euler(0, 0, 0, 'ZYX') + mesh.fix_position = new THREE.Vector3(...el.position) + + return result + } + } + return value + }, +}) + +registerPatch({ + id: `animated_java:bounding_box/custom_properties`, + + apply: () => { + const properties = [ + new Property(BoundingBox, 'string', 'onSummonFunction', { + condition: activeProjectIsBlueprintFormat, + default: '', + }), + new DeepClonedObjectProperty(BoundingBox, 'config', { + condition: activeProjectIsBlueprintFormat, + default: () => { + return { default: new DisplayEntityConfig().toJSON(), variants: {} } + }, + }), + ] + + return { properties } + }, + + revert: ({ properties }) => { + properties.forEach(prop => prop.delete()) + }, +}) + +registerPropertyOverridePatch({ + id: `animated_java:override_function/bounding_box/save_name`, + target: BoundingBox.prototype, + key: 'saveName', + + condition: () => activeProjectIsBlueprintFormat(), + + get: original => { + return function (this: BoundingBox, save?: boolean) { + this.name = sanitizeOutlinerElementName(this.name, this.uuid) + return original.call(this, save) + } + }, +}) + +registerPropertyOverridePatch({ + id: `animated_java:override_function/bounding_box/sanitize_name`, + target: BoundingBox.prototype, + key: 'sanitizeName', + + condition: () => activeProjectIsBlueprintFormat(), + + get: original => { + return function (this: BoundingBox) { + this.name = sanitizeOutlinerElementName(this.name, this.uuid) + return original.call(this) + } + }, +}) diff --git a/src/mods/locatorAnimatorMod.ts b/src/mods/locatorAnimatorMod.ts index 29687958..a70f65b3 100644 --- a/src/mods/locatorAnimatorMod.ts +++ b/src/mods/locatorAnimatorMod.ts @@ -171,7 +171,7 @@ registerProjectPatch({ apply: () => { const unsub = EVENTS.UPDATE_SELECTION.subscribe(() => { if (Mode.selected.id !== Modes.options.animate.id) return - if (selected.at(0) instanceof Locator) { + if (Outliner.selected.at(0) instanceof Locator) { Canvas.gizmos[0].visible = false Transformer.visible = false } diff --git a/src/nodeConfigs.ts b/src/nodeConfigs.ts index c5ec2973..5f2a4d1a 100644 --- a/src/nodeConfigs.ts +++ b/src/nodeConfigs.ts @@ -1,6 +1,7 @@ import { NbtByte, NbtCompound, NbtFloat, NbtInt, NbtList, NbtString } from 'deepslate/lib/nbt' import type { IBlueprintDisplayEntityConfigJSON, + IBlueprintInteractionConfigJSON, IBlueprintLocatorConfigJSON, } from './formats/blueprint' import { scrubUndefined } from './util/misc' @@ -397,3 +398,118 @@ export class LocatorConfig { ) } } + +export class InteractionConfig { + private __response?: boolean + private __onInteractionFunction?: string + private __onAttackFunction?: string + private __onSummonFunction?: string + private __onRemoveFunction?: string + private __onTickFunction?: string + + getDefault(): InteractionConfig { + return InteractionConfig.fromJSON({ + response: false, + on_interaction_function: '', + on_attack_function: '', + on_summon_function: '', + on_remove_function: '', + on_tick_function: '', + }) + } + + get response(): NonNullable { + if (this.__response !== undefined) return this.__response + const defaultConfig = this.getDefault() + return defaultConfig.response + } + set response(value: NonNullable) { + this.__response = value + } + + get onInteractionFunction(): NonNullable { + if (this.__onInteractionFunction !== undefined) return this.__onInteractionFunction + const defaultConfig = this.getDefault() + return defaultConfig.onInteractionFunction + } + set onInteractionFunction(value: NonNullable) { + this.__onInteractionFunction = value + } + + get onAttackFunction(): NonNullable { + if (this.__onAttackFunction !== undefined) return this.__onAttackFunction + const defaultConfig = this.getDefault() + return defaultConfig.onAttackFunction + } + set onAttackFunction(value: NonNullable) { + this.__onAttackFunction = value + } + + get onSummonFunction(): NonNullable { + if (this.__onSummonFunction !== undefined) return this.__onSummonFunction + const defaultConfig = this.getDefault() + return defaultConfig.onSummonFunction + } + set onSummonFunction(value: NonNullable) { + this.__onSummonFunction = value + } + + get onRemoveFunction(): NonNullable { + if (this.__onRemoveFunction !== undefined) return this.__onRemoveFunction + const defaultConfig = this.getDefault() + return defaultConfig.onRemoveFunction + } + set onRemoveFunction(value: NonNullable) { + this.__onRemoveFunction = value + } + + get onTickFunction(): NonNullable { + if (this.__onTickFunction !== undefined) return this.__onTickFunction + const defaultConfig = this.getDefault() + return defaultConfig.onTickFunction + } + set onTickFunction(value: NonNullable) { + this.__onTickFunction = value + } + + toJSON(): IBlueprintInteractionConfigJSON { + return scrubUndefined({ + response: this.__response, + on_interaction_function: this.__onInteractionFunction, + on_attack_function: this.__onAttackFunction, + on_summon_function: this.__onSummonFunction, + on_remove_function: this.__onRemoveFunction, + on_tick_function: this.__onTickFunction, + }) + } + + static fromJSON(json: IBlueprintInteractionConfigJSON): InteractionConfig { + const config = new InteractionConfig() + if (json.response !== undefined) config.__response = json.response + if (json.on_interaction_function !== undefined) + config.__onInteractionFunction = json.on_interaction_function + if (json.on_attack_function !== undefined) + config.__onAttackFunction = json.on_attack_function + if (json.on_summon_function !== undefined) + config.__onSummonFunction = json.on_summon_function + if (json.on_remove_function !== undefined) + config.__onRemoveFunction = json.on_remove_function + if (json.on_tick_function !== undefined) config.__onTickFunction = json.on_tick_function + return config + } + + isDefault(): boolean { + return this.checkIfEqual(new InteractionConfig()) + } + + checkIfEqual(other: InteractionConfig) { + return ( + this.response === other.response && + this.onInteractionFunction === other.onInteractionFunction && + this.onAttackFunction === other.onAttackFunction && + this.onSummonFunction === other.onSummonFunction && + this.onRemoveFunction === other.onRemoveFunction && + this.onTickFunction === other.onTickFunction + ) + } +} diff --git a/src/systems/animationRenderer.ts b/src/systems/animationRenderer.ts index 67ea1cb8..7f4c0aa9 100644 --- a/src/systems/animationRenderer.ts +++ b/src/systems/animationRenderer.ts @@ -216,6 +216,7 @@ export function getFrame( // lastFrameCache.set(uuid, { matrix, keyframe }) break } + case 'interaction': case 'camera': case 'struct': { transform.matrix = getNodeMatrix(outlinerNode, 1) @@ -232,7 +233,7 @@ export function getFrame( transform.matrix.decompose(pos, rot, scale) transform.decomposed = getDecomposedTransformation(transform.matrix) - if (node.type === 'locator' || node.type === 'camera') { + if (node.type === 'locator' || node.type === 'camera' || node.type === 'interaction') { node.max_distance = Math.max(node.max_distance, pos.length()) } @@ -288,18 +289,7 @@ function getFunctionKeyframe( export function updatePreview(animation: _Animation, time: number) { Timeline.time = time Animator.showDefaultPose(true) - const nodes: OutlinerNode[] = [ - ...Group.all, - ...NullObject.all, - ...Locator.all, - ...TextDisplay.all, - ...VanillaBlockDisplay.all, - ...VanillaItemDisplay.all, - ] - if (OutlinerElement.types.camera) { - // @ts-expect-error - Broken BB types - nodes.push(...OutlinerElement.types.camera.all) - } + const nodes: OutlinerNode[] = getAnimatableNodes() for (const node of nodes) { if (!(node.constructor as any).animator) continue Animator.resetLastValues() @@ -377,6 +367,7 @@ export function getAnimatableNodes(): OutlinerElement[] { return [ ...Group.all, ...Locator.all, + ...BoundingBox.all, ...TextDisplay.all, ...VanillaBlockDisplay.all, ...VanillaItemDisplay.all, diff --git a/src/systems/rigRenderer.ts b/src/systems/rigRenderer.ts index c1154e0f..6a5945fd 100644 --- a/src/systems/rigRenderer.ts +++ b/src/systems/rigRenderer.ts @@ -3,6 +3,7 @@ import * as crypto from 'node:crypto' import { getFsModule } from '../constants' import type { IBlueprintDisplayEntityConfigJSON, + IBlueprintInteractionConfigJSON, IBlueprintLocatorConfigJSON, IBlueprintVariantJSON, } from '../formats/blueprint' @@ -150,6 +151,14 @@ export interface IRenderedNodes { max_distance: number config?: IBlueprintLocatorConfigJSON } + Interaction: IRenderedNode & { + type: 'interaction' + width: number + height: number + /** The maximum distance this node travels away from the root entity while animating. */ + max_distance: number + config: IBlueprintInteractionConfigJSON + } } export type AnyRenderedNode = IRenderedNodes[keyof IRenderedNodes] @@ -593,6 +602,27 @@ function renderLocator(locator: Locator, rig: IRenderedRig) { rig.nodes[locator.uuid] = renderedLocator } +function renderInteraction(box: BoundingBox, rig: IRenderedRig) { + if (!box.export) return + const parentId = box.parent instanceof Group ? box.parent.uuid : undefined + + const renderedInteraction: IRenderedNodes['Interaction'] = { + type: 'interaction', + name: box.name, + storage_name: sanitizeStorageKey(box.name), + uuid: box.uuid, + parent: parentId, + // @ts-expect-error - Broken BB types + config: structuredClone(box.config), + max_distance: 0, + default_transform: {} as INodeTransform, + width: box.to[0] - box.from[0], + height: box.to[1] - box.from[1], + } + + rig.nodes[box.uuid] = renderedInteraction +} + function renderCamera(camera: ICamera, rig: IRenderedRig) { if (!camera.export) return const parentId = typeof camera.parent === 'string' ? camera.parent : camera.parent.uuid @@ -712,6 +742,14 @@ export function hashRig(rig: IRenderedRig) { } break } + + case 'interaction': { + hash.update(`;${node.width};${node.height}`) + if (node.config) { + hash.update(';' + JSON.stringify(node.config)) + } + break + } } } return hash.digest('hex') @@ -725,6 +763,7 @@ function renderVariant(variant: Variant, rig: IRenderedRig): IRenderedVariant { } function getDefaultTransforms(rig: IRenderedRig) { + // @ts-expect-error - Broken BB types const anim = new Blockbench.Animation() correctSceneAngle() updatePreview(anim, 0) @@ -781,6 +820,10 @@ export function renderRig(modelExportFolder: string, textureExportFolder: string renderBlockDisplay(node, rig) break } + case node instanceof BoundingBox: { + renderInteraction(node, rig) + break + } case node instanceof Cube: { throw new IntentionalExportError( `Cubes cannot be exported as root nodes. Please parent them to a bone. (Found '${node.name}' outside of a bone)` From 1dfe134e2a123fc02916fb6f30e2f42aebcc7c5f Mon Sep 17 00:00:00 2001 From: SnaveSutit Date: Sun, 3 May 2026 07:07:56 -0400 Subject: [PATCH 09/17] =?UTF-8?q?=E2=9C=A8=EF=B8=8F=20Merge=20`animation.m?= =?UTF-8?q?cb`=20and=20`static.mcb`=20into=20`main.mcb`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../1.20.4/{animation.mcb => main.mcb} | 864 +++++++++-------- .../datapackCompiler/1.20.4/static.mcb | 864 ----------------- .../1.20.5/{animation.mcb => main.mcb} | 864 +++++++++-------- .../datapackCompiler/1.20.5/static.mcb | 867 ----------------- .../1.21.0/{animation.mcb => main.mcb} | 864 +++++++++-------- .../datapackCompiler/1.21.0/static.mcb | 868 ----------------- .../1.21.2/{animation.mcb => main.mcb} | 864 +++++++++-------- .../datapackCompiler/1.21.2/static.mcb | 867 ----------------- .../1.21.4/{animation.mcb => main.mcb} | 885 ++++++++--------- .../datapackCompiler/1.21.4/static.mcb | 912 ------------------ .../1.21.5/{animation.mcb => main.mcb} | 881 ++++++++--------- .../datapackCompiler/1.21.5/static.mcb | 907 ----------------- src/systems/datapackCompiler/index.ts | 5 +- src/systems/datapackCompiler/mcbFiles.ts | 48 +- src/systems/datapackCompiler/tellraw.ts | 12 + 15 files changed, 2702 insertions(+), 7870 deletions(-) rename src/systems/datapackCompiler/1.20.4/{animation.mcb => main.mcb} (60%) delete mode 100644 src/systems/datapackCompiler/1.20.4/static.mcb rename src/systems/datapackCompiler/1.20.5/{animation.mcb => main.mcb} (60%) delete mode 100644 src/systems/datapackCompiler/1.20.5/static.mcb rename src/systems/datapackCompiler/1.21.0/{animation.mcb => main.mcb} (60%) delete mode 100644 src/systems/datapackCompiler/1.21.0/static.mcb rename src/systems/datapackCompiler/1.21.2/{animation.mcb => main.mcb} (60%) delete mode 100644 src/systems/datapackCompiler/1.21.2/static.mcb rename src/systems/datapackCompiler/1.21.4/{animation.mcb => main.mcb} (61%) delete mode 100644 src/systems/datapackCompiler/1.21.4/static.mcb rename src/systems/datapackCompiler/1.21.5/{animation.mcb => main.mcb} (61%) delete mode 100644 src/systems/datapackCompiler/1.21.5/static.mcb diff --git a/src/systems/datapackCompiler/1.20.4/animation.mcb b/src/systems/datapackCompiler/1.20.4/main.mcb similarity index 60% rename from src/systems/datapackCompiler/1.20.4/animation.mcb rename to src/systems/datapackCompiler/1.20.4/main.mcb index 77f9b92a..b889c46b 100644 --- a/src/systems/datapackCompiler/1.20.4/animation.mcb +++ b/src/systems/datapackCompiler/1.20.4/main.mcb @@ -3,26 +3,30 @@ function on_load { data modify storage <%project_storage%> rig_hash set value <%"'" + rig_hash + "'"%> - IF (use_storage_for_animation) { - REPEAT (animations) as animation { - data remove storage <%project_storage%>/animations <%animation.storage_name%> + IF (has_animations) { + IF (use_storage_for_animation) { + REPEAT (animations) as animation { + data remove storage <%project_storage%>/animations <%animation.storage_name%> + } + <%animationStorage.join('\n')%> } - <%animationStorage.join('\n')%> + <%% + animations.forEach(animation => { + emit(`scoreboard objectives add ${OBJECTIVES.FRAME(animation.storage_name)} dummy`) + }) + %%> } - <%% - animations.forEach(animation => { - emit(`scoreboard objectives add ${OBJECTIVES.FRAME(animation.storage_name)} dummy`) - }) - %%> } -function remove_animation_objectives { - <%% - animations.forEach(animation => { - emit(`scoreboard objectives remove ${OBJECTIVES.FRAME(animation.storage_name)}`) - }) - %%> - tellraw @a <%TELLRAW.UNINSTALL()%> +IF (has_animations) { + function remove_animation_objectives { + <%% + animations.forEach(animation => { + emit(`scoreboard objectives remove ${OBJECTIVES.FRAME(animation.storage_name)}`) + }) + %%> + tellraw @a <%TELLRAW.UNINSTALL()%> + } } dir root { @@ -34,26 +38,28 @@ dir root { %%> } - # animated_java:global/root/on_tick already runs this right before calling this function. - # data_manager prep read - - # Once we have more than 8 animations, calling a function only if at least one animation is playing is more efficient. - IF (animations.length > 8) { - # If no animations are playing, we can skip all animation logic. - # This helps reduce ticking commands for rigs that are idle. - execute \ - unless entity @s[<%animations.map(anim => 'tag=!' + TAGS.ANIMATION_PLAYING(blueprint_id, anim.storage_name)).join(',')%>] \ - run block tick_animations { + IF (has_animations) { + # animated_java:global/root/on_tick already runs this right before calling this function. + # data_manager prep read + + # Once we have more than 8 animations, calling a function only if at least one animation is playing is more efficient. + IF (animations.length > 8) { + # If no animations are playing, we can skip all animation logic. + # This helps reduce ticking commands for rigs that are idle. + execute \ + unless entity @s[<%animations.map(anim => 'tag=!' + TAGS.ANIMATION_PLAYING(blueprint_id, anim.storage_name)).join(',')%>] \ + run block tick_animations { + REPEAT (animations) as animation { + execute if entity @s[tag=<%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%>] run \ + function <%blueprint_id%>/animations/<%animation.storage_name%>/zzz/on_tick + } + } + } ELSE { REPEAT (animations) as animation { execute if entity @s[tag=<%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%>] run \ function <%blueprint_id%>/animations/<%animation.storage_name%>/zzz/on_tick } } - } ELSE { - REPEAT (animations) as animation { - execute if entity @s[tag=<%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%>] run \ - function <%blueprint_id%>/animations/<%animation.storage_name%>/zzz/on_tick - } } IF (auto_update_rig_orientation) { @@ -145,405 +151,413 @@ IF (!auto_update_rig_orientation) { } } -dir animations { - REPEAT (animations) as animation { - dir <%animation.storage_name%> { - function play { - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> +IF (has_animations) { + dir animations { + REPEAT (animations) as animation { + dir <%animation.storage_name%> { + function play { + debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - function <%blueprint_id%>/animations/pause_all + function <%blueprint_id%>/animations/pause_all - tag @s add <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%> - scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> 0 - tag @s add <%TAGS.TRANSFORMS_ONLY()%> - execute at @s run function ./zzz/set_frame {frame: 0} - tag @s remove <%TAGS.TRANSFORMS_ONLY()%> - } + tag @s add <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%> + scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> 0 + tag @s add <%TAGS.TRANSFORMS_ONLY()%> + execute at @s run function ./zzz/set_frame {frame: 0} + tag @s remove <%TAGS.TRANSFORMS_ONLY()%> + } - function stop { - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> + function stop { + debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - function <%blueprint_id%>/animations/pause_all + function <%blueprint_id%>/animations/pause_all - scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> 0 - tag @s add <%TAGS.TRANSFORMS_ONLY()%> - execute at @s run function ./zzz/set_frame {frame: 0} - tag @s remove <%TAGS.TRANSFORMS_ONLY()%> - } + scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> 0 + tag @s add <%TAGS.TRANSFORMS_ONLY()%> + execute at @s run function ./zzz/set_frame {frame: 0} + tag @s remove <%TAGS.TRANSFORMS_ONLY()%> + } - function pause { - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> + function pause { + debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - tag @s remove <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%> - } + tag @s remove <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%> + } - function resume { - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> + function resume { + debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - tag @s add <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%> - } + tag @s add <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%> + } - function next_frame { - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> + function next_frame { + debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - execute if score @s <%OBJECTIVES.FRAME(animation.storage_name)%> matches <%animation.duration%>.. run scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> 1 - data remove storage <%temp_storage%> args - execute store result storage <%temp_storage%> args.frame int 1 run scoreboard players get @s <%OBJECTIVES.FRAME(animation.storage_name)%> - execute at @s run function ./zzz/apply_frame with storage <%temp_storage%> args - scoreboard players add @s <%OBJECTIVES.FRAME(animation.storage_name)%> 1 - } + execute if score @s <%OBJECTIVES.FRAME(animation.storage_name)%> matches <%animation.duration%>.. run scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> 1 + data remove storage <%temp_storage%> args + execute store result storage <%temp_storage%> args.frame int 1 run scoreboard players get @s <%OBJECTIVES.FRAME(animation.storage_name)%> + execute at @s run function ./zzz/apply_frame with storage <%temp_storage%> args + scoreboard players add @s <%OBJECTIVES.FRAME(animation.storage_name)%> 1 + } - function set_frame { - # Sets the frame without interpolation - #ARGS: {frame: int} - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> + function set_frame { + # Sets the frame without interpolation + #ARGS: {frame: int} + debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - data_manager prep read + data_manager prep read - data remove storage <%temp_storage%> args - $execute store result storage <%temp_storage%> args.frame int 1 run scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> $(frame) - execute at @s run function ./zzz/set_frame with storage <%temp_storage%> args - } + data remove storage <%temp_storage%> args + $execute store result storage <%temp_storage%> args.frame int 1 run scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> $(frame) + execute at @s run function ./zzz/set_frame with storage <%temp_storage%> args + } - function apply_frame { - #ARGS: {frame: int} - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> + function apply_frame { + #ARGS: {frame: int} + debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - data_manager prep read + data_manager prep read - data remove storage <%temp_storage%> args - $execute store result storage <%temp_storage%> args.frame int 1 run scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> $(frame) - execute at @s run function ./zzz/apply_frame with storage <%temp_storage%> args - } + data remove storage <%temp_storage%> args + $execute store result storage <%temp_storage%> args.frame int 1 run scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> $(frame) + execute at @s run function ./zzz/apply_frame with storage <%temp_storage%> args + } - function tween { - # Attempts to smoothly transition from the currently playing animation into this one. - #ARGS: {duration: int, to_frame: int} - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> + function tween { + # Attempts to smoothly transition from the currently playing animation into this one. + #ARGS: {duration: int, to_frame: int} + debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - function <%blueprint_id%>/animations/pause_all + function <%blueprint_id%>/animations/pause_all - tag @s add <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%> - $scoreboard players set @s <%OBJECTIVES.TWEEN_DURATION()%> $(duration) - $scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> $(to_frame) + tag @s add <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%> + $scoreboard players set @s <%OBJECTIVES.TWEEN_DURATION()%> $(duration) + $scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> $(to_frame) - scoreboard players operation #this <%OBJECTIVES.I()%> = @s <%OBJECTIVES.TWEEN_DURATION()%> - tag @s add <%TAGS.TRANSFORMS_ONLY()%> - execute at @s run function ./zzz/apply_frame {frame: 0} - $execute at @s run function ./zzz/apply_frame {frame: $(to_frame)} - tag @s remove <%TAGS.TRANSFORMS_ONLY()%> - execute on passengers store result entity @s interpolation_duration int 1 run scoreboard players get #this <%OBJECTIVES.I()%> - } + scoreboard players operation #this <%OBJECTIVES.I()%> = @s <%OBJECTIVES.TWEEN_DURATION()%> + tag @s add <%TAGS.TRANSFORMS_ONLY()%> + execute at @s run function ./zzz/apply_frame {frame: 0} + $execute at @s run function ./zzz/apply_frame {frame: $(to_frame)} + tag @s remove <%TAGS.TRANSFORMS_ONLY()%> + execute on passengers store result entity @s interpolation_duration int 1 run scoreboard players get #this <%OBJECTIVES.I()%> + } - dir zzz { - function on_tick { - # Tweening logic - scoreboard players remove @s <%OBJECTIVES.TWEEN_DURATION()%> 1 - execute if score @s <%OBJECTIVES.TWEEN_DURATION()%> matches 1.. run return 1 - execute if score @s <%OBJECTIVES.TWEEN_DURATION()%> matches 0 on passengers run \ - data modify entity @s interpolation_duration set value <%interpolation_duration%> - # Animation logic - IF (animation.loop_mode === 'loop' && animation.loop_delay === 0) { - # Makes sure function keyframes in the last frame of the animation are activated. - execute if score @s <%OBJECTIVES.FRAME(animation.storage_name)%> matches -1 run \ - block function_keyframe_loop_patch { - function ./frames/last_frame_effects with storage <%temp_storage%> entry.data.uuids_by_name - scoreboard players add @s <%OBJECTIVES.FRAME(animation.storage_name)%> 1 + dir zzz { + function on_tick { + # Tweening logic + scoreboard players remove @s <%OBJECTIVES.TWEEN_DURATION()%> 1 + execute if score @s <%OBJECTIVES.TWEEN_DURATION()%> matches 1.. run return 1 + execute if score @s <%OBJECTIVES.TWEEN_DURATION()%> matches 0 on passengers run \ + data modify entity @s interpolation_duration set value <%interpolation_duration%> + # Animation logic + IF (animation.loop_mode === 'loop' && animation.loop_delay === 0) { + # Makes sure function keyframes in the last frame of the animation are activated. + execute if score @s <%OBJECTIVES.FRAME(animation.storage_name)%> matches -1 run \ + block function_keyframe_loop_patch { + function ./frames/last_frame_effects with storage <%temp_storage%> entry.data.uuids_by_name + scoreboard players add @s <%OBJECTIVES.FRAME(animation.storage_name)%> 1 + } + } + data remove storage <%temp_storage%> args + execute store result storage <%temp_storage%> args.frame int 1 run \ + scoreboard players get @s <%OBJECTIVES.FRAME(animation.storage_name)%> + function ./apply_frame with storage <%temp_storage%> args + IF (animation.loop_mode === 'loop') { + # Loop the animation back to the start once it reaches the last frame. + # If loop_delay is 0, the animation will loop instantly, otherwise, it will wait for the specified amount of ticks. + execute \ + if score @s <%OBJECTIVES.FRAME(animation.storage_name)%> \ + matches <%animation.duration-2 + animation.loop_delay%>.. \ + run return run \ + scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> <%animation.loop_delay === 0 ? -1 : 0%> + } ELSE IF (animation.loop_mode === 'hold') { + # Pause the animation at the last frame. + execute \ + if score @s <%OBJECTIVES.FRAME(animation.storage_name)%> \ + matches <%animation.duration-1%>.. \ + run return run \ + function ../pause + } ELSE IF (animation.loop_mode === 'once') { + # Stop the animation once it reaches the last frame. + execute \ + if score @s <%OBJECTIVES.FRAME(animation.storage_name)%> \ + matches <%animation.duration-1%> \ + run return run block loop_mode_stop { + scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> 0 + tag @s add <%TAGS.TRANSFORMS_ONLY()%> + execute at @s run function ./zzz/set_frame {frame: 0} + tag @s remove <%TAGS.TRANSFORMS_ONLY()%> + tag @s remove <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%> } - } - data remove storage <%temp_storage%> args - execute store result storage <%temp_storage%> args.frame int 1 run \ - scoreboard players get @s <%OBJECTIVES.FRAME(animation.storage_name)%> - function ./apply_frame with storage <%temp_storage%> args - IF (animation.loop_mode === 'loop') { - # Loop the animation back to the start once it reaches the last frame. - # If loop_delay is 0, the animation will loop instantly, otherwise, it will wait for the specified amount of ticks. - execute \ - if score @s <%OBJECTIVES.FRAME(animation.storage_name)%> \ - matches <%animation.duration-2 + animation.loop_delay%>.. \ - run return run \ - scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> <%animation.loop_delay === 0 ? -1 : 0%> - } ELSE IF (animation.loop_mode === 'hold') { - # Pause the animation at the last frame. - execute \ - if score @s <%OBJECTIVES.FRAME(animation.storage_name)%> \ - matches <%animation.duration-1%>.. \ - run return run \ - function ../pause - } ELSE IF (animation.loop_mode === 'once') { - # Stop the animation once it reaches the last frame. - execute \ - if score @s <%OBJECTIVES.FRAME(animation.storage_name)%> \ - matches <%animation.duration-1%> \ - run return run block loop_mode_stop { - scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> 0 - tag @s add <%TAGS.TRANSFORMS_ONLY()%> - execute at @s run function ./zzz/set_frame {frame: 0} - tag @s remove <%TAGS.TRANSFORMS_ONLY()%> - tag @s remove <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%> } + scoreboard players add @s <%OBJECTIVES.FRAME(animation.storage_name)%> 1 } - scoreboard players add @s <%OBJECTIVES.FRAME(animation.storage_name)%> 1 - } - IF (use_storage_for_animation) { - function set_frame { - #ARGS: {frame: int} - $function ./apply_frame {frame: $(frame)} - execute on passengers run data modify entity @s start_interpolation set value -1 - return 1 - } + IF (use_storage_for_animation) { + function set_frame { + #ARGS: {frame: int} + $function ./apply_frame {frame: $(frame)} + execute on passengers run data modify entity @s start_interpolation set value -1 + return 1 + } - function apply_frame { - #ARGS: {frame: int} - REPEAT (Object.values(animation.modified_nodes).sort(nodeSorter)) as node { - IF (BONE_TYPES.includes(node.type)) { - $execute on passengers if entity @s[tag=<%TAGS.PROJECT_NODE_NAMED(blueprint_id, node.storage_name)%>] run \ - data modify entity @s {} merge from \ - storage <%project_storage%>/animations <%animation.storage_name%>.$(frame).<%node.storage_name%> - } ELSE IF (node.type === 'locator' || node.type === 'camera') { - $data modify storage <%temp_storage%> entry.data.uuids_by_name.<%node.storage_name%> merge from \ - storage <%project_storage%>/animations <%animation.storage_name%>.$(frame).<%node.storage_name%> + function apply_frame { + #ARGS: {frame: int} + REPEAT (Object.values(animation.modified_nodes).sort(nodeSorter)) as node { + IF (BONE_TYPES.includes(node.type)) { + $execute on passengers if entity @s[tag=<%TAGS.PROJECT_NODE_NAMED(blueprint_id, node.storage_name)%>] run \ + data modify entity @s {} merge from \ + storage <%project_storage%>/animations <%animation.storage_name%>.$(frame).<%node.storage_name%> + } ELSE IF (node.type === 'locator' || node.type === 'camera') { + $data modify storage <%temp_storage%> entry.data.uuids_by_name.<%node.storage_name%> merge from \ + storage <%project_storage%>/animations <%animation.storage_name%>.$(frame).<%node.storage_name%> + } } - } - IF (animation.frames.some(anim => anim.variant)) { - $execute \ - if data storage <%project_storage%>/animations <%animation.storage_name%>.$(frame).variant \ - unless entity @s[tag=<%TAGS.TRANSFORMS_ONLY()%>] \ - run { with storage <%project_storage%>/animations <%animation.storage_name%>.$(frame).variant - #ARGS: {name: string, condition: string} - $execute $(condition)run function <%blueprint_id%>/variants/$(name)/apply + IF (animation.frames.some(anim => anim.variant)) { + $execute \ + if data storage <%project_storage%>/animations <%animation.storage_name%>.$(frame).variant \ + unless entity @s[tag=<%TAGS.TRANSFORMS_ONLY()%>] \ + run { with storage <%project_storage%>/animations <%animation.storage_name%>.$(frame).variant + #ARGS: {name: string, condition: string} + $execute $(condition)run function <%blueprint_id%>/variants/$(name)/apply + } } - } - return 1 - } - } ELSE { - function set_frame { - # Sets the frame without interpolation - #ARGS: {frame: int} + return 1 + } + } ELSE { + function set_frame { + # Sets the frame without interpolation + #ARGS: {frame: int} - $function ./frames/$(frame) with storage <%temp_storage%> entry.data.uuids_by_name + $function ./frames/$(frame) with storage <%temp_storage%> entry.data.uuids_by_name - execute on passengers run \ - data modify entity @s start_interpolation set value -1 + execute on passengers run \ + data modify entity @s start_interpolation set value -1 - return 1 - } + return 1 + } - function apply_frame { - #ARGS: {frame: int} + function apply_frame { + #ARGS: {frame: int} - $function ./frames/$(frame) with storage <%temp_storage%> entry.data.uuids_by_name + $function ./frames/$(frame) with storage <%temp_storage%> entry.data.uuids_by_name - return 1 - } + return 1 + } - # FIXME - %NEWLINE_PATCH% is a temporary solution to temporarily fix an MCB bug where extra newlines are being added to the output. - dir frames { - <%% - global.frame = animation.frames.at(-1) - global.modified_effect_nodes = Object.values(animation.modified_nodes).filter( - node => node.type === 'locator' && global.frame.node_transforms[node.uuid] - ) - console.log(global.modified_effect_nodes) - %%> - IF(Object.keys(global.modified_effect_nodes).length > 0) { - function last_frame_effects { - REPEAT(global.modified_effect_nodes) as node { - <%% - global.transform = global.frame.node_transforms[node.uuid] - %%> - IF (node.config?.use_entity) { - $execute \ - as $(<%node.storage_name%>) \ - positioned \ - ^<%roundTo(global.transform.pos[0], 10)%> \ - ^<%roundTo(global.transform.pos[1], 10)%> \ - ^<%roundTo(global.transform.pos[2], 10)%> \ - rotated \ - ~<%roundTo(global.transform.head_rot[1], 10)%> \ - ~<%roundTo(global.transform.head_rot[0], 10)%> \ - <%global.transform.function_execute_condition ? global.transform.function_execute_condition + ' ' : ''%>run \ - function ./<%animation.duration%>_locator_<%node.storage_name%> - } ELSE { - execute \ - positioned \ - ^<%roundTo(global.transform.pos[0], 10)%> \ - ^<%roundTo(global.transform.pos[1], 10)%> \ - ^<%roundTo(global.transform.pos[2], 10)%> \ - rotated \ - ~<%roundTo(global.transform.head_rot[1], 10)%> \ - ~<%roundTo(global.transform.head_rot[0], 10)%> \ - <%global.transform.function_execute_condition ? global.transform.function_execute_condition + ' ' : ''%>run \ - function ./<%animation.duration%>_locator_<%node.storage_name%> + # FIXME - %NEWLINE_PATCH% is a temporary solution to temporarily fix an MCB bug where extra newlines are being added to the output. + dir frames { + <%% + global.frame = animation.frames.at(-1) + global.modified_effect_nodes = Object.values(animation.modified_nodes).filter( + node => node.type === 'locator' && global.frame.node_transforms[node.uuid] + ) + console.log(global.modified_effect_nodes) + %%> + IF(Object.keys(global.modified_effect_nodes).length > 0) { + function last_frame_effects { + REPEAT(global.modified_effect_nodes) as node { + <%% + global.transform = global.frame.node_transforms[node.uuid] + %%> + IF (node.config?.use_entity) { + $execute \ + as $(<%node.storage_name%>) \ + positioned \ + ^<%roundTo(global.transform.pos[0], 10)%> \ + ^<%roundTo(global.transform.pos[1], 10)%> \ + ^<%roundTo(global.transform.pos[2], 10)%> \ + rotated \ + ~<%roundTo(global.transform.head_rot[1], 10)%> \ + ~<%roundTo(global.transform.head_rot[0], 10)%> \ + <%global.transform.function_execute_condition ? global.transform.function_execute_condition + ' ' : ''%>run \ + function ./<%animation.duration%>_locator_<%node.storage_name%> + } ELSE { + execute \ + positioned \ + ^<%roundTo(global.transform.pos[0], 10)%> \ + ^<%roundTo(global.transform.pos[1], 10)%> \ + ^<%roundTo(global.transform.pos[2], 10)%> \ + rotated \ + ~<%roundTo(global.transform.head_rot[1], 10)%> \ + ~<%roundTo(global.transform.head_rot[0], 10)%> \ + <%global.transform.function_execute_condition ? global.transform.function_execute_condition + ' ' : ''%>run \ + function ./<%animation.duration%>_locator_<%node.storage_name%> + } } - } - IF (global.frame.variants?.length > 0) { - execute <%global.frame.variants_execute_condition ? global.frame.variants_execute_condition + ' ' : ''%>run \ - function <%blueprint_id%>/variants/<%global.frame.variants[0].name%>/apply - } + IF (global.frame.variants?.length > 0) { + execute <%global.frame.variants_execute_condition ? global.frame.variants_execute_condition + ' ' : ''%>run \ + function <%blueprint_id%>/variants/<%global.frame.variants[0].name%>/apply + } - IF (global.frame.function) { - execute <%global.frame.function_execute_condition ? global.frame.function_execute_condition + ' ' : ''%>run \ - block <%animation.duration%>_function_keyframe { - <%global.frame.function%> - } + IF (global.frame.function) { + execute <%global.frame.function_execute_condition ? global.frame.function_execute_condition + ' ' : ''%>run \ + block <%animation.duration%>_function_keyframe { + <%global.frame.function%> + } + } } } - } - - <%% - // A record of node uuid to INodeTransform. - // Keeps track of the last time a bone was updated. - // Only used for step keyframe interpolation. - let hasFunction = false - const lastActiveFrame = {} - const modifiedNodes = Object.values(animation.modified_nodes).filter(n => n.type !== 'struct').sort(nodeSorter); - for (const [frameIndex, frame] of animation.frames.entries()) { - const to_merge = {cameras: {}, locators: {}} - let frameFunc = ``; - for (const node of modifiedNodes) { - const transform = frame.node_transforms[node.uuid] - // Skip if the node doesn't have a transform for this frame. - if (!transform) continue - switch (node.type) { - case 'bone': - case 'text_display': - case 'item_display': - case 'block_display': { - const lastFrame = lastActiveFrame[node.uuid] - const isStepInterpolation = !!(lastFrame?.interpolation === 'step') - lastActiveFrame[node.uuid] = transform - - if (transform.interpolation === 'pre-post' || isStepInterpolation) { - frameFunc += - `\n$data merge entity $(${node.storage_name})%NEWLINE_PATCH%{` - + `transformation: ${matrixToNbtFloatArray(transform.matrix).toString()},` - + `start_interpolation: ${isStepInterpolation ? -1 : 0},` - + `interpolation_duration: ${isStepInterpolation ? 0 : interpolation_duration}` - + `}` - } else { - frameFunc += - `\n$data merge entity $(${node.storage_name})%NEWLINE_PATCH%{` - + `transformation: ${matrixToNbtFloatArray(transform.matrix).toString()},` - + `start_interpolation: 0,` - + `interpolation_duration: ${interpolation_duration}` - + `}` - } - ;hasFunction = true - break - } - case 'locator': { - const lastFrame = lastActiveFrame[node.uuid] - lastActiveFrame[node.uuid] = transform - ;if (!lastFrame || matrixToNbtFloatArray(transform.matrix).toString() !== matrixToNbtFloatArray(lastFrame.matrix).toString()) { - to_merge.locators[node.storage_name] = { - px: roundTo(transform.pos[0], 10), - py: roundTo(transform.pos[1], 10), - pz: roundTo(transform.pos[2], 10), - ry: roundTo(transform.head_rot[1], 10), - rx: roundTo(transform.head_rot[0], 10) - }; - } - - if (transform.function) { - if (node.config?.use_entity) { + <%% + // A record of node uuid to INodeTransform. + // Keeps track of the last time a bone was updated. + // Only used for step keyframe interpolation. + let hasFunction = false + const lastActiveFrame = {} + const modifiedNodes = Object.values(animation.modified_nodes).filter(n => n.type !== 'struct').sort(nodeSorter); + for (const [frameIndex, frame] of animation.frames.entries()) { + const to_merge = {cameras: {}, locators: {}} + let frameFunc = ``; + for (const node of modifiedNodes) { + const transform = frame.node_transforms[node.uuid] + // Skip if the node doesn't have a transform for this frame. + if (!transform) continue + switch (node.type) { + case 'bone': + case 'text_display': + case 'item_display': + case 'block_display': { + const lastFrame = lastActiveFrame[node.uuid] + const isStepInterpolation = !!(lastFrame?.interpolation === 'step') + lastActiveFrame[node.uuid] = transform + + if (transform.interpolation === 'pre-post' || isStepInterpolation) { frameFunc += - `\n$execute unless entity @s[tag=${TAGS.TRANSFORMS_ONLY()}] as $(${node.storage_name}) ` - + `positioned ^${roundTo(transform.pos[0], 10)} ^${roundTo(transform.pos[1], 10)} ^${roundTo(transform.pos[2], 10)} ` - + `rotated ~${roundTo(transform.head_rot[1], 10)} ~${roundTo(transform.head_rot[0], 10)} ` - + `${transform.function_execute_condition ? transform.function_execute_condition + ' ' : ''}run ` - + `block ${frameIndex}_locator_${node.storage_name}%NEWLINE_PATCH%{\n` - + `tp @s ~ ~ ~ ~ ~\n` - + `${transform.function}` - + `\n}` + `\n$data merge entity $(${node.storage_name})%NEWLINE_PATCH%{` + + `transformation: ${matrixToNbtFloatArray(transform.matrix).toString()},` + + `start_interpolation: ${isStepInterpolation ? -1 : 0},` + + `interpolation_duration: ${isStepInterpolation ? 0 : interpolation_duration}` + + `}` } else { frameFunc += - `\nexecute unless entity @s[tag=${TAGS.TRANSFORMS_ONLY()}] ` - + `positioned ^${roundTo(transform.pos[0], 10)} ^${roundTo(transform.pos[1], 10)} ^${roundTo(transform.pos[2], 10)} ` - + `rotated ~${roundTo(transform.head_rot[1], 10)} ~${roundTo(transform.head_rot[0], 10)} ` - + `${transform.function_execute_condition ? transform.function_execute_condition + ' ' : ''}run ` - + `block ${frameIndex}_locator_${node.storage_name}%NEWLINE_PATCH%{\n` - + `${transform.function}` - + `\n}` + `\n$data merge entity $(${node.storage_name})%NEWLINE_PATCH%{` + + `transformation: ${matrixToNbtFloatArray(transform.matrix).toString()},` + + `start_interpolation: 0,` + + `interpolation_duration: ${interpolation_duration}` + + `}` } + + ;hasFunction = true + break } - break - } - case 'camera': { - const lastFrame = lastActiveFrame[node.uuid] - lastActiveFrame[node.uuid] = transform - ;if (!lastFrame || matrixToNbtFloatArray(transform.matrix).toString() !== matrixToNbtFloatArray(lastFrame.matrix).toString()) { - to_merge.cameras[node.storage_name] = { - px: transform.pos[0], - py: transform.pos[1], - pz: transform.pos[2], - ry: transform.head_rot[1], - rx: transform.head_rot[0] - }; + case 'locator': { + const lastFrame = lastActiveFrame[node.uuid] + lastActiveFrame[node.uuid] = transform + ;if (!lastFrame || matrixToNbtFloatArray(transform.matrix).toString() !== matrixToNbtFloatArray(lastFrame.matrix).toString()) { + to_merge.locators[node.storage_name] = { + px: roundTo(transform.pos[0], 10), + py: roundTo(transform.pos[1], 10), + pz: roundTo(transform.pos[2], 10), + ry: roundTo(transform.head_rot[1], 10), + rx: roundTo(transform.head_rot[0], 10) + }; + } + + if (transform.function) { + if (node.config?.use_entity) { + frameFunc += + `\n$execute unless entity @s[tag=${TAGS.TRANSFORMS_ONLY()}] as $(${node.storage_name}) ` + + `positioned ^${roundTo(transform.pos[0], 10)} ^${roundTo(transform.pos[1], 10)} ^${roundTo(transform.pos[2], 10)} ` + + `rotated ~${roundTo(transform.head_rot[1], 10)} ~${roundTo(transform.head_rot[0], 10)} ` + + `${transform.function_execute_condition ? transform.function_execute_condition + ' ' : ''}run ` + + `block ${frameIndex}_locator_${node.storage_name}%NEWLINE_PATCH%{\n` + + `tp @s ~ ~ ~ ~ ~\n` + + `${transform.function}` + + `\n}` + } else { + frameFunc += + `\nexecute unless entity @s[tag=${TAGS.TRANSFORMS_ONLY()}] ` + + `positioned ^${roundTo(transform.pos[0], 10)} ^${roundTo(transform.pos[1], 10)} ^${roundTo(transform.pos[2], 10)} ` + + `rotated ~${roundTo(transform.head_rot[1], 10)} ~${roundTo(transform.head_rot[0], 10)} ` + + `${transform.function_execute_condition ? transform.function_execute_condition + ' ' : ''}run ` + + `block ${frameIndex}_locator_${node.storage_name}%NEWLINE_PATCH%{\n` + + `${transform.function}` + + `\n}` + } + } + break + } + case 'camera': { + const lastFrame = lastActiveFrame[node.uuid] + lastActiveFrame[node.uuid] = transform + ;if (!lastFrame || matrixToNbtFloatArray(transform.matrix).toString() !== matrixToNbtFloatArray(lastFrame.matrix).toString()) { + to_merge.cameras[node.storage_name] = { + px: transform.pos[0], + py: transform.pos[1], + pz: transform.pos[2], + ry: transform.head_rot[1], + rx: transform.head_rot[0] + }; + } + ;break } - ;break } } - } - if (Object.keys(to_merge.locators).length > 0 || Object.keys(to_merge.cameras).length > 0) { - frameFunc += `\ndata modify storage <%temp_storage%> entry.data merge value ${JSON.stringify(to_merge)}` - frameFunc += `\ndata_manager write` - if (!auto_update_rig_orientation) { - frameFunc += `\nfunction ${blueprint_id}/root/on_tick/transform_floating_entities` + if (Object.keys(to_merge.locators).length > 0 || Object.keys(to_merge.cameras).length > 0) { + frameFunc += `\ndata modify storage <%temp_storage%> entry.data merge value ${JSON.stringify(to_merge)}` + frameFunc += `\ndata_manager write` + if (!auto_update_rig_orientation) { + frameFunc += `\nfunction ${blueprint_id}/root/on_tick/transform_floating_entities` + } + hasFunction = true } - hasFunction = true - } - if (frame.variants?.length) { - const variant = rig.variants[frame.variants[0]] - if (!variant) { - throw new Error(`Could not find Variant with uuid "${frame.variants[0]}" while generating frame "${frameIndex}" of animation "${animation.name}".`) + if (frame.variants?.length) { + const variant = rig.variants[frame.variants[0]] + if (!variant) { + throw new Error(`Could not find Variant with uuid "${frame.variants[0]}" while generating frame "${frameIndex}" of animation "${animation.name}".`) + } + const execute_condition = frame.variants_execute_condition ? frame.variants_execute_condition + ' ' : '' + frameFunc += `\nexecute unless entity @s[tag=${TAGS.TRANSFORMS_ONLY()}] ${execute_condition}run function ${blueprint_id}/variants/${variant.name}/apply` + ;hasFunction = true } - const execute_condition = frame.variants_execute_condition ? frame.variants_execute_condition + ' ' : '' - frameFunc += `\nexecute unless entity @s[tag=${TAGS.TRANSFORMS_ONLY()}] ${execute_condition}run function ${blueprint_id}/variants/${variant.name}/apply` - ;hasFunction = true - } - // Root function keyframes. - if (frame.function) { - const execute_condition = frame.function_execute_condition ? frame.function_execute_condition + ' ' : '' - frameFunc += `\nexecute unless entity @s[tag=${TAGS.TRANSFORMS_ONLY()}] at @s ${execute_condition}run block ${frameIndex}_root_function%NEWLINE_PATCH%{\n${frame.function}\n}` - ;hasFunction = true - } - ;if (frameFunc.length > 0) { - frameFunc = `function ${frameIndex}%NEWLINE_PATCH%{${frameFunc}\n}` - emit.mcb(frameFunc.replaceAll(/%NEWLINE_PATCH%\n?/g, ' ')) + // Root function keyframes. + if (frame.function) { + const execute_condition = frame.function_execute_condition ? frame.function_execute_condition + ' ' : '' + frameFunc += `\nexecute unless entity @s[tag=${TAGS.TRANSFORMS_ONLY()}] at @s ${execute_condition}run block ${frameIndex}_root_function%NEWLINE_PATCH%{\n${frame.function}\n}` + ;hasFunction = true + } + ;if (frameFunc.length > 0) { + frameFunc = `function ${frameIndex}%NEWLINE_PATCH%{${frameFunc}\n}` + emit.mcb(frameFunc.replaceAll(/%NEWLINE_PATCH%\n?/g, ' ')) + } } - } - %%> + %%> + } } } } } - } - function pause_all { - # Pauses all animations - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> + function pause_all { + # Pauses all animations + debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - REPEAT (animations) as animation { - tag @s remove <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%> + REPEAT (animations) as animation { + tag @s remove <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%> + } } } } function summon { - #Args: {args:{variant: string, animation: string, frame: int, start_animation: boolean}} + #Args: {args:{variant?: string, animation?: string, frame?: int, start_animation?: boolean}} # frame is ignored unless animation is specified. - data modify storage <%temp_storage%> args set value {variant:'', animation:'', frame: 0} $execute store success score #success <%OBJECTIVES.I()%> run data modify storage <%temp_storage%> args set value $(args) + IF (!has_animations && debug_mode) { + execute if data storage <%temp_storage%> args.animation run return run \ + tellraw @a <%TELLRAW.ANIMATION_ARG_NO_RIG_ANIMATIONS()%> + execute if data storage <%temp_storage%> args.frame run return run \ + tellraw @a <%TELLRAW.FRAME_ARG_NO_RIG_FRAMES()%> + } + summon minecraft:item_display ~ ~ ~ { \ Tags:[ \ '<%TAGS.NEW()%>', \ @@ -588,7 +602,7 @@ function summon { type=<%locator.config.entity_type%>, \ tag=<%TAGS.PROJECT_LOCATOR_NAMED(blueprint_id, locator.storage_name)%>, \ tag=<%TAGS.NEW()%>, \ - limit=1, distance=..<%Math.ceil(locator.max_distance)%> \ + limit=1, distance=..<%Math.ceil(locator.max_distance + 0.5)%> \ ] \ run block as_locator/<%locator.storage_name%> { # run block ../as_locator/<%locator.storage_name%> { @@ -613,7 +627,7 @@ function summon { type=minecraft:item_display, \ tag=<%TAGS.PROJECT_CAMERA_NAMED(blueprint_id, camera.storage_name)%>, \ tag=<%TAGS.NEW()%>, \ - limit=1, distance=..<%Math.ceil(camera.max_distance)%> \ + limit=1, distance=..<%Math.ceil(camera.max_distance + 0.5)%> \ ] \ run block as_camera/<%camera.storage_name%> { # run block ../as_camera/<%camera.storage_name%> { @@ -689,52 +703,54 @@ function summon { } execute if score #success <%OBJECTIVES.I()%> matches 0 run return fail - # Animation Argument - # If the animation argument is provided, attempt to apply the animation. - execute if data storage <%temp_storage%> args.animation run block animation_arg/process { with storage <%temp_storage%> args - scoreboard players set #success <%OBJECTIVES.I()%> 0 - # If the animation argument is *explicitly* set to an empty string, return an error. - execute if data storage <%temp_storage%> {args:{animation:''}} run return run block if_empty { - tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('animation')%> - function <%blueprint_id%>/remove/this/without_on_remove_function - } - # Automatically set the frame argument to 0 if the frame argument is not provided. - # Takes advantage of `store result score` setting the score to 0 if the command fails. - execute \ - store result storage <%temp_storage%> args.frame int 1 \ - store result score #frame <%OBJECTIVES.I()%> \ - run \ - data get storage <%temp_storage%> args.frame - # If the frame argument is negative, return an error. - execute if score #frame <%OBJECTIVES.I()%> matches ..-1 run return run block no_negative { - # Tell the user that the frame argument cannot be negative. - tellraw @a <%TELLRAW.FRAME_CANNOT_BE_NEGATIVE()%> - function <%blueprint_id%>/remove/this/without_on_remove_function - } - # Attempt to apply the animation frame. - execute store success score #success <%OBJECTIVES.I()%> run block try_set_frame { with storage <%temp_storage%> args - # Make sure we're only applying transforms when setting the summon pose. - tag @s add <%TAGS.TRANSFORMS_ONLY()%> - $execute store success score #success <%OBJECTIVES.I()%> run function <%blueprint_id%>/animations/$(animation)/zzz/set_frame with storage <%temp_storage%> args - tag @s remove <%TAGS.TRANSFORMS_ONLY()%> - execute if score #success <%OBJECTIVES.I()%> matches 1 run return 1 - # If the set_frame function fails, the animation doesn't exist, so we return an error. - return fail - } - # If the set_frame function failed, return an error. - execute unless score #success <%OBJECTIVES.I()%> matches 1 run return run block invalid_animation { - # Tell the user that the provided animation doesn't exist, remove the rig, and list all available animations for this rig. - tellraw @a <%TELLRAW.INVALID_ANIMATION(animations)%> - function <%blueprint_id%>/remove/this/without_on_remove_function - } + IF (has_animations) { + # Animation Argument + # If the animation argument is provided, attempt to apply the animation. + execute if data storage <%temp_storage%> args.animation run block animation_arg/process { with storage <%temp_storage%> args + scoreboard players set #success <%OBJECTIVES.I()%> 0 + # If the animation argument is *explicitly* set to an empty string, return an error. + execute if data storage <%temp_storage%> {args:{animation:''}} run return run block if_empty { + tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('animation')%> + function <%blueprint_id%>/remove/this/without_on_remove_function + } + # Automatically set the frame argument to 0 if the frame argument is not provided. + # Takes advantage of `store result score` setting the score to 0 if the command fails. + execute \ + store result storage <%temp_storage%> args.frame int 1 \ + store result score #frame <%OBJECTIVES.I()%> \ + run \ + data get storage <%temp_storage%> args.frame + # If the frame argument is negative, return an error. + execute if score #frame <%OBJECTIVES.I()%> matches ..-1 run return run block no_negative { + # Tell the user that the frame argument cannot be negative. + tellraw @a <%TELLRAW.FRAME_CANNOT_BE_NEGATIVE()%> + function <%blueprint_id%>/remove/this/without_on_remove_function + } + # Attempt to apply the animation frame. + execute store success score #success <%OBJECTIVES.I()%> run block try_set_frame { with storage <%temp_storage%> args + # Make sure we're only applying transforms when setting the summon pose. + tag @s add <%TAGS.TRANSFORMS_ONLY()%> + $execute store success score #success <%OBJECTIVES.I()%> run function <%blueprint_id%>/animations/$(animation)/zzz/set_frame with storage <%temp_storage%> args + tag @s remove <%TAGS.TRANSFORMS_ONLY()%> + execute if score #success <%OBJECTIVES.I()%> matches 1 run return 1 + # If the set_frame function fails, the animation doesn't exist, so we return an error. + return fail + } + # If the set_frame function failed, return an error. + execute unless score #success <%OBJECTIVES.I()%> matches 1 run return run block invalid_animation { + # Tell the user that the provided animation doesn't exist, remove the rig, and list all available animations for this rig. + tellraw @a <%TELLRAW.INVALID_ANIMATION(animations)%> + function <%blueprint_id%>/remove/this/without_on_remove_function + } - # If the animation is successfully applied, and the start_animation argument is set to true, start the animation. - execute if data storage <%temp_storage%> {args:{start_animation: true}} run block start_animation { with storage <%temp_storage%> args - $function <%blueprint_id%>/animations/$(animation)/resume + # If the animation is successfully applied, and the start_animation argument is set to true, start the animation. + execute if data storage <%temp_storage%> {args:{start_animation: true}} run block start_animation { with storage <%temp_storage%> args + $function <%blueprint_id%>/animations/$(animation)/resume + } + scoreboard players set #success <%OBJECTIVES.I()%> 1 } - scoreboard players set #success <%OBJECTIVES.I()%> 1 + execute if score #success <%OBJECTIVES.I()%> matches 0 run return fail } - execute if score #success <%OBJECTIVES.I()%> matches 0 run return fail IF (has_locators || has_cameras) { function <%blueprint_id%>/root/on_tick/transform_floating_entities @@ -1318,20 +1334,22 @@ IF (has_locators || has_cameras) { } dir zzz { - function apply_default_pose { - IF (has_locators || has_cameras) { - function ../zzz/reset_floating_entities - } + IF (has_animations) { + function apply_default_pose { + IF (has_locators || has_cameras) { + function ../zzz/reset_floating_entities + } - REPEAT (Object.values(rig.nodes).filter(node => BONE_TYPES.includes(node.type))) as node { - execute \ - on passengers \ - if entity @s[tag=<%TAGS.PROJECT_NODE_NAMED(blueprint_id, node.storage_name)%>] \ - run \ - data merge entity @s { \ - transformation: <%matrixToNbtFloatArray(node.default_transform.matrix).toString()%>, \ - start_interpolation: 0 \ - } + REPEAT (Object.values(rig.nodes).filter(node => BONE_TYPES.includes(node.type))) as node { + execute \ + on passengers \ + if entity @s[tag=<%TAGS.PROJECT_NODE_NAMED(blueprint_id, node.storage_name)%>] \ + run \ + data merge entity @s { \ + transformation: <%matrixToNbtFloatArray(node.default_transform.matrix).toString()%>, \ + start_interpolation: 0 \ + } + } } } @@ -1353,14 +1371,16 @@ dir zzz { } } -function apply_default_pose { - # Changes the pose of the rig to the the default pose with interpolation - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> +IF (has_animations) { + function apply_default_pose { + # Changes the pose of the rig to the the default pose with interpolation + debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - IF (has_locators || has_cameras) { - data_manager prep read + IF (has_locators || has_cameras) { + data_manager prep read + } + function ./zzz/apply_default_pose } - function ./zzz/apply_default_pose } function set_default_pose { diff --git a/src/systems/datapackCompiler/1.20.4/static.mcb b/src/systems/datapackCompiler/1.20.4/static.mcb deleted file mode 100644 index 55e9d740..00000000 --- a/src/systems/datapackCompiler/1.20.4/static.mcb +++ /dev/null @@ -1,864 +0,0 @@ -# TODO - Move all internal functions into an internal namespace, and only have user-facing functions in the main `animated_java:<%export_namespace%>` namespace. - -function on_load { - data modify storage <%project_storage%> rig_hash set value <%"'" + rig_hash + "'"%> -} - -dir root { - function on_tick { - # Custom pre-tick function - IF (on_pre_tick_function) { - <%% - emit.mcb(on_pre_tick_function) - %%> - } - - IF (auto_update_rig_orientation) { - IF (has_locators || has_cameras) { - function <%blueprint_id%>/root/on_tick/transform_floating_entities - } - execute on passengers run tp @s ~ ~ ~ ~ ~ - } ELSE IF (has_ticking_locators) { - function <%blueprint_id%>/root/on_tick/transform_locators - } - - # Custom post-tick function - IF (on_post_tick_function) { - <%% - emit.mcb(on_post_tick_function) - %%> - } - } - - IF (has_locators || has_cameras) { - dir on_tick { - function transform_locators { - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'locator')) as locator { - block select_locator_<%locator.storage_name%> { with storage <%temp_storage%> entry.data.locators.<%locator.storage_name%> - IF (locator.config?.use_entity) { - $execute \ - as $(uuid) \ - positioned ^$(px) ^$(py) ^$(pz) \ - rotated ~$(ry) ~$(rx) \ - run block as_locator_<%locator.storage_name%> { - tp @s ~ ~ ~ ~ ~ - - IF (locator.config?.sync_passenger_rotation) { - execute on passengers run tp @s ~ ~ ~ ~ ~ - } - - IF (locator.config?.on_tick_function) { - <%% - emit.mcb(locator.config.on_tick_function) - %%> - } - } - } ELSE IF (locator.config?.on_tick_function) { - $execute \ - positioned ^$(px) ^$(py) ^$(pz) \ - rotated ~$(ry) ~$(rx) \ - run block at_locator_<%locator.storage_name%> { - <%% - emit.mcb(locator.config.on_tick_function) - %%> - } - } - } - } - } - - function transform_floating_entities { - function ./transform_locators - - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'camera')) as camera { - block select_camera_<%camera.storage_name%> { with storage <%temp_storage%> entry.data.cameras.<%camera.storage_name%> - $execute \ - as $(uuid) \ - positioned ^$(px) ^$(py) ^$(pz) \ - rotated ~$(ry) ~$(rx) \ - run tp @s ~ ~ ~ ~ ~ - } - } - } - } - } -} - -IF (!auto_update_rig_orientation) { - function move { - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - - tp @s ~ ~ ~ ~ ~ - - IF (has_locators || has_cameras) { - data_manager prep read - function <%blueprint_id%>/root/on_tick/transform_floating_entities - } - execute at @s on passengers run tp @s ~ ~ ~ ~ ~ - } -} ELSE { - function move { - tellraw @a <%TELLRAW.AUTO_UPDATE_RIG_ORIENTATION_MOVE_WARNING()%> - } -} - -function summon { - #Args: {args:{variant: string}} - - data modify storage <%temp_storage%> args set value {variant:''} - $execute store success score #success <%OBJECTIVES.I()%> run data modify storage <%temp_storage%> args set value $(args) - - summon minecraft:item_display ~ ~ ~ { \ - Tags:[ \ - '<%TAGS.NEW()%>', \ - '<%TAGS.GLOBAL_ENTITY()%>', \ - '<%TAGS.GLOBAL_ROOT()%>', \ - '<%TAGS.PROJECT_ENTITY(blueprint_id)%>', \ - '<%TAGS.PROJECT_ROOT(blueprint_id)%>' \ - ], \ - teleport_duration: 0, \ - interpolation_duration: <%interpolation_duration%>, \ - Passengers:<%root_entity_passengers%>, \ - CustomName: '<%ENTITY_NAMES.ROOT(blueprint_id)%>', \ - } - execute as @e[ \ - type=minecraft:item_display, \ - tag=<%TAGS.PROJECT_ROOT(blueprint_id)%>, \ - tag=<%TAGS.NEW()%>, \ - limit=1, distance=..0.01 \ - ] run block zzz/summon/as_root_entity { - execute store result score @s <%OBJECTIVES.ID()%> run scoreboard players add aj.last_id <%OBJECTIVES.ID()%> 1 - - data_manager init prep read - # Data manager init runs gu:get_entity_uuid_string. So we don't need to call it again here. - # function animated_java:global/gu/get_entity_uuid_string - data modify storage <%temp_storage%> entry.data.uuids append from storage <%gu_storage%> out - data modify storage <%temp_storage%> entry.data.root_uuid set from storage <%gu_storage%> out - - data modify storage <%temp_storage%> entry.data.blueprint_id set value "<%blueprint_id%>" - data modify storage <%temp_storage%> entry.data.rig_hash set value "<%rig_hash%>" - - # Align the position and rotation of the root with the command context. - tp @s ~ ~ ~ ~ ~ - - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'locator' && node.config?.use_entity)) as locator { - summon <%locator.config.entity_type%> \ - ^<%roundTo(locator.default_transform.pos[0], 10)%> \ - ^<%roundTo(locator.default_transform.pos[1], 10)%> \ - ^<%roundTo(locator.default_transform.pos[2], 10)%> \ - {Tags:<%getNodeTags(locator, rig)%>} - execute \ - as @e[ \ - type=<%locator.config.entity_type%>, \ - tag=<%TAGS.PROJECT_LOCATOR_NAMED(blueprint_id, locator.storage_name)%>, \ - tag=<%TAGS.NEW()%>, \ - limit=1, distance=..<%Math.ceil(locator.max_distance)%> \ - ] \ - run block as_locator/<%locator.storage_name%> { - # run block ../as_locator/<%locator.storage_name%> { - tag @s remove <%TAGS.NEW()%> - data modify entity @s CustomName set value '<%ENTITY_NAMES.NODE(blueprint_id, locator.type, locator.storage_name)%>' - function animated_java:global/gu/get_entity_uuid_string - scoreboard players operation @s <%OBJECTIVES.ID()%> = aj.last_id <%OBJECTIVES.ID()%> - } - data modify storage <%temp_storage%> entry.data.uuids append from storage <%gu_storage%> out - data modify storage <%temp_storage%> entry.data.uuids_by_name.<%locator.storage_name%> set from storage <%gu_storage%> out - data modify storage <%temp_storage%> entry.data.locators.<%locator.storage_name%>.uuid set from storage <%gu_storage%> out - } - - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'camera')) as camera { - summon minecraft:item_display \ - ^<%roundTo(camera.default_transform.pos[0], 10)%> \ - ^<%roundTo(camera.default_transform.pos[1], 10)%> \ - ^<%roundTo(camera.default_transform.pos[2], 10)%> \ - {Tags:<%getNodeTags(camera, rig)%>, teleport_duration: 2} - execute \ - as @e[ \ - type=minecraft:item_display, \ - tag=<%TAGS.PROJECT_CAMERA_NAMED(blueprint_id, camera.storage_name)%>, \ - tag=<%TAGS.NEW()%>, \ - limit=1, distance=..<%Math.ceil(camera.max_distance)%> \ - ] \ - run block as_camera/<%camera.storage_name%> { - # run block ../as_camera/<%camera.storage_name%> { - tag @s remove <%TAGS.NEW()%> - data modify entity @s CustomName set value '<%ENTITY_NAMES.NODE(blueprint_id, camera.type, camera.storage_name)%>' - function animated_java:global/gu/get_entity_uuid_string - scoreboard players operation @s <%OBJECTIVES.ID()%> = aj.last_id <%OBJECTIVES.ID()%> - } - data modify storage <%temp_storage%> entry.data.uuids append from storage <%gu_storage%> out - data modify storage <%temp_storage%> entry.data.uuids_by_name.<%camera.storage_name%> set from storage <%gu_storage%> out - data modify storage <%temp_storage%> entry.data.cameras.<%camera.storage_name%>.uuid set from storage <%gu_storage%> out - } - - REPEAT (Object.values(rig.nodes).filter(node => BONE_TYPES.includes(node.type))) as node { - execute \ - on passengers \ - if entity @s[tag=<%TAGS.PROJECT_NODE_NAMED(blueprint_id, node.storage_name)%>] \ - run block as_node/<%node.storage_name%> { - data modify entity @s CustomName set value '<%ENTITY_NAMES.NODE(blueprint_id, node.type, node.storage_name)%>' - function animated_java:global/gu/get_entity_uuid_string - scoreboard players operation @s <%OBJECTIVES.ID()%> = aj.last_id <%OBJECTIVES.ID()%> - } - - data modify storage <%temp_storage%> entry.data.uuids append from storage <%gu_storage%> out - data modify storage <%temp_storage%> entry.data.uuids_by_name.<%node.storage_name%> set from storage <%gu_storage%> out - } - - IF (has_entity_locators) { - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'locator' && node.config?.use_entity)) as locator { - block { with storage <%temp_storage%> entry.data.locators.<%locator.storage_name%> - # Track any custom entities on the locator. - $execute at @s as $(uuid) at @s run function animated_java:global/util/get_entity_stack_uuids - } - data modify storage <%temp_storage%> entry.data.uuids append from storage <%temp_storage%> uuids - } - } - - function <%blueprint_id%>/zzz/set_default_pose - - data_manager write - - # Variant Arguement - IF (Object.keys(rig.variants).length > 1) { - execute if data storage <%temp_storage%> args.variant run block variant_arg/process { with storage <%temp_storage%> args - scoreboard players set #success <%OBJECTIVES.I()%> 0 - # If the variant argument is *explicitly* set to an empty string, return an error. - execute if data storage <%temp_storage%> {args:{variant:''}} run return run block if_empty { - # Tell the user that the variant cannot be empty. - tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('variant')%> - function <%blueprint_id%>/remove/this/without_on_remove_function - } - # Attempt to apply the requested variant. - # We get the success of the `try_apply` function in just in case the user's arguments are *very* wrong. - execute store success score #success <%OBJECTIVES.I()%> run block try_apply { with storage <%temp_storage%> args - $execute if function <%blueprint_id%>/variants/$(variant)/apply run return 1 - # If the apply function fails, the variant doesn't exist, so we return an error. - return fail - } - # If the apply function failed, return an error. - execute unless score #success <%OBJECTIVES.I()%> matches 1 run return run block invalid_variant { - # Tell the user that the provided variant doesn't exist, remove the rig, and list all available variants for this rig. - tellraw @a <%TELLRAW.INVALID_VARIANT(rig.variants)%> - function <%blueprint_id%>/remove/this/without_on_remove_function - } - scoreboard players set #success <%OBJECTIVES.I()%> 1 - } - } ELSE { - execute if data storage <%temp_storage%> args.variant run block zzz/variant_arg/no_variants_warning { - tellraw @a <%TELLRAW.NO_VARIANTS()%> - function <%blueprint_id%>/remove/this/without_on_remove_function - scoreboard players set #success <%OBJECTIVES.I()%> 0 - } - } - execute if score #success <%OBJECTIVES.I()%> matches 0 run return fail - - IF (has_locators || has_cameras) { - function <%blueprint_id%>/root/on_tick/transform_floating_entities - } - execute on passengers run tp @s ~ ~ ~ ~ ~ - - # Apply teleport duration - data modify entity @s teleport_duration set value <%teleportation_duration%> - execute on passengers run data modify entity @s teleport_duration set value <%teleportation_duration%> - - IF (has_entity_locators) { - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'locator' && node.config?.use_entity && node.config.on_summon_function)) as locator { - block { with storage <%temp_storage%> entry.data.locators.<%locator.storage_name%> - $execute at @s as $(uuid) at @s run block on_summon/custom_<%locator.type + '_' + locator.storage_name%> { - <%% - emit.mcb(locator.config.on_summon_function) - %%> - } - } - } - } - - REPEAT (Object.values(rig.nodes).filter(node => BONE_TYPES.includes(node.type) && node.on_summon_function?.trim())) as node { - execute \ - on passengers if entity @s[tag=<%TAGS.PROJECT_NODE_NAMED(blueprint_id, node.storage_name)%>] \ - run block on_summon/<%node.type + '_' + node.storage_name%> { - <%% - emit.mcb(node.on_summon_function.trim()) - %%> - } - } - - IF (on_summon_function) { - execute at @s run block on_summon/rig { - <%% - emit.mcb(on_summon_function) - %%> - } - } - - # Remove the NEW tag from the root entity, and it's passengers. - tag @s remove <%TAGS.NEW()%> - execute on passengers run tag @s remove <%TAGS.NEW()%> - } -} - -function as_node { - #ARGS: {name: string, command: string} - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - data remove storage <%temp_storage%> args - $data modify storage <%temp_storage%> args merge value {name:'$(name)', command:'$(command)', uuid:'+MISSING_UUID+'} - - IF (debug_mode) { - execute if data storage <%temp_storage%> {args:{name:''}} run return run tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('name')%> - execute if data storage <%temp_storage%> {args:{command:''}} run return run tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('command')%> - } - - data_manager prep read - - block zzz/as_node/as_data { with storage <%temp_storage%> args - $data modify storage <%temp_storage%> args.uuid set from storage <%temp_storage%> entry.data.uuids_by_name.$(name) - IF (debug_mode) { - scoreboard players set #aj.check <%OBJECTIVES.I()%> 0 - } - block execute_as_uuid { with storage <%temp_storage%> args - IF (debug_mode) { - # If the function successfully instantiated, the provided command is valid. - scoreboard players set #aj.check <%OBJECTIVES.I()%> 1 - } - $execute as $(uuid) run return run $(command) - IF (debug_mode) { - # If the entity with the provided UUID doesn't exist, the node wasn't found. - tellraw @a <%TELLRAW.NODE_ENTITY_NOT_FOUND()%> - } - } - IF (debug_mode) { - execute if score #aj.check <%OBJECTIVES.I()%> matches 0 run tellraw @a <%TELLRAW.NODE_COMMAND_FAILED_TO_EXECUTE()%> - } - } -} - -IF (has_entity_locators) { - function as_locator { - #ARGS: {name: string, command: string} - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - - data remove storage <%temp_storage%> args - $data modify storage <%temp_storage%> args merge value {name:'$(name)', command:'$(command)', uuid:'+MISSING_UUID+'} - - IF (debug_mode) { - execute if data storage <%temp_storage%> {args:{name:''}} run return run tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('name')%> - execute if data storage <%temp_storage%> {args:{command:''}} run return run tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('command')%> - } - - data_manager prep read - - block zzz/as_locator/as_data { with storage <%temp_storage%> args - $data modify storage <%temp_storage%> args.uuid set from storage <%temp_storage%> entry.data.locators.$(name).uuid - IF (debug_mode) { - scoreboard players set #aj.check <%OBJECTIVES.I()%> 0 - } - block execute_as_uuid { with storage <%temp_storage%> args - IF (debug_mode) { - # If the function successfully instantiated, the provided command is valid. - scoreboard players set #aj.check <%OBJECTIVES.I()%> 1 - } - $execute as $(uuid) run return run $(command) - IF (debug_mode) { - # If the entity with the provided UUID doesn't exist, the locator wasn't found. - tellraw @a <%TELLRAW.LOCATOR_ENTITY_NOT_FOUND()%> - } - } - IF (debug_mode) { - execute if score #aj.check <%OBJECTIVES.I()%> matches 0 run tellraw @a <%TELLRAW.LOCATOR_COMMAND_FAILED_TO_EXECUTE()%> - } - } - } - - function as_at_locator { - #ARGS: {name: string, command: string} - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - - data remove storage <%temp_storage%> args - $data modify storage <%temp_storage%> args merge value {name:'$(name)', command:'$(command)', uuid:'+MISSING_UUID+'} - - IF (debug_mode) { - execute if data storage <%temp_storage%> {args:{name:''}} run return run tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('name')%> - execute if data storage <%temp_storage%> {args:{command:''}} run return run tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('command')%> - } - - data_manager prep read - - block zzz/as_locator/as_data { with storage <%temp_storage%> args - $data modify storage <%temp_storage%> args.uuid set from storage <%temp_storage%> entry.data.locators.$(name).uuid - IF (debug_mode) { - scoreboard players set #aj.check <%OBJECTIVES.I()%> 0 - } - block execute_as_uuid { with storage <%temp_storage%> args - IF (debug_mode) { - # If the function successfully instantiated, the provided command is valid. - scoreboard players set #aj.check <%OBJECTIVES.I()%> 1 - } - $execute as $(uuid) at @s run return run $(command) - IF (debug_mode) { - # If the entity with the provided UUID doesn't exist, the locator wasn't found. - tellraw @a <%TELLRAW.LOCATOR_ENTITY_NOT_FOUND()%> - } - } - IF (debug_mode) { - execute if score #aj.check <%OBJECTIVES.I()%> matches 0 run tellraw @a <%TELLRAW.LOCATOR_COMMAND_FAILED_TO_EXECUTE()%> - } - } - } - - function as_all_locators { - #ARGS: {command: string} - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - - data remove storage <%temp_storage%> args - $data modify storage <%temp_storage%> args merge value {command:'$(command)'} - - IF (debug_mode) { - execute if data storage <%temp_storage%> {args:{command:''}} run return run tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('command')%> - } - - data_manager prep read - - block zzz/as_all_locators/as_data { - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'locator' && node.config?.use_entity)) as locator { - data modify storage <%temp_storage%> args.uuid set from storage <%temp_storage%> entry.data.locators.<%locator.storage_name%>.uuid - - IF (debug_mode) { - scoreboard players set #aj.check <%OBJECTIVES.I()%> 0 - } - - block execute_as_uuid { with storage <%temp_storage%> args - IF (debug_mode) { - # If the function successfully instantiated, the provided command is valid. - scoreboard players set #aj.check <%OBJECTIVES.I()%> 1 - } - - $execute as $(uuid) run return run $(command) - } - - IF (debug_mode) { - execute if score #aj.check <%OBJECTIVES.I()%> matches 0 run tellraw @a <%TELLRAW.LOCATOR_COMMAND_FAILED_TO_EXECUTE({text: locator.storage_name, color: 'aqua'})%> - } - } - } - } - - function as_at_all_locators { - #ARGS: {command: string} - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - - data remove storage <%temp_storage%> args - $data modify storage <%temp_storage%> args merge value {command:'$(command)'} - - IF (debug_mode) { - execute if data storage <%temp_storage%> {args:{command:''}} run return run tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('command')%> - } - - data_manager prep read - - block zzz/as_all_locators/as_data { - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'locator' && node.config?.use_entity)) as locator { - data modify storage <%temp_storage%> args.uuid set from storage <%temp_storage%> entry.data.locators.<%locator.storage_name%>.uuid - - IF (debug_mode) { - scoreboard players set #aj.check <%OBJECTIVES.I()%> 0 - } - - block execute_as_uuid { with storage <%temp_storage%> args - IF (debug_mode) { - # If the function successfully instantiated, the provided command is valid. - scoreboard players set #aj.check <%OBJECTIVES.I()%> 1 - } - - $execute as $(uuid) at @s run return run $(command) - } - - IF (debug_mode) { - execute if score #aj.check <%OBJECTIVES.I()%> matches 0 run tellraw @a <%TELLRAW.LOCATOR_COMMAND_FAILED_TO_EXECUTE({text: locator.storage_name, color: 'aqua'})%> - } - } - } - } -} - -IF (has_locators) { - function at_locator { - #ARGS: {name: string, command: string} - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - - data remove storage <%temp_storage%> args - $data modify storage <%temp_storage%> args merge value {name:'$(name)', command:'$(command)'} - - IF (debug_mode) { - execute if data storage <%temp_storage%> {args:{name:''}} run return run tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('name')%> - execute if data storage <%temp_storage%> {args:{command:''}} run return run tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('command')%> - } - - data_manager prep read - - execute at @s run block zzz/at_locator/as_data { with storage <%temp_storage%> args - $data modify storage <%temp_storage%> args merge from storage <%temp_storage%> entry.data.locators.$(name) - - IF (debug_mode) { - execute unless data storage <%temp_storage%> args.px run return run tellraw @a <%TELLRAW.LOCATOR_NOT_FOUND()%> - scoreboard players set #aj.check <%OBJECTIVES.I()%> 0 - } - - block execute_at_transform { with storage <%temp_storage%> args - IF (debug_mode) { - # If the function successfully instantiated, the provided command is valid. - scoreboard players set #aj.check <%OBJECTIVES.I()%> 1 - } - - $execute \ - positioned ^$(px) ^$(py) ^$(pz) \ - rotated ~$(ry) ~$(rx) \ - run $(command) - } - - IF (debug_mode) { - execute if score #aj.check <%OBJECTIVES.I()%> matches 0 run tellraw @a <%TELLRAW.LOCATOR_COMMAND_FAILED_TO_EXECUTE()%> - } - } - } - - function at_all_locators { - #ARGS: {command: string} - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - - data remove storage <%temp_storage%> args - $data modify storage <%temp_storage%> args merge value {command:'$(command)'} - - IF (debug_mode) { - execute if data storage <%temp_storage%> {args:{command:''}} run return run tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('command')%> - } - - data_manager prep read - - block zzz/at_all_locators/as_data { - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'locator')) as locator { - data modify storage <%temp_storage%> args merge from storage <%temp_storage%> entry.data.locators.<%locator.storage_name%> - - IF (debug_mode) { - scoreboard players set #aj.check <%OBJECTIVES.I()%> 0 - } - - block execute_at_transform { with storage <%temp_storage%> args - IF (debug_mode) { - # If the function successfully instantiated, the provided command is valid. - scoreboard players set #aj.check <%OBJECTIVES.I()%> 1 - } - - $execute \ - positioned ^$(px) ^$(py) ^$(pz) \ - rotated ~$(ry) ~$(rx) \ - run $(command) - } - - IF (debug_mode) { - execute if score #aj.check <%OBJECTIVES.I()%> matches 0 run tellraw @a <%TELLRAW.LOCATOR_COMMAND_FAILED_TO_EXECUTE({text: locator.storage_name, color: 'aqua'})%> - } - } - } - } -} - -IF (has_cameras) { - function as_camera { - #ARGS: {name: string, command: string} - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - - data remove storage <%temp_storage%> args - $data modify storage <%temp_storage%> args merge value {name:'$(name)', command:'$(command)', uuid:'+MISSING_UUID+'} - - IF (debug_mode) { - execute if data storage <%temp_storage%> {args:{name:''}} run return run tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('name')%> - execute if data storage <%temp_storage%> {args:{command:''}} run return run tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('command')%> - } - - data_manager prep read - - block zzz/as_camera/as_data { with storage <%temp_storage%> args - $data modify storage <%temp_storage%> args.uuid set from storage <%temp_storage%> entry.data.cameras.$(name).uuid - - IF (debug_mode) { - scoreboard players set #aj.check <%OBJECTIVES.I()%> 0 - } - - block execute_as_uuid { with storage <%temp_storage%> args - IF (debug_mode) { - # If the function successfully instantiated, the provided command is valid. - scoreboard players set #aj.check <%OBJECTIVES.I()%> 1 - } - - $execute as $(uuid) at @s run return run $(command) - - IF (debug_mode) { - # If the entity with the provided UUID doesn't exist, the camera wasn't found. - tellraw @a <%TELLRAW.CAMERA_ENTITY_NOT_FOUND()%> - } - } - - IF (debug_mode) { - execute if score #aj.check <%OBJECTIVES.I()%> matches 0 run tellraw @a <%TELLRAW.CAMERA_COMMAND_FAILED_TO_EXECUTE()%> - } - } - } -} - -function as_root { - #ARGS: {command: string} - execute unless score @s <%OBJECTIVES.ID()%> matches <%-(2**31)%>..<%(2**31)-1%> run return run \ - tellraw @a <%TELLRAW.FUNCTION_NOT_EXECUTED_AS_ENTITY_WITH_ID_SCORE(context.functions.at(-1))%> - - data_manager prep read - - $data modify storage <%temp_storage%> args.command set value '$(command)' - data modify storage <%temp_storage%> args.root_uuid set from storage <%temp_storage%> entry.data.root_uuid - - IF (debug_mode) { - scoreboard players set #aj.check <%OBJECTIVES.I()%> 0 - } - block as_root_entity { with storage <%temp_storage%> args - $execute as $(root_uuid) run $(command) - IF (debug_mode) { - # If the function successfully instantiated, the provided command is valid. - scoreboard players set #aj.check <%OBJECTIVES.I()%> 1 - } - } - IF (debug_mode) { - execute if score #aj.check <%OBJECTIVES.I()%> matches 0 run tellraw @a <%TELLRAW.ROOT_COMMAND_FAILED_TO_EXECUTE()%> - } - -} - -dir remove { - function all { - # Removes all instances of this rig from the world. - execute as @e[type=minecraft:item_display,tag=<%TAGS.PROJECT_ROOT(blueprint_id)%>] run function <%blueprint_id%>/remove/this - } - - function entities { - # Removes all entities related to this rig from the world. - kill @e[tag=<%TAGS.PROJECT_ENTITY(blueprint_id)%>] - } - - function this { - # Removes the rig this function is executed as. - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - - <%% - if (on_remove_function) emit.mcb(on_remove_function) - %%> - - IF (has_entity_locators) { - data_manager prep read - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'locator')) as locator { - IF (locator.config?.on_remove_function) { - IF (locator.config.use_entity) { - block as_locator_<%locator.storage_name%> { with storage <%temp_storage%> entry.data.locators.<%locator.storage_name%> - $execute as $(uuid) at @s run block locator_<%locator.storage_name%>_on_remove { - <%% - emit.mcb(locator.config.on_remove_function) - %%> - } - } - } ELSE { - block at_locator_<%locator.storage_name%> { with storage <%temp_storage%> entry.data.locators.<%locator.storage_name%> - $execute \ - positioned ^$(px) ^$(py) ^$(pz) \ - rotated ~$(ry) ~$(rx) \ - run block locator_<%locator.storage_name%>_on_remove { - <%% - emit.mcb(locator.config.on_remove_function) - %%> - } - } - } - } - } - } - - function ./this/without_on_remove_function - } - - dir this { - function without_on_remove_function { - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - - data_manager prep read - - IF (has_entity_locators || has_cameras) { - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'locator' && node.config?.use_entity)) as locator { - function animated_java:global/remove/entity_stack_by_uuid with storage <%temp_storage%> entry.data.locators.<%locator.storage_name%> - } - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'camera')) as camera { - function animated_java:global/remove/entity_stack_by_uuid with storage <%temp_storage%> entry.data.cameras.<%camera.storage_name%> - } - } - - # Remove the rig using the more expensive & thorough method if the rig_hash doesn't match. - execute \ - unless data storage <%temp_storage%> {entry:{data:{rig_hash: '<%rig_hash%>'}}} \ - run function animated_java:global/remove/outdated_rig - - block { with storage <%temp_storage%> entry.data.uuids_by_name - REPEAT (Object.values(rig.nodes).filter(node => BONE_TYPES.includes(node.type))) as node { - $kill $(<%node.storage_name%>) - } - } - - function animated_java:global/remove/entity_stack - } - } -} - -IF (Object.keys(rig.variants).length > 1) { - dir variants { - REPEAT (Object.values(rig.variants)) as variant { - dir <%variant.name%> { - function apply { - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - - <%% - global.filteredNodes = Object.values(rig.nodes).filter( - node => ( - node.type === 'bone' && - !variant.excluded_nodes.includes(node.uuid) && - ( // Variant has a model override or a config override for this bone. - variant.models[node.uuid] !== undefined || - node.configs.variants[variant.uuid] !== undefined - ) - ) || ( - BONE_TYPES.includes(node.type) && - !variant.excluded_nodes.includes(node.uuid) && - // Variant has a config override for this node. - node.configs.variants[variant.uuid] !== undefined - ) - ) - %%> - - REPEAT (global.filteredNodes) as node { - execute \ - on passengers \ - if entity @s[tag=<%TAGS.PROJECT_NODE_NAMED(blueprint_id, node.storage_name)%>] \ - at @s \ - run \ - block zzz/apply_to_node_<%node.storage_name%> { - IF (node.type === 'bone' && variant.models[node.uuid] !== undefined) { - # Special case for `animated_java:empty` model. - IF (variant.models[node.uuid].model === null) { - data modify entity @s item.tag.CustomModelData set value 1 - } ELSE { - data modify entity @s item.tag.CustomModelData set value <%variant.models[node.uuid].custom_model_data%> - } - } - IF (node.configs.variants[variant.uuid]) { - <%% - global.config = DisplayEntityConfig.fromJSON(node.configs.variants[variant.uuid]) - %%> - IF (!global.config.isDefault()) { - data merge entity @s <%global.config.toNBT(undefined, variant.is_default)%> - } - IF (global.config.onApplyFunction) { - <%% - emit.mcb(global.config.onApplyFunction) - %%> - } - } - } - } - # Return success to allow this function to be used in function conditions. - return 1 - } - } - } - } -} - -IF (has_locators || has_cameras) { - dir zzz { - function reset_floating_entities { - IF (has_locators) { - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'locator')) as locator { - IF (locator.config?.use_entity) { - execute at @s run block set_default_pose/as_locator_<%locator.storage_name%> { with storage <%temp_storage%> entry.data.locators.<%locator.storage_name%> - $tp $(uuid) \ - ^<%roundTo(locator.default_transform.pos[0], 10)%> \ - ^<%roundTo(locator.default_transform.pos[1], 10)%> \ - ^<%roundTo(locator.default_transform.pos[2], 10)%> \ - ~<%roundTo(locator.default_transform.head_rot[1], 10)%> \ - ~<%roundTo(locator.default_transform.head_rot[0], 10)%> - - data modify storage <%temp_storage%> entry.data.locators.<%locator.storage_name%> merge value { \ - px: <%roundTo(locator.default_transform.pos[0], 10)%>, \ - py: <%roundTo(locator.default_transform.pos[1], 10)%>, \ - pz: <%roundTo(locator.default_transform.pos[2], 10)%>, \ - ry: <%roundTo(locator.default_transform.head_rot[1], 10)%>, \ - rx: <%roundTo(locator.default_transform.head_rot[0], 10)%> \ - } - } - } ELSE { - data modify storage <%temp_storage%> entry.data.locators.<%locator.storage_name%> merge value { \ - px: <%roundTo(locator.default_transform.pos[0], 10)%>, \ - py: <%roundTo(locator.default_transform.pos[1], 10)%>, \ - pz: <%roundTo(locator.default_transform.pos[2], 10)%>, \ - ry: <%roundTo(locator.default_transform.head_rot[1], 10)%>, \ - rx: <%roundTo(locator.default_transform.head_rot[0], 10)%> \ - } - } - } - } - - IF (has_cameras) { - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'camera')) as camera { - execute at @s run block set_default_pose/as_camera_<%camera.storage_name%> { with storage <%temp_storage%> entry.data.cameras.<%camera.storage_name%> - $tp $(uuid) \ - ^<%roundTo(camera.default_transform.pos[0], 10)%> \ - ^<%roundTo(camera.default_transform.pos[1], 10)%> \ - ^<%roundTo(camera.default_transform.pos[2], 10)%> \ - ~<%roundTo(camera.default_transform.head_rot[1], 10)%> \ - ~<%roundTo(camera.default_transform.head_rot[0], 10)%> - - data modify storage <%temp_storage%> entry.data.cameras.<%camera.storage_name%> merge value { \ - px: <%roundTo(camera.default_transform.pos[0], 10)%>, \ - py: <%roundTo(camera.default_transform.pos[1], 10)%>, \ - pz: <%roundTo(camera.default_transform.pos[2], 10)%>, \ - ry: <%roundTo(camera.default_transform.head_rot[1], 10)%>, \ - rx: <%roundTo(camera.default_transform.head_rot[0], 10)%> \ - } - } - } - } - } - } -} - -dir zzz { - function set_default_pose { - IF (has_locators || has_cameras) { - function ../zzz/reset_floating_entities - } - - REPEAT (Object.values(rig.nodes).filter(node => BONE_TYPES.includes(node.type))) as node { - execute \ - on passengers \ - if entity @s[tag=<%TAGS.PROJECT_NODE_NAMED(blueprint_id, node.storage_name)%>] \ - run \ - data merge entity @s { \ - transformation: <%matrixToNbtFloatArray(node.default_transform.matrix).toString()%>, \ - start_interpolation: -1 \ - } - } - } -} - -function set_default_pose { - # Changes the pose of the rig to the the default pose without interpolation - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - - IF (has_locators || has_cameras) { - data_manager prep read - } - function ./zzz/set_default_pose -} \ No newline at end of file diff --git a/src/systems/datapackCompiler/1.20.5/animation.mcb b/src/systems/datapackCompiler/1.20.5/main.mcb similarity index 60% rename from src/systems/datapackCompiler/1.20.5/animation.mcb rename to src/systems/datapackCompiler/1.20.5/main.mcb index b5be4fce..4cbe5f48 100644 --- a/src/systems/datapackCompiler/1.20.5/animation.mcb +++ b/src/systems/datapackCompiler/1.20.5/main.mcb @@ -6,26 +6,30 @@ function on_load { data modify storage <%project_storage%> rig_hash set value <%"'" + rig_hash + "'"%> - IF (use_storage_for_animation) { - REPEAT (animations) as animation { - data remove storage <%project_storage%>/animations <%animation.storage_name%> + IF (has_animations) { + IF (use_storage_for_animation) { + REPEAT (animations) as animation { + data remove storage <%project_storage%>/animations <%animation.storage_name%> + } + <%animationStorage.join('\n')%> } - <%animationStorage.join('\n')%> + <%% + animations.forEach(animation => { + emit(`scoreboard objectives add ${OBJECTIVES.FRAME(animation.storage_name)} dummy`) + }) + %%> } - <%% - animations.forEach(animation => { - emit(`scoreboard objectives add ${OBJECTIVES.FRAME(animation.storage_name)} dummy`) - }) - %%> } -function remove_animation_objectives { - <%% - animations.forEach(animation => { - emit(`scoreboard objectives remove ${OBJECTIVES.FRAME(animation.storage_name)}`) - }) - %%> - tellraw @a <%TELLRAW.UNINSTALL()%> +IF (has_animations) { + function remove_animation_objectives { + <%% + animations.forEach(animation => { + emit(`scoreboard objectives remove ${OBJECTIVES.FRAME(animation.storage_name)}`) + }) + %%> + tellraw @a <%TELLRAW.UNINSTALL()%> + } } dir root { @@ -37,26 +41,28 @@ dir root { %%> } - # animated_java:global/root/on_tick already runs this right before calling this function. - # data_manager prep read - - # Once we have more than 8 animations, calling a function only if at least one animation is playing is more efficient. - IF (animations.length > 8) { - # If no animations are playing, we can skip all animation logic. - # This helps reduce ticking commands for rigs that are idle. - execute \ - unless entity @s[<%animations.map(anim => 'tag=!' + TAGS.ANIMATION_PLAYING(blueprint_id, anim.storage_name)).join(',')%>] \ - run block tick_animations { + IF (has_animations) { + # animated_java:global/root/on_tick already runs this right before calling this function. + # data_manager prep read + + # Once we have more than 8 animations, calling a function only if at least one animation is playing is more efficient. + IF (animations.length > 8) { + # If no animations are playing, we can skip all animation logic. + # This helps reduce ticking commands for rigs that are idle. + execute \ + unless entity @s[<%animations.map(anim => 'tag=!' + TAGS.ANIMATION_PLAYING(blueprint_id, anim.storage_name)).join(',')%>] \ + run block tick_animations { + REPEAT (animations) as animation { + execute if entity @s[tag=<%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%>] run \ + function <%blueprint_id%>/animations/<%animation.storage_name%>/zzz/on_tick + } + } + } ELSE { REPEAT (animations) as animation { execute if entity @s[tag=<%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%>] run \ function <%blueprint_id%>/animations/<%animation.storage_name%>/zzz/on_tick } } - } ELSE { - REPEAT (animations) as animation { - execute if entity @s[tag=<%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%>] run \ - function <%blueprint_id%>/animations/<%animation.storage_name%>/zzz/on_tick - } } IF (auto_update_rig_orientation) { @@ -148,405 +154,413 @@ IF (!auto_update_rig_orientation) { } } -dir animations { - REPEAT (animations) as animation { - dir <%animation.storage_name%> { - function play { - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> +IF (has_animations) { + dir animations { + REPEAT (animations) as animation { + dir <%animation.storage_name%> { + function play { + debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - function <%blueprint_id%>/animations/pause_all + function <%blueprint_id%>/animations/pause_all - tag @s add <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%> - scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> 0 - tag @s add <%TAGS.TRANSFORMS_ONLY()%> - execute at @s run function ./zzz/set_frame {frame: 0} - tag @s remove <%TAGS.TRANSFORMS_ONLY()%> - } + tag @s add <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%> + scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> 0 + tag @s add <%TAGS.TRANSFORMS_ONLY()%> + execute at @s run function ./zzz/set_frame {frame: 0} + tag @s remove <%TAGS.TRANSFORMS_ONLY()%> + } - function stop { - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> + function stop { + debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - function <%blueprint_id%>/animations/pause_all + function <%blueprint_id%>/animations/pause_all - scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> 0 - tag @s add <%TAGS.TRANSFORMS_ONLY()%> - execute at @s run function ./zzz/set_frame {frame: 0} - tag @s remove <%TAGS.TRANSFORMS_ONLY()%> - } + scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> 0 + tag @s add <%TAGS.TRANSFORMS_ONLY()%> + execute at @s run function ./zzz/set_frame {frame: 0} + tag @s remove <%TAGS.TRANSFORMS_ONLY()%> + } - function pause { - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> + function pause { + debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - tag @s remove <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%> - } + tag @s remove <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%> + } - function resume { - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> + function resume { + debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - tag @s add <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%> - } + tag @s add <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%> + } - function next_frame { - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> + function next_frame { + debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - execute if score @s <%OBJECTIVES.FRAME(animation.storage_name)%> matches <%animation.duration%>.. run scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> 1 - data remove storage <%temp_storage%> args - execute store result storage <%temp_storage%> args.frame int 1 run scoreboard players get @s <%OBJECTIVES.FRAME(animation.storage_name)%> - execute at @s run function ./zzz/apply_frame with storage <%temp_storage%> args - scoreboard players add @s <%OBJECTIVES.FRAME(animation.storage_name)%> 1 - } + execute if score @s <%OBJECTIVES.FRAME(animation.storage_name)%> matches <%animation.duration%>.. run scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> 1 + data remove storage <%temp_storage%> args + execute store result storage <%temp_storage%> args.frame int 1 run scoreboard players get @s <%OBJECTIVES.FRAME(animation.storage_name)%> + execute at @s run function ./zzz/apply_frame with storage <%temp_storage%> args + scoreboard players add @s <%OBJECTIVES.FRAME(animation.storage_name)%> 1 + } - function set_frame { - # Sets the frame without interpolation - #ARGS: {frame: int} - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> + function set_frame { + # Sets the frame without interpolation + #ARGS: {frame: int} + debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - data_manager prep read + data_manager prep read - data remove storage <%temp_storage%> args - $execute store result storage <%temp_storage%> args.frame int 1 run scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> $(frame) - execute at @s run function ./zzz/set_frame with storage <%temp_storage%> args - } + data remove storage <%temp_storage%> args + $execute store result storage <%temp_storage%> args.frame int 1 run scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> $(frame) + execute at @s run function ./zzz/set_frame with storage <%temp_storage%> args + } - function apply_frame { - #ARGS: {frame: int} - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> + function apply_frame { + #ARGS: {frame: int} + debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - data_manager prep read + data_manager prep read - data remove storage <%temp_storage%> args - $execute store result storage <%temp_storage%> args.frame int 1 run scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> $(frame) - execute at @s run function ./zzz/apply_frame with storage <%temp_storage%> args - } + data remove storage <%temp_storage%> args + $execute store result storage <%temp_storage%> args.frame int 1 run scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> $(frame) + execute at @s run function ./zzz/apply_frame with storage <%temp_storage%> args + } - function tween { - # Attempts to smoothly transition from the currently playing animation into this one. - #ARGS: {duration: int, to_frame: int} - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> + function tween { + # Attempts to smoothly transition from the currently playing animation into this one. + #ARGS: {duration: int, to_frame: int} + debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - function <%blueprint_id%>/animations/pause_all + function <%blueprint_id%>/animations/pause_all - tag @s add <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%> - $scoreboard players set @s <%OBJECTIVES.TWEEN_DURATION()%> $(duration) - $scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> $(to_frame) + tag @s add <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%> + $scoreboard players set @s <%OBJECTIVES.TWEEN_DURATION()%> $(duration) + $scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> $(to_frame) - scoreboard players operation #this <%OBJECTIVES.I()%> = @s <%OBJECTIVES.TWEEN_DURATION()%> - tag @s add <%TAGS.TRANSFORMS_ONLY()%> - execute at @s run function ./zzz/apply_frame {frame: 0} - $execute at @s run function ./zzz/apply_frame {frame: $(to_frame)} - tag @s remove <%TAGS.TRANSFORMS_ONLY()%> - execute on passengers store result entity @s interpolation_duration int 1 run scoreboard players get #this <%OBJECTIVES.I()%> - } + scoreboard players operation #this <%OBJECTIVES.I()%> = @s <%OBJECTIVES.TWEEN_DURATION()%> + tag @s add <%TAGS.TRANSFORMS_ONLY()%> + execute at @s run function ./zzz/apply_frame {frame: 0} + $execute at @s run function ./zzz/apply_frame {frame: $(to_frame)} + tag @s remove <%TAGS.TRANSFORMS_ONLY()%> + execute on passengers store result entity @s interpolation_duration int 1 run scoreboard players get #this <%OBJECTIVES.I()%> + } - dir zzz { - function on_tick { - # Tweening logic - scoreboard players remove @s <%OBJECTIVES.TWEEN_DURATION()%> 1 - execute if score @s <%OBJECTIVES.TWEEN_DURATION()%> matches 1.. run return 1 - execute if score @s <%OBJECTIVES.TWEEN_DURATION()%> matches 0 on passengers run \ - data modify entity @s interpolation_duration set value <%interpolation_duration%> - # Animation logic - IF (animation.loop_mode === 'loop' && animation.loop_delay === 0) { - # Makes sure function keyframes in the last frame of the animation are activated. - execute if score @s <%OBJECTIVES.FRAME(animation.storage_name)%> matches -1 run \ - block function_keyframe_loop_patch { - function ./frames/last_frame_effects with storage <%temp_storage%> entry.data.uuids_by_name - scoreboard players add @s <%OBJECTIVES.FRAME(animation.storage_name)%> 1 + dir zzz { + function on_tick { + # Tweening logic + scoreboard players remove @s <%OBJECTIVES.TWEEN_DURATION()%> 1 + execute if score @s <%OBJECTIVES.TWEEN_DURATION()%> matches 1.. run return 1 + execute if score @s <%OBJECTIVES.TWEEN_DURATION()%> matches 0 on passengers run \ + data modify entity @s interpolation_duration set value <%interpolation_duration%> + # Animation logic + IF (animation.loop_mode === 'loop' && animation.loop_delay === 0) { + # Makes sure function keyframes in the last frame of the animation are activated. + execute if score @s <%OBJECTIVES.FRAME(animation.storage_name)%> matches -1 run \ + block function_keyframe_loop_patch { + function ./frames/last_frame_effects with storage <%temp_storage%> entry.data.uuids_by_name + scoreboard players add @s <%OBJECTIVES.FRAME(animation.storage_name)%> 1 + } + } + data remove storage <%temp_storage%> args + execute store result storage <%temp_storage%> args.frame int 1 run \ + scoreboard players get @s <%OBJECTIVES.FRAME(animation.storage_name)%> + function ./apply_frame with storage <%temp_storage%> args + IF (animation.loop_mode === 'loop') { + # Loop the animation back to the start once it reaches the last frame. + # If loop_delay is 0, the animation will loop instantly, otherwise, it will wait for the specified amount of ticks. + execute \ + if score @s <%OBJECTIVES.FRAME(animation.storage_name)%> \ + matches <%animation.duration-2 + animation.loop_delay%>.. \ + run return run \ + scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> <%animation.loop_delay === 0 ? -1 : 0%> + } ELSE IF (animation.loop_mode === 'hold') { + # Pause the animation at the last frame. + execute \ + if score @s <%OBJECTIVES.FRAME(animation.storage_name)%> \ + matches <%animation.duration-1%>.. \ + run return run \ + function ../pause + } ELSE IF (animation.loop_mode === 'once') { + # Stop the animation once it reaches the last frame. + execute \ + if score @s <%OBJECTIVES.FRAME(animation.storage_name)%> \ + matches <%animation.duration-1%> \ + run return run block loop_mode_stop { + scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> 0 + tag @s add <%TAGS.TRANSFORMS_ONLY()%> + execute at @s run function ./zzz/set_frame {frame: 0} + tag @s remove <%TAGS.TRANSFORMS_ONLY()%> + tag @s remove <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%> } - } - data remove storage <%temp_storage%> args - execute store result storage <%temp_storage%> args.frame int 1 run \ - scoreboard players get @s <%OBJECTIVES.FRAME(animation.storage_name)%> - function ./apply_frame with storage <%temp_storage%> args - IF (animation.loop_mode === 'loop') { - # Loop the animation back to the start once it reaches the last frame. - # If loop_delay is 0, the animation will loop instantly, otherwise, it will wait for the specified amount of ticks. - execute \ - if score @s <%OBJECTIVES.FRAME(animation.storage_name)%> \ - matches <%animation.duration-2 + animation.loop_delay%>.. \ - run return run \ - scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> <%animation.loop_delay === 0 ? -1 : 0%> - } ELSE IF (animation.loop_mode === 'hold') { - # Pause the animation at the last frame. - execute \ - if score @s <%OBJECTIVES.FRAME(animation.storage_name)%> \ - matches <%animation.duration-1%>.. \ - run return run \ - function ../pause - } ELSE IF (animation.loop_mode === 'once') { - # Stop the animation once it reaches the last frame. - execute \ - if score @s <%OBJECTIVES.FRAME(animation.storage_name)%> \ - matches <%animation.duration-1%> \ - run return run block loop_mode_stop { - scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> 0 - tag @s add <%TAGS.TRANSFORMS_ONLY()%> - execute at @s run function ./zzz/set_frame {frame: 0} - tag @s remove <%TAGS.TRANSFORMS_ONLY()%> - tag @s remove <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%> } + scoreboard players add @s <%OBJECTIVES.FRAME(animation.storage_name)%> 1 } - scoreboard players add @s <%OBJECTIVES.FRAME(animation.storage_name)%> 1 - } - IF (use_storage_for_animation) { - function set_frame { - #ARGS: {frame: int} - $function ./apply_frame {frame: $(frame)} - execute on passengers run data modify entity @s start_interpolation set value -1 - return 1 - } + IF (use_storage_for_animation) { + function set_frame { + #ARGS: {frame: int} + $function ./apply_frame {frame: $(frame)} + execute on passengers run data modify entity @s start_interpolation set value -1 + return 1 + } - function apply_frame { - #ARGS: {frame: int} - REPEAT (Object.values(animation.modified_nodes).sort(nodeSorter)) as node { - IF (BONE_TYPES.includes(node.type)) { - $execute on passengers if entity @s[tag=<%TAGS.PROJECT_NODE_NAMED(blueprint_id, node.storage_name)%>] run \ - data modify entity @s {} merge from \ - storage <%project_storage%>/animations <%animation.storage_name%>.$(frame).<%node.storage_name%> - } ELSE IF (node.type === 'locator' || node.type === 'camera') { - $data modify storage <%temp_storage%> entry.data.uuids_by_name.<%node.storage_name%> merge from \ - storage <%project_storage%>/animations <%animation.storage_name%>.$(frame).<%node.storage_name%> + function apply_frame { + #ARGS: {frame: int} + REPEAT (Object.values(animation.modified_nodes).sort(nodeSorter)) as node { + IF (BONE_TYPES.includes(node.type)) { + $execute on passengers if entity @s[tag=<%TAGS.PROJECT_NODE_NAMED(blueprint_id, node.storage_name)%>] run \ + data modify entity @s {} merge from \ + storage <%project_storage%>/animations <%animation.storage_name%>.$(frame).<%node.storage_name%> + } ELSE IF (node.type === 'locator' || node.type === 'camera') { + $data modify storage <%temp_storage%> entry.data.uuids_by_name.<%node.storage_name%> merge from \ + storage <%project_storage%>/animations <%animation.storage_name%>.$(frame).<%node.storage_name%> + } } - } - IF (animation.frames.some(anim => anim.variant)) { - $execute \ - if data storage <%project_storage%>/animations <%animation.storage_name%>.$(frame).variant \ - unless entity @s[tag=<%TAGS.TRANSFORMS_ONLY()%>] \ - run { with storage <%project_storage%>/animations <%animation.storage_name%>.$(frame).variant - #ARGS: {name: string, condition: string} - $execute $(condition)run function <%blueprint_id%>/variants/$(name)/apply + IF (animation.frames.some(anim => anim.variant)) { + $execute \ + if data storage <%project_storage%>/animations <%animation.storage_name%>.$(frame).variant \ + unless entity @s[tag=<%TAGS.TRANSFORMS_ONLY()%>] \ + run { with storage <%project_storage%>/animations <%animation.storage_name%>.$(frame).variant + #ARGS: {name: string, condition: string} + $execute $(condition)run function <%blueprint_id%>/variants/$(name)/apply + } } - } - return 1 - } - } ELSE { - function set_frame { - # Sets the frame without interpolation - #ARGS: {frame: int} + return 1 + } + } ELSE { + function set_frame { + # Sets the frame without interpolation + #ARGS: {frame: int} - $function ./frames/$(frame) with storage <%temp_storage%> entry.data.uuids_by_name + $function ./frames/$(frame) with storage <%temp_storage%> entry.data.uuids_by_name - execute on passengers run \ - data modify entity @s start_interpolation set value -1 + execute on passengers run \ + data modify entity @s start_interpolation set value -1 - return 1 - } + return 1 + } - function apply_frame { - #ARGS: {frame: int} + function apply_frame { + #ARGS: {frame: int} - $function ./frames/$(frame) with storage <%temp_storage%> entry.data.uuids_by_name + $function ./frames/$(frame) with storage <%temp_storage%> entry.data.uuids_by_name - return 1 - } + return 1 + } - # FIXME - %NEWLINE_PATCH% is a temporary solution to temporarily fix an MCB bug where extra newlines are being added to the output. - dir frames { - <%% - global.frame = animation.frames.at(-1) - global.modified_effect_nodes = Object.values(animation.modified_nodes).filter( - node => node.type === 'locator' && global.frame.node_transforms[node.uuid] - ) - console.log(global.modified_effect_nodes) - %%> - IF(Object.keys(global.modified_effect_nodes).length > 0) { - function last_frame_effects { - REPEAT(global.modified_effect_nodes) as node { - <%% - global.transform = global.frame.node_transforms[node.uuid] - %%> - IF (node.config?.use_entity) { - $execute \ - as $(<%node.storage_name%>) \ - positioned \ - ^<%roundTo(global.transform.pos[0], 10)%> \ - ^<%roundTo(global.transform.pos[1], 10)%> \ - ^<%roundTo(global.transform.pos[2], 10)%> \ - rotated \ - ~<%roundTo(global.transform.head_rot[1], 10)%> \ - ~<%roundTo(global.transform.head_rot[0], 10)%> \ - <%global.transform.function_execute_condition ? global.transform.function_execute_condition + ' ' : ''%>run \ - function ./<%animation.duration%>_locator_<%node.storage_name%> - } ELSE { - execute \ - positioned \ - ^<%roundTo(global.transform.pos[0], 10)%> \ - ^<%roundTo(global.transform.pos[1], 10)%> \ - ^<%roundTo(global.transform.pos[2], 10)%> \ - rotated \ - ~<%roundTo(global.transform.head_rot[1], 10)%> \ - ~<%roundTo(global.transform.head_rot[0], 10)%> \ - <%global.transform.function_execute_condition ? global.transform.function_execute_condition + ' ' : ''%>run \ - function ./<%animation.duration%>_locator_<%node.storage_name%> + # FIXME - %NEWLINE_PATCH% is a temporary solution to temporarily fix an MCB bug where extra newlines are being added to the output. + dir frames { + <%% + global.frame = animation.frames.at(-1) + global.modified_effect_nodes = Object.values(animation.modified_nodes).filter( + node => node.type === 'locator' && global.frame.node_transforms[node.uuid] + ) + console.log(global.modified_effect_nodes) + %%> + IF(Object.keys(global.modified_effect_nodes).length > 0) { + function last_frame_effects { + REPEAT(global.modified_effect_nodes) as node { + <%% + global.transform = global.frame.node_transforms[node.uuid] + %%> + IF (node.config?.use_entity) { + $execute \ + as $(<%node.storage_name%>) \ + positioned \ + ^<%roundTo(global.transform.pos[0], 10)%> \ + ^<%roundTo(global.transform.pos[1], 10)%> \ + ^<%roundTo(global.transform.pos[2], 10)%> \ + rotated \ + ~<%roundTo(global.transform.head_rot[1], 10)%> \ + ~<%roundTo(global.transform.head_rot[0], 10)%> \ + <%global.transform.function_execute_condition ? global.transform.function_execute_condition + ' ' : ''%>run \ + function ./<%animation.duration%>_locator_<%node.storage_name%> + } ELSE { + execute \ + positioned \ + ^<%roundTo(global.transform.pos[0], 10)%> \ + ^<%roundTo(global.transform.pos[1], 10)%> \ + ^<%roundTo(global.transform.pos[2], 10)%> \ + rotated \ + ~<%roundTo(global.transform.head_rot[1], 10)%> \ + ~<%roundTo(global.transform.head_rot[0], 10)%> \ + <%global.transform.function_execute_condition ? global.transform.function_execute_condition + ' ' : ''%>run \ + function ./<%animation.duration%>_locator_<%node.storage_name%> + } } - } - IF (global.frame.variants?.length > 0) { - execute <%global.frame.variants_execute_condition ? global.frame.variants_execute_condition + ' ' : ''%>run \ - function <%blueprint_id%>/variants/<%global.frame.variants[0].name%>/apply - } + IF (global.frame.variants?.length > 0) { + execute <%global.frame.variants_execute_condition ? global.frame.variants_execute_condition + ' ' : ''%>run \ + function <%blueprint_id%>/variants/<%global.frame.variants[0].name%>/apply + } - IF (global.frame.function) { - execute <%global.frame.function_execute_condition ? global.frame.function_execute_condition + ' ' : ''%>run \ - block <%animation.duration%>_function_keyframe { - <%global.frame.function%> - } + IF (global.frame.function) { + execute <%global.frame.function_execute_condition ? global.frame.function_execute_condition + ' ' : ''%>run \ + block <%animation.duration%>_function_keyframe { + <%global.frame.function%> + } + } } } - } - - <%% - // A record of node uuid to INodeTransform. - // Keeps track of the last time a bone was updated. - // Only used for step keyframe interpolation. - let hasFunction = false - const lastActiveFrame = {} - const modifiedNodes = Object.values(animation.modified_nodes).filter(n => n.type !== 'struct').sort(nodeSorter); - for (const [frameIndex, frame] of animation.frames.entries()) { - const to_merge = {cameras: {}, locators: {}} - let frameFunc = ``; - for (const node of modifiedNodes) { - const transform = frame.node_transforms[node.uuid] - // Skip if the node doesn't have a transform for this frame. - if (!transform) continue - switch (node.type) { - case 'bone': - case 'text_display': - case 'item_display': - case 'block_display': { - const lastFrame = lastActiveFrame[node.uuid] - const isStepInterpolation = !!(lastFrame?.interpolation === 'step') - lastActiveFrame[node.uuid] = transform - - if (transform.interpolation === 'pre-post' || isStepInterpolation) { - frameFunc += - `\n$data merge entity $(${node.storage_name})%NEWLINE_PATCH%{` - + `transformation: ${matrixToNbtFloatArray(transform.matrix).toString()},` - + `start_interpolation: ${isStepInterpolation ? -1 : 0},` - + `interpolation_duration: ${isStepInterpolation ? 0 : interpolation_duration}` - + `}` - } else { - frameFunc += - `\n$data merge entity $(${node.storage_name})%NEWLINE_PATCH%{` - + `transformation: ${matrixToNbtFloatArray(transform.matrix).toString()},` - + `start_interpolation: 0,` - + `interpolation_duration: ${interpolation_duration}` - + `}` - } - ;hasFunction = true - break - } - case 'locator': { - const lastFrame = lastActiveFrame[node.uuid] - lastActiveFrame[node.uuid] = transform - ;if (!lastFrame || matrixToNbtFloatArray(transform.matrix).toString() !== matrixToNbtFloatArray(lastFrame.matrix).toString()) { - to_merge.locators[node.storage_name] = { - px: roundTo(transform.pos[0], 10), - py: roundTo(transform.pos[1], 10), - pz: roundTo(transform.pos[2], 10), - ry: roundTo(transform.head_rot[1], 10), - rx: roundTo(transform.head_rot[0], 10) - }; - } - - if (transform.function) { - if (node.config?.use_entity) { + <%% + // A record of node uuid to INodeTransform. + // Keeps track of the last time a bone was updated. + // Only used for step keyframe interpolation. + let hasFunction = false + const lastActiveFrame = {} + const modifiedNodes = Object.values(animation.modified_nodes).filter(n => n.type !== 'struct').sort(nodeSorter); + for (const [frameIndex, frame] of animation.frames.entries()) { + const to_merge = {cameras: {}, locators: {}} + let frameFunc = ``; + for (const node of modifiedNodes) { + const transform = frame.node_transforms[node.uuid] + // Skip if the node doesn't have a transform for this frame. + if (!transform) continue + switch (node.type) { + case 'bone': + case 'text_display': + case 'item_display': + case 'block_display': { + const lastFrame = lastActiveFrame[node.uuid] + const isStepInterpolation = !!(lastFrame?.interpolation === 'step') + lastActiveFrame[node.uuid] = transform + + if (transform.interpolation === 'pre-post' || isStepInterpolation) { frameFunc += - `\n$execute unless entity @s[tag=${TAGS.TRANSFORMS_ONLY()}] as $(${node.storage_name}) ` - + `positioned ^${roundTo(transform.pos[0], 10)} ^${roundTo(transform.pos[1], 10)} ^${roundTo(transform.pos[2], 10)} ` - + `rotated ~${roundTo(transform.head_rot[1], 10)} ~${roundTo(transform.head_rot[0], 10)} ` - + `${transform.function_execute_condition ? transform.function_execute_condition + ' ' : ''}run ` - + `block ${frameIndex}_locator_${node.storage_name}%NEWLINE_PATCH%{\n` - + `tp @s ~ ~ ~ ~ ~\n` - + `${transform.function}` - + `\n}` + `\n$data merge entity $(${node.storage_name})%NEWLINE_PATCH%{` + + `transformation: ${matrixToNbtFloatArray(transform.matrix).toString()},` + + `start_interpolation: ${isStepInterpolation ? -1 : 0},` + + `interpolation_duration: ${isStepInterpolation ? 0 : interpolation_duration}` + + `}` } else { frameFunc += - `\nexecute unless entity @s[tag=${TAGS.TRANSFORMS_ONLY()}] ` - + `positioned ^${roundTo(transform.pos[0], 10)} ^${roundTo(transform.pos[1], 10)} ^${roundTo(transform.pos[2], 10)} ` - + `rotated ~${roundTo(transform.head_rot[1], 10)} ~${roundTo(transform.head_rot[0], 10)} ` - + `${transform.function_execute_condition ? transform.function_execute_condition + ' ' : ''}run ` - + `block ${frameIndex}_locator_${node.storage_name}%NEWLINE_PATCH%{\n` - + `${transform.function}` - + `\n}` + `\n$data merge entity $(${node.storage_name})%NEWLINE_PATCH%{` + + `transformation: ${matrixToNbtFloatArray(transform.matrix).toString()},` + + `start_interpolation: 0,` + + `interpolation_duration: ${interpolation_duration}` + + `}` } + + ;hasFunction = true + break } - break - } - case 'camera': { - const lastFrame = lastActiveFrame[node.uuid] - lastActiveFrame[node.uuid] = transform - ;if (!lastFrame || matrixToNbtFloatArray(transform.matrix).toString() !== matrixToNbtFloatArray(lastFrame.matrix).toString()) { - to_merge.cameras[node.storage_name] = { - px: transform.pos[0], - py: transform.pos[1], - pz: transform.pos[2], - ry: transform.head_rot[1], - rx: transform.head_rot[0] - }; + case 'locator': { + const lastFrame = lastActiveFrame[node.uuid] + lastActiveFrame[node.uuid] = transform + ;if (!lastFrame || matrixToNbtFloatArray(transform.matrix).toString() !== matrixToNbtFloatArray(lastFrame.matrix).toString()) { + to_merge.locators[node.storage_name] = { + px: roundTo(transform.pos[0], 10), + py: roundTo(transform.pos[1], 10), + pz: roundTo(transform.pos[2], 10), + ry: roundTo(transform.head_rot[1], 10), + rx: roundTo(transform.head_rot[0], 10) + }; + } + + if (transform.function) { + if (node.config?.use_entity) { + frameFunc += + `\n$execute unless entity @s[tag=${TAGS.TRANSFORMS_ONLY()}] as $(${node.storage_name}) ` + + `positioned ^${roundTo(transform.pos[0], 10)} ^${roundTo(transform.pos[1], 10)} ^${roundTo(transform.pos[2], 10)} ` + + `rotated ~${roundTo(transform.head_rot[1], 10)} ~${roundTo(transform.head_rot[0], 10)} ` + + `${transform.function_execute_condition ? transform.function_execute_condition + ' ' : ''}run ` + + `block ${frameIndex}_locator_${node.storage_name}%NEWLINE_PATCH%{\n` + + `tp @s ~ ~ ~ ~ ~\n` + + `${transform.function}` + + `\n}` + } else { + frameFunc += + `\nexecute unless entity @s[tag=${TAGS.TRANSFORMS_ONLY()}] ` + + `positioned ^${roundTo(transform.pos[0], 10)} ^${roundTo(transform.pos[1], 10)} ^${roundTo(transform.pos[2], 10)} ` + + `rotated ~${roundTo(transform.head_rot[1], 10)} ~${roundTo(transform.head_rot[0], 10)} ` + + `${transform.function_execute_condition ? transform.function_execute_condition + ' ' : ''}run ` + + `block ${frameIndex}_locator_${node.storage_name}%NEWLINE_PATCH%{\n` + + `${transform.function}` + + `\n}` + } + } + break + } + case 'camera': { + const lastFrame = lastActiveFrame[node.uuid] + lastActiveFrame[node.uuid] = transform + ;if (!lastFrame || matrixToNbtFloatArray(transform.matrix).toString() !== matrixToNbtFloatArray(lastFrame.matrix).toString()) { + to_merge.cameras[node.storage_name] = { + px: transform.pos[0], + py: transform.pos[1], + pz: transform.pos[2], + ry: transform.head_rot[1], + rx: transform.head_rot[0] + }; + } + ;break } - ;break } } - } - if (Object.keys(to_merge.locators).length > 0 || Object.keys(to_merge.cameras).length > 0) { - frameFunc += `\ndata modify storage <%temp_storage%> entry.data merge value ${JSON.stringify(to_merge)}` - frameFunc += `\ndata_manager write` - if (!auto_update_rig_orientation) { - frameFunc += `\nfunction ${blueprint_id}/root/on_tick/transform_floating_entities` + if (Object.keys(to_merge.locators).length > 0 || Object.keys(to_merge.cameras).length > 0) { + frameFunc += `\ndata modify storage <%temp_storage%> entry.data merge value ${JSON.stringify(to_merge)}` + frameFunc += `\ndata_manager write` + if (!auto_update_rig_orientation) { + frameFunc += `\nfunction ${blueprint_id}/root/on_tick/transform_floating_entities` + } + hasFunction = true } - hasFunction = true - } - if (frame.variants?.length) { - const variant = rig.variants[frame.variants[0]] - if (!variant) { - throw new Error(`Could not find Variant with uuid "${frame.variants[0]}" while generating frame "${frameIndex}" of animation "${animation.name}".`) + if (frame.variants?.length) { + const variant = rig.variants[frame.variants[0]] + if (!variant) { + throw new Error(`Could not find Variant with uuid "${frame.variants[0]}" while generating frame "${frameIndex}" of animation "${animation.name}".`) + } + const execute_condition = frame.variants_execute_condition ? frame.variants_execute_condition + ' ' : '' + frameFunc += `\nexecute unless entity @s[tag=${TAGS.TRANSFORMS_ONLY()}] ${execute_condition}run function ${blueprint_id}/variants/${variant.name}/apply` + ;hasFunction = true } - const execute_condition = frame.variants_execute_condition ? frame.variants_execute_condition + ' ' : '' - frameFunc += `\nexecute unless entity @s[tag=${TAGS.TRANSFORMS_ONLY()}] ${execute_condition}run function ${blueprint_id}/variants/${variant.name}/apply` - ;hasFunction = true - } - // Root function keyframes. - if (frame.function) { - const execute_condition = frame.function_execute_condition ? frame.function_execute_condition + ' ' : '' - frameFunc += `\nexecute unless entity @s[tag=${TAGS.TRANSFORMS_ONLY()}] at @s ${execute_condition}run block ${frameIndex}_root_function%NEWLINE_PATCH%{\n${frame.function}\n}` - ;hasFunction = true - } - ;if (frameFunc.length > 0) { - frameFunc = `function ${frameIndex}%NEWLINE_PATCH%{${frameFunc}\n}` - emit.mcb(frameFunc.replaceAll(/%NEWLINE_PATCH%\n?/g, ' ')) + // Root function keyframes. + if (frame.function) { + const execute_condition = frame.function_execute_condition ? frame.function_execute_condition + ' ' : '' + frameFunc += `\nexecute unless entity @s[tag=${TAGS.TRANSFORMS_ONLY()}] at @s ${execute_condition}run block ${frameIndex}_root_function%NEWLINE_PATCH%{\n${frame.function}\n}` + ;hasFunction = true + } + ;if (frameFunc.length > 0) { + frameFunc = `function ${frameIndex}%NEWLINE_PATCH%{${frameFunc}\n}` + emit.mcb(frameFunc.replaceAll(/%NEWLINE_PATCH%\n?/g, ' ')) + } } - } - %%> + %%> + } } } } } - } - function pause_all { - # Pauses all animations - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> + function pause_all { + # Pauses all animations + debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - REPEAT (animations) as animation { - tag @s remove <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%> + REPEAT (animations) as animation { + tag @s remove <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%> + } } } } function summon { - #Args: {args:{variant: string, animation: string, frame: int, start_animation: boolean}} + #Args: {args:{variant?: string, animation?: string, frame?: int, start_animation?: boolean}} # frame is ignored unless animation is specified. - data modify storage <%temp_storage%> args set value {variant:'', animation:'', frame: 0} $execute store success score #success <%OBJECTIVES.I()%> run data modify storage <%temp_storage%> args set value $(args) + IF (!has_animations && debug_mode) { + execute if data storage <%temp_storage%> args.animation run return run \ + tellraw @a <%TELLRAW.ANIMATION_ARG_NO_RIG_ANIMATIONS()%> + execute if data storage <%temp_storage%> args.frame run return run \ + tellraw @a <%TELLRAW.FRAME_ARG_NO_RIG_FRAMES()%> + } + summon minecraft:item_display ~ ~ ~ { \ Tags:[ \ '<%TAGS.NEW()%>', \ @@ -591,7 +605,7 @@ function summon { type=<%locator.config.entity_type%>, \ tag=<%TAGS.PROJECT_LOCATOR_NAMED(blueprint_id, locator.storage_name)%>, \ tag=<%TAGS.NEW()%>, \ - limit=1, distance=..<%Math.ceil(locator.max_distance)%> \ + limit=1, distance=..<%Math.ceil(locator.max_distance + 0.5)%> \ ] \ run block as_locator/<%locator.storage_name%> { # run block ../as_locator/<%locator.storage_name%> { @@ -616,7 +630,7 @@ function summon { type=minecraft:item_display, \ tag=<%TAGS.PROJECT_CAMERA_NAMED(blueprint_id, camera.storage_name)%>, \ tag=<%TAGS.NEW()%>, \ - limit=1, distance=..<%Math.ceil(camera.max_distance)%> \ + limit=1, distance=..<%Math.ceil(camera.max_distance + 0.5)%> \ ] \ run block as_camera/<%camera.storage_name%> { # run block ../as_camera/<%camera.storage_name%> { @@ -692,52 +706,54 @@ function summon { } execute if score #success <%OBJECTIVES.I()%> matches 0 run return fail - # Animation Argument - # If the animation argument is provided, attempt to apply the animation. - execute if data storage <%temp_storage%> args.animation run block animation_arg/process { with storage <%temp_storage%> args - scoreboard players set #success <%OBJECTIVES.I()%> 0 - # If the animation argument is *explicitly* set to an empty string, return an error. - execute if data storage <%temp_storage%> {args:{animation:''}} run return run block if_empty { - tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('animation')%> - function <%blueprint_id%>/remove/this/without_on_remove_function - } - # Automatically set the frame argument to 0 if the frame argument is not provided. - # Takes advantage of `store result score` setting the score to 0 if the command fails. - execute \ - store result storage <%temp_storage%> args.frame int 1 \ - store result score #frame <%OBJECTIVES.I()%> \ - run \ - data get storage <%temp_storage%> args.frame - # If the frame argument is negative, return an error. - execute if score #frame <%OBJECTIVES.I()%> matches ..-1 run return run block no_negative { - # Tell the user that the frame argument cannot be negative. - tellraw @a <%TELLRAW.FRAME_CANNOT_BE_NEGATIVE()%> - function <%blueprint_id%>/remove/this/without_on_remove_function - } - # Attempt to apply the animation frame. - execute store success score #success <%OBJECTIVES.I()%> run block try_set_frame { with storage <%temp_storage%> args - # Make sure we're only applying transforms when setting the summon pose. - tag @s add <%TAGS.TRANSFORMS_ONLY()%> - $execute store success score #success <%OBJECTIVES.I()%> run function <%blueprint_id%>/animations/$(animation)/zzz/set_frame with storage <%temp_storage%> args - tag @s remove <%TAGS.TRANSFORMS_ONLY()%> - execute if score #success <%OBJECTIVES.I()%> matches 1 run return 1 - # If the set_frame function fails, the animation doesn't exist, so we return an error. - return fail - } - # If the set_frame function failed, return an error. - execute unless score #success <%OBJECTIVES.I()%> matches 1 run return run block invalid_animation { - # Tell the user that the provided animation doesn't exist, remove the rig, and list all available animations for this rig. - tellraw @a <%TELLRAW.INVALID_ANIMATION(animations)%> - function <%blueprint_id%>/remove/this/without_on_remove_function - } + IF (has_animations) { + # Animation Argument + # If the animation argument is provided, attempt to apply the animation. + execute if data storage <%temp_storage%> args.animation run block animation_arg/process { with storage <%temp_storage%> args + scoreboard players set #success <%OBJECTIVES.I()%> 0 + # If the animation argument is *explicitly* set to an empty string, return an error. + execute if data storage <%temp_storage%> {args:{animation:''}} run return run block if_empty { + tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('animation')%> + function <%blueprint_id%>/remove/this/without_on_remove_function + } + # Automatically set the frame argument to 0 if the frame argument is not provided. + # Takes advantage of `store result score` setting the score to 0 if the command fails. + execute \ + store result storage <%temp_storage%> args.frame int 1 \ + store result score #frame <%OBJECTIVES.I()%> \ + run \ + data get storage <%temp_storage%> args.frame + # If the frame argument is negative, return an error. + execute if score #frame <%OBJECTIVES.I()%> matches ..-1 run return run block no_negative { + # Tell the user that the frame argument cannot be negative. + tellraw @a <%TELLRAW.FRAME_CANNOT_BE_NEGATIVE()%> + function <%blueprint_id%>/remove/this/without_on_remove_function + } + # Attempt to apply the animation frame. + execute store success score #success <%OBJECTIVES.I()%> run block try_set_frame { with storage <%temp_storage%> args + # Make sure we're only applying transforms when setting the summon pose. + tag @s add <%TAGS.TRANSFORMS_ONLY()%> + $execute store success score #success <%OBJECTIVES.I()%> run function <%blueprint_id%>/animations/$(animation)/zzz/set_frame with storage <%temp_storage%> args + tag @s remove <%TAGS.TRANSFORMS_ONLY()%> + execute if score #success <%OBJECTIVES.I()%> matches 1 run return 1 + # If the set_frame function fails, the animation doesn't exist, so we return an error. + return fail + } + # If the set_frame function failed, return an error. + execute unless score #success <%OBJECTIVES.I()%> matches 1 run return run block invalid_animation { + # Tell the user that the provided animation doesn't exist, remove the rig, and list all available animations for this rig. + tellraw @a <%TELLRAW.INVALID_ANIMATION(animations)%> + function <%blueprint_id%>/remove/this/without_on_remove_function + } - # If the animation is successfully applied, and the start_animation argument is set to true, start the animation. - execute if data storage <%temp_storage%> {args:{start_animation: true}} run block start_animation { with storage <%temp_storage%> args - $function <%blueprint_id%>/animations/$(animation)/resume + # If the animation is successfully applied, and the start_animation argument is set to true, start the animation. + execute if data storage <%temp_storage%> {args:{start_animation: true}} run block start_animation { with storage <%temp_storage%> args + $function <%blueprint_id%>/animations/$(animation)/resume + } + scoreboard players set #success <%OBJECTIVES.I()%> 1 } - scoreboard players set #success <%OBJECTIVES.I()%> 1 + execute if score #success <%OBJECTIVES.I()%> matches 0 run return fail } - execute if score #success <%OBJECTIVES.I()%> matches 0 run return fail IF (has_locators || has_cameras) { function <%blueprint_id%>/root/on_tick/transform_floating_entities @@ -1321,20 +1337,22 @@ IF (has_locators || has_cameras) { } dir zzz { - function apply_default_pose { - IF (has_locators || has_cameras) { - function ../zzz/reset_floating_entities - } + IF (has_animations) { + function apply_default_pose { + IF (has_locators || has_cameras) { + function ../zzz/reset_floating_entities + } - REPEAT (Object.values(rig.nodes).filter(node => BONE_TYPES.includes(node.type))) as node { - execute \ - on passengers \ - if entity @s[tag=<%TAGS.PROJECT_NODE_NAMED(blueprint_id, node.storage_name)%>] \ - run \ - data merge entity @s { \ - transformation: <%matrixToNbtFloatArray(node.default_transform.matrix).toString()%>, \ - start_interpolation: 0 \ - } + REPEAT (Object.values(rig.nodes).filter(node => BONE_TYPES.includes(node.type))) as node { + execute \ + on passengers \ + if entity @s[tag=<%TAGS.PROJECT_NODE_NAMED(blueprint_id, node.storage_name)%>] \ + run \ + data merge entity @s { \ + transformation: <%matrixToNbtFloatArray(node.default_transform.matrix).toString()%>, \ + start_interpolation: 0 \ + } + } } } @@ -1356,14 +1374,16 @@ dir zzz { } } -function apply_default_pose { - # Changes the pose of the rig to the the default pose with interpolation - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> +IF (has_animations) { + function apply_default_pose { + # Changes the pose of the rig to the the default pose with interpolation + debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - IF (has_locators || has_cameras) { - data_manager prep read + IF (has_locators || has_cameras) { + data_manager prep read + } + function ./zzz/apply_default_pose } - function ./zzz/apply_default_pose } function set_default_pose { diff --git a/src/systems/datapackCompiler/1.20.5/static.mcb b/src/systems/datapackCompiler/1.20.5/static.mcb deleted file mode 100644 index fb97cddb..00000000 --- a/src/systems/datapackCompiler/1.20.5/static.mcb +++ /dev/null @@ -1,867 +0,0 @@ -# TODO - Move all internal functions into an internal namespace, and only have user-facing functions in the main `animated_java:<%export_namespace%>` namespace. - -# DIFFERENCES FROM 1.20.4: -# - Item components: item.tag.CustomModelData -> item.components."minecraft:custom_model_data" - -function on_load { - data modify storage <%project_storage%> rig_hash set value <%"'" + rig_hash + "'"%> -} - -dir root { - function on_tick { - # Custom pre-tick function - IF (on_pre_tick_function) { - <%% - emit.mcb(on_pre_tick_function) - %%> - } - - IF (auto_update_rig_orientation) { - IF (has_locators || has_cameras) { - function <%blueprint_id%>/root/on_tick/transform_floating_entities - } - execute on passengers run tp @s ~ ~ ~ ~ ~ - } ELSE IF (has_ticking_locators) { - function <%blueprint_id%>/root/on_tick/transform_locators - } - - # Custom post-tick function - IF (on_post_tick_function) { - <%% - emit.mcb(on_post_tick_function) - %%> - } - } - - IF (has_locators || has_cameras) { - dir on_tick { - function transform_locators { - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'locator')) as locator { - block select_locator_<%locator.storage_name%> { with storage <%temp_storage%> entry.data.locators.<%locator.storage_name%> - IF (locator.config?.use_entity) { - $execute \ - as $(uuid) \ - positioned ^$(px) ^$(py) ^$(pz) \ - rotated ~$(ry) ~$(rx) \ - run block as_locator_<%locator.storage_name%> { - tp @s ~ ~ ~ ~ ~ - - IF (locator.config?.sync_passenger_rotation) { - execute on passengers run tp @s ~ ~ ~ ~ ~ - } - - IF (locator.config?.on_tick_function) { - <%% - emit.mcb(locator.config.on_tick_function) - %%> - } - } - } ELSE IF (locator.config?.on_tick_function) { - $execute \ - positioned ^$(px) ^$(py) ^$(pz) \ - rotated ~$(ry) ~$(rx) \ - run block at_locator_<%locator.storage_name%> { - <%% - emit.mcb(locator.config.on_tick_function) - %%> - } - } - } - } - } - - function transform_floating_entities { - function ./transform_locators - - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'camera')) as camera { - block select_camera_<%camera.storage_name%> { with storage <%temp_storage%> entry.data.cameras.<%camera.storage_name%> - $execute \ - as $(uuid) \ - positioned ^$(px) ^$(py) ^$(pz) \ - rotated ~$(ry) ~$(rx) \ - run tp @s ~ ~ ~ ~ ~ - } - } - } - } - } -} - -IF (!auto_update_rig_orientation) { - function move { - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - - tp @s ~ ~ ~ ~ ~ - - IF (has_locators || has_cameras) { - data_manager prep read - function <%blueprint_id%>/root/on_tick/transform_floating_entities - } - execute at @s on passengers run tp @s ~ ~ ~ ~ ~ - } -} ELSE { - function move { - tellraw @a <%TELLRAW.AUTO_UPDATE_RIG_ORIENTATION_MOVE_WARNING()%> - } -} - -function summon { - #Args: {args:{variant: string}} - - data modify storage <%temp_storage%> args set value {variant:''} - $execute store success score #success <%OBJECTIVES.I()%> run data modify storage <%temp_storage%> args set value $(args) - - summon minecraft:item_display ~ ~ ~ { \ - Tags:[ \ - '<%TAGS.NEW()%>', \ - '<%TAGS.GLOBAL_ENTITY()%>', \ - '<%TAGS.GLOBAL_ROOT()%>', \ - '<%TAGS.PROJECT_ENTITY(blueprint_id)%>', \ - '<%TAGS.PROJECT_ROOT(blueprint_id)%>' \ - ], \ - teleport_duration: 0, \ - interpolation_duration: <%interpolation_duration%>, \ - Passengers:<%root_entity_passengers%>, \ - CustomName: '<%ENTITY_NAMES.ROOT(blueprint_id)%>', \ - } - execute as @e[ \ - type=minecraft:item_display, \ - tag=<%TAGS.PROJECT_ROOT(blueprint_id)%>, \ - tag=<%TAGS.NEW()%>, \ - limit=1, distance=..0.01 \ - ] run block zzz/summon/as_root_entity { - execute store result score @s <%OBJECTIVES.ID()%> run scoreboard players add aj.last_id <%OBJECTIVES.ID()%> 1 - - data_manager init prep read - # Data manager init runs gu:get_entity_uuid_string. So we don't need to call it again here. - # function animated_java:global/gu/get_entity_uuid_string - data modify storage <%temp_storage%> entry.data.uuids append from storage <%gu_storage%> out - data modify storage <%temp_storage%> entry.data.root_uuid set from storage <%gu_storage%> out - - data modify storage <%temp_storage%> entry.data.blueprint_id set value "<%blueprint_id%>" - data modify storage <%temp_storage%> entry.data.rig_hash set value "<%rig_hash%>" - - # Align the position and rotation of the root with the command context. - tp @s ~ ~ ~ ~ ~ - - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'locator' && node.config?.use_entity)) as locator { - summon <%locator.config.entity_type%> \ - ^<%roundTo(locator.default_transform.pos[0], 10)%> \ - ^<%roundTo(locator.default_transform.pos[1], 10)%> \ - ^<%roundTo(locator.default_transform.pos[2], 10)%> \ - {Tags:<%getNodeTags(locator, rig)%>} - execute \ - as @e[ \ - type=<%locator.config.entity_type%>, \ - tag=<%TAGS.PROJECT_LOCATOR_NAMED(blueprint_id, locator.storage_name)%>, \ - tag=<%TAGS.NEW()%>, \ - limit=1, distance=..<%Math.ceil(locator.max_distance)%> \ - ] \ - run block as_locator/<%locator.storage_name%> { - # run block ../as_locator/<%locator.storage_name%> { - tag @s remove <%TAGS.NEW()%> - data modify entity @s CustomName set value '<%ENTITY_NAMES.NODE(blueprint_id, locator.type, locator.storage_name)%>' - function animated_java:global/gu/get_entity_uuid_string - scoreboard players operation @s <%OBJECTIVES.ID()%> = aj.last_id <%OBJECTIVES.ID()%> - } - data modify storage <%temp_storage%> entry.data.uuids append from storage <%gu_storage%> out - data modify storage <%temp_storage%> entry.data.uuids_by_name.<%locator.storage_name%> set from storage <%gu_storage%> out - data modify storage <%temp_storage%> entry.data.locators.<%locator.storage_name%>.uuid set from storage <%gu_storage%> out - } - - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'camera')) as camera { - summon minecraft:item_display \ - ^<%roundTo(camera.default_transform.pos[0], 10)%> \ - ^<%roundTo(camera.default_transform.pos[1], 10)%> \ - ^<%roundTo(camera.default_transform.pos[2], 10)%> \ - {Tags:<%getNodeTags(camera, rig)%>, teleport_duration: 2} - execute \ - as @e[ \ - type=minecraft:item_display, \ - tag=<%TAGS.PROJECT_CAMERA_NAMED(blueprint_id, camera.storage_name)%>, \ - tag=<%TAGS.NEW()%>, \ - limit=1, distance=..<%Math.ceil(camera.max_distance)%> \ - ] \ - run block as_camera/<%camera.storage_name%> { - # run block ../as_camera/<%camera.storage_name%> { - tag @s remove <%TAGS.NEW()%> - data modify entity @s CustomName set value '<%ENTITY_NAMES.NODE(blueprint_id, camera.type, camera.storage_name)%>' - function animated_java:global/gu/get_entity_uuid_string - scoreboard players operation @s <%OBJECTIVES.ID()%> = aj.last_id <%OBJECTIVES.ID()%> - } - data modify storage <%temp_storage%> entry.data.uuids append from storage <%gu_storage%> out - data modify storage <%temp_storage%> entry.data.uuids_by_name.<%camera.storage_name%> set from storage <%gu_storage%> out - data modify storage <%temp_storage%> entry.data.cameras.<%camera.storage_name%>.uuid set from storage <%gu_storage%> out - } - - REPEAT (Object.values(rig.nodes).filter(node => BONE_TYPES.includes(node.type))) as node { - execute \ - on passengers \ - if entity @s[tag=<%TAGS.PROJECT_NODE_NAMED(blueprint_id, node.storage_name)%>] \ - run block as_node/<%node.storage_name%> { - data modify entity @s CustomName set value '<%ENTITY_NAMES.NODE(blueprint_id, node.type, node.storage_name)%>' - function animated_java:global/gu/get_entity_uuid_string - scoreboard players operation @s <%OBJECTIVES.ID()%> = aj.last_id <%OBJECTIVES.ID()%> - } - - data modify storage <%temp_storage%> entry.data.uuids append from storage <%gu_storage%> out - data modify storage <%temp_storage%> entry.data.uuids_by_name.<%node.storage_name%> set from storage <%gu_storage%> out - } - - IF (has_entity_locators) { - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'locator' && node.config?.use_entity)) as locator { - block { with storage <%temp_storage%> entry.data.locators.<%locator.storage_name%> - # Track any custom entities on the locator. - $execute at @s as $(uuid) at @s run function animated_java:global/util/get_entity_stack_uuids - } - data modify storage <%temp_storage%> entry.data.uuids append from storage <%temp_storage%> uuids - } - } - - function <%blueprint_id%>/zzz/set_default_pose - - data_manager write - - # Variant Arguement - IF (Object.keys(rig.variants).length > 1) { - execute if data storage <%temp_storage%> args.variant run block variant_arg/process { with storage <%temp_storage%> args - scoreboard players set #success <%OBJECTIVES.I()%> 0 - # If the variant argument is *explicitly* set to an empty string, return an error. - execute if data storage <%temp_storage%> {args:{variant:''}} run return run block if_empty { - # Tell the user that the variant cannot be empty. - tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('variant')%> - function <%blueprint_id%>/remove/this/without_on_remove_function - } - # Attempt to apply the requested variant. - # We get the success of the `try_apply` function in just in case the user's arguments are *very* wrong. - execute store success score #success <%OBJECTIVES.I()%> run block try_apply { with storage <%temp_storage%> args - $execute if function <%blueprint_id%>/variants/$(variant)/apply run return 1 - # If the apply function fails, the variant doesn't exist, so we return an error. - return fail - } - # If the apply function failed, return an error. - execute unless score #success <%OBJECTIVES.I()%> matches 1 run return run block invalid_variant { - # Tell the user that the provided variant doesn't exist, remove the rig, and list all available variants for this rig. - tellraw @a <%TELLRAW.INVALID_VARIANT(rig.variants)%> - function <%blueprint_id%>/remove/this/without_on_remove_function - } - scoreboard players set #success <%OBJECTIVES.I()%> 1 - } - } ELSE { - execute if data storage <%temp_storage%> args.variant run block zzz/variant_arg/no_variants_warning { - tellraw @a <%TELLRAW.NO_VARIANTS()%> - function <%blueprint_id%>/remove/this/without_on_remove_function - scoreboard players set #success <%OBJECTIVES.I()%> 0 - } - } - execute if score #success <%OBJECTIVES.I()%> matches 0 run return fail - - IF (has_locators || has_cameras) { - function <%blueprint_id%>/root/on_tick/transform_floating_entities - } - execute on passengers run tp @s ~ ~ ~ ~ ~ - - # Apply teleport duration - data modify entity @s teleport_duration set value <%teleportation_duration%> - execute on passengers run data modify entity @s teleport_duration set value <%teleportation_duration%> - - IF (has_entity_locators) { - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'locator' && node.config?.use_entity && node.config.on_summon_function)) as locator { - block { with storage <%temp_storage%> entry.data.locators.<%locator.storage_name%> - $execute at @s as $(uuid) at @s run block on_summon/custom_<%locator.type + '_' + locator.storage_name%> { - <%% - emit.mcb(locator.config.on_summon_function) - %%> - } - } - } - } - - REPEAT (Object.values(rig.nodes).filter(node => BONE_TYPES.includes(node.type) && node.on_summon_function?.trim())) as node { - execute \ - on passengers if entity @s[tag=<%TAGS.PROJECT_NODE_NAMED(blueprint_id, node.storage_name)%>] \ - run block on_summon/<%node.type + '_' + node.storage_name%> { - <%% - emit.mcb(node.on_summon_function.trim()) - %%> - } - } - - IF (on_summon_function) { - execute at @s run block on_summon/rig { - <%% - emit.mcb(on_summon_function) - %%> - } - } - - # Remove the NEW tag from the root entity, and it's passengers. - tag @s remove <%TAGS.NEW()%> - execute on passengers run tag @s remove <%TAGS.NEW()%> - } -} - -function as_node { - #ARGS: {name: string, command: string} - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - data remove storage <%temp_storage%> args - $data modify storage <%temp_storage%> args merge value {name:'$(name)', command:'$(command)', uuid:'+MISSING_UUID+'} - - IF (debug_mode) { - execute if data storage <%temp_storage%> {args:{name:''}} run return run tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('name')%> - execute if data storage <%temp_storage%> {args:{command:''}} run return run tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('command')%> - } - - data_manager prep read - - block zzz/as_node/as_data { with storage <%temp_storage%> args - $data modify storage <%temp_storage%> args.uuid set from storage <%temp_storage%> entry.data.uuids_by_name.$(name) - IF (debug_mode) { - scoreboard players set #aj.check <%OBJECTIVES.I()%> 0 - } - block execute_as_uuid { with storage <%temp_storage%> args - IF (debug_mode) { - # If the function successfully instantiated, the provided command is valid. - scoreboard players set #aj.check <%OBJECTIVES.I()%> 1 - } - $execute as $(uuid) run return run $(command) - IF (debug_mode) { - # If the entity with the provided UUID doesn't exist, the node wasn't found. - tellraw @a <%TELLRAW.NODE_ENTITY_NOT_FOUND()%> - } - } - IF (debug_mode) { - execute if score #aj.check <%OBJECTIVES.I()%> matches 0 run tellraw @a <%TELLRAW.NODE_COMMAND_FAILED_TO_EXECUTE()%> - } - } -} - -IF (has_entity_locators) { - function as_locator { - #ARGS: {name: string, command: string} - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - - data remove storage <%temp_storage%> args - $data modify storage <%temp_storage%> args merge value {name:'$(name)', command:'$(command)', uuid:'+MISSING_UUID+'} - - IF (debug_mode) { - execute if data storage <%temp_storage%> {args:{name:''}} run return run tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('name')%> - execute if data storage <%temp_storage%> {args:{command:''}} run return run tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('command')%> - } - - data_manager prep read - - block zzz/as_locator/as_data { with storage <%temp_storage%> args - $data modify storage <%temp_storage%> args.uuid set from storage <%temp_storage%> entry.data.locators.$(name).uuid - IF (debug_mode) { - scoreboard players set #aj.check <%OBJECTIVES.I()%> 0 - } - block execute_as_uuid { with storage <%temp_storage%> args - IF (debug_mode) { - # If the function successfully instantiated, the provided command is valid. - scoreboard players set #aj.check <%OBJECTIVES.I()%> 1 - } - $execute as $(uuid) run return run $(command) - IF (debug_mode) { - # If the entity with the provided UUID doesn't exist, the locator wasn't found. - tellraw @a <%TELLRAW.LOCATOR_ENTITY_NOT_FOUND()%> - } - } - IF (debug_mode) { - execute if score #aj.check <%OBJECTIVES.I()%> matches 0 run tellraw @a <%TELLRAW.LOCATOR_COMMAND_FAILED_TO_EXECUTE()%> - } - } - } - - function as_at_locator { - #ARGS: {name: string, command: string} - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - - data remove storage <%temp_storage%> args - $data modify storage <%temp_storage%> args merge value {name:'$(name)', command:'$(command)', uuid:'+MISSING_UUID+'} - - IF (debug_mode) { - execute if data storage <%temp_storage%> {args:{name:''}} run return run tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('name')%> - execute if data storage <%temp_storage%> {args:{command:''}} run return run tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('command')%> - } - - data_manager prep read - - block zzz/as_locator/as_data { with storage <%temp_storage%> args - $data modify storage <%temp_storage%> args.uuid set from storage <%temp_storage%> entry.data.locators.$(name).uuid - IF (debug_mode) { - scoreboard players set #aj.check <%OBJECTIVES.I()%> 0 - } - block execute_as_uuid { with storage <%temp_storage%> args - IF (debug_mode) { - # If the function successfully instantiated, the provided command is valid. - scoreboard players set #aj.check <%OBJECTIVES.I()%> 1 - } - $execute as $(uuid) at @s run return run $(command) - IF (debug_mode) { - # If the entity with the provided UUID doesn't exist, the locator wasn't found. - tellraw @a <%TELLRAW.LOCATOR_ENTITY_NOT_FOUND()%> - } - } - IF (debug_mode) { - execute if score #aj.check <%OBJECTIVES.I()%> matches 0 run tellraw @a <%TELLRAW.LOCATOR_COMMAND_FAILED_TO_EXECUTE()%> - } - } - } - - function as_all_locators { - #ARGS: {command: string} - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - - data remove storage <%temp_storage%> args - $data modify storage <%temp_storage%> args merge value {command:'$(command)'} - - IF (debug_mode) { - execute if data storage <%temp_storage%> {args:{command:''}} run return run tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('command')%> - } - - data_manager prep read - - block zzz/as_all_locators/as_data { - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'locator' && node.config?.use_entity)) as locator { - data modify storage <%temp_storage%> args.uuid set from storage <%temp_storage%> entry.data.locators.<%locator.storage_name%>.uuid - - IF (debug_mode) { - scoreboard players set #aj.check <%OBJECTIVES.I()%> 0 - } - - block execute_as_uuid { with storage <%temp_storage%> args - IF (debug_mode) { - # If the function successfully instantiated, the provided command is valid. - scoreboard players set #aj.check <%OBJECTIVES.I()%> 1 - } - - $execute as $(uuid) run return run $(command) - } - - IF (debug_mode) { - execute if score #aj.check <%OBJECTIVES.I()%> matches 0 run tellraw @a <%TELLRAW.LOCATOR_COMMAND_FAILED_TO_EXECUTE({text: locator.storage_name, color: 'aqua'})%> - } - } - } - } - - function as_at_all_locators { - #ARGS: {command: string} - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - - data remove storage <%temp_storage%> args - $data modify storage <%temp_storage%> args merge value {command:'$(command)'} - - IF (debug_mode) { - execute if data storage <%temp_storage%> {args:{command:''}} run return run tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('command')%> - } - - data_manager prep read - - block zzz/as_all_locators/as_data { - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'locator' && node.config?.use_entity)) as locator { - data modify storage <%temp_storage%> args.uuid set from storage <%temp_storage%> entry.data.locators.<%locator.storage_name%>.uuid - - IF (debug_mode) { - scoreboard players set #aj.check <%OBJECTIVES.I()%> 0 - } - - block execute_as_uuid { with storage <%temp_storage%> args - IF (debug_mode) { - # If the function successfully instantiated, the provided command is valid. - scoreboard players set #aj.check <%OBJECTIVES.I()%> 1 - } - - $execute as $(uuid) at @s run return run $(command) - } - - IF (debug_mode) { - execute if score #aj.check <%OBJECTIVES.I()%> matches 0 run tellraw @a <%TELLRAW.LOCATOR_COMMAND_FAILED_TO_EXECUTE({text: locator.storage_name, color: 'aqua'})%> - } - } - } - } -} - -IF (has_locators) { - function at_locator { - #ARGS: {name: string, command: string} - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - - data remove storage <%temp_storage%> args - $data modify storage <%temp_storage%> args merge value {name:'$(name)', command:'$(command)'} - - IF (debug_mode) { - execute if data storage <%temp_storage%> {args:{name:''}} run return run tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('name')%> - execute if data storage <%temp_storage%> {args:{command:''}} run return run tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('command')%> - } - - data_manager prep read - - execute at @s run block zzz/at_locator/as_data { with storage <%temp_storage%> args - $data modify storage <%temp_storage%> args merge from storage <%temp_storage%> entry.data.locators.$(name) - - IF (debug_mode) { - execute unless data storage <%temp_storage%> args.px run return run tellraw @a <%TELLRAW.LOCATOR_NOT_FOUND()%> - scoreboard players set #aj.check <%OBJECTIVES.I()%> 0 - } - - block execute_at_transform { with storage <%temp_storage%> args - IF (debug_mode) { - # If the function successfully instantiated, the provided command is valid. - scoreboard players set #aj.check <%OBJECTIVES.I()%> 1 - } - - $execute \ - positioned ^$(px) ^$(py) ^$(pz) \ - rotated ~$(ry) ~$(rx) \ - run $(command) - } - - IF (debug_mode) { - execute if score #aj.check <%OBJECTIVES.I()%> matches 0 run tellraw @a <%TELLRAW.LOCATOR_COMMAND_FAILED_TO_EXECUTE()%> - } - } - } - - function at_all_locators { - #ARGS: {command: string} - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - - data remove storage <%temp_storage%> args - $data modify storage <%temp_storage%> args merge value {command:'$(command)'} - - IF (debug_mode) { - execute if data storage <%temp_storage%> {args:{command:''}} run return run tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('command')%> - } - - data_manager prep read - - block zzz/at_all_locators/as_data { - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'locator')) as locator { - data modify storage <%temp_storage%> args merge from storage <%temp_storage%> entry.data.locators.<%locator.storage_name%> - - IF (debug_mode) { - scoreboard players set #aj.check <%OBJECTIVES.I()%> 0 - } - - block execute_at_transform { with storage <%temp_storage%> args - IF (debug_mode) { - # If the function successfully instantiated, the provided command is valid. - scoreboard players set #aj.check <%OBJECTIVES.I()%> 1 - } - - $execute \ - positioned ^$(px) ^$(py) ^$(pz) \ - rotated ~$(ry) ~$(rx) \ - run $(command) - } - - IF (debug_mode) { - execute if score #aj.check <%OBJECTIVES.I()%> matches 0 run tellraw @a <%TELLRAW.LOCATOR_COMMAND_FAILED_TO_EXECUTE({text: locator.storage_name, color: 'aqua'})%> - } - } - } - } -} - -IF (has_cameras) { - function as_camera { - #ARGS: {name: string, command: string} - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - - data remove storage <%temp_storage%> args - $data modify storage <%temp_storage%> args merge value {name:'$(name)', command:'$(command)', uuid:'+MISSING_UUID+'} - - IF (debug_mode) { - execute if data storage <%temp_storage%> {args:{name:''}} run return run tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('name')%> - execute if data storage <%temp_storage%> {args:{command:''}} run return run tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('command')%> - } - - data_manager prep read - - block zzz/as_camera/as_data { with storage <%temp_storage%> args - $data modify storage <%temp_storage%> args.uuid set from storage <%temp_storage%> entry.data.cameras.$(name).uuid - - IF (debug_mode) { - scoreboard players set #aj.check <%OBJECTIVES.I()%> 0 - } - - block execute_as_uuid { with storage <%temp_storage%> args - IF (debug_mode) { - # If the function successfully instantiated, the provided command is valid. - scoreboard players set #aj.check <%OBJECTIVES.I()%> 1 - } - - $execute as $(uuid) at @s run return run $(command) - - IF (debug_mode) { - # If the entity with the provided UUID doesn't exist, the camera wasn't found. - tellraw @a <%TELLRAW.CAMERA_ENTITY_NOT_FOUND()%> - } - } - - IF (debug_mode) { - execute if score #aj.check <%OBJECTIVES.I()%> matches 0 run tellraw @a <%TELLRAW.CAMERA_COMMAND_FAILED_TO_EXECUTE()%> - } - } - } -} - -function as_root { - #ARGS: {command: string} - execute unless score @s <%OBJECTIVES.ID()%> matches <%-(2**31)%>..<%(2**31)-1%> run return run \ - tellraw @a <%TELLRAW.FUNCTION_NOT_EXECUTED_AS_ENTITY_WITH_ID_SCORE(context.functions.at(-1))%> - - data_manager prep read - - $data modify storage <%temp_storage%> args.command set value '$(command)' - data modify storage <%temp_storage%> args.root_uuid set from storage <%temp_storage%> entry.data.root_uuid - - IF (debug_mode) { - scoreboard players set #aj.check <%OBJECTIVES.I()%> 0 - } - block as_root_entity { with storage <%temp_storage%> args - $execute as $(root_uuid) run $(command) - IF (debug_mode) { - # If the function successfully instantiated, the provided command is valid. - scoreboard players set #aj.check <%OBJECTIVES.I()%> 1 - } - } - IF (debug_mode) { - execute if score #aj.check <%OBJECTIVES.I()%> matches 0 run tellraw @a <%TELLRAW.ROOT_COMMAND_FAILED_TO_EXECUTE()%> - } - -} - -dir remove { - function all { - # Removes all instances of this rig from the world. - execute as @e[type=minecraft:item_display,tag=<%TAGS.PROJECT_ROOT(blueprint_id)%>] run function <%blueprint_id%>/remove/this - } - - function entities { - # Removes all entities related to this rig from the world. - kill @e[tag=<%TAGS.PROJECT_ENTITY(blueprint_id)%>] - } - - function this { - # Removes the rig this function is executed as. - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - - <%% - if (on_remove_function) emit.mcb(on_remove_function) - %%> - - IF (has_entity_locators) { - data_manager prep read - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'locator')) as locator { - IF (locator.config?.on_remove_function) { - IF (locator.config.use_entity) { - block as_locator_<%locator.storage_name%> { with storage <%temp_storage%> entry.data.locators.<%locator.storage_name%> - $execute as $(uuid) at @s run block locator_<%locator.storage_name%>_on_remove { - <%% - emit.mcb(locator.config.on_remove_function) - %%> - } - } - } ELSE { - block at_locator_<%locator.storage_name%> { with storage <%temp_storage%> entry.data.locators.<%locator.storage_name%> - $execute \ - positioned ^$(px) ^$(py) ^$(pz) \ - rotated ~$(ry) ~$(rx) \ - run block locator_<%locator.storage_name%>_on_remove { - <%% - emit.mcb(locator.config.on_remove_function) - %%> - } - } - } - } - } - } - - function ./this/without_on_remove_function - } - - dir this { - function without_on_remove_function { - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - - data_manager prep read - - IF (has_entity_locators || has_cameras) { - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'locator' && node.config?.use_entity)) as locator { - function animated_java:global/remove/entity_stack_by_uuid with storage <%temp_storage%> entry.data.locators.<%locator.storage_name%> - } - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'camera')) as camera { - function animated_java:global/remove/entity_stack_by_uuid with storage <%temp_storage%> entry.data.cameras.<%camera.storage_name%> - } - } - - # Remove the rig using the more expensive & thorough method if the rig_hash doesn't match. - execute \ - unless data storage <%temp_storage%> {entry:{data:{rig_hash: '<%rig_hash%>'}}} \ - run function animated_java:global/remove/outdated_rig - - block { with storage <%temp_storage%> entry.data.uuids_by_name - REPEAT (Object.values(rig.nodes).filter(node => BONE_TYPES.includes(node.type))) as node { - $kill $(<%node.storage_name%>) - } - } - - function animated_java:global/remove/entity_stack - } - } -} - -IF (Object.keys(rig.variants).length > 1) { - dir variants { - REPEAT (Object.values(rig.variants)) as variant { - dir <%variant.name%> { - function apply { - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - - <%% - global.filteredNodes = Object.values(rig.nodes).filter( - node => ( - node.type === 'bone' && - !variant.excluded_nodes.includes(node.uuid) && - ( // Variant has a model override or a config override for this bone. - variant.models[node.uuid] !== undefined || - node.configs.variants[variant.uuid] !== undefined - ) - ) || ( - BONE_TYPES.includes(node.type) && - !variant.excluded_nodes.includes(node.uuid) && - // Variant has a config override for this node. - node.configs.variants[variant.uuid] !== undefined - ) - ) - %%> - - REPEAT (global.filteredNodes) as node { - execute \ - on passengers \ - if entity @s[tag=<%TAGS.PROJECT_NODE_NAMED(blueprint_id, node.storage_name)%>] \ - at @s \ - run \ - block zzz/apply_to_node_<%node.storage_name%> { - IF (node.type === 'bone' && variant.models[node.uuid] !== undefined) { - # Special case for `animated_java:empty` model. - IF (variant.models[node.uuid].model === null) { - data modify entity @s item.components."minecraft:custom_model_data" set value 1 - } ELSE { - data modify entity @s item.components."minecraft:custom_model_data" set value <%variant.models[node.uuid].custom_model_data%> - } - } - IF (node.configs.variants[variant.uuid]) { - <%% - global.config = DisplayEntityConfig.fromJSON(node.configs.variants[variant.uuid]) - %%> - IF (!global.config.isDefault()) { - data merge entity @s <%global.config.toNBT(undefined, variant.is_default)%> - } - IF (global.config.onApplyFunction) { - <%% - emit.mcb(global.config.onApplyFunction) - %%> - } - } - } - } - # Return success to allow this function to be used in function conditions. - return 1 - } - } - } - } -} - -IF (has_locators || has_cameras) { - dir zzz { - function reset_floating_entities { - IF (has_locators) { - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'locator')) as locator { - IF (locator.config?.use_entity) { - execute at @s run block set_default_pose/as_locator_<%locator.storage_name%> { with storage <%temp_storage%> entry.data.locators.<%locator.storage_name%> - $tp $(uuid) \ - ^<%roundTo(locator.default_transform.pos[0], 10)%> \ - ^<%roundTo(locator.default_transform.pos[1], 10)%> \ - ^<%roundTo(locator.default_transform.pos[2], 10)%> \ - ~<%roundTo(locator.default_transform.head_rot[1], 10)%> \ - ~<%roundTo(locator.default_transform.head_rot[0], 10)%> - - data modify storage <%temp_storage%> entry.data.locators.<%locator.storage_name%> merge value { \ - px: <%roundTo(locator.default_transform.pos[0], 10)%>, \ - py: <%roundTo(locator.default_transform.pos[1], 10)%>, \ - pz: <%roundTo(locator.default_transform.pos[2], 10)%>, \ - ry: <%roundTo(locator.default_transform.head_rot[1], 10)%>, \ - rx: <%roundTo(locator.default_transform.head_rot[0], 10)%> \ - } - } - } ELSE { - data modify storage <%temp_storage%> entry.data.locators.<%locator.storage_name%> merge value { \ - px: <%roundTo(locator.default_transform.pos[0], 10)%>, \ - py: <%roundTo(locator.default_transform.pos[1], 10)%>, \ - pz: <%roundTo(locator.default_transform.pos[2], 10)%>, \ - ry: <%roundTo(locator.default_transform.head_rot[1], 10)%>, \ - rx: <%roundTo(locator.default_transform.head_rot[0], 10)%> \ - } - } - } - } - - IF (has_cameras) { - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'camera')) as camera { - execute at @s run block set_default_pose/as_camera_<%camera.storage_name%> { with storage <%temp_storage%> entry.data.cameras.<%camera.storage_name%> - $tp $(uuid) \ - ^<%roundTo(camera.default_transform.pos[0], 10)%> \ - ^<%roundTo(camera.default_transform.pos[1], 10)%> \ - ^<%roundTo(camera.default_transform.pos[2], 10)%> \ - ~<%roundTo(camera.default_transform.head_rot[1], 10)%> \ - ~<%roundTo(camera.default_transform.head_rot[0], 10)%> - - data modify storage <%temp_storage%> entry.data.cameras.<%camera.storage_name%> merge value { \ - px: <%roundTo(camera.default_transform.pos[0], 10)%>, \ - py: <%roundTo(camera.default_transform.pos[1], 10)%>, \ - pz: <%roundTo(camera.default_transform.pos[2], 10)%>, \ - ry: <%roundTo(camera.default_transform.head_rot[1], 10)%>, \ - rx: <%roundTo(camera.default_transform.head_rot[0], 10)%> \ - } - } - } - } - } - } -} - -dir zzz { - function set_default_pose { - IF (has_locators || has_cameras) { - function ../zzz/reset_floating_entities - } - - REPEAT (Object.values(rig.nodes).filter(node => BONE_TYPES.includes(node.type))) as node { - execute \ - on passengers \ - if entity @s[tag=<%TAGS.PROJECT_NODE_NAMED(blueprint_id, node.storage_name)%>] \ - run \ - data merge entity @s { \ - transformation: <%matrixToNbtFloatArray(node.default_transform.matrix).toString()%>, \ - start_interpolation: -1 \ - } - } - } -} - -function set_default_pose { - # Changes the pose of the rig to the the default pose without interpolation - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - - IF (has_locators || has_cameras) { - data_manager prep read - } - function ./zzz/set_default_pose -} \ No newline at end of file diff --git a/src/systems/datapackCompiler/1.21.0/animation.mcb b/src/systems/datapackCompiler/1.21.0/main.mcb similarity index 60% rename from src/systems/datapackCompiler/1.21.0/animation.mcb rename to src/systems/datapackCompiler/1.21.0/main.mcb index fdecf1e2..e927e04a 100644 --- a/src/systems/datapackCompiler/1.21.0/animation.mcb +++ b/src/systems/datapackCompiler/1.21.0/main.mcb @@ -7,26 +7,30 @@ function on_load { data modify storage <%project_storage%> rig_hash set value <%"'" + rig_hash + "'"%> - IF (use_storage_for_animation) { - REPEAT (animations) as animation { - data remove storage <%project_storage%>/animations <%animation.storage_name%> + IF (has_animations) { + IF (use_storage_for_animation) { + REPEAT (animations) as animation { + data remove storage <%project_storage%>/animations <%animation.storage_name%> + } + <%animationStorage.join('\n')%> } - <%animationStorage.join('\n')%> + <%% + animations.forEach(animation => { + emit(`scoreboard objectives add ${OBJECTIVES.FRAME(animation.storage_name)} dummy`) + }) + %%> } - <%% - animations.forEach(animation => { - emit(`scoreboard objectives add ${OBJECTIVES.FRAME(animation.storage_name)} dummy`) - }) - %%> } -function remove_animation_objectives { - <%% - animations.forEach(animation => { - emit(`scoreboard objectives remove ${OBJECTIVES.FRAME(animation.storage_name)}`) - }) - %%> - tellraw @a <%TELLRAW.UNINSTALL()%> +IF (has_animations) { + function remove_animation_objectives { + <%% + animations.forEach(animation => { + emit(`scoreboard objectives remove ${OBJECTIVES.FRAME(animation.storage_name)}`) + }) + %%> + tellraw @a <%TELLRAW.UNINSTALL()%> + } } dir root { @@ -38,26 +42,28 @@ dir root { %%> } - # animated_java:global/root/on_tick already runs this right before calling this function. - # data_manager prep read - - # Once we have more than 8 animations, calling a function only if at least one animation is playing is more efficient. - IF (animations.length > 8) { - # If no animations are playing, we can skip all animation logic. - # This helps reduce ticking commands for rigs that are idle. - execute \ - unless entity @s[<%animations.map(anim => 'tag=!' + TAGS.ANIMATION_PLAYING(blueprint_id, anim.storage_name)).join(',')%>] \ - run block tick_animations { + IF (has_animations) { + # animated_java:global/root/on_tick already runs this right before calling this function. + # data_manager prep read + + # Once we have more than 8 animations, calling a function only if at least one animation is playing is more efficient. + IF (animations.length > 8) { + # If no animations are playing, we can skip all animation logic. + # This helps reduce ticking commands for rigs that are idle. + execute \ + unless entity @s[<%animations.map(anim => 'tag=!' + TAGS.ANIMATION_PLAYING(blueprint_id, anim.storage_name)).join(',')%>] \ + run block tick_animations { + REPEAT (animations) as animation { + execute if entity @s[tag=<%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%>] run \ + function <%blueprint_id%>/animations/<%animation.storage_name%>/zzz/on_tick + } + } + } ELSE { REPEAT (animations) as animation { execute if entity @s[tag=<%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%>] run \ function <%blueprint_id%>/animations/<%animation.storage_name%>/zzz/on_tick } } - } ELSE { - REPEAT (animations) as animation { - execute if entity @s[tag=<%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%>] run \ - function <%blueprint_id%>/animations/<%animation.storage_name%>/zzz/on_tick - } } IF (auto_update_rig_orientation) { @@ -149,405 +155,413 @@ IF (!auto_update_rig_orientation) { } } -dir animations { - REPEAT (animations) as animation { - dir <%animation.storage_name%> { - function play { - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> +IF (has_animations) { + dir animations { + REPEAT (animations) as animation { + dir <%animation.storage_name%> { + function play { + debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - function <%blueprint_id%>/animations/pause_all + function <%blueprint_id%>/animations/pause_all - tag @s add <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%> - scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> 0 - tag @s add <%TAGS.TRANSFORMS_ONLY()%> - execute at @s run function ./zzz/set_frame {frame: 0} - tag @s remove <%TAGS.TRANSFORMS_ONLY()%> - } + tag @s add <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%> + scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> 0 + tag @s add <%TAGS.TRANSFORMS_ONLY()%> + execute at @s run function ./zzz/set_frame {frame: 0} + tag @s remove <%TAGS.TRANSFORMS_ONLY()%> + } - function stop { - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> + function stop { + debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - function <%blueprint_id%>/animations/pause_all + function <%blueprint_id%>/animations/pause_all - scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> 0 - tag @s add <%TAGS.TRANSFORMS_ONLY()%> - execute at @s run function ./zzz/set_frame {frame: 0} - tag @s remove <%TAGS.TRANSFORMS_ONLY()%> - } + scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> 0 + tag @s add <%TAGS.TRANSFORMS_ONLY()%> + execute at @s run function ./zzz/set_frame {frame: 0} + tag @s remove <%TAGS.TRANSFORMS_ONLY()%> + } - function pause { - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> + function pause { + debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - tag @s remove <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%> - } + tag @s remove <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%> + } - function resume { - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> + function resume { + debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - tag @s add <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%> - } + tag @s add <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%> + } - function next_frame { - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> + function next_frame { + debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - execute if score @s <%OBJECTIVES.FRAME(animation.storage_name)%> matches <%animation.duration%>.. run scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> 1 - data remove storage <%temp_storage%> args - execute store result storage <%temp_storage%> args.frame int 1 run scoreboard players get @s <%OBJECTIVES.FRAME(animation.storage_name)%> - execute at @s run function ./zzz/apply_frame with storage <%temp_storage%> args - scoreboard players add @s <%OBJECTIVES.FRAME(animation.storage_name)%> 1 - } + execute if score @s <%OBJECTIVES.FRAME(animation.storage_name)%> matches <%animation.duration%>.. run scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> 1 + data remove storage <%temp_storage%> args + execute store result storage <%temp_storage%> args.frame int 1 run scoreboard players get @s <%OBJECTIVES.FRAME(animation.storage_name)%> + execute at @s run function ./zzz/apply_frame with storage <%temp_storage%> args + scoreboard players add @s <%OBJECTIVES.FRAME(animation.storage_name)%> 1 + } - function set_frame { - # Sets the frame without interpolation - #ARGS: {frame: int} - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> + function set_frame { + # Sets the frame without interpolation + #ARGS: {frame: int} + debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - data_manager prep read + data_manager prep read - data remove storage <%temp_storage%> args - $execute store result storage <%temp_storage%> args.frame int 1 run scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> $(frame) - execute at @s run function ./zzz/set_frame with storage <%temp_storage%> args - } + data remove storage <%temp_storage%> args + $execute store result storage <%temp_storage%> args.frame int 1 run scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> $(frame) + execute at @s run function ./zzz/set_frame with storage <%temp_storage%> args + } - function apply_frame { - #ARGS: {frame: int} - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> + function apply_frame { + #ARGS: {frame: int} + debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - data_manager prep read + data_manager prep read - data remove storage <%temp_storage%> args - $execute store result storage <%temp_storage%> args.frame int 1 run scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> $(frame) - execute at @s run function ./zzz/apply_frame with storage <%temp_storage%> args - } + data remove storage <%temp_storage%> args + $execute store result storage <%temp_storage%> args.frame int 1 run scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> $(frame) + execute at @s run function ./zzz/apply_frame with storage <%temp_storage%> args + } - function tween { - # Attempts to smoothly transition from the currently playing animation into this one. - #ARGS: {duration: int, to_frame: int} - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> + function tween { + # Attempts to smoothly transition from the currently playing animation into this one. + #ARGS: {duration: int, to_frame: int} + debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - function <%blueprint_id%>/animations/pause_all + function <%blueprint_id%>/animations/pause_all - tag @s add <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%> - $scoreboard players set @s <%OBJECTIVES.TWEEN_DURATION()%> $(duration) - $scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> $(to_frame) + tag @s add <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%> + $scoreboard players set @s <%OBJECTIVES.TWEEN_DURATION()%> $(duration) + $scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> $(to_frame) - scoreboard players operation #this <%OBJECTIVES.I()%> = @s <%OBJECTIVES.TWEEN_DURATION()%> - tag @s add <%TAGS.TRANSFORMS_ONLY()%> - execute at @s run function ./zzz/apply_frame {frame: 0} - $execute at @s run function ./zzz/apply_frame {frame: $(to_frame)} - tag @s remove <%TAGS.TRANSFORMS_ONLY()%> - execute on passengers store result entity @s interpolation_duration int 1 run scoreboard players get #this <%OBJECTIVES.I()%> - } + scoreboard players operation #this <%OBJECTIVES.I()%> = @s <%OBJECTIVES.TWEEN_DURATION()%> + tag @s add <%TAGS.TRANSFORMS_ONLY()%> + execute at @s run function ./zzz/apply_frame {frame: 0} + $execute at @s run function ./zzz/apply_frame {frame: $(to_frame)} + tag @s remove <%TAGS.TRANSFORMS_ONLY()%> + execute on passengers store result entity @s interpolation_duration int 1 run scoreboard players get #this <%OBJECTIVES.I()%> + } - dir zzz { - function on_tick { - # Tweening logic - scoreboard players remove @s <%OBJECTIVES.TWEEN_DURATION()%> 1 - execute if score @s <%OBJECTIVES.TWEEN_DURATION()%> matches 1.. run return 1 - execute if score @s <%OBJECTIVES.TWEEN_DURATION()%> matches 0 on passengers run \ - data modify entity @s interpolation_duration set value <%interpolation_duration%> - # Animation logic - IF (animation.loop_mode === 'loop' && animation.loop_delay === 0) { - # Makes sure function keyframes in the last frame of the animation are activated. - execute if score @s <%OBJECTIVES.FRAME(animation.storage_name)%> matches -1 run \ - block function_keyframe_loop_patch { - function ./frames/last_frame_effects with storage <%temp_storage%> entry.data.uuids_by_name - scoreboard players add @s <%OBJECTIVES.FRAME(animation.storage_name)%> 1 + dir zzz { + function on_tick { + # Tweening logic + scoreboard players remove @s <%OBJECTIVES.TWEEN_DURATION()%> 1 + execute if score @s <%OBJECTIVES.TWEEN_DURATION()%> matches 1.. run return 1 + execute if score @s <%OBJECTIVES.TWEEN_DURATION()%> matches 0 on passengers run \ + data modify entity @s interpolation_duration set value <%interpolation_duration%> + # Animation logic + IF (animation.loop_mode === 'loop' && animation.loop_delay === 0) { + # Makes sure function keyframes in the last frame of the animation are activated. + execute if score @s <%OBJECTIVES.FRAME(animation.storage_name)%> matches -1 run \ + block function_keyframe_loop_patch { + function ./frames/last_frame_effects with storage <%temp_storage%> entry.data.uuids_by_name + scoreboard players add @s <%OBJECTIVES.FRAME(animation.storage_name)%> 1 + } + } + data remove storage <%temp_storage%> args + execute store result storage <%temp_storage%> args.frame int 1 run \ + scoreboard players get @s <%OBJECTIVES.FRAME(animation.storage_name)%> + function ./apply_frame with storage <%temp_storage%> args + IF (animation.loop_mode === 'loop') { + # Loop the animation back to the start once it reaches the last frame. + # If loop_delay is 0, the animation will loop instantly, otherwise, it will wait for the specified amount of ticks. + execute \ + if score @s <%OBJECTIVES.FRAME(animation.storage_name)%> \ + matches <%animation.duration-2 + animation.loop_delay%>.. \ + run return run \ + scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> <%animation.loop_delay === 0 ? -1 : 0%> + } ELSE IF (animation.loop_mode === 'hold') { + # Pause the animation at the last frame. + execute \ + if score @s <%OBJECTIVES.FRAME(animation.storage_name)%> \ + matches <%animation.duration-1%>.. \ + run return run \ + function ../pause + } ELSE IF (animation.loop_mode === 'once') { + # Stop the animation once it reaches the last frame. + execute \ + if score @s <%OBJECTIVES.FRAME(animation.storage_name)%> \ + matches <%animation.duration-1%> \ + run return run block loop_mode_stop { + scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> 0 + tag @s add <%TAGS.TRANSFORMS_ONLY()%> + execute at @s run function ./zzz/set_frame {frame: 0} + tag @s remove <%TAGS.TRANSFORMS_ONLY()%> + tag @s remove <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%> } - } - data remove storage <%temp_storage%> args - execute store result storage <%temp_storage%> args.frame int 1 run \ - scoreboard players get @s <%OBJECTIVES.FRAME(animation.storage_name)%> - function ./apply_frame with storage <%temp_storage%> args - IF (animation.loop_mode === 'loop') { - # Loop the animation back to the start once it reaches the last frame. - # If loop_delay is 0, the animation will loop instantly, otherwise, it will wait for the specified amount of ticks. - execute \ - if score @s <%OBJECTIVES.FRAME(animation.storage_name)%> \ - matches <%animation.duration-2 + animation.loop_delay%>.. \ - run return run \ - scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> <%animation.loop_delay === 0 ? -1 : 0%> - } ELSE IF (animation.loop_mode === 'hold') { - # Pause the animation at the last frame. - execute \ - if score @s <%OBJECTIVES.FRAME(animation.storage_name)%> \ - matches <%animation.duration-1%>.. \ - run return run \ - function ../pause - } ELSE IF (animation.loop_mode === 'once') { - # Stop the animation once it reaches the last frame. - execute \ - if score @s <%OBJECTIVES.FRAME(animation.storage_name)%> \ - matches <%animation.duration-1%> \ - run return run block loop_mode_stop { - scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> 0 - tag @s add <%TAGS.TRANSFORMS_ONLY()%> - execute at @s run function ./zzz/set_frame {frame: 0} - tag @s remove <%TAGS.TRANSFORMS_ONLY()%> - tag @s remove <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%> } + scoreboard players add @s <%OBJECTIVES.FRAME(animation.storage_name)%> 1 } - scoreboard players add @s <%OBJECTIVES.FRAME(animation.storage_name)%> 1 - } - IF (use_storage_for_animation) { - function set_frame { - #ARGS: {frame: int} - $function ./apply_frame {frame: $(frame)} - execute on passengers run data modify entity @s start_interpolation set value -1 - return 1 - } + IF (use_storage_for_animation) { + function set_frame { + #ARGS: {frame: int} + $function ./apply_frame {frame: $(frame)} + execute on passengers run data modify entity @s start_interpolation set value -1 + return 1 + } - function apply_frame { - #ARGS: {frame: int} - REPEAT (Object.values(animation.modified_nodes).sort(nodeSorter)) as node { - IF (BONE_TYPES.includes(node.type)) { - $execute on passengers if entity @s[tag=<%TAGS.PROJECT_NODE_NAMED(blueprint_id, node.storage_name)%>] run \ - data modify entity @s {} merge from \ - storage <%project_storage%>/animations <%animation.storage_name%>.$(frame).<%node.storage_name%> - } ELSE IF (node.type === 'locator' || node.type === 'camera') { - $data modify storage <%temp_storage%> entry.data.uuids_by_name.<%node.storage_name%> merge from \ - storage <%project_storage%>/animations <%animation.storage_name%>.$(frame).<%node.storage_name%> + function apply_frame { + #ARGS: {frame: int} + REPEAT (Object.values(animation.modified_nodes).sort(nodeSorter)) as node { + IF (BONE_TYPES.includes(node.type)) { + $execute on passengers if entity @s[tag=<%TAGS.PROJECT_NODE_NAMED(blueprint_id, node.storage_name)%>] run \ + data modify entity @s {} merge from \ + storage <%project_storage%>/animations <%animation.storage_name%>.$(frame).<%node.storage_name%> + } ELSE IF (node.type === 'locator' || node.type === 'camera') { + $data modify storage <%temp_storage%> entry.data.uuids_by_name.<%node.storage_name%> merge from \ + storage <%project_storage%>/animations <%animation.storage_name%>.$(frame).<%node.storage_name%> + } } - } - IF (animation.frames.some(anim => anim.variant)) { - $execute \ - if data storage <%project_storage%>/animations <%animation.storage_name%>.$(frame).variant \ - unless entity @s[tag=<%TAGS.TRANSFORMS_ONLY()%>] \ - run { with storage <%project_storage%>/animations <%animation.storage_name%>.$(frame).variant - #ARGS: {name: string, condition: string} - $execute $(condition)run function <%blueprint_id%>/variants/$(name)/apply + IF (animation.frames.some(anim => anim.variant)) { + $execute \ + if data storage <%project_storage%>/animations <%animation.storage_name%>.$(frame).variant \ + unless entity @s[tag=<%TAGS.TRANSFORMS_ONLY()%>] \ + run { with storage <%project_storage%>/animations <%animation.storage_name%>.$(frame).variant + #ARGS: {name: string, condition: string} + $execute $(condition)run function <%blueprint_id%>/variants/$(name)/apply + } } - } - return 1 - } - } ELSE { - function set_frame { - # Sets the frame without interpolation - #ARGS: {frame: int} + return 1 + } + } ELSE { + function set_frame { + # Sets the frame without interpolation + #ARGS: {frame: int} - $function ./frames/$(frame) with storage <%temp_storage%> entry.data.uuids_by_name + $function ./frames/$(frame) with storage <%temp_storage%> entry.data.uuids_by_name - execute on passengers run \ - data modify entity @s start_interpolation set value -1 + execute on passengers run \ + data modify entity @s start_interpolation set value -1 - return 1 - } + return 1 + } - function apply_frame { - #ARGS: {frame: int} + function apply_frame { + #ARGS: {frame: int} - $function ./frames/$(frame) with storage <%temp_storage%> entry.data.uuids_by_name + $function ./frames/$(frame) with storage <%temp_storage%> entry.data.uuids_by_name - return 1 - } + return 1 + } - # FIXME - %NEWLINE_PATCH% is a temporary solution to temporarily fix an MCB bug where extra newlines are being added to the output. - dir frames { - <%% - global.frame = animation.frames.at(-1) - global.modified_effect_nodes = Object.values(animation.modified_nodes).filter( - node => node.type === 'locator' && global.frame.node_transforms[node.uuid] - ) - console.log(global.modified_effect_nodes) - %%> - IF(Object.keys(global.modified_effect_nodes).length > 0) { - function last_frame_effects { - REPEAT(global.modified_effect_nodes) as node { - <%% - global.transform = global.frame.node_transforms[node.uuid] - %%> - IF (node.config?.use_entity) { - $execute \ - as $(<%node.storage_name%>) \ - positioned \ - ^<%roundTo(global.transform.pos[0], 10)%> \ - ^<%roundTo(global.transform.pos[1], 10)%> \ - ^<%roundTo(global.transform.pos[2], 10)%> \ - rotated \ - ~<%roundTo(global.transform.head_rot[1], 10)%> \ - ~<%roundTo(global.transform.head_rot[0], 10)%> \ - <%global.transform.function_execute_condition ? global.transform.function_execute_condition + ' ' : ''%>run \ - function ./<%animation.duration%>_locator_<%node.storage_name%> - } ELSE { - execute \ - positioned \ - ^<%roundTo(global.transform.pos[0], 10)%> \ - ^<%roundTo(global.transform.pos[1], 10)%> \ - ^<%roundTo(global.transform.pos[2], 10)%> \ - rotated \ - ~<%roundTo(global.transform.head_rot[1], 10)%> \ - ~<%roundTo(global.transform.head_rot[0], 10)%> \ - <%global.transform.function_execute_condition ? global.transform.function_execute_condition + ' ' : ''%>run \ - function ./<%animation.duration%>_locator_<%node.storage_name%> + # FIXME - %NEWLINE_PATCH% is a temporary solution to temporarily fix an MCB bug where extra newlines are being added to the output. + dir frames { + <%% + global.frame = animation.frames.at(-1) + global.modified_effect_nodes = Object.values(animation.modified_nodes).filter( + node => node.type === 'locator' && global.frame.node_transforms[node.uuid] + ) + console.log(global.modified_effect_nodes) + %%> + IF(Object.keys(global.modified_effect_nodes).length > 0) { + function last_frame_effects { + REPEAT(global.modified_effect_nodes) as node { + <%% + global.transform = global.frame.node_transforms[node.uuid] + %%> + IF (node.config?.use_entity) { + $execute \ + as $(<%node.storage_name%>) \ + positioned \ + ^<%roundTo(global.transform.pos[0], 10)%> \ + ^<%roundTo(global.transform.pos[1], 10)%> \ + ^<%roundTo(global.transform.pos[2], 10)%> \ + rotated \ + ~<%roundTo(global.transform.head_rot[1], 10)%> \ + ~<%roundTo(global.transform.head_rot[0], 10)%> \ + <%global.transform.function_execute_condition ? global.transform.function_execute_condition + ' ' : ''%>run \ + function ./<%animation.duration%>_locator_<%node.storage_name%> + } ELSE { + execute \ + positioned \ + ^<%roundTo(global.transform.pos[0], 10)%> \ + ^<%roundTo(global.transform.pos[1], 10)%> \ + ^<%roundTo(global.transform.pos[2], 10)%> \ + rotated \ + ~<%roundTo(global.transform.head_rot[1], 10)%> \ + ~<%roundTo(global.transform.head_rot[0], 10)%> \ + <%global.transform.function_execute_condition ? global.transform.function_execute_condition + ' ' : ''%>run \ + function ./<%animation.duration%>_locator_<%node.storage_name%> + } } - } - IF (global.frame.variants?.length > 0) { - execute <%global.frame.variants_execute_condition ? global.frame.variants_execute_condition + ' ' : ''%>run \ - function <%blueprint_id%>/variants/<%global.frame.variants[0].name%>/apply - } + IF (global.frame.variants?.length > 0) { + execute <%global.frame.variants_execute_condition ? global.frame.variants_execute_condition + ' ' : ''%>run \ + function <%blueprint_id%>/variants/<%global.frame.variants[0].name%>/apply + } - IF (global.frame.function) { - execute <%global.frame.function_execute_condition ? global.frame.function_execute_condition + ' ' : ''%>run \ - block <%animation.duration%>_function_keyframe { - <%global.frame.function%> - } + IF (global.frame.function) { + execute <%global.frame.function_execute_condition ? global.frame.function_execute_condition + ' ' : ''%>run \ + block <%animation.duration%>_function_keyframe { + <%global.frame.function%> + } + } } } - } - - <%% - // A record of node uuid to INodeTransform. - // Keeps track of the last time a bone was updated. - // Only used for step keyframe interpolation. - let hasFunction = false - const lastActiveFrame = {} - const modifiedNodes = Object.values(animation.modified_nodes).filter(n => n.type !== 'struct').sort(nodeSorter); - for (const [frameIndex, frame] of animation.frames.entries()) { - const to_merge = {cameras: {}, locators: {}} - let frameFunc = ``; - for (const node of modifiedNodes) { - const transform = frame.node_transforms[node.uuid] - // Skip if the node doesn't have a transform for this frame. - if (!transform) continue - switch (node.type) { - case 'bone': - case 'text_display': - case 'item_display': - case 'block_display': { - const lastFrame = lastActiveFrame[node.uuid] - const isStepInterpolation = !!(lastFrame?.interpolation === 'step') - lastActiveFrame[node.uuid] = transform - - if (transform.interpolation === 'pre-post' || isStepInterpolation) { - frameFunc += - `\n$data merge entity $(${node.storage_name})%NEWLINE_PATCH%{` - + `transformation: ${matrixToNbtFloatArray(transform.matrix).toString()},` - + `start_interpolation: ${isStepInterpolation ? -1 : 0},` - + `interpolation_duration: ${isStepInterpolation ? 0 : interpolation_duration}` - + `}` - } else { - frameFunc += - `\n$data merge entity $(${node.storage_name})%NEWLINE_PATCH%{` - + `transformation: ${matrixToNbtFloatArray(transform.matrix).toString()},` - + `start_interpolation: 0,` - + `interpolation_duration: ${interpolation_duration}` - + `}` - } - ;hasFunction = true - break - } - case 'locator': { - const lastFrame = lastActiveFrame[node.uuid] - lastActiveFrame[node.uuid] = transform - ;if (!lastFrame || matrixToNbtFloatArray(transform.matrix).toString() !== matrixToNbtFloatArray(lastFrame.matrix).toString()) { - to_merge.locators[node.storage_name] = { - px: roundTo(transform.pos[0], 10), - py: roundTo(transform.pos[1], 10), - pz: roundTo(transform.pos[2], 10), - ry: roundTo(transform.head_rot[1], 10), - rx: roundTo(transform.head_rot[0], 10) - }; - } - - if (transform.function) { - if (node.config?.use_entity) { + <%% + // A record of node uuid to INodeTransform. + // Keeps track of the last time a bone was updated. + // Only used for step keyframe interpolation. + let hasFunction = false + const lastActiveFrame = {} + const modifiedNodes = Object.values(animation.modified_nodes).filter(n => n.type !== 'struct').sort(nodeSorter); + for (const [frameIndex, frame] of animation.frames.entries()) { + const to_merge = {cameras: {}, locators: {}} + let frameFunc = ``; + for (const node of modifiedNodes) { + const transform = frame.node_transforms[node.uuid] + // Skip if the node doesn't have a transform for this frame. + if (!transform) continue + switch (node.type) { + case 'bone': + case 'text_display': + case 'item_display': + case 'block_display': { + const lastFrame = lastActiveFrame[node.uuid] + const isStepInterpolation = !!(lastFrame?.interpolation === 'step') + lastActiveFrame[node.uuid] = transform + + if (transform.interpolation === 'pre-post' || isStepInterpolation) { frameFunc += - `\n$execute unless entity @s[tag=${TAGS.TRANSFORMS_ONLY()}] as $(${node.storage_name}) ` - + `positioned ^${roundTo(transform.pos[0], 10)} ^${roundTo(transform.pos[1], 10)} ^${roundTo(transform.pos[2], 10)} ` - + `rotated ~${roundTo(transform.head_rot[1], 10)} ~${roundTo(transform.head_rot[0], 10)} ` - + `${transform.function_execute_condition ? transform.function_execute_condition + ' ' : ''}run ` - + `block ${frameIndex}_locator_${node.storage_name}%NEWLINE_PATCH%{\n` - + `tp @s ~ ~ ~ ~ ~\n` - + `${transform.function}` - + `\n}` + `\n$data merge entity $(${node.storage_name})%NEWLINE_PATCH%{` + + `transformation: ${matrixToNbtFloatArray(transform.matrix).toString()},` + + `start_interpolation: ${isStepInterpolation ? -1 : 0},` + + `interpolation_duration: ${isStepInterpolation ? 0 : interpolation_duration}` + + `}` } else { frameFunc += - `\nexecute unless entity @s[tag=${TAGS.TRANSFORMS_ONLY()}] ` - + `positioned ^${roundTo(transform.pos[0], 10)} ^${roundTo(transform.pos[1], 10)} ^${roundTo(transform.pos[2], 10)} ` - + `rotated ~${roundTo(transform.head_rot[1], 10)} ~${roundTo(transform.head_rot[0], 10)} ` - + `${transform.function_execute_condition ? transform.function_execute_condition + ' ' : ''}run ` - + `block ${frameIndex}_locator_${node.storage_name}%NEWLINE_PATCH%{\n` - + `${transform.function}` - + `\n}` + `\n$data merge entity $(${node.storage_name})%NEWLINE_PATCH%{` + + `transformation: ${matrixToNbtFloatArray(transform.matrix).toString()},` + + `start_interpolation: 0,` + + `interpolation_duration: ${interpolation_duration}` + + `}` } + + ;hasFunction = true + break } - break - } - case 'camera': { - const lastFrame = lastActiveFrame[node.uuid] - lastActiveFrame[node.uuid] = transform - ;if (!lastFrame || matrixToNbtFloatArray(transform.matrix).toString() !== matrixToNbtFloatArray(lastFrame.matrix).toString()) { - to_merge.cameras[node.storage_name] = { - px: transform.pos[0], - py: transform.pos[1], - pz: transform.pos[2], - ry: transform.head_rot[1], - rx: transform.head_rot[0] - }; + case 'locator': { + const lastFrame = lastActiveFrame[node.uuid] + lastActiveFrame[node.uuid] = transform + ;if (!lastFrame || matrixToNbtFloatArray(transform.matrix).toString() !== matrixToNbtFloatArray(lastFrame.matrix).toString()) { + to_merge.locators[node.storage_name] = { + px: roundTo(transform.pos[0], 10), + py: roundTo(transform.pos[1], 10), + pz: roundTo(transform.pos[2], 10), + ry: roundTo(transform.head_rot[1], 10), + rx: roundTo(transform.head_rot[0], 10) + }; + } + + if (transform.function) { + if (node.config?.use_entity) { + frameFunc += + `\n$execute unless entity @s[tag=${TAGS.TRANSFORMS_ONLY()}] as $(${node.storage_name}) ` + + `positioned ^${roundTo(transform.pos[0], 10)} ^${roundTo(transform.pos[1], 10)} ^${roundTo(transform.pos[2], 10)} ` + + `rotated ~${roundTo(transform.head_rot[1], 10)} ~${roundTo(transform.head_rot[0], 10)} ` + + `${transform.function_execute_condition ? transform.function_execute_condition + ' ' : ''}run ` + + `block ${frameIndex}_locator_${node.storage_name}%NEWLINE_PATCH%{\n` + + `tp @s ~ ~ ~ ~ ~\n` + + `${transform.function}` + + `\n}` + } else { + frameFunc += + `\nexecute unless entity @s[tag=${TAGS.TRANSFORMS_ONLY()}] ` + + `positioned ^${roundTo(transform.pos[0], 10)} ^${roundTo(transform.pos[1], 10)} ^${roundTo(transform.pos[2], 10)} ` + + `rotated ~${roundTo(transform.head_rot[1], 10)} ~${roundTo(transform.head_rot[0], 10)} ` + + `${transform.function_execute_condition ? transform.function_execute_condition + ' ' : ''}run ` + + `block ${frameIndex}_locator_${node.storage_name}%NEWLINE_PATCH%{\n` + + `${transform.function}` + + `\n}` + } + } + break + } + case 'camera': { + const lastFrame = lastActiveFrame[node.uuid] + lastActiveFrame[node.uuid] = transform + ;if (!lastFrame || matrixToNbtFloatArray(transform.matrix).toString() !== matrixToNbtFloatArray(lastFrame.matrix).toString()) { + to_merge.cameras[node.storage_name] = { + px: transform.pos[0], + py: transform.pos[1], + pz: transform.pos[2], + ry: transform.head_rot[1], + rx: transform.head_rot[0] + }; + } + ;break } - ;break } } - } - if (Object.keys(to_merge.locators).length > 0 || Object.keys(to_merge.cameras).length > 0) { - frameFunc += `\ndata modify storage <%temp_storage%> entry.data merge value ${JSON.stringify(to_merge)}` - frameFunc += `\ndata_manager write` - if (!auto_update_rig_orientation) { - frameFunc += `\nfunction ${blueprint_id}/root/on_tick/transform_floating_entities` + if (Object.keys(to_merge.locators).length > 0 || Object.keys(to_merge.cameras).length > 0) { + frameFunc += `\ndata modify storage <%temp_storage%> entry.data merge value ${JSON.stringify(to_merge)}` + frameFunc += `\ndata_manager write` + if (!auto_update_rig_orientation) { + frameFunc += `\nfunction ${blueprint_id}/root/on_tick/transform_floating_entities` + } + hasFunction = true } - hasFunction = true - } - if (frame.variants?.length) { - const variant = rig.variants[frame.variants[0]] - if (!variant) { - throw new Error(`Could not find Variant with uuid "${frame.variants[0]}" while generating frame "${frameIndex}" of animation "${animation.name}".`) + if (frame.variants?.length) { + const variant = rig.variants[frame.variants[0]] + if (!variant) { + throw new Error(`Could not find Variant with uuid "${frame.variants[0]}" while generating frame "${frameIndex}" of animation "${animation.name}".`) + } + const execute_condition = frame.variants_execute_condition ? frame.variants_execute_condition + ' ' : '' + frameFunc += `\nexecute unless entity @s[tag=${TAGS.TRANSFORMS_ONLY()}] ${execute_condition}run function ${blueprint_id}/variants/${variant.name}/apply` + ;hasFunction = true } - const execute_condition = frame.variants_execute_condition ? frame.variants_execute_condition + ' ' : '' - frameFunc += `\nexecute unless entity @s[tag=${TAGS.TRANSFORMS_ONLY()}] ${execute_condition}run function ${blueprint_id}/variants/${variant.name}/apply` - ;hasFunction = true - } - // Root function keyframes. - if (frame.function) { - const execute_condition = frame.function_execute_condition ? frame.function_execute_condition + ' ' : '' - frameFunc += `\nexecute unless entity @s[tag=${TAGS.TRANSFORMS_ONLY()}] at @s ${execute_condition}run block ${frameIndex}_root_function%NEWLINE_PATCH%{\n${frame.function}\n}` - ;hasFunction = true - } - ;if (frameFunc.length > 0) { - frameFunc = `function ${frameIndex}%NEWLINE_PATCH%{${frameFunc}\n}` - emit.mcb(frameFunc.replaceAll(/%NEWLINE_PATCH%\n?/g, ' ')) + // Root function keyframes. + if (frame.function) { + const execute_condition = frame.function_execute_condition ? frame.function_execute_condition + ' ' : '' + frameFunc += `\nexecute unless entity @s[tag=${TAGS.TRANSFORMS_ONLY()}] at @s ${execute_condition}run block ${frameIndex}_root_function%NEWLINE_PATCH%{\n${frame.function}\n}` + ;hasFunction = true + } + ;if (frameFunc.length > 0) { + frameFunc = `function ${frameIndex}%NEWLINE_PATCH%{${frameFunc}\n}` + emit.mcb(frameFunc.replaceAll(/%NEWLINE_PATCH%\n?/g, ' ')) + } } - } - %%> + %%> + } } } } } - } - function pause_all { - # Pauses all animations - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> + function pause_all { + # Pauses all animations + debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - REPEAT (animations) as animation { - tag @s remove <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%> + REPEAT (animations) as animation { + tag @s remove <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%> + } } } } function summon { - #Args: {args:{variant: string, animation: string, frame: int, start_animation: boolean}} + #Args: {args:{variant?: string, animation?: string, frame?: int, start_animation?: boolean}} # frame is ignored unless animation is specified. - data modify storage <%temp_storage%> args set value {variant:'', animation:'', frame: 0} $execute store success score #success <%OBJECTIVES.I()%> run data modify storage <%temp_storage%> args set value $(args) + IF (!has_animations && debug_mode) { + execute if data storage <%temp_storage%> args.animation run return run \ + tellraw @a <%TELLRAW.ANIMATION_ARG_NO_RIG_ANIMATIONS()%> + execute if data storage <%temp_storage%> args.frame run return run \ + tellraw @a <%TELLRAW.FRAME_ARG_NO_RIG_FRAMES()%> + } + summon minecraft:item_display ~ ~ ~ { \ Tags:[ \ '<%TAGS.NEW()%>', \ @@ -592,7 +606,7 @@ function summon { type=<%locator.config.entity_type%>, \ tag=<%TAGS.PROJECT_LOCATOR_NAMED(blueprint_id, locator.storage_name)%>, \ tag=<%TAGS.NEW()%>, \ - distance=..<%Math.ceil(locator.max_distance)%> \ + distance=..<%Math.ceil(locator.max_distance + 0.5)%> \ ] \ run block as_locator/<%locator.storage_name%> { # run block ../as_locator/<%locator.storage_name%> { @@ -617,7 +631,7 @@ function summon { type=minecraft:item_display, \ tag=<%TAGS.PROJECT_CAMERA_NAMED(blueprint_id, camera.storage_name)%>, \ tag=<%TAGS.NEW()%>, \ - distance=..<%Math.ceil(camera.max_distance)%> \ + distance=..<%Math.ceil(camera.max_distance + 0.5)%> \ ] \ run block as_camera/<%camera.storage_name%> { # run block ../as_camera/<%camera.storage_name%> { @@ -693,52 +707,54 @@ function summon { } execute if score #success <%OBJECTIVES.I()%> matches 0 run return fail - # Animation Argument - # If the animation argument is provided, attempt to apply the animation. - execute if data storage <%temp_storage%> args.animation run block animation_arg/process { with storage <%temp_storage%> args - scoreboard players set #success <%OBJECTIVES.I()%> 0 - # If the animation argument is *explicitly* set to an empty string, return an error. - execute if data storage <%temp_storage%> {args:{animation:''}} run return run block if_empty { - tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('animation')%> - function <%blueprint_id%>/remove/this/without_on_remove_function - } - # Automatically set the frame argument to 0 if the frame argument is not provided. - # Takes advantage of `store result score` setting the score to 0 if the command fails. - execute \ - store result storage <%temp_storage%> args.frame int 1 \ - store result score #frame <%OBJECTIVES.I()%> \ - run \ - data get storage <%temp_storage%> args.frame - # If the frame argument is negative, return an error. - execute if score #frame <%OBJECTIVES.I()%> matches ..-1 run return run block no_negative { - # Tell the user that the frame argument cannot be negative. - tellraw @a <%TELLRAW.FRAME_CANNOT_BE_NEGATIVE()%> - function <%blueprint_id%>/remove/this/without_on_remove_function - } - # Attempt to apply the animation frame. - execute store success score #success <%OBJECTIVES.I()%> run block try_set_frame { with storage <%temp_storage%> args - # Make sure we're only applying transforms when setting the summon pose. - tag @s add <%TAGS.TRANSFORMS_ONLY()%> - $execute store success score #success <%OBJECTIVES.I()%> run function <%blueprint_id%>/animations/$(animation)/zzz/set_frame with storage <%temp_storage%> args - tag @s remove <%TAGS.TRANSFORMS_ONLY()%> - execute if score #success <%OBJECTIVES.I()%> matches 1 run return 1 - # If the set_frame function fails, the animation doesn't exist, so we return an error. - return fail - } - # If the set_frame function failed, return an error. - execute unless score #success <%OBJECTIVES.I()%> matches 1 run return run block invalid_animation { - # Tell the user that the provided animation doesn't exist, remove the rig, and list all available animations for this rig. - tellraw @a <%TELLRAW.INVALID_ANIMATION(animations)%> - function <%blueprint_id%>/remove/this/without_on_remove_function - } + IF (has_animations) { + # Animation Argument + # If the animation argument is provided, attempt to apply the animation. + execute if data storage <%temp_storage%> args.animation run block animation_arg/process { with storage <%temp_storage%> args + scoreboard players set #success <%OBJECTIVES.I()%> 0 + # If the animation argument is *explicitly* set to an empty string, return an error. + execute if data storage <%temp_storage%> {args:{animation:''}} run return run block if_empty { + tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('animation')%> + function <%blueprint_id%>/remove/this/without_on_remove_function + } + # Automatically set the frame argument to 0 if the frame argument is not provided. + # Takes advantage of `store result score` setting the score to 0 if the command fails. + execute \ + store result storage <%temp_storage%> args.frame int 1 \ + store result score #frame <%OBJECTIVES.I()%> \ + run \ + data get storage <%temp_storage%> args.frame + # If the frame argument is negative, return an error. + execute if score #frame <%OBJECTIVES.I()%> matches ..-1 run return run block no_negative { + # Tell the user that the frame argument cannot be negative. + tellraw @a <%TELLRAW.FRAME_CANNOT_BE_NEGATIVE()%> + function <%blueprint_id%>/remove/this/without_on_remove_function + } + # Attempt to apply the animation frame. + execute store success score #success <%OBJECTIVES.I()%> run block try_set_frame { with storage <%temp_storage%> args + # Make sure we're only applying transforms when setting the summon pose. + tag @s add <%TAGS.TRANSFORMS_ONLY()%> + $execute store success score #success <%OBJECTIVES.I()%> run function <%blueprint_id%>/animations/$(animation)/zzz/set_frame with storage <%temp_storage%> args + tag @s remove <%TAGS.TRANSFORMS_ONLY()%> + execute if score #success <%OBJECTIVES.I()%> matches 1 run return 1 + # If the set_frame function fails, the animation doesn't exist, so we return an error. + return fail + } + # If the set_frame function failed, return an error. + execute unless score #success <%OBJECTIVES.I()%> matches 1 run return run block invalid_animation { + # Tell the user that the provided animation doesn't exist, remove the rig, and list all available animations for this rig. + tellraw @a <%TELLRAW.INVALID_ANIMATION(animations)%> + function <%blueprint_id%>/remove/this/without_on_remove_function + } - # If the animation is successfully applied, and the start_animation argument is set to true, start the animation. - execute if data storage <%temp_storage%> {args:{start_animation: true}} run block start_animation { with storage <%temp_storage%> args - $function <%blueprint_id%>/animations/$(animation)/resume + # If the animation is successfully applied, and the start_animation argument is set to true, start the animation. + execute if data storage <%temp_storage%> {args:{start_animation: true}} run block start_animation { with storage <%temp_storage%> args + $function <%blueprint_id%>/animations/$(animation)/resume + } + scoreboard players set #success <%OBJECTIVES.I()%> 1 } - scoreboard players set #success <%OBJECTIVES.I()%> 1 + execute if score #success <%OBJECTIVES.I()%> matches 0 run return fail } - execute if score #success <%OBJECTIVES.I()%> matches 0 run return fail IF (has_locators || has_cameras) { function <%blueprint_id%>/root/on_tick/transform_floating_entities @@ -1322,20 +1338,22 @@ IF (has_locators || has_cameras) { } dir zzz { - function apply_default_pose { - IF (has_locators || has_cameras) { - function ../zzz/reset_floating_entities - } + IF (has_animations) { + function apply_default_pose { + IF (has_locators || has_cameras) { + function ../zzz/reset_floating_entities + } - REPEAT (Object.values(rig.nodes).filter(node => BONE_TYPES.includes(node.type))) as node { - execute \ - on passengers \ - if entity @s[tag=<%TAGS.PROJECT_NODE_NAMED(blueprint_id, node.storage_name)%>] \ - run \ - data merge entity @s { \ - transformation: <%matrixToNbtFloatArray(node.default_transform.matrix).toString()%>, \ - start_interpolation: 0 \ - } + REPEAT (Object.values(rig.nodes).filter(node => BONE_TYPES.includes(node.type))) as node { + execute \ + on passengers \ + if entity @s[tag=<%TAGS.PROJECT_NODE_NAMED(blueprint_id, node.storage_name)%>] \ + run \ + data merge entity @s { \ + transformation: <%matrixToNbtFloatArray(node.default_transform.matrix).toString()%>, \ + start_interpolation: 0 \ + } + } } } @@ -1357,14 +1375,16 @@ dir zzz { } } -function apply_default_pose { - # Changes the pose of the rig to the the default pose with interpolation - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> +IF (has_animations) { + function apply_default_pose { + # Changes the pose of the rig to the the default pose with interpolation + debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - IF (has_locators || has_cameras) { - data_manager prep read + IF (has_locators || has_cameras) { + data_manager prep read + } + function ./zzz/apply_default_pose } - function ./zzz/apply_default_pose } function set_default_pose { diff --git a/src/systems/datapackCompiler/1.21.0/static.mcb b/src/systems/datapackCompiler/1.21.0/static.mcb deleted file mode 100644 index 4d2376c0..00000000 --- a/src/systems/datapackCompiler/1.21.0/static.mcb +++ /dev/null @@ -1,868 +0,0 @@ -# TODO - Move all internal functions into an internal namespace, and only have user-facing functions in the main `animated_java:<%export_namespace%>` namespace. - -# DIFFERENCES FROM 1.20.5: -# - @n entity selector -# - minecraft:item_model item component: item.components."minecraft:custom_model_data" -> item.components."minecraft:item_model" - -function on_load { - data modify storage <%project_storage%> rig_hash set value <%"'" + rig_hash + "'"%> -} - -dir root { - function on_tick { - # Custom pre-tick function - IF (on_pre_tick_function) { - <%% - emit.mcb(on_pre_tick_function) - %%> - } - - IF (auto_update_rig_orientation) { - IF (has_locators || has_cameras) { - function <%blueprint_id%>/root/on_tick/transform_floating_entities - } - execute on passengers run tp @s ~ ~ ~ ~ ~ - } ELSE IF (has_ticking_locators) { - function <%blueprint_id%>/root/on_tick/transform_locators - } - - # Custom post-tick function - IF (on_post_tick_function) { - <%% - emit.mcb(on_post_tick_function) - %%> - } - } - - IF (has_locators || has_cameras) { - dir on_tick { - function transform_locators { - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'locator')) as locator { - block select_locator_<%locator.storage_name%> { with storage <%temp_storage%> entry.data.locators.<%locator.storage_name%> - IF (locator.config?.use_entity) { - $execute \ - as $(uuid) \ - positioned ^$(px) ^$(py) ^$(pz) \ - rotated ~$(ry) ~$(rx) \ - run block as_locator_<%locator.storage_name%> { - tp @s ~ ~ ~ ~ ~ - - IF (locator.config?.sync_passenger_rotation) { - execute on passengers run tp @s ~ ~ ~ ~ ~ - } - - IF (locator.config?.on_tick_function) { - <%% - emit.mcb(locator.config.on_tick_function) - %%> - } - } - } ELSE IF (locator.config?.on_tick_function) { - $execute \ - positioned ^$(px) ^$(py) ^$(pz) \ - rotated ~$(ry) ~$(rx) \ - run block at_locator_<%locator.storage_name%> { - <%% - emit.mcb(locator.config.on_tick_function) - %%> - } - } - } - } - } - - function transform_floating_entities { - function ./transform_locators - - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'camera')) as camera { - block select_camera_<%camera.storage_name%> { with storage <%temp_storage%> entry.data.cameras.<%camera.storage_name%> - $execute \ - as $(uuid) \ - positioned ^$(px) ^$(py) ^$(pz) \ - rotated ~$(ry) ~$(rx) \ - run tp @s ~ ~ ~ ~ ~ - } - } - } - } - } -} - -IF (!auto_update_rig_orientation) { - function move { - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - - tp @s ~ ~ ~ ~ ~ - - IF (has_locators || has_cameras) { - data_manager prep read - function <%blueprint_id%>/root/on_tick/transform_floating_entities - } - execute at @s on passengers run tp @s ~ ~ ~ ~ ~ - } -} ELSE { - function move { - tellraw @a <%TELLRAW.AUTO_UPDATE_RIG_ORIENTATION_MOVE_WARNING()%> - } -} - -function summon { - #Args: {args:{variant: string}} - - data modify storage <%temp_storage%> args set value {variant:''} - $execute store success score #success <%OBJECTIVES.I()%> run data modify storage <%temp_storage%> args set value $(args) - - summon minecraft:item_display ~ ~ ~ { \ - Tags:[ \ - '<%TAGS.NEW()%>', \ - '<%TAGS.GLOBAL_ENTITY()%>', \ - '<%TAGS.GLOBAL_ROOT()%>', \ - '<%TAGS.PROJECT_ENTITY(blueprint_id)%>', \ - '<%TAGS.PROJECT_ROOT(blueprint_id)%>' \ - ], \ - teleport_duration: 0, \ - interpolation_duration: <%interpolation_duration%>, \ - Passengers:<%root_entity_passengers%>, \ - CustomName: '<%ENTITY_NAMES.ROOT(blueprint_id)%>', \ - } - execute as @n[ \ - type=minecraft:item_display, \ - tag=<%TAGS.PROJECT_ROOT(blueprint_id)%>, \ - tag=<%TAGS.NEW()%>, \ - distance=..0.01 \ - ] run block zzz/summon/as_root_entity { - execute store result score @s <%OBJECTIVES.ID()%> run scoreboard players add aj.last_id <%OBJECTIVES.ID()%> 1 - - data_manager init prep read - # Data manager init runs gu:get_entity_uuid_string. So we don't need to call it again here. - # function animated_java:global/gu/get_entity_uuid_string - data modify storage <%temp_storage%> entry.data.uuids append from storage <%gu_storage%> out - data modify storage <%temp_storage%> entry.data.root_uuid set from storage <%gu_storage%> out - - data modify storage <%temp_storage%> entry.data.blueprint_id set value "<%blueprint_id%>" - data modify storage <%temp_storage%> entry.data.rig_hash set value "<%rig_hash%>" - - # Align the position and rotation of the root with the command context. - tp @s ~ ~ ~ ~ ~ - - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'locator' && node.config?.use_entity)) as locator { - summon <%locator.config.entity_type%> \ - ^<%roundTo(locator.default_transform.pos[0], 10)%> \ - ^<%roundTo(locator.default_transform.pos[1], 10)%> \ - ^<%roundTo(locator.default_transform.pos[2], 10)%> \ - {Tags:<%getNodeTags(locator, rig)%>} - execute \ - as @n[ \ - type=<%locator.config.entity_type%>, \ - tag=<%TAGS.PROJECT_LOCATOR_NAMED(blueprint_id, locator.storage_name)%>, \ - tag=<%TAGS.NEW()%>, \ - distance=..<%Math.ceil(locator.max_distance)%> \ - ] \ - run block as_locator/<%locator.storage_name%> { - # run block ../as_locator/<%locator.storage_name%> { - tag @s remove <%TAGS.NEW()%> - data modify entity @s CustomName set value '<%ENTITY_NAMES.NODE(blueprint_id, locator.type, locator.storage_name)%>' - function animated_java:global/gu/get_entity_uuid_string - scoreboard players operation @s <%OBJECTIVES.ID()%> = aj.last_id <%OBJECTIVES.ID()%> - } - data modify storage <%temp_storage%> entry.data.uuids append from storage <%gu_storage%> out - data modify storage <%temp_storage%> entry.data.uuids_by_name.<%locator.storage_name%> set from storage <%gu_storage%> out - data modify storage <%temp_storage%> entry.data.locators.<%locator.storage_name%>.uuid set from storage <%gu_storage%> out - } - - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'camera')) as camera { - summon minecraft:item_display \ - ^<%roundTo(camera.default_transform.pos[0], 10)%> \ - ^<%roundTo(camera.default_transform.pos[1], 10)%> \ - ^<%roundTo(camera.default_transform.pos[2], 10)%> \ - {Tags:<%getNodeTags(camera, rig)%>, teleport_duration: 2} - execute \ - as @n[ \ - type=minecraft:item_display, \ - tag=<%TAGS.PROJECT_CAMERA_NAMED(blueprint_id, camera.storage_name)%>, \ - tag=<%TAGS.NEW()%>, \ - distance=..<%Math.ceil(camera.max_distance)%> \ - ] \ - run block as_camera/<%camera.storage_name%> { - # run block ../as_camera/<%camera.storage_name%> { - tag @s remove <%TAGS.NEW()%> - data modify entity @s CustomName set value '<%ENTITY_NAMES.NODE(blueprint_id, camera.type, camera.storage_name)%>' - function animated_java:global/gu/get_entity_uuid_string - scoreboard players operation @s <%OBJECTIVES.ID()%> = aj.last_id <%OBJECTIVES.ID()%> - } - data modify storage <%temp_storage%> entry.data.uuids append from storage <%gu_storage%> out - data modify storage <%temp_storage%> entry.data.uuids_by_name.<%camera.storage_name%> set from storage <%gu_storage%> out - data modify storage <%temp_storage%> entry.data.cameras.<%camera.storage_name%>.uuid set from storage <%gu_storage%> out - } - - REPEAT (Object.values(rig.nodes).filter(node => BONE_TYPES.includes(node.type))) as node { - execute \ - on passengers \ - if entity @s[tag=<%TAGS.PROJECT_NODE_NAMED(blueprint_id, node.storage_name)%>] \ - run block as_node/<%node.storage_name%> { - data modify entity @s CustomName set value '<%ENTITY_NAMES.NODE(blueprint_id, node.type, node.storage_name)%>' - function animated_java:global/gu/get_entity_uuid_string - scoreboard players operation @s <%OBJECTIVES.ID()%> = aj.last_id <%OBJECTIVES.ID()%> - } - - data modify storage <%temp_storage%> entry.data.uuids append from storage <%gu_storage%> out - data modify storage <%temp_storage%> entry.data.uuids_by_name.<%node.storage_name%> set from storage <%gu_storage%> out - } - - IF (has_entity_locators) { - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'locator' && node.config?.use_entity)) as locator { - block { with storage <%temp_storage%> entry.data.locators.<%locator.storage_name%> - # Track any custom entities on the locator. - $execute at @s as $(uuid) at @s run function animated_java:global/util/get_entity_stack_uuids - } - data modify storage <%temp_storage%> entry.data.uuids append from storage <%temp_storage%> uuids - } - } - - function <%blueprint_id%>/zzz/set_default_pose - - data_manager write - - # Variant Arguement - IF (Object.keys(rig.variants).length > 1) { - execute if data storage <%temp_storage%> args.variant run block variant_arg/process { with storage <%temp_storage%> args - scoreboard players set #success <%OBJECTIVES.I()%> 0 - # If the variant argument is *explicitly* set to an empty string, return an error. - execute if data storage <%temp_storage%> {args:{variant:''}} run return run block if_empty { - # Tell the user that the variant cannot be empty. - tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('variant')%> - function <%blueprint_id%>/remove/this/without_on_remove_function - } - # Attempt to apply the requested variant. - # We get the success of the `try_apply` function in just in case the user's arguments are *very* wrong. - execute store success score #success <%OBJECTIVES.I()%> run block try_apply { with storage <%temp_storage%> args - $execute if function <%blueprint_id%>/variants/$(variant)/apply run return 1 - # If the apply function fails, the variant doesn't exist, so we return an error. - return fail - } - # If the apply function failed, return an error. - execute unless score #success <%OBJECTIVES.I()%> matches 1 run return run block invalid_variant { - # Tell the user that the provided variant doesn't exist, remove the rig, and list all available variants for this rig. - tellraw @a <%TELLRAW.INVALID_VARIANT(rig.variants)%> - function <%blueprint_id%>/remove/this/without_on_remove_function - } - scoreboard players set #success <%OBJECTIVES.I()%> 1 - } - } ELSE { - execute if data storage <%temp_storage%> args.variant run block zzz/variant_arg/no_variants_warning { - tellraw @a <%TELLRAW.NO_VARIANTS()%> - function <%blueprint_id%>/remove/this/without_on_remove_function - scoreboard players set #success <%OBJECTIVES.I()%> 0 - } - } - execute if score #success <%OBJECTIVES.I()%> matches 0 run return fail - - IF (has_locators || has_cameras) { - function <%blueprint_id%>/root/on_tick/transform_floating_entities - } - execute on passengers run tp @s ~ ~ ~ ~ ~ - - # Apply teleport duration - data modify entity @s teleport_duration set value <%teleportation_duration%> - execute on passengers run data modify entity @s teleport_duration set value <%teleportation_duration%> - - IF (has_entity_locators) { - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'locator' && node.config?.use_entity && node.config.on_summon_function)) as locator { - block { with storage <%temp_storage%> entry.data.locators.<%locator.storage_name%> - $execute at @s as $(uuid) at @s run block on_summon/custom_<%locator.type + '_' + locator.storage_name%> { - <%% - emit.mcb(locator.config.on_summon_function) - %%> - } - } - } - } - - REPEAT (Object.values(rig.nodes).filter(node => BONE_TYPES.includes(node.type) && node.on_summon_function?.trim())) as node { - execute \ - on passengers if entity @s[tag=<%TAGS.PROJECT_NODE_NAMED(blueprint_id, node.storage_name)%>] \ - run block on_summon/<%node.type + '_' + node.storage_name%> { - <%% - emit.mcb(node.on_summon_function.trim()) - %%> - } - } - - IF (on_summon_function) { - execute at @s run block on_summon/rig { - <%% - emit.mcb(on_summon_function) - %%> - } - } - - # Remove the NEW tag from the root entity, and it's passengers. - tag @s remove <%TAGS.NEW()%> - execute on passengers run tag @s remove <%TAGS.NEW()%> - } -} - -function as_node { - #ARGS: {name: string, command: string} - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - data remove storage <%temp_storage%> args - $data modify storage <%temp_storage%> args merge value {name:'$(name)', command:'$(command)', uuid:'+MISSING_UUID+'} - - IF (debug_mode) { - execute if data storage <%temp_storage%> {args:{name:''}} run return run tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('name')%> - execute if data storage <%temp_storage%> {args:{command:''}} run return run tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('command')%> - } - - data_manager prep read - - block zzz/as_node/as_data { with storage <%temp_storage%> args - $data modify storage <%temp_storage%> args.uuid set from storage <%temp_storage%> entry.data.uuids_by_name.$(name) - IF (debug_mode) { - scoreboard players set #aj.check <%OBJECTIVES.I()%> 0 - } - block execute_as_uuid { with storage <%temp_storage%> args - IF (debug_mode) { - # If the function successfully instantiated, the provided command is valid. - scoreboard players set #aj.check <%OBJECTIVES.I()%> 1 - } - $execute as $(uuid) run return run $(command) - IF (debug_mode) { - # If the entity with the provided UUID doesn't exist, the node wasn't found. - tellraw @a <%TELLRAW.NODE_ENTITY_NOT_FOUND()%> - } - } - IF (debug_mode) { - execute if score #aj.check <%OBJECTIVES.I()%> matches 0 run tellraw @a <%TELLRAW.NODE_COMMAND_FAILED_TO_EXECUTE()%> - } - } -} - -IF (has_entity_locators) { - function as_locator { - #ARGS: {name: string, command: string} - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - - data remove storage <%temp_storage%> args - $data modify storage <%temp_storage%> args merge value {name:'$(name)', command:'$(command)', uuid:'+MISSING_UUID+'} - - IF (debug_mode) { - execute if data storage <%temp_storage%> {args:{name:''}} run return run tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('name')%> - execute if data storage <%temp_storage%> {args:{command:''}} run return run tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('command')%> - } - - data_manager prep read - - block zzz/as_locator/as_data { with storage <%temp_storage%> args - $data modify storage <%temp_storage%> args.uuid set from storage <%temp_storage%> entry.data.locators.$(name).uuid - IF (debug_mode) { - scoreboard players set #aj.check <%OBJECTIVES.I()%> 0 - } - block execute_as_uuid { with storage <%temp_storage%> args - IF (debug_mode) { - # If the function successfully instantiated, the provided command is valid. - scoreboard players set #aj.check <%OBJECTIVES.I()%> 1 - } - $execute as $(uuid) run return run $(command) - IF (debug_mode) { - # If the entity with the provided UUID doesn't exist, the locator wasn't found. - tellraw @a <%TELLRAW.LOCATOR_ENTITY_NOT_FOUND()%> - } - } - IF (debug_mode) { - execute if score #aj.check <%OBJECTIVES.I()%> matches 0 run tellraw @a <%TELLRAW.LOCATOR_COMMAND_FAILED_TO_EXECUTE()%> - } - } - } - - function as_at_locator { - #ARGS: {name: string, command: string} - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - - data remove storage <%temp_storage%> args - $data modify storage <%temp_storage%> args merge value {name:'$(name)', command:'$(command)', uuid:'+MISSING_UUID+'} - - IF (debug_mode) { - execute if data storage <%temp_storage%> {args:{name:''}} run return run tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('name')%> - execute if data storage <%temp_storage%> {args:{command:''}} run return run tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('command')%> - } - - data_manager prep read - - block zzz/as_locator/as_data { with storage <%temp_storage%> args - $data modify storage <%temp_storage%> args.uuid set from storage <%temp_storage%> entry.data.locators.$(name).uuid - IF (debug_mode) { - scoreboard players set #aj.check <%OBJECTIVES.I()%> 0 - } - block execute_as_uuid { with storage <%temp_storage%> args - IF (debug_mode) { - # If the function successfully instantiated, the provided command is valid. - scoreboard players set #aj.check <%OBJECTIVES.I()%> 1 - } - $execute as $(uuid) at @s run return run $(command) - IF (debug_mode) { - # If the entity with the provided UUID doesn't exist, the locator wasn't found. - tellraw @a <%TELLRAW.LOCATOR_ENTITY_NOT_FOUND()%> - } - } - IF (debug_mode) { - execute if score #aj.check <%OBJECTIVES.I()%> matches 0 run tellraw @a <%TELLRAW.LOCATOR_COMMAND_FAILED_TO_EXECUTE()%> - } - } - } - - function as_all_locators { - #ARGS: {command: string} - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - - data remove storage <%temp_storage%> args - $data modify storage <%temp_storage%> args merge value {command:'$(command)'} - - IF (debug_mode) { - execute if data storage <%temp_storage%> {args:{command:''}} run return run tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('command')%> - } - - data_manager prep read - - block zzz/as_all_locators/as_data { - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'locator' && node.config?.use_entity)) as locator { - data modify storage <%temp_storage%> args.uuid set from storage <%temp_storage%> entry.data.locators.<%locator.storage_name%>.uuid - - IF (debug_mode) { - scoreboard players set #aj.check <%OBJECTIVES.I()%> 0 - } - - block execute_as_uuid { with storage <%temp_storage%> args - IF (debug_mode) { - # If the function successfully instantiated, the provided command is valid. - scoreboard players set #aj.check <%OBJECTIVES.I()%> 1 - } - - $execute as $(uuid) run return run $(command) - } - - IF (debug_mode) { - execute if score #aj.check <%OBJECTIVES.I()%> matches 0 run tellraw @a <%TELLRAW.LOCATOR_COMMAND_FAILED_TO_EXECUTE({text: locator.storage_name, color: 'aqua'})%> - } - } - } - } - - function as_at_all_locators { - #ARGS: {command: string} - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - - data remove storage <%temp_storage%> args - $data modify storage <%temp_storage%> args merge value {command:'$(command)'} - - IF (debug_mode) { - execute if data storage <%temp_storage%> {args:{command:''}} run return run tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('command')%> - } - - data_manager prep read - - block zzz/as_all_locators/as_data { - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'locator' && node.config?.use_entity)) as locator { - data modify storage <%temp_storage%> args.uuid set from storage <%temp_storage%> entry.data.locators.<%locator.storage_name%>.uuid - - IF (debug_mode) { - scoreboard players set #aj.check <%OBJECTIVES.I()%> 0 - } - - block execute_as_uuid { with storage <%temp_storage%> args - IF (debug_mode) { - # If the function successfully instantiated, the provided command is valid. - scoreboard players set #aj.check <%OBJECTIVES.I()%> 1 - } - - $execute as $(uuid) at @s run return run $(command) - } - - IF (debug_mode) { - execute if score #aj.check <%OBJECTIVES.I()%> matches 0 run tellraw @a <%TELLRAW.LOCATOR_COMMAND_FAILED_TO_EXECUTE({text: locator.storage_name, color: 'aqua'})%> - } - } - } - } -} - -IF (has_locators) { - function at_locator { - #ARGS: {name: string, command: string} - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - - data remove storage <%temp_storage%> args - $data modify storage <%temp_storage%> args merge value {name:'$(name)', command:'$(command)'} - - IF (debug_mode) { - execute if data storage <%temp_storage%> {args:{name:''}} run return run tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('name')%> - execute if data storage <%temp_storage%> {args:{command:''}} run return run tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('command')%> - } - - data_manager prep read - - execute at @s run block zzz/at_locator/as_data { with storage <%temp_storage%> args - $data modify storage <%temp_storage%> args merge from storage <%temp_storage%> entry.data.locators.$(name) - - IF (debug_mode) { - execute unless data storage <%temp_storage%> args.px run return run tellraw @a <%TELLRAW.LOCATOR_NOT_FOUND()%> - scoreboard players set #aj.check <%OBJECTIVES.I()%> 0 - } - - block execute_at_transform { with storage <%temp_storage%> args - IF (debug_mode) { - # If the function successfully instantiated, the provided command is valid. - scoreboard players set #aj.check <%OBJECTIVES.I()%> 1 - } - - $execute \ - positioned ^$(px) ^$(py) ^$(pz) \ - rotated ~$(ry) ~$(rx) \ - run $(command) - } - - IF (debug_mode) { - execute if score #aj.check <%OBJECTIVES.I()%> matches 0 run tellraw @a <%TELLRAW.LOCATOR_COMMAND_FAILED_TO_EXECUTE()%> - } - } - } - - function at_all_locators { - #ARGS: {command: string} - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - - data remove storage <%temp_storage%> args - $data modify storage <%temp_storage%> args merge value {command:'$(command)'} - - IF (debug_mode) { - execute if data storage <%temp_storage%> {args:{command:''}} run return run tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('command')%> - } - - data_manager prep read - - block zzz/at_all_locators/as_data { - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'locator')) as locator { - data modify storage <%temp_storage%> args merge from storage <%temp_storage%> entry.data.locators.<%locator.storage_name%> - - IF (debug_mode) { - scoreboard players set #aj.check <%OBJECTIVES.I()%> 0 - } - - block execute_at_transform { with storage <%temp_storage%> args - IF (debug_mode) { - # If the function successfully instantiated, the provided command is valid. - scoreboard players set #aj.check <%OBJECTIVES.I()%> 1 - } - - $execute \ - positioned ^$(px) ^$(py) ^$(pz) \ - rotated ~$(ry) ~$(rx) \ - run $(command) - } - - IF (debug_mode) { - execute if score #aj.check <%OBJECTIVES.I()%> matches 0 run tellraw @a <%TELLRAW.LOCATOR_COMMAND_FAILED_TO_EXECUTE({text: locator.storage_name, color: 'aqua'})%> - } - } - } - } -} - -IF (has_cameras) { - function as_camera { - #ARGS: {name: string, command: string} - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - - data remove storage <%temp_storage%> args - $data modify storage <%temp_storage%> args merge value {name:'$(name)', command:'$(command)', uuid:'+MISSING_UUID+'} - - IF (debug_mode) { - execute if data storage <%temp_storage%> {args:{name:''}} run return run tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('name')%> - execute if data storage <%temp_storage%> {args:{command:''}} run return run tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('command')%> - } - - data_manager prep read - - block zzz/as_camera/as_data { with storage <%temp_storage%> args - $data modify storage <%temp_storage%> args.uuid set from storage <%temp_storage%> entry.data.cameras.$(name).uuid - - IF (debug_mode) { - scoreboard players set #aj.check <%OBJECTIVES.I()%> 0 - } - - block execute_as_uuid { with storage <%temp_storage%> args - IF (debug_mode) { - # If the function successfully instantiated, the provided command is valid. - scoreboard players set #aj.check <%OBJECTIVES.I()%> 1 - } - - $execute as $(uuid) at @s run return run $(command) - - IF (debug_mode) { - # If the entity with the provided UUID doesn't exist, the camera wasn't found. - tellraw @a <%TELLRAW.CAMERA_ENTITY_NOT_FOUND()%> - } - } - - IF (debug_mode) { - execute if score #aj.check <%OBJECTIVES.I()%> matches 0 run tellraw @a <%TELLRAW.CAMERA_COMMAND_FAILED_TO_EXECUTE()%> - } - } - } -} - -function as_root { - #ARGS: {command: string} - execute unless score @s <%OBJECTIVES.ID()%> matches <%-(2**31)%>..<%(2**31)-1%> run return run \ - tellraw @a <%TELLRAW.FUNCTION_NOT_EXECUTED_AS_ENTITY_WITH_ID_SCORE(context.functions.at(-1))%> - - data_manager prep read - - $data modify storage <%temp_storage%> args.command set value '$(command)' - data modify storage <%temp_storage%> args.root_uuid set from storage <%temp_storage%> entry.data.root_uuid - - IF (debug_mode) { - scoreboard players set #aj.check <%OBJECTIVES.I()%> 0 - } - block as_root_entity { with storage <%temp_storage%> args - $execute as $(root_uuid) run $(command) - IF (debug_mode) { - # If the function successfully instantiated, the provided command is valid. - scoreboard players set #aj.check <%OBJECTIVES.I()%> 1 - } - } - IF (debug_mode) { - execute if score #aj.check <%OBJECTIVES.I()%> matches 0 run tellraw @a <%TELLRAW.ROOT_COMMAND_FAILED_TO_EXECUTE()%> - } - -} - -dir remove { - function all { - # Removes all instances of this rig from the world. - execute as @e[type=minecraft:item_display,tag=<%TAGS.PROJECT_ROOT(blueprint_id)%>] run function <%blueprint_id%>/remove/this - } - - function entities { - # Removes all entities related to this rig from the world. - kill @e[tag=<%TAGS.PROJECT_ENTITY(blueprint_id)%>] - } - - function this { - # Removes the rig this function is executed as. - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - - <%% - if (on_remove_function) emit.mcb(on_remove_function) - %%> - - IF (has_entity_locators) { - data_manager prep read - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'locator')) as locator { - IF (locator.config?.on_remove_function) { - IF (locator.config.use_entity) { - block as_locator_<%locator.storage_name%> { with storage <%temp_storage%> entry.data.locators.<%locator.storage_name%> - $execute as $(uuid) at @s run block locator_<%locator.storage_name%>_on_remove { - <%% - emit.mcb(locator.config.on_remove_function) - %%> - } - } - } ELSE { - block at_locator_<%locator.storage_name%> { with storage <%temp_storage%> entry.data.locators.<%locator.storage_name%> - $execute \ - positioned ^$(px) ^$(py) ^$(pz) \ - rotated ~$(ry) ~$(rx) \ - run block locator_<%locator.storage_name%>_on_remove { - <%% - emit.mcb(locator.config.on_remove_function) - %%> - } - } - } - } - } - } - - function ./this/without_on_remove_function - } - - dir this { - function without_on_remove_function { - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - - data_manager prep read - - IF (has_entity_locators || has_cameras) { - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'locator' && node.config?.use_entity)) as locator { - function animated_java:global/remove/entity_stack_by_uuid with storage <%temp_storage%> entry.data.locators.<%locator.storage_name%> - } - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'camera')) as camera { - function animated_java:global/remove/entity_stack_by_uuid with storage <%temp_storage%> entry.data.cameras.<%camera.storage_name%> - } - } - - # Remove the rig using the more expensive & thorough method if the rig_hash doesn't match. - execute \ - unless data storage <%temp_storage%> {entry:{data:{rig_hash: '<%rig_hash%>'}}} \ - run function animated_java:global/remove/outdated_rig - - block { with storage <%temp_storage%> entry.data.uuids_by_name - REPEAT (Object.values(rig.nodes).filter(node => BONE_TYPES.includes(node.type))) as node { - $kill $(<%node.storage_name%>) - } - } - - function animated_java:global/remove/entity_stack - } - } -} - -IF (Object.keys(rig.variants).length > 1) { - dir variants { - REPEAT (Object.values(rig.variants)) as variant { - dir <%variant.name%> { - function apply { - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - - <%% - global.filteredNodes = Object.values(rig.nodes).filter( - node => ( - node.type === 'bone' && - !variant.excluded_nodes.includes(node.uuid) && - ( // Variant has a model override or a config override for this bone. - variant.models[node.uuid] !== undefined || - node.configs.variants[variant.uuid] !== undefined - ) - ) || ( - BONE_TYPES.includes(node.type) && - !variant.excluded_nodes.includes(node.uuid) && - // Variant has a config override for this node. - node.configs.variants[variant.uuid] !== undefined - ) - ) - %%> - - REPEAT (global.filteredNodes) as node { - execute \ - on passengers \ - if entity @s[tag=<%TAGS.PROJECT_NODE_NAMED(blueprint_id, node.storage_name)%>] \ - at @s \ - run \ - block zzz/apply_to_node_<%node.storage_name%> { - IF (node.type === 'bone' && variant.models[node.uuid] !== undefined) { - # Special case for `animated_java:empty` model. - IF (variant.models[node.uuid].model === null) { - data modify entity @s item.components."minecraft:item_model" set value "animated_java:empty" - } ELSE { - data modify entity @s item.components."minecraft:item_model" set value "<%variant.models[node.uuid].item_model%>" - } - } - IF (node.configs.variants[variant.uuid]) { - <%% - global.config = DisplayEntityConfig.fromJSON(node.configs.variants[variant.uuid]) - %%> - IF (!global.config.isDefault()) { - data merge entity @s <%global.config.toNBT(undefined, variant.is_default)%> - } - IF (global.config.onApplyFunction) { - <%% - emit.mcb(global.config.onApplyFunction) - %%> - } - } - } - } - # Return success to allow this function to be used in function conditions. - return 1 - } - } - } - } -} - -IF (has_locators || has_cameras) { - dir zzz { - function reset_floating_entities { - IF (has_locators) { - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'locator')) as locator { - IF (locator.config?.use_entity) { - execute at @s run block set_default_pose/as_locator_<%locator.storage_name%> { with storage <%temp_storage%> entry.data.locators.<%locator.storage_name%> - $tp $(uuid) \ - ^<%roundTo(locator.default_transform.pos[0], 10)%> \ - ^<%roundTo(locator.default_transform.pos[1], 10)%> \ - ^<%roundTo(locator.default_transform.pos[2], 10)%> \ - ~<%roundTo(locator.default_transform.head_rot[1], 10)%> \ - ~<%roundTo(locator.default_transform.head_rot[0], 10)%> - - data modify storage <%temp_storage%> entry.data.locators.<%locator.storage_name%> merge value { \ - px: <%roundTo(locator.default_transform.pos[0], 10)%>, \ - py: <%roundTo(locator.default_transform.pos[1], 10)%>, \ - pz: <%roundTo(locator.default_transform.pos[2], 10)%>, \ - ry: <%roundTo(locator.default_transform.head_rot[1], 10)%>, \ - rx: <%roundTo(locator.default_transform.head_rot[0], 10)%> \ - } - } - } ELSE { - data modify storage <%temp_storage%> entry.data.locators.<%locator.storage_name%> merge value { \ - px: <%roundTo(locator.default_transform.pos[0], 10)%>, \ - py: <%roundTo(locator.default_transform.pos[1], 10)%>, \ - pz: <%roundTo(locator.default_transform.pos[2], 10)%>, \ - ry: <%roundTo(locator.default_transform.head_rot[1], 10)%>, \ - rx: <%roundTo(locator.default_transform.head_rot[0], 10)%> \ - } - } - } - } - - IF (has_cameras) { - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'camera')) as camera { - execute at @s run block set_default_pose/as_camera_<%camera.storage_name%> { with storage <%temp_storage%> entry.data.cameras.<%camera.storage_name%> - $tp $(uuid) \ - ^<%roundTo(camera.default_transform.pos[0], 10)%> \ - ^<%roundTo(camera.default_transform.pos[1], 10)%> \ - ^<%roundTo(camera.default_transform.pos[2], 10)%> \ - ~<%roundTo(camera.default_transform.head_rot[1], 10)%> \ - ~<%roundTo(camera.default_transform.head_rot[0], 10)%> - - data modify storage <%temp_storage%> entry.data.cameras.<%camera.storage_name%> merge value { \ - px: <%roundTo(camera.default_transform.pos[0], 10)%>, \ - py: <%roundTo(camera.default_transform.pos[1], 10)%>, \ - pz: <%roundTo(camera.default_transform.pos[2], 10)%>, \ - ry: <%roundTo(camera.default_transform.head_rot[1], 10)%>, \ - rx: <%roundTo(camera.default_transform.head_rot[0], 10)%> \ - } - } - } - } - } - } -} - -dir zzz { - function set_default_pose { - IF (has_locators || has_cameras) { - function ../zzz/reset_floating_entities - } - - REPEAT (Object.values(rig.nodes).filter(node => BONE_TYPES.includes(node.type))) as node { - execute \ - on passengers \ - if entity @s[tag=<%TAGS.PROJECT_NODE_NAMED(blueprint_id, node.storage_name)%>] \ - run \ - data merge entity @s { \ - transformation: <%matrixToNbtFloatArray(node.default_transform.matrix).toString()%>, \ - start_interpolation: -1 \ - } - } - } -} - -function set_default_pose { - # Changes the pose of the rig to the the default pose without interpolation - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - - IF (has_locators || has_cameras) { - data_manager prep read - } - function ./zzz/set_default_pose -} \ No newline at end of file diff --git a/src/systems/datapackCompiler/1.21.2/animation.mcb b/src/systems/datapackCompiler/1.21.2/main.mcb similarity index 60% rename from src/systems/datapackCompiler/1.21.2/animation.mcb rename to src/systems/datapackCompiler/1.21.2/main.mcb index bf9445c7..310f992e 100644 --- a/src/systems/datapackCompiler/1.21.2/animation.mcb +++ b/src/systems/datapackCompiler/1.21.2/main.mcb @@ -6,26 +6,30 @@ function on_load { data modify storage <%project_storage%> rig_hash set value <%"'" + rig_hash + "'"%> - IF (use_storage_for_animation) { - REPEAT (animations) as animation { - data remove storage <%project_storage%>/animations <%animation.storage_name%> + IF (has_animations) { + IF (use_storage_for_animation) { + REPEAT (animations) as animation { + data remove storage <%project_storage%>/animations <%animation.storage_name%> + } + <%animationStorage.join('\n')%> } - <%animationStorage.join('\n')%> + <%% + animations.forEach(animation => { + emit(`scoreboard objectives add ${OBJECTIVES.FRAME(animation.storage_name)} dummy`) + }) + %%> } - <%% - animations.forEach(animation => { - emit(`scoreboard objectives add ${OBJECTIVES.FRAME(animation.storage_name)} dummy`) - }) - %%> } -function remove_animation_objectives { - <%% - animations.forEach(animation => { - emit(`scoreboard objectives remove ${OBJECTIVES.FRAME(animation.storage_name)}`) - }) - %%> - tellraw @a <%TELLRAW.UNINSTALL()%> +IF (has_animations) { + function remove_animation_objectives { + <%% + animations.forEach(animation => { + emit(`scoreboard objectives remove ${OBJECTIVES.FRAME(animation.storage_name)}`) + }) + %%> + tellraw @a <%TELLRAW.UNINSTALL()%> + } } dir root { @@ -37,26 +41,28 @@ dir root { %%> } - # animated_java:global/root/on_tick already runs this right before calling this function. - # data_manager prep read - - # Once we have more than 8 animations, calling a function only if at least one animation is playing is more efficient. - IF (animations.length > 8) { - # If no animations are playing, we can skip all animation logic. - # This helps reduce ticking commands for rigs that are idle. - execute \ - unless entity @s[<%animations.map(anim => 'tag=!' + TAGS.ANIMATION_PLAYING(blueprint_id, anim.storage_name)).join(',')%>] \ - run block tick_animations { + IF (has_animations) { + # animated_java:global/root/on_tick already runs this right before calling this function. + # data_manager prep read + + # Once we have more than 8 animations, calling a function only if at least one animation is playing is more efficient. + IF (animations.length > 8) { + # If no animations are playing, we can skip all animation logic. + # This helps reduce ticking commands for rigs that are idle. + execute \ + unless entity @s[<%animations.map(anim => 'tag=!' + TAGS.ANIMATION_PLAYING(blueprint_id, anim.storage_name)).join(',')%>] \ + run block tick_animations { + REPEAT (animations) as animation { + execute if entity @s[tag=<%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%>] run \ + function <%blueprint_id%>/animations/<%animation.storage_name%>/zzz/on_tick + } + } + } ELSE { REPEAT (animations) as animation { execute if entity @s[tag=<%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%>] run \ function <%blueprint_id%>/animations/<%animation.storage_name%>/zzz/on_tick } } - } ELSE { - REPEAT (animations) as animation { - execute if entity @s[tag=<%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%>] run \ - function <%blueprint_id%>/animations/<%animation.storage_name%>/zzz/on_tick - } } IF (auto_update_rig_orientation) { @@ -148,405 +154,413 @@ IF (!auto_update_rig_orientation) { } } -dir animations { - REPEAT (animations) as animation { - dir <%animation.storage_name%> { - function play { - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> +IF (has_animations) { + dir animations { + REPEAT (animations) as animation { + dir <%animation.storage_name%> { + function play { + debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - function <%blueprint_id%>/animations/pause_all + function <%blueprint_id%>/animations/pause_all - tag @s add <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%> - scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> 0 - tag @s add <%TAGS.TRANSFORMS_ONLY()%> - execute at @s run function ./zzz/set_frame {frame: 0} - tag @s remove <%TAGS.TRANSFORMS_ONLY()%> - } + tag @s add <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%> + scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> 0 + tag @s add <%TAGS.TRANSFORMS_ONLY()%> + execute at @s run function ./zzz/set_frame {frame: 0} + tag @s remove <%TAGS.TRANSFORMS_ONLY()%> + } - function stop { - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> + function stop { + debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - function <%blueprint_id%>/animations/pause_all + function <%blueprint_id%>/animations/pause_all - scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> 0 - tag @s add <%TAGS.TRANSFORMS_ONLY()%> - execute at @s run function ./zzz/set_frame {frame: 0} - tag @s remove <%TAGS.TRANSFORMS_ONLY()%> - } + scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> 0 + tag @s add <%TAGS.TRANSFORMS_ONLY()%> + execute at @s run function ./zzz/set_frame {frame: 0} + tag @s remove <%TAGS.TRANSFORMS_ONLY()%> + } - function pause { - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> + function pause { + debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - tag @s remove <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%> - } + tag @s remove <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%> + } - function resume { - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> + function resume { + debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - tag @s add <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%> - } + tag @s add <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%> + } - function next_frame { - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> + function next_frame { + debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - execute if score @s <%OBJECTIVES.FRAME(animation.storage_name)%> matches <%animation.duration%>.. run scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> 1 - data remove storage <%temp_storage%> args - execute store result storage <%temp_storage%> args.frame int 1 run scoreboard players get @s <%OBJECTIVES.FRAME(animation.storage_name)%> - execute at @s run function ./zzz/apply_frame with storage <%temp_storage%> args - scoreboard players add @s <%OBJECTIVES.FRAME(animation.storage_name)%> 1 - } + execute if score @s <%OBJECTIVES.FRAME(animation.storage_name)%> matches <%animation.duration%>.. run scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> 1 + data remove storage <%temp_storage%> args + execute store result storage <%temp_storage%> args.frame int 1 run scoreboard players get @s <%OBJECTIVES.FRAME(animation.storage_name)%> + execute at @s run function ./zzz/apply_frame with storage <%temp_storage%> args + scoreboard players add @s <%OBJECTIVES.FRAME(animation.storage_name)%> 1 + } - function set_frame { - # Sets the frame without interpolation - #ARGS: {frame: int} - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> + function set_frame { + # Sets the frame without interpolation + #ARGS: {frame: int} + debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - data_manager prep read + data_manager prep read - data remove storage <%temp_storage%> args - $execute store result storage <%temp_storage%> args.frame int 1 run scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> $(frame) - execute at @s run function ./zzz/set_frame with storage <%temp_storage%> args - } + data remove storage <%temp_storage%> args + $execute store result storage <%temp_storage%> args.frame int 1 run scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> $(frame) + execute at @s run function ./zzz/set_frame with storage <%temp_storage%> args + } - function apply_frame { - #ARGS: {frame: int} - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> + function apply_frame { + #ARGS: {frame: int} + debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - data_manager prep read + data_manager prep read - data remove storage <%temp_storage%> args - $execute store result storage <%temp_storage%> args.frame int 1 run scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> $(frame) - execute at @s run function ./zzz/apply_frame with storage <%temp_storage%> args - } + data remove storage <%temp_storage%> args + $execute store result storage <%temp_storage%> args.frame int 1 run scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> $(frame) + execute at @s run function ./zzz/apply_frame with storage <%temp_storage%> args + } - function tween { - # Attempts to smoothly transition from the currently playing animation into this one. - #ARGS: {duration: int, to_frame: int} - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> + function tween { + # Attempts to smoothly transition from the currently playing animation into this one. + #ARGS: {duration: int, to_frame: int} + debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - function <%blueprint_id%>/animations/pause_all + function <%blueprint_id%>/animations/pause_all - tag @s add <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%> - $scoreboard players set @s <%OBJECTIVES.TWEEN_DURATION()%> $(duration) - $scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> $(to_frame) + tag @s add <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%> + $scoreboard players set @s <%OBJECTIVES.TWEEN_DURATION()%> $(duration) + $scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> $(to_frame) - scoreboard players operation #this <%OBJECTIVES.I()%> = @s <%OBJECTIVES.TWEEN_DURATION()%> - tag @s add <%TAGS.TRANSFORMS_ONLY()%> - execute at @s run function ./zzz/apply_frame {frame: 0} - $execute at @s run function ./zzz/apply_frame {frame: $(to_frame)} - tag @s remove <%TAGS.TRANSFORMS_ONLY()%> - execute on passengers store result entity @s interpolation_duration int 1 run scoreboard players get #this <%OBJECTIVES.I()%> - } + scoreboard players operation #this <%OBJECTIVES.I()%> = @s <%OBJECTIVES.TWEEN_DURATION()%> + tag @s add <%TAGS.TRANSFORMS_ONLY()%> + execute at @s run function ./zzz/apply_frame {frame: 0} + $execute at @s run function ./zzz/apply_frame {frame: $(to_frame)} + tag @s remove <%TAGS.TRANSFORMS_ONLY()%> + execute on passengers store result entity @s interpolation_duration int 1 run scoreboard players get #this <%OBJECTIVES.I()%> + } - dir zzz { - function on_tick { - # Tweening logic - scoreboard players remove @s <%OBJECTIVES.TWEEN_DURATION()%> 1 - execute if score @s <%OBJECTIVES.TWEEN_DURATION()%> matches 1.. run return 1 - execute if score @s <%OBJECTIVES.TWEEN_DURATION()%> matches 0 on passengers run \ - data modify entity @s interpolation_duration set value <%interpolation_duration%> - # Animation logic - IF (animation.loop_mode === 'loop' && animation.loop_delay === 0) { - # Makes sure function keyframes in the last frame of the animation are activated. - execute if score @s <%OBJECTIVES.FRAME(animation.storage_name)%> matches -1 run \ - block function_keyframe_loop_patch { - function ./frames/last_frame_effects with storage <%temp_storage%> entry.data.uuids_by_name - scoreboard players add @s <%OBJECTIVES.FRAME(animation.storage_name)%> 1 + dir zzz { + function on_tick { + # Tweening logic + scoreboard players remove @s <%OBJECTIVES.TWEEN_DURATION()%> 1 + execute if score @s <%OBJECTIVES.TWEEN_DURATION()%> matches 1.. run return 1 + execute if score @s <%OBJECTIVES.TWEEN_DURATION()%> matches 0 on passengers run \ + data modify entity @s interpolation_duration set value <%interpolation_duration%> + # Animation logic + IF (animation.loop_mode === 'loop' && animation.loop_delay === 0) { + # Makes sure function keyframes in the last frame of the animation are activated. + execute if score @s <%OBJECTIVES.FRAME(animation.storage_name)%> matches -1 run \ + block function_keyframe_loop_patch { + function ./frames/last_frame_effects with storage <%temp_storage%> entry.data.uuids_by_name + scoreboard players add @s <%OBJECTIVES.FRAME(animation.storage_name)%> 1 + } + } + data remove storage <%temp_storage%> args + execute store result storage <%temp_storage%> args.frame int 1 run \ + scoreboard players get @s <%OBJECTIVES.FRAME(animation.storage_name)%> + function ./apply_frame with storage <%temp_storage%> args + IF (animation.loop_mode === 'loop') { + # Loop the animation back to the start once it reaches the last frame. + # If loop_delay is 0, the animation will loop instantly, otherwise, it will wait for the specified amount of ticks. + execute \ + if score @s <%OBJECTIVES.FRAME(animation.storage_name)%> \ + matches <%animation.duration-2 + animation.loop_delay%>.. \ + run return run \ + scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> <%animation.loop_delay === 0 ? -1 : 0%> + } ELSE IF (animation.loop_mode === 'hold') { + # Pause the animation at the last frame. + execute \ + if score @s <%OBJECTIVES.FRAME(animation.storage_name)%> \ + matches <%animation.duration-1%>.. \ + run return run \ + function ../pause + } ELSE IF (animation.loop_mode === 'once') { + # Stop the animation once it reaches the last frame. + execute \ + if score @s <%OBJECTIVES.FRAME(animation.storage_name)%> \ + matches <%animation.duration-1%> \ + run return run block loop_mode_stop { + scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> 0 + tag @s add <%TAGS.TRANSFORMS_ONLY()%> + execute at @s run function ./zzz/set_frame {frame: 0} + tag @s remove <%TAGS.TRANSFORMS_ONLY()%> + tag @s remove <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%> } - } - data remove storage <%temp_storage%> args - execute store result storage <%temp_storage%> args.frame int 1 run \ - scoreboard players get @s <%OBJECTIVES.FRAME(animation.storage_name)%> - function ./apply_frame with storage <%temp_storage%> args - IF (animation.loop_mode === 'loop') { - # Loop the animation back to the start once it reaches the last frame. - # If loop_delay is 0, the animation will loop instantly, otherwise, it will wait for the specified amount of ticks. - execute \ - if score @s <%OBJECTIVES.FRAME(animation.storage_name)%> \ - matches <%animation.duration-2 + animation.loop_delay%>.. \ - run return run \ - scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> <%animation.loop_delay === 0 ? -1 : 0%> - } ELSE IF (animation.loop_mode === 'hold') { - # Pause the animation at the last frame. - execute \ - if score @s <%OBJECTIVES.FRAME(animation.storage_name)%> \ - matches <%animation.duration-1%>.. \ - run return run \ - function ../pause - } ELSE IF (animation.loop_mode === 'once') { - # Stop the animation once it reaches the last frame. - execute \ - if score @s <%OBJECTIVES.FRAME(animation.storage_name)%> \ - matches <%animation.duration-1%> \ - run return run block loop_mode_stop { - scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> 0 - tag @s add <%TAGS.TRANSFORMS_ONLY()%> - execute at @s run function ./zzz/set_frame {frame: 0} - tag @s remove <%TAGS.TRANSFORMS_ONLY()%> - tag @s remove <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%> } + scoreboard players add @s <%OBJECTIVES.FRAME(animation.storage_name)%> 1 } - scoreboard players add @s <%OBJECTIVES.FRAME(animation.storage_name)%> 1 - } - IF (use_storage_for_animation) { - function set_frame { - #ARGS: {frame: int} - $function ./apply_frame {frame: $(frame)} - execute on passengers run data modify entity @s start_interpolation set value -1 - return 1 - } + IF (use_storage_for_animation) { + function set_frame { + #ARGS: {frame: int} + $function ./apply_frame {frame: $(frame)} + execute on passengers run data modify entity @s start_interpolation set value -1 + return 1 + } - function apply_frame { - #ARGS: {frame: int} - REPEAT (Object.values(animation.modified_nodes).sort(nodeSorter)) as node { - IF (BONE_TYPES.includes(node.type)) { - $execute on passengers if entity @s[tag=<%TAGS.PROJECT_NODE_NAMED(blueprint_id, node.storage_name)%>] run \ - data modify entity @s {} merge from \ - storage <%project_storage%>/animations <%animation.storage_name%>.$(frame).<%node.storage_name%> - } ELSE IF (node.type === 'locator' || node.type === 'camera') { - $data modify storage <%temp_storage%> entry.data.uuids_by_name.<%node.storage_name%> merge from \ - storage <%project_storage%>/animations <%animation.storage_name%>.$(frame).<%node.storage_name%> + function apply_frame { + #ARGS: {frame: int} + REPEAT (Object.values(animation.modified_nodes).sort(nodeSorter)) as node { + IF (BONE_TYPES.includes(node.type)) { + $execute on passengers if entity @s[tag=<%TAGS.PROJECT_NODE_NAMED(blueprint_id, node.storage_name)%>] run \ + data modify entity @s {} merge from \ + storage <%project_storage%>/animations <%animation.storage_name%>.$(frame).<%node.storage_name%> + } ELSE IF (node.type === 'locator' || node.type === 'camera') { + $data modify storage <%temp_storage%> entry.data.uuids_by_name.<%node.storage_name%> merge from \ + storage <%project_storage%>/animations <%animation.storage_name%>.$(frame).<%node.storage_name%> + } } - } - IF (animation.frames.some(anim => anim.variant)) { - $execute \ - if data storage <%project_storage%>/animations <%animation.storage_name%>.$(frame).variant \ - unless entity @s[tag=<%TAGS.TRANSFORMS_ONLY()%>] \ - run { with storage <%project_storage%>/animations <%animation.storage_name%>.$(frame).variant - #ARGS: {name: string, condition: string} - $execute $(condition)run function <%blueprint_id%>/variants/$(name)/apply + IF (animation.frames.some(anim => anim.variant)) { + $execute \ + if data storage <%project_storage%>/animations <%animation.storage_name%>.$(frame).variant \ + unless entity @s[tag=<%TAGS.TRANSFORMS_ONLY()%>] \ + run { with storage <%project_storage%>/animations <%animation.storage_name%>.$(frame).variant + #ARGS: {name: string, condition: string} + $execute $(condition)run function <%blueprint_id%>/variants/$(name)/apply + } } - } - return 1 - } - } ELSE { - function set_frame { - # Sets the frame without interpolation - #ARGS: {frame: int} + return 1 + } + } ELSE { + function set_frame { + # Sets the frame without interpolation + #ARGS: {frame: int} - $function ./frames/$(frame) with storage <%temp_storage%> entry.data.uuids_by_name + $function ./frames/$(frame) with storage <%temp_storage%> entry.data.uuids_by_name - execute on passengers run \ - data modify entity @s start_interpolation set value -1 + execute on passengers run \ + data modify entity @s start_interpolation set value -1 - return 1 - } + return 1 + } - function apply_frame { - #ARGS: {frame: int} + function apply_frame { + #ARGS: {frame: int} - $function ./frames/$(frame) with storage <%temp_storage%> entry.data.uuids_by_name + $function ./frames/$(frame) with storage <%temp_storage%> entry.data.uuids_by_name - return 1 - } + return 1 + } - # FIXME - %NEWLINE_PATCH% is a temporary solution to temporarily fix an MCB bug where extra newlines are being added to the output. - dir frames { - <%% - global.frame = animation.frames.at(-1) - global.modified_effect_nodes = Object.values(animation.modified_nodes).filter( - node => node.type === 'locator' && global.frame.node_transforms[node.uuid] - ) - console.log(global.modified_effect_nodes) - %%> - IF(Object.keys(global.modified_effect_nodes).length > 0) { - function last_frame_effects { - REPEAT(global.modified_effect_nodes) as node { - <%% - global.transform = global.frame.node_transforms[node.uuid] - %%> - IF (node.config?.use_entity) { - $execute \ - as $(<%node.storage_name%>) \ - positioned \ - ^<%roundTo(global.transform.pos[0], 10)%> \ - ^<%roundTo(global.transform.pos[1], 10)%> \ - ^<%roundTo(global.transform.pos[2], 10)%> \ - rotated \ - ~<%roundTo(global.transform.head_rot[1], 10)%> \ - ~<%roundTo(global.transform.head_rot[0], 10)%> \ - <%global.transform.function_execute_condition ? global.transform.function_execute_condition + ' ' : ''%>run \ - function ./<%animation.duration%>_locator_<%node.storage_name%> - } ELSE { - execute \ - positioned \ - ^<%roundTo(global.transform.pos[0], 10)%> \ - ^<%roundTo(global.transform.pos[1], 10)%> \ - ^<%roundTo(global.transform.pos[2], 10)%> \ - rotated \ - ~<%roundTo(global.transform.head_rot[1], 10)%> \ - ~<%roundTo(global.transform.head_rot[0], 10)%> \ - <%global.transform.function_execute_condition ? global.transform.function_execute_condition + ' ' : ''%>run \ - function ./<%animation.duration%>_locator_<%node.storage_name%> + # FIXME - %NEWLINE_PATCH% is a temporary solution to temporarily fix an MCB bug where extra newlines are being added to the output. + dir frames { + <%% + global.frame = animation.frames.at(-1) + global.modified_effect_nodes = Object.values(animation.modified_nodes).filter( + node => node.type === 'locator' && global.frame.node_transforms[node.uuid] + ) + console.log(global.modified_effect_nodes) + %%> + IF(Object.keys(global.modified_effect_nodes).length > 0) { + function last_frame_effects { + REPEAT(global.modified_effect_nodes) as node { + <%% + global.transform = global.frame.node_transforms[node.uuid] + %%> + IF (node.config?.use_entity) { + $execute \ + as $(<%node.storage_name%>) \ + positioned \ + ^<%roundTo(global.transform.pos[0], 10)%> \ + ^<%roundTo(global.transform.pos[1], 10)%> \ + ^<%roundTo(global.transform.pos[2], 10)%> \ + rotated \ + ~<%roundTo(global.transform.head_rot[1], 10)%> \ + ~<%roundTo(global.transform.head_rot[0], 10)%> \ + <%global.transform.function_execute_condition ? global.transform.function_execute_condition + ' ' : ''%>run \ + function ./<%animation.duration%>_locator_<%node.storage_name%> + } ELSE { + execute \ + positioned \ + ^<%roundTo(global.transform.pos[0], 10)%> \ + ^<%roundTo(global.transform.pos[1], 10)%> \ + ^<%roundTo(global.transform.pos[2], 10)%> \ + rotated \ + ~<%roundTo(global.transform.head_rot[1], 10)%> \ + ~<%roundTo(global.transform.head_rot[0], 10)%> \ + <%global.transform.function_execute_condition ? global.transform.function_execute_condition + ' ' : ''%>run \ + function ./<%animation.duration%>_locator_<%node.storage_name%> + } } - } - IF (global.frame.variants?.length > 0) { - execute <%global.frame.variants_execute_condition ? global.frame.variants_execute_condition + ' ' : ''%>run \ - function <%blueprint_id%>/variants/<%global.frame.variants[0].name%>/apply - } + IF (global.frame.variants?.length > 0) { + execute <%global.frame.variants_execute_condition ? global.frame.variants_execute_condition + ' ' : ''%>run \ + function <%blueprint_id%>/variants/<%global.frame.variants[0].name%>/apply + } - IF (global.frame.function) { - execute <%global.frame.function_execute_condition ? global.frame.function_execute_condition + ' ' : ''%>run \ - block <%animation.duration%>_function_keyframe { - <%global.frame.function%> - } + IF (global.frame.function) { + execute <%global.frame.function_execute_condition ? global.frame.function_execute_condition + ' ' : ''%>run \ + block <%animation.duration%>_function_keyframe { + <%global.frame.function%> + } + } } } - } - - <%% - // A record of node uuid to INodeTransform. - // Keeps track of the last time a bone was updated. - // Only used for step keyframe interpolation. - let hasFunction = false - const lastActiveFrame = {} - const modifiedNodes = Object.values(animation.modified_nodes).filter(n => n.type !== 'struct').sort(nodeSorter); - for (const [frameIndex, frame] of animation.frames.entries()) { - const to_merge = {cameras: {}, locators: {}} - let frameFunc = ``; - for (const node of modifiedNodes) { - const transform = frame.node_transforms[node.uuid] - // Skip if the node doesn't have a transform for this frame. - if (!transform) continue - switch (node.type) { - case 'bone': - case 'text_display': - case 'item_display': - case 'block_display': { - const lastFrame = lastActiveFrame[node.uuid] - const isStepInterpolation = !!(lastFrame?.interpolation === 'step') - lastActiveFrame[node.uuid] = transform - - if (transform.interpolation === 'pre-post' || isStepInterpolation) { - frameFunc += - `\n$data merge entity $(${node.storage_name})%NEWLINE_PATCH%{` - + `transformation: ${matrixToNbtFloatArray(transform.matrix).toString()},` - + `start_interpolation: ${isStepInterpolation ? -1 : 0},` - + `interpolation_duration: ${isStepInterpolation ? 0 : interpolation_duration}` - + `}` - } else { - frameFunc += - `\n$data merge entity $(${node.storage_name})%NEWLINE_PATCH%{` - + `transformation: ${matrixToNbtFloatArray(transform.matrix).toString()},` - + `start_interpolation: 0,` - + `interpolation_duration: ${interpolation_duration}` - + `}` - } - ;hasFunction = true - break - } - case 'locator': { - const lastFrame = lastActiveFrame[node.uuid] - lastActiveFrame[node.uuid] = transform - ;if (!lastFrame || matrixToNbtFloatArray(transform.matrix).toString() !== matrixToNbtFloatArray(lastFrame.matrix).toString()) { - to_merge.locators[node.storage_name] = { - px: roundTo(transform.pos[0], 10), - py: roundTo(transform.pos[1], 10), - pz: roundTo(transform.pos[2], 10), - ry: roundTo(transform.head_rot[1], 10), - rx: roundTo(transform.head_rot[0], 10) - }; - } - - if (transform.function) { - if (node.config?.use_entity) { + <%% + // A record of node uuid to INodeTransform. + // Keeps track of the last time a bone was updated. + // Only used for step keyframe interpolation. + let hasFunction = false + const lastActiveFrame = {} + const modifiedNodes = Object.values(animation.modified_nodes).filter(n => n.type !== 'struct').sort(nodeSorter); + for (const [frameIndex, frame] of animation.frames.entries()) { + const to_merge = {cameras: {}, locators: {}} + let frameFunc = ``; + for (const node of modifiedNodes) { + const transform = frame.node_transforms[node.uuid] + // Skip if the node doesn't have a transform for this frame. + if (!transform) continue + switch (node.type) { + case 'bone': + case 'text_display': + case 'item_display': + case 'block_display': { + const lastFrame = lastActiveFrame[node.uuid] + const isStepInterpolation = !!(lastFrame?.interpolation === 'step') + lastActiveFrame[node.uuid] = transform + + if (transform.interpolation === 'pre-post' || isStepInterpolation) { frameFunc += - `\n$execute unless entity @s[tag=${TAGS.TRANSFORMS_ONLY()}] as $(${node.storage_name}) ` - + `positioned ^${roundTo(transform.pos[0], 10)} ^${roundTo(transform.pos[1], 10)} ^${roundTo(transform.pos[2], 10)} ` - + `rotated ~${roundTo(transform.head_rot[1], 10)} ~${roundTo(transform.head_rot[0], 10)} ` - + `${transform.function_execute_condition ? transform.function_execute_condition + ' ' : ''}run ` - + `block ${frameIndex}_locator_${node.storage_name}%NEWLINE_PATCH%{\n` - + `tp @s ~ ~ ~ ~ ~\n` - + `${transform.function}` - + `\n}` + `\n$data merge entity $(${node.storage_name})%NEWLINE_PATCH%{` + + `transformation: ${matrixToNbtFloatArray(transform.matrix).toString()},` + + `start_interpolation: ${isStepInterpolation ? -1 : 0},` + + `interpolation_duration: ${isStepInterpolation ? 0 : interpolation_duration}` + + `}` } else { frameFunc += - `\nexecute unless entity @s[tag=${TAGS.TRANSFORMS_ONLY()}] ` - + `positioned ^${roundTo(transform.pos[0], 10)} ^${roundTo(transform.pos[1], 10)} ^${roundTo(transform.pos[2], 10)} ` - + `rotated ~${roundTo(transform.head_rot[1], 10)} ~${roundTo(transform.head_rot[0], 10)} ` - + `${transform.function_execute_condition ? transform.function_execute_condition + ' ' : ''}run ` - + `block ${frameIndex}_locator_${node.storage_name}%NEWLINE_PATCH%{\n` - + `${transform.function}` - + `\n}` + `\n$data merge entity $(${node.storage_name})%NEWLINE_PATCH%{` + + `transformation: ${matrixToNbtFloatArray(transform.matrix).toString()},` + + `start_interpolation: 0,` + + `interpolation_duration: ${interpolation_duration}` + + `}` } + + ;hasFunction = true + break } - break - } - case 'camera': { - const lastFrame = lastActiveFrame[node.uuid] - lastActiveFrame[node.uuid] = transform - ;if (!lastFrame || matrixToNbtFloatArray(transform.matrix).toString() !== matrixToNbtFloatArray(lastFrame.matrix).toString()) { - to_merge.cameras[node.storage_name] = { - px: transform.pos[0], - py: transform.pos[1], - pz: transform.pos[2], - ry: transform.head_rot[1], - rx: transform.head_rot[0] - }; + case 'locator': { + const lastFrame = lastActiveFrame[node.uuid] + lastActiveFrame[node.uuid] = transform + ;if (!lastFrame || matrixToNbtFloatArray(transform.matrix).toString() !== matrixToNbtFloatArray(lastFrame.matrix).toString()) { + to_merge.locators[node.storage_name] = { + px: roundTo(transform.pos[0], 10), + py: roundTo(transform.pos[1], 10), + pz: roundTo(transform.pos[2], 10), + ry: roundTo(transform.head_rot[1], 10), + rx: roundTo(transform.head_rot[0], 10) + }; + } + + if (transform.function) { + if (node.config?.use_entity) { + frameFunc += + `\n$execute unless entity @s[tag=${TAGS.TRANSFORMS_ONLY()}] as $(${node.storage_name}) ` + + `positioned ^${roundTo(transform.pos[0], 10)} ^${roundTo(transform.pos[1], 10)} ^${roundTo(transform.pos[2], 10)} ` + + `rotated ~${roundTo(transform.head_rot[1], 10)} ~${roundTo(transform.head_rot[0], 10)} ` + + `${transform.function_execute_condition ? transform.function_execute_condition + ' ' : ''}run ` + + `block ${frameIndex}_locator_${node.storage_name}%NEWLINE_PATCH%{\n` + + `tp @s ~ ~ ~ ~ ~\n` + + `${transform.function}` + + `\n}` + } else { + frameFunc += + `\nexecute unless entity @s[tag=${TAGS.TRANSFORMS_ONLY()}] ` + + `positioned ^${roundTo(transform.pos[0], 10)} ^${roundTo(transform.pos[1], 10)} ^${roundTo(transform.pos[2], 10)} ` + + `rotated ~${roundTo(transform.head_rot[1], 10)} ~${roundTo(transform.head_rot[0], 10)} ` + + `${transform.function_execute_condition ? transform.function_execute_condition + ' ' : ''}run ` + + `block ${frameIndex}_locator_${node.storage_name}%NEWLINE_PATCH%{\n` + + `${transform.function}` + + `\n}` + } + } + break + } + case 'camera': { + const lastFrame = lastActiveFrame[node.uuid] + lastActiveFrame[node.uuid] = transform + ;if (!lastFrame || matrixToNbtFloatArray(transform.matrix).toString() !== matrixToNbtFloatArray(lastFrame.matrix).toString()) { + to_merge.cameras[node.storage_name] = { + px: transform.pos[0], + py: transform.pos[1], + pz: transform.pos[2], + ry: transform.head_rot[1], + rx: transform.head_rot[0] + }; + } + ;break } - ;break } } - } - if (Object.keys(to_merge.locators).length > 0 || Object.keys(to_merge.cameras).length > 0) { - frameFunc += `\ndata modify storage <%temp_storage%> entry.data merge value ${JSON.stringify(to_merge)}` - frameFunc += `\ndata_manager write` - if (!auto_update_rig_orientation) { - frameFunc += `\nfunction ${blueprint_id}/root/on_tick/transform_floating_entities` + if (Object.keys(to_merge.locators).length > 0 || Object.keys(to_merge.cameras).length > 0) { + frameFunc += `\ndata modify storage <%temp_storage%> entry.data merge value ${JSON.stringify(to_merge)}` + frameFunc += `\ndata_manager write` + if (!auto_update_rig_orientation) { + frameFunc += `\nfunction ${blueprint_id}/root/on_tick/transform_floating_entities` + } + hasFunction = true } - hasFunction = true - } - if (frame.variants?.length) { - const variant = rig.variants[frame.variants[0]] - if (!variant) { - throw new Error(`Could not find Variant with uuid "${frame.variants[0]}" while generating frame "${frameIndex}" of animation "${animation.name}".`) + if (frame.variants?.length) { + const variant = rig.variants[frame.variants[0]] + if (!variant) { + throw new Error(`Could not find Variant with uuid "${frame.variants[0]}" while generating frame "${frameIndex}" of animation "${animation.name}".`) + } + const execute_condition = frame.variants_execute_condition ? frame.variants_execute_condition + ' ' : '' + frameFunc += `\nexecute unless entity @s[tag=${TAGS.TRANSFORMS_ONLY()}] ${execute_condition}run function ${blueprint_id}/variants/${variant.name}/apply` + ;hasFunction = true } - const execute_condition = frame.variants_execute_condition ? frame.variants_execute_condition + ' ' : '' - frameFunc += `\nexecute unless entity @s[tag=${TAGS.TRANSFORMS_ONLY()}] ${execute_condition}run function ${blueprint_id}/variants/${variant.name}/apply` - ;hasFunction = true - } - // Root function keyframes. - if (frame.function) { - const execute_condition = frame.function_execute_condition ? frame.function_execute_condition + ' ' : '' - frameFunc += `\nexecute unless entity @s[tag=${TAGS.TRANSFORMS_ONLY()}] at @s ${execute_condition}run block ${frameIndex}_root_function%NEWLINE_PATCH%{\n${frame.function}\n}` - ;hasFunction = true - } - ;if (frameFunc.length > 0) { - frameFunc = `function ${frameIndex}%NEWLINE_PATCH%{${frameFunc}\n}` - emit.mcb(frameFunc.replaceAll(/%NEWLINE_PATCH%\n?/g, ' ')) + // Root function keyframes. + if (frame.function) { + const execute_condition = frame.function_execute_condition ? frame.function_execute_condition + ' ' : '' + frameFunc += `\nexecute unless entity @s[tag=${TAGS.TRANSFORMS_ONLY()}] at @s ${execute_condition}run block ${frameIndex}_root_function%NEWLINE_PATCH%{\n${frame.function}\n}` + ;hasFunction = true + } + ;if (frameFunc.length > 0) { + frameFunc = `function ${frameIndex}%NEWLINE_PATCH%{${frameFunc}\n}` + emit.mcb(frameFunc.replaceAll(/%NEWLINE_PATCH%\n?/g, ' ')) + } } - } - %%> + %%> + } } } } } - } - function pause_all { - # Pauses all animations - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> + function pause_all { + # Pauses all animations + debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - REPEAT (animations) as animation { - tag @s remove <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%> + REPEAT (animations) as animation { + tag @s remove <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%> + } } } } function summon { - #Args: {args:{variant: string, animation: string, frame: int, start_animation: boolean}} + #Args: {args:{variant?: string, animation?: string, frame?: int, start_animation?: boolean}} # frame is ignored unless animation is specified. - data modify storage <%temp_storage%> args set value {variant:'', animation:'', frame: 0} $execute store success score #success <%OBJECTIVES.I()%> run data modify storage <%temp_storage%> args set value $(args) + IF (!has_animations && debug_mode) { + execute if data storage <%temp_storage%> args.animation run return run \ + tellraw @a <%TELLRAW.ANIMATION_ARG_NO_RIG_ANIMATIONS()%> + execute if data storage <%temp_storage%> args.frame run return run \ + tellraw @a <%TELLRAW.FRAME_ARG_NO_RIG_FRAMES()%> + } + summon minecraft:item_display ~ ~ ~ { \ Tags:[ \ '<%TAGS.NEW()%>', \ @@ -591,7 +605,7 @@ function summon { type=<%locator.config.entity_type%>, \ tag=<%TAGS.PROJECT_LOCATOR_NAMED(blueprint_id, locator.storage_name)%>, \ tag=<%TAGS.NEW()%>, \ - distance=..<%Math.ceil(locator.max_distance)%> \ + distance=..<%Math.ceil(locator.max_distance + 0.5)%> \ ] \ run block as_locator/<%locator.storage_name%> { # run block ../as_locator/<%locator.storage_name%> { @@ -616,7 +630,7 @@ function summon { type=minecraft:item_display, \ tag=<%TAGS.PROJECT_CAMERA_NAMED(blueprint_id, camera.storage_name)%>, \ tag=<%TAGS.NEW()%>, \ - distance=..<%Math.ceil(camera.max_distance)%> \ + distance=..<%Math.ceil(camera.max_distance + 0.5)%> \ ] \ run block as_camera/<%camera.storage_name%> { # run block ../as_camera/<%camera.storage_name%> { @@ -692,52 +706,54 @@ function summon { } execute if score #success <%OBJECTIVES.I()%> matches 0 run return fail - # Animation Argument - # If the animation argument is provided, attempt to apply the animation. - execute if data storage <%temp_storage%> args.animation run block animation_arg/process { with storage <%temp_storage%> args - scoreboard players set #success <%OBJECTIVES.I()%> 0 - # If the animation argument is *explicitly* set to an empty string, return an error. - execute if data storage <%temp_storage%> {args:{animation:''}} run return run block if_empty { - tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('animation')%> - function <%blueprint_id%>/remove/this/without_on_remove_function - } - # Automatically set the frame argument to 0 if the frame argument is not provided. - # Takes advantage of `store result score` setting the score to 0 if the command fails. - execute \ - store result storage <%temp_storage%> args.frame int 1 \ - store result score #frame <%OBJECTIVES.I()%> \ - run \ - data get storage <%temp_storage%> args.frame - # If the frame argument is negative, return an error. - execute if score #frame <%OBJECTIVES.I()%> matches ..-1 run return run block no_negative { - # Tell the user that the frame argument cannot be negative. - tellraw @a <%TELLRAW.FRAME_CANNOT_BE_NEGATIVE()%> - function <%blueprint_id%>/remove/this/without_on_remove_function - } - # Attempt to apply the animation frame. - execute store success score #success <%OBJECTIVES.I()%> run block try_set_frame { with storage <%temp_storage%> args - # Make sure we're only applying transforms when setting the summon pose. - tag @s add <%TAGS.TRANSFORMS_ONLY()%> - $execute store success score #success <%OBJECTIVES.I()%> run function <%blueprint_id%>/animations/$(animation)/zzz/set_frame with storage <%temp_storage%> args - tag @s remove <%TAGS.TRANSFORMS_ONLY()%> - execute if score #success <%OBJECTIVES.I()%> matches 1 run return 1 - # If the set_frame function fails, the animation doesn't exist, so we return an error. - return fail - } - # If the set_frame function failed, return an error. - execute unless score #success <%OBJECTIVES.I()%> matches 1 run return run block invalid_animation { - # Tell the user that the provided animation doesn't exist, remove the rig, and list all available animations for this rig. - tellraw @a <%TELLRAW.INVALID_ANIMATION(animations)%> - function <%blueprint_id%>/remove/this/without_on_remove_function - } + IF (has_animations) { + # Animation Argument + # If the animation argument is provided, attempt to apply the animation. + execute if data storage <%temp_storage%> args.animation run block animation_arg/process { with storage <%temp_storage%> args + scoreboard players set #success <%OBJECTIVES.I()%> 0 + # If the animation argument is *explicitly* set to an empty string, return an error. + execute if data storage <%temp_storage%> {args:{animation:''}} run return run block if_empty { + tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('animation')%> + function <%blueprint_id%>/remove/this/without_on_remove_function + } + # Automatically set the frame argument to 0 if the frame argument is not provided. + # Takes advantage of `store result score` setting the score to 0 if the command fails. + execute \ + store result storage <%temp_storage%> args.frame int 1 \ + store result score #frame <%OBJECTIVES.I()%> \ + run \ + data get storage <%temp_storage%> args.frame + # If the frame argument is negative, return an error. + execute if score #frame <%OBJECTIVES.I()%> matches ..-1 run return run block no_negative { + # Tell the user that the frame argument cannot be negative. + tellraw @a <%TELLRAW.FRAME_CANNOT_BE_NEGATIVE()%> + function <%blueprint_id%>/remove/this/without_on_remove_function + } + # Attempt to apply the animation frame. + execute store success score #success <%OBJECTIVES.I()%> run block try_set_frame { with storage <%temp_storage%> args + # Make sure we're only applying transforms when setting the summon pose. + tag @s add <%TAGS.TRANSFORMS_ONLY()%> + $execute store success score #success <%OBJECTIVES.I()%> run function <%blueprint_id%>/animations/$(animation)/zzz/set_frame with storage <%temp_storage%> args + tag @s remove <%TAGS.TRANSFORMS_ONLY()%> + execute if score #success <%OBJECTIVES.I()%> matches 1 run return 1 + # If the set_frame function fails, the animation doesn't exist, so we return an error. + return fail + } + # If the set_frame function failed, return an error. + execute unless score #success <%OBJECTIVES.I()%> matches 1 run return run block invalid_animation { + # Tell the user that the provided animation doesn't exist, remove the rig, and list all available animations for this rig. + tellraw @a <%TELLRAW.INVALID_ANIMATION(animations)%> + function <%blueprint_id%>/remove/this/without_on_remove_function + } - # If the animation is successfully applied, and the start_animation argument is set to true, start the animation. - execute if data storage <%temp_storage%> {args:{start_animation: true}} run block start_animation { with storage <%temp_storage%> args - $function <%blueprint_id%>/animations/$(animation)/resume + # If the animation is successfully applied, and the start_animation argument is set to true, start the animation. + execute if data storage <%temp_storage%> {args:{start_animation: true}} run block start_animation { with storage <%temp_storage%> args + $function <%blueprint_id%>/animations/$(animation)/resume + } + scoreboard players set #success <%OBJECTIVES.I()%> 1 } - scoreboard players set #success <%OBJECTIVES.I()%> 1 + execute if score #success <%OBJECTIVES.I()%> matches 0 run return fail } - execute if score #success <%OBJECTIVES.I()%> matches 0 run return fail IF (has_locators || has_cameras) { function <%blueprint_id%>/root/on_tick/transform_floating_entities @@ -1321,20 +1337,22 @@ IF (has_locators || has_cameras) { } dir zzz { - function apply_default_pose { - IF (has_locators || has_cameras) { - function ../zzz/reset_floating_entities - } + IF (has_animations) { + function apply_default_pose { + IF (has_locators || has_cameras) { + function ../zzz/reset_floating_entities + } - REPEAT (Object.values(rig.nodes).filter(node => BONE_TYPES.includes(node.type))) as node { - execute \ - on passengers \ - if entity @s[tag=<%TAGS.PROJECT_NODE_NAMED(blueprint_id, node.storage_name)%>] \ - run \ - data merge entity @s { \ - transformation: <%matrixToNbtFloatArray(node.default_transform.matrix).toString()%>, \ - start_interpolation: 0 \ - } + REPEAT (Object.values(rig.nodes).filter(node => BONE_TYPES.includes(node.type))) as node { + execute \ + on passengers \ + if entity @s[tag=<%TAGS.PROJECT_NODE_NAMED(blueprint_id, node.storage_name)%>] \ + run \ + data merge entity @s { \ + transformation: <%matrixToNbtFloatArray(node.default_transform.matrix).toString()%>, \ + start_interpolation: 0 \ + } + } } } @@ -1356,14 +1374,16 @@ dir zzz { } } -function apply_default_pose { - # Changes the pose of the rig to the the default pose with interpolation - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> +IF (has_animations) { + function apply_default_pose { + # Changes the pose of the rig to the the default pose with interpolation + debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - IF (has_locators || has_cameras) { - data_manager prep read + IF (has_locators || has_cameras) { + data_manager prep read + } + function ./zzz/apply_default_pose } - function ./zzz/apply_default_pose } function set_default_pose { diff --git a/src/systems/datapackCompiler/1.21.2/static.mcb b/src/systems/datapackCompiler/1.21.2/static.mcb deleted file mode 100644 index 79b96d9b..00000000 --- a/src/systems/datapackCompiler/1.21.2/static.mcb +++ /dev/null @@ -1,867 +0,0 @@ -# TODO - Move all internal functions into an internal namespace, and only have user-facing functions in the main `animated_java:<%export_namespace%>` namespace. - -# DIFFERENCES FROM 1.21.0: -# - /rotate command - -function on_load { - data modify storage <%project_storage%> rig_hash set value <%"'" + rig_hash + "'"%> -} - -dir root { - function on_tick { - # Custom pre-tick function - IF (on_pre_tick_function) { - <%% - emit.mcb(on_pre_tick_function) - %%> - } - - IF (auto_update_rig_orientation) { - IF (has_locators || has_cameras) { - function <%blueprint_id%>/root/on_tick/transform_floating_entities - } - execute on passengers run rotate @s ~ ~ - } ELSE IF (has_ticking_locators) { - function <%blueprint_id%>/root/on_tick/transform_locators - } - - # Custom post-tick function - IF (on_post_tick_function) { - <%% - emit.mcb(on_post_tick_function) - %%> - } - } - - IF (has_locators || has_cameras) { - dir on_tick { - function transform_locators { - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'locator')) as locator { - block select_locator_<%locator.storage_name%> { with storage <%temp_storage%> entry.data.locators.<%locator.storage_name%> - IF (locator.config?.use_entity) { - $execute \ - as $(uuid) \ - positioned ^$(px) ^$(py) ^$(pz) \ - rotated ~$(ry) ~$(rx) \ - run block as_locator_<%locator.storage_name%> { - tp @s ~ ~ ~ ~ ~ - - IF (locator.config?.sync_passenger_rotation) { - execute on passengers run rotate @s ~ ~ - } - - IF (locator.config?.on_tick_function) { - <%% - emit.mcb(locator.config.on_tick_function) - %%> - } - } - } ELSE IF (locator.config?.on_tick_function) { - $execute \ - positioned ^$(px) ^$(py) ^$(pz) \ - rotated ~$(ry) ~$(rx) \ - run block at_locator_<%locator.storage_name%> { - <%% - emit.mcb(locator.config.on_tick_function) - %%> - } - } - } - } - } - - function transform_floating_entities { - function ./transform_locators - - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'camera')) as camera { - block select_camera_<%camera.storage_name%> { with storage <%temp_storage%> entry.data.cameras.<%camera.storage_name%> - $execute \ - as $(uuid) \ - positioned ^$(px) ^$(py) ^$(pz) \ - rotated ~$(ry) ~$(rx) \ - run tp @s ~ ~ ~ ~ ~ - } - } - } - } - } -} - -IF (!auto_update_rig_orientation) { - function move { - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - - tp @s ~ ~ ~ ~ ~ - - IF (has_locators || has_cameras) { - data_manager prep read - function <%blueprint_id%>/root/on_tick/transform_floating_entities - } - execute at @s on passengers run rotate @s ~ ~ - } -} ELSE { - function move { - tellraw @a <%TELLRAW.AUTO_UPDATE_RIG_ORIENTATION_MOVE_WARNING()%> - } -} - -function summon { - #Args: {args:{variant: string}} - - data modify storage <%temp_storage%> args set value {variant:''} - $execute store success score #success <%OBJECTIVES.I()%> run data modify storage <%temp_storage%> args set value $(args) - - summon minecraft:item_display ~ ~ ~ { \ - Tags:[ \ - '<%TAGS.NEW()%>', \ - '<%TAGS.GLOBAL_ENTITY()%>', \ - '<%TAGS.GLOBAL_ROOT()%>', \ - '<%TAGS.PROJECT_ENTITY(blueprint_id)%>', \ - '<%TAGS.PROJECT_ROOT(blueprint_id)%>' \ - ], \ - teleport_duration: 0, \ - interpolation_duration: <%interpolation_duration%>, \ - Passengers:<%root_entity_passengers%>, \ - CustomName: '<%ENTITY_NAMES.ROOT(blueprint_id)%>', \ - } - execute as @n[ \ - type=minecraft:item_display, \ - tag=<%TAGS.PROJECT_ROOT(blueprint_id)%>, \ - tag=<%TAGS.NEW()%>, \ - distance=..0.01 \ - ] run block zzz/summon/as_root_entity { - execute store result score @s <%OBJECTIVES.ID()%> run scoreboard players add aj.last_id <%OBJECTIVES.ID()%> 1 - - data_manager init prep read - # Data manager init runs gu:get_entity_uuid_string. So we don't need to call it again here. - # function animated_java:global/gu/get_entity_uuid_string - data modify storage <%temp_storage%> entry.data.uuids append from storage <%gu_storage%> out - data modify storage <%temp_storage%> entry.data.root_uuid set from storage <%gu_storage%> out - - data modify storage <%temp_storage%> entry.data.blueprint_id set value "<%blueprint_id%>" - data modify storage <%temp_storage%> entry.data.rig_hash set value "<%rig_hash%>" - - # Align the position and rotation of the root with the command context. - tp @s ~ ~ ~ ~ ~ - - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'locator' && node.config?.use_entity)) as locator { - summon <%locator.config.entity_type%> \ - ^<%roundTo(locator.default_transform.pos[0], 10)%> \ - ^<%roundTo(locator.default_transform.pos[1], 10)%> \ - ^<%roundTo(locator.default_transform.pos[2], 10)%> \ - {Tags:<%getNodeTags(locator, rig)%>} - execute \ - as @n[ \ - type=<%locator.config.entity_type%>, \ - tag=<%TAGS.PROJECT_LOCATOR_NAMED(blueprint_id, locator.storage_name)%>, \ - tag=<%TAGS.NEW()%>, \ - distance=..<%Math.ceil(locator.max_distance)%> \ - ] \ - run block as_locator/<%locator.storage_name%> { - # run block ../as_locator/<%locator.storage_name%> { - tag @s remove <%TAGS.NEW()%> - data modify entity @s CustomName set value '<%ENTITY_NAMES.NODE(blueprint_id, locator.type, locator.storage_name)%>' - function animated_java:global/gu/get_entity_uuid_string - scoreboard players operation @s <%OBJECTIVES.ID()%> = aj.last_id <%OBJECTIVES.ID()%> - } - data modify storage <%temp_storage%> entry.data.uuids append from storage <%gu_storage%> out - data modify storage <%temp_storage%> entry.data.uuids_by_name.<%locator.storage_name%> set from storage <%gu_storage%> out - data modify storage <%temp_storage%> entry.data.locators.<%locator.storage_name%>.uuid set from storage <%gu_storage%> out - } - - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'camera')) as camera { - summon minecraft:item_display \ - ^<%roundTo(camera.default_transform.pos[0], 10)%> \ - ^<%roundTo(camera.default_transform.pos[1], 10)%> \ - ^<%roundTo(camera.default_transform.pos[2], 10)%> \ - {Tags:<%getNodeTags(camera, rig)%>, teleport_duration: 2} - execute \ - as @n[ \ - type=minecraft:item_display, \ - tag=<%TAGS.PROJECT_CAMERA_NAMED(blueprint_id, camera.storage_name)%>, \ - tag=<%TAGS.NEW()%>, \ - distance=..<%Math.ceil(camera.max_distance)%> \ - ] \ - run block as_camera/<%camera.storage_name%> { - # run block ../as_camera/<%camera.storage_name%> { - tag @s remove <%TAGS.NEW()%> - data modify entity @s CustomName set value '<%ENTITY_NAMES.NODE(blueprint_id, camera.type, camera.storage_name)%>' - function animated_java:global/gu/get_entity_uuid_string - scoreboard players operation @s <%OBJECTIVES.ID()%> = aj.last_id <%OBJECTIVES.ID()%> - } - data modify storage <%temp_storage%> entry.data.uuids append from storage <%gu_storage%> out - data modify storage <%temp_storage%> entry.data.uuids_by_name.<%camera.storage_name%> set from storage <%gu_storage%> out - data modify storage <%temp_storage%> entry.data.cameras.<%camera.storage_name%>.uuid set from storage <%gu_storage%> out - } - - REPEAT (Object.values(rig.nodes).filter(node => BONE_TYPES.includes(node.type))) as node { - execute \ - on passengers \ - if entity @s[tag=<%TAGS.PROJECT_NODE_NAMED(blueprint_id, node.storage_name)%>] \ - run block as_node/<%node.storage_name%> { - data modify entity @s CustomName set value '<%ENTITY_NAMES.NODE(blueprint_id, node.type, node.storage_name)%>' - function animated_java:global/gu/get_entity_uuid_string - scoreboard players operation @s <%OBJECTIVES.ID()%> = aj.last_id <%OBJECTIVES.ID()%> - } - - data modify storage <%temp_storage%> entry.data.uuids append from storage <%gu_storage%> out - data modify storage <%temp_storage%> entry.data.uuids_by_name.<%node.storage_name%> set from storage <%gu_storage%> out - } - - IF (has_entity_locators) { - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'locator' && node.config?.use_entity)) as locator { - block { with storage <%temp_storage%> entry.data.locators.<%locator.storage_name%> - # Track any custom entities on the locator. - $execute at @s as $(uuid) at @s run function animated_java:global/util/get_entity_stack_uuids - } - data modify storage <%temp_storage%> entry.data.uuids append from storage <%temp_storage%> uuids - } - } - - function <%blueprint_id%>/zzz/set_default_pose - - data_manager write - - # Variant Arguement - IF (Object.keys(rig.variants).length > 1) { - execute if data storage <%temp_storage%> args.variant run block variant_arg/process { with storage <%temp_storage%> args - scoreboard players set #success <%OBJECTIVES.I()%> 0 - # If the variant argument is *explicitly* set to an empty string, return an error. - execute if data storage <%temp_storage%> {args:{variant:''}} run return run block if_empty { - # Tell the user that the variant cannot be empty. - tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('variant')%> - function <%blueprint_id%>/remove/this/without_on_remove_function - } - # Attempt to apply the requested variant. - # We get the success of the `try_apply` function in just in case the user's arguments are *very* wrong. - execute store success score #success <%OBJECTIVES.I()%> run block try_apply { with storage <%temp_storage%> args - $execute if function <%blueprint_id%>/variants/$(variant)/apply run return 1 - # If the apply function fails, the variant doesn't exist, so we return an error. - return fail - } - # If the apply function failed, return an error. - execute unless score #success <%OBJECTIVES.I()%> matches 1 run return run block invalid_variant { - # Tell the user that the provided variant doesn't exist, remove the rig, and list all available variants for this rig. - tellraw @a <%TELLRAW.INVALID_VARIANT(rig.variants)%> - function <%blueprint_id%>/remove/this/without_on_remove_function - } - scoreboard players set #success <%OBJECTIVES.I()%> 1 - } - } ELSE { - execute if data storage <%temp_storage%> args.variant run block zzz/variant_arg/no_variants_warning { - tellraw @a <%TELLRAW.NO_VARIANTS()%> - function <%blueprint_id%>/remove/this/without_on_remove_function - scoreboard players set #success <%OBJECTIVES.I()%> 0 - } - } - execute if score #success <%OBJECTIVES.I()%> matches 0 run return fail - - IF (has_locators || has_cameras) { - function <%blueprint_id%>/root/on_tick/transform_floating_entities - } - execute on passengers run rotate @s ~ ~ - - # Apply teleport duration - data modify entity @s teleport_duration set value <%teleportation_duration%> - execute on passengers run data modify entity @s teleport_duration set value <%teleportation_duration%> - - IF (has_entity_locators) { - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'locator' && node.config?.use_entity && node.config.on_summon_function)) as locator { - block { with storage <%temp_storage%> entry.data.locators.<%locator.storage_name%> - $execute at @s as $(uuid) at @s run block on_summon/custom_<%locator.type + '_' + locator.storage_name%> { - <%% - emit.mcb(locator.config.on_summon_function) - %%> - } - } - } - } - - REPEAT (Object.values(rig.nodes).filter(node => BONE_TYPES.includes(node.type) && node.on_summon_function?.trim())) as node { - execute \ - on passengers if entity @s[tag=<%TAGS.PROJECT_NODE_NAMED(blueprint_id, node.storage_name)%>] \ - run block on_summon/<%node.type + '_' + node.storage_name%> { - <%% - emit.mcb(node.on_summon_function.trim()) - %%> - } - } - - IF (on_summon_function) { - execute at @s run block on_summon/rig { - <%% - emit.mcb(on_summon_function) - %%> - } - } - - # Remove the NEW tag from the root entity, and it's passengers. - tag @s remove <%TAGS.NEW()%> - execute on passengers run tag @s remove <%TAGS.NEW()%> - } -} - -function as_node { - #ARGS: {name: string, command: string} - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - data remove storage <%temp_storage%> args - $data modify storage <%temp_storage%> args merge value {name:'$(name)', command:'$(command)', uuid:'+MISSING_UUID+'} - - IF (debug_mode) { - execute if data storage <%temp_storage%> {args:{name:''}} run return run tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('name')%> - execute if data storage <%temp_storage%> {args:{command:''}} run return run tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('command')%> - } - - data_manager prep read - - block zzz/as_node/as_data { with storage <%temp_storage%> args - $data modify storage <%temp_storage%> args.uuid set from storage <%temp_storage%> entry.data.uuids_by_name.$(name) - IF (debug_mode) { - scoreboard players set #aj.check <%OBJECTIVES.I()%> 0 - } - block execute_as_uuid { with storage <%temp_storage%> args - IF (debug_mode) { - # If the function successfully instantiated, the provided command is valid. - scoreboard players set #aj.check <%OBJECTIVES.I()%> 1 - } - $execute as $(uuid) run return run $(command) - IF (debug_mode) { - # If the entity with the provided UUID doesn't exist, the node wasn't found. - tellraw @a <%TELLRAW.NODE_ENTITY_NOT_FOUND()%> - } - } - IF (debug_mode) { - execute if score #aj.check <%OBJECTIVES.I()%> matches 0 run tellraw @a <%TELLRAW.NODE_COMMAND_FAILED_TO_EXECUTE()%> - } - } -} - -IF (has_entity_locators) { - function as_locator { - #ARGS: {name: string, command: string} - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - - data remove storage <%temp_storage%> args - $data modify storage <%temp_storage%> args merge value {name:'$(name)', command:'$(command)', uuid:'+MISSING_UUID+'} - - IF (debug_mode) { - execute if data storage <%temp_storage%> {args:{name:''}} run return run tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('name')%> - execute if data storage <%temp_storage%> {args:{command:''}} run return run tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('command')%> - } - - data_manager prep read - - block zzz/as_locator/as_data { with storage <%temp_storage%> args - $data modify storage <%temp_storage%> args.uuid set from storage <%temp_storage%> entry.data.locators.$(name).uuid - IF (debug_mode) { - scoreboard players set #aj.check <%OBJECTIVES.I()%> 0 - } - block execute_as_uuid { with storage <%temp_storage%> args - IF (debug_mode) { - # If the function successfully instantiated, the provided command is valid. - scoreboard players set #aj.check <%OBJECTIVES.I()%> 1 - } - $execute as $(uuid) run return run $(command) - IF (debug_mode) { - # If the entity with the provided UUID doesn't exist, the locator wasn't found. - tellraw @a <%TELLRAW.LOCATOR_ENTITY_NOT_FOUND()%> - } - } - IF (debug_mode) { - execute if score #aj.check <%OBJECTIVES.I()%> matches 0 run tellraw @a <%TELLRAW.LOCATOR_COMMAND_FAILED_TO_EXECUTE()%> - } - } - } - - function as_at_locator { - #ARGS: {name: string, command: string} - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - - data remove storage <%temp_storage%> args - $data modify storage <%temp_storage%> args merge value {name:'$(name)', command:'$(command)', uuid:'+MISSING_UUID+'} - - IF (debug_mode) { - execute if data storage <%temp_storage%> {args:{name:''}} run return run tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('name')%> - execute if data storage <%temp_storage%> {args:{command:''}} run return run tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('command')%> - } - - data_manager prep read - - block zzz/as_locator/as_data { with storage <%temp_storage%> args - $data modify storage <%temp_storage%> args.uuid set from storage <%temp_storage%> entry.data.locators.$(name).uuid - IF (debug_mode) { - scoreboard players set #aj.check <%OBJECTIVES.I()%> 0 - } - block execute_as_uuid { with storage <%temp_storage%> args - IF (debug_mode) { - # If the function successfully instantiated, the provided command is valid. - scoreboard players set #aj.check <%OBJECTIVES.I()%> 1 - } - $execute as $(uuid) at @s run return run $(command) - IF (debug_mode) { - # If the entity with the provided UUID doesn't exist, the locator wasn't found. - tellraw @a <%TELLRAW.LOCATOR_ENTITY_NOT_FOUND()%> - } - } - IF (debug_mode) { - execute if score #aj.check <%OBJECTIVES.I()%> matches 0 run tellraw @a <%TELLRAW.LOCATOR_COMMAND_FAILED_TO_EXECUTE()%> - } - } - } - - function as_all_locators { - #ARGS: {command: string} - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - - data remove storage <%temp_storage%> args - $data modify storage <%temp_storage%> args merge value {command:'$(command)'} - - IF (debug_mode) { - execute if data storage <%temp_storage%> {args:{command:''}} run return run tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('command')%> - } - - data_manager prep read - - block zzz/as_all_locators/as_data { - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'locator' && node.config?.use_entity)) as locator { - data modify storage <%temp_storage%> args.uuid set from storage <%temp_storage%> entry.data.locators.<%locator.storage_name%>.uuid - - IF (debug_mode) { - scoreboard players set #aj.check <%OBJECTIVES.I()%> 0 - } - - block execute_as_uuid { with storage <%temp_storage%> args - IF (debug_mode) { - # If the function successfully instantiated, the provided command is valid. - scoreboard players set #aj.check <%OBJECTIVES.I()%> 1 - } - - $execute as $(uuid) run return run $(command) - } - - IF (debug_mode) { - execute if score #aj.check <%OBJECTIVES.I()%> matches 0 run tellraw @a <%TELLRAW.LOCATOR_COMMAND_FAILED_TO_EXECUTE({text: locator.storage_name, color: 'aqua'})%> - } - } - } - } - - function as_at_all_locators { - #ARGS: {command: string} - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - - data remove storage <%temp_storage%> args - $data modify storage <%temp_storage%> args merge value {command:'$(command)'} - - IF (debug_mode) { - execute if data storage <%temp_storage%> {args:{command:''}} run return run tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('command')%> - } - - data_manager prep read - - block zzz/as_all_locators/as_data { - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'locator' && node.config?.use_entity)) as locator { - data modify storage <%temp_storage%> args.uuid set from storage <%temp_storage%> entry.data.locators.<%locator.storage_name%>.uuid - - IF (debug_mode) { - scoreboard players set #aj.check <%OBJECTIVES.I()%> 0 - } - - block execute_as_uuid { with storage <%temp_storage%> args - IF (debug_mode) { - # If the function successfully instantiated, the provided command is valid. - scoreboard players set #aj.check <%OBJECTIVES.I()%> 1 - } - - $execute as $(uuid) at @s run return run $(command) - } - - IF (debug_mode) { - execute if score #aj.check <%OBJECTIVES.I()%> matches 0 run tellraw @a <%TELLRAW.LOCATOR_COMMAND_FAILED_TO_EXECUTE({text: locator.storage_name, color: 'aqua'})%> - } - } - } - } -} - -IF (has_locators) { - function at_locator { - #ARGS: {name: string, command: string} - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - - data remove storage <%temp_storage%> args - $data modify storage <%temp_storage%> args merge value {name:'$(name)', command:'$(command)'} - - IF (debug_mode) { - execute if data storage <%temp_storage%> {args:{name:''}} run return run tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('name')%> - execute if data storage <%temp_storage%> {args:{command:''}} run return run tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('command')%> - } - - data_manager prep read - - execute at @s run block zzz/at_locator/as_data { with storage <%temp_storage%> args - $data modify storage <%temp_storage%> args merge from storage <%temp_storage%> entry.data.locators.$(name) - - IF (debug_mode) { - execute unless data storage <%temp_storage%> args.px run return run tellraw @a <%TELLRAW.LOCATOR_NOT_FOUND()%> - scoreboard players set #aj.check <%OBJECTIVES.I()%> 0 - } - - block execute_at_transform { with storage <%temp_storage%> args - IF (debug_mode) { - # If the function successfully instantiated, the provided command is valid. - scoreboard players set #aj.check <%OBJECTIVES.I()%> 1 - } - - $execute \ - positioned ^$(px) ^$(py) ^$(pz) \ - rotated ~$(ry) ~$(rx) \ - run $(command) - } - - IF (debug_mode) { - execute if score #aj.check <%OBJECTIVES.I()%> matches 0 run tellraw @a <%TELLRAW.LOCATOR_COMMAND_FAILED_TO_EXECUTE()%> - } - } - } - - function at_all_locators { - #ARGS: {command: string} - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - - data remove storage <%temp_storage%> args - $data modify storage <%temp_storage%> args merge value {command:'$(command)'} - - IF (debug_mode) { - execute if data storage <%temp_storage%> {args:{command:''}} run return run tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('command')%> - } - - data_manager prep read - - block zzz/at_all_locators/as_data { - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'locator')) as locator { - data modify storage <%temp_storage%> args merge from storage <%temp_storage%> entry.data.locators.<%locator.storage_name%> - - IF (debug_mode) { - scoreboard players set #aj.check <%OBJECTIVES.I()%> 0 - } - - block execute_at_transform { with storage <%temp_storage%> args - IF (debug_mode) { - # If the function successfully instantiated, the provided command is valid. - scoreboard players set #aj.check <%OBJECTIVES.I()%> 1 - } - - $execute \ - positioned ^$(px) ^$(py) ^$(pz) \ - rotated ~$(ry) ~$(rx) \ - run $(command) - } - - IF (debug_mode) { - execute if score #aj.check <%OBJECTIVES.I()%> matches 0 run tellraw @a <%TELLRAW.LOCATOR_COMMAND_FAILED_TO_EXECUTE({text: locator.storage_name, color: 'aqua'})%> - } - } - } - } -} - -IF (has_cameras) { - function as_camera { - #ARGS: {name: string, command: string} - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - - data remove storage <%temp_storage%> args - $data modify storage <%temp_storage%> args merge value {name:'$(name)', command:'$(command)', uuid:'+MISSING_UUID+'} - - IF (debug_mode) { - execute if data storage <%temp_storage%> {args:{name:''}} run return run tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('name')%> - execute if data storage <%temp_storage%> {args:{command:''}} run return run tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('command')%> - } - - data_manager prep read - - block zzz/as_camera/as_data { with storage <%temp_storage%> args - $data modify storage <%temp_storage%> args.uuid set from storage <%temp_storage%> entry.data.cameras.$(name).uuid - - IF (debug_mode) { - scoreboard players set #aj.check <%OBJECTIVES.I()%> 0 - } - - block execute_as_uuid { with storage <%temp_storage%> args - IF (debug_mode) { - # If the function successfully instantiated, the provided command is valid. - scoreboard players set #aj.check <%OBJECTIVES.I()%> 1 - } - - $execute as $(uuid) at @s run return run $(command) - - IF (debug_mode) { - # If the entity with the provided UUID doesn't exist, the camera wasn't found. - tellraw @a <%TELLRAW.CAMERA_ENTITY_NOT_FOUND()%> - } - } - - IF (debug_mode) { - execute if score #aj.check <%OBJECTIVES.I()%> matches 0 run tellraw @a <%TELLRAW.CAMERA_COMMAND_FAILED_TO_EXECUTE()%> - } - } - } -} - -function as_root { - #ARGS: {command: string} - execute unless score @s <%OBJECTIVES.ID()%> matches <%-(2**31)%>..<%(2**31)-1%> run return run \ - tellraw @a <%TELLRAW.FUNCTION_NOT_EXECUTED_AS_ENTITY_WITH_ID_SCORE(context.functions.at(-1))%> - - data_manager prep read - - $data modify storage <%temp_storage%> args.command set value '$(command)' - data modify storage <%temp_storage%> args.root_uuid set from storage <%temp_storage%> entry.data.root_uuid - - IF (debug_mode) { - scoreboard players set #aj.check <%OBJECTIVES.I()%> 0 - } - block as_root_entity { with storage <%temp_storage%> args - $execute as $(root_uuid) run $(command) - IF (debug_mode) { - # If the function successfully instantiated, the provided command is valid. - scoreboard players set #aj.check <%OBJECTIVES.I()%> 1 - } - } - IF (debug_mode) { - execute if score #aj.check <%OBJECTIVES.I()%> matches 0 run tellraw @a <%TELLRAW.ROOT_COMMAND_FAILED_TO_EXECUTE()%> - } - -} - -dir remove { - function all { - # Removes all instances of this rig from the world. - execute as @e[type=minecraft:item_display,tag=<%TAGS.PROJECT_ROOT(blueprint_id)%>] run function <%blueprint_id%>/remove/this - } - - function entities { - # Removes all entities related to this rig from the world. - kill @e[tag=<%TAGS.PROJECT_ENTITY(blueprint_id)%>] - } - - function this { - # Removes the rig this function is executed as. - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - - <%% - if (on_remove_function) emit.mcb(on_remove_function) - %%> - - IF (has_entity_locators) { - data_manager prep read - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'locator')) as locator { - IF (locator.config?.on_remove_function) { - IF (locator.config.use_entity) { - block as_locator_<%locator.storage_name%> { with storage <%temp_storage%> entry.data.locators.<%locator.storage_name%> - $execute as $(uuid) at @s run block locator_<%locator.storage_name%>_on_remove { - <%% - emit.mcb(locator.config.on_remove_function) - %%> - } - } - } ELSE { - block at_locator_<%locator.storage_name%> { with storage <%temp_storage%> entry.data.locators.<%locator.storage_name%> - $execute \ - positioned ^$(px) ^$(py) ^$(pz) \ - rotated ~$(ry) ~$(rx) \ - run block locator_<%locator.storage_name%>_on_remove { - <%% - emit.mcb(locator.config.on_remove_function) - %%> - } - } - } - } - } - } - - function ./this/without_on_remove_function - } - - dir this { - function without_on_remove_function { - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - - data_manager prep read - - IF (has_entity_locators || has_cameras) { - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'locator' && node.config?.use_entity)) as locator { - function animated_java:global/remove/entity_stack_by_uuid with storage <%temp_storage%> entry.data.locators.<%locator.storage_name%> - } - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'camera')) as camera { - function animated_java:global/remove/entity_stack_by_uuid with storage <%temp_storage%> entry.data.cameras.<%camera.storage_name%> - } - } - - # Remove the rig using the more expensive & thorough method if the rig_hash doesn't match. - execute \ - unless data storage <%temp_storage%> {entry:{data:{rig_hash: '<%rig_hash%>'}}} \ - run function animated_java:global/remove/outdated_rig - - block { with storage <%temp_storage%> entry.data.uuids_by_name - REPEAT (Object.values(rig.nodes).filter(node => BONE_TYPES.includes(node.type))) as node { - $kill $(<%node.storage_name%>) - } - } - - function animated_java:global/remove/entity_stack - } - } -} - -IF (Object.keys(rig.variants).length > 1) { - dir variants { - REPEAT (Object.values(rig.variants)) as variant { - dir <%variant.name%> { - function apply { - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - - <%% - global.filteredNodes = Object.values(rig.nodes).filter( - node => ( - node.type === 'bone' && - !variant.excluded_nodes.includes(node.uuid) && - ( // Variant has a model override or a config override for this bone. - variant.models[node.uuid] !== undefined || - node.configs.variants[variant.uuid] !== undefined - ) - ) || ( - BONE_TYPES.includes(node.type) && - !variant.excluded_nodes.includes(node.uuid) && - // Variant has a config override for this node. - node.configs.variants[variant.uuid] !== undefined - ) - ) - %%> - - REPEAT (global.filteredNodes) as node { - execute \ - on passengers \ - if entity @s[tag=<%TAGS.PROJECT_NODE_NAMED(blueprint_id, node.storage_name)%>] \ - at @s \ - run \ - block zzz/apply_to_node_<%node.storage_name%> { - IF (node.type === 'bone' && variant.models[node.uuid] !== undefined) { - # Special case for `animated_java:empty` model. - IF (variant.models[node.uuid].model === null) { - data modify entity @s item.components."minecraft:item_model" set value "animated_java:empty" - } ELSE { - data modify entity @s item.components."minecraft:item_model" set value "<%variant.models[node.uuid].item_model%>" - } - } - IF (node.configs.variants[variant.uuid]) { - <%% - global.config = DisplayEntityConfig.fromJSON(node.configs.variants[variant.uuid]) - %%> - IF (!global.config.isDefault()) { - data merge entity @s <%global.config.toNBT(undefined, variant.is_default)%> - } - IF (global.config.onApplyFunction) { - <%% - emit.mcb(global.config.onApplyFunction) - %%> - } - } - } - } - # Return success to allow this function to be used in function conditions. - return 1 - } - } - } - } -} - -IF (has_locators || has_cameras) { - dir zzz { - function reset_floating_entities { - IF (has_locators) { - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'locator')) as locator { - IF (locator.config?.use_entity) { - execute at @s run block set_default_pose/as_locator_<%locator.storage_name%> { with storage <%temp_storage%> entry.data.locators.<%locator.storage_name%> - $tp $(uuid) \ - ^<%roundTo(locator.default_transform.pos[0], 10)%> \ - ^<%roundTo(locator.default_transform.pos[1], 10)%> \ - ^<%roundTo(locator.default_transform.pos[2], 10)%> \ - ~<%roundTo(locator.default_transform.head_rot[1], 10)%> \ - ~<%roundTo(locator.default_transform.head_rot[0], 10)%> - - data modify storage <%temp_storage%> entry.data.locators.<%locator.storage_name%> merge value { \ - px: <%roundTo(locator.default_transform.pos[0], 10)%>, \ - py: <%roundTo(locator.default_transform.pos[1], 10)%>, \ - pz: <%roundTo(locator.default_transform.pos[2], 10)%>, \ - ry: <%roundTo(locator.default_transform.head_rot[1], 10)%>, \ - rx: <%roundTo(locator.default_transform.head_rot[0], 10)%> \ - } - } - } ELSE { - data modify storage <%temp_storage%> entry.data.locators.<%locator.storage_name%> merge value { \ - px: <%roundTo(locator.default_transform.pos[0], 10)%>, \ - py: <%roundTo(locator.default_transform.pos[1], 10)%>, \ - pz: <%roundTo(locator.default_transform.pos[2], 10)%>, \ - ry: <%roundTo(locator.default_transform.head_rot[1], 10)%>, \ - rx: <%roundTo(locator.default_transform.head_rot[0], 10)%> \ - } - } - } - } - - IF (has_cameras) { - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'camera')) as camera { - execute at @s run block set_default_pose/as_camera_<%camera.storage_name%> { with storage <%temp_storage%> entry.data.cameras.<%camera.storage_name%> - $tp $(uuid) \ - ^<%roundTo(camera.default_transform.pos[0], 10)%> \ - ^<%roundTo(camera.default_transform.pos[1], 10)%> \ - ^<%roundTo(camera.default_transform.pos[2], 10)%> \ - ~<%roundTo(camera.default_transform.head_rot[1], 10)%> \ - ~<%roundTo(camera.default_transform.head_rot[0], 10)%> - - data modify storage <%temp_storage%> entry.data.cameras.<%camera.storage_name%> merge value { \ - px: <%roundTo(camera.default_transform.pos[0], 10)%>, \ - py: <%roundTo(camera.default_transform.pos[1], 10)%>, \ - pz: <%roundTo(camera.default_transform.pos[2], 10)%>, \ - ry: <%roundTo(camera.default_transform.head_rot[1], 10)%>, \ - rx: <%roundTo(camera.default_transform.head_rot[0], 10)%> \ - } - } - } - } - } - } -} - -dir zzz { - function set_default_pose { - IF (has_locators || has_cameras) { - function ../zzz/reset_floating_entities - } - - REPEAT (Object.values(rig.nodes).filter(node => BONE_TYPES.includes(node.type))) as node { - execute \ - on passengers \ - if entity @s[tag=<%TAGS.PROJECT_NODE_NAMED(blueprint_id, node.storage_name)%>] \ - run \ - data merge entity @s { \ - transformation: <%matrixToNbtFloatArray(node.default_transform.matrix).toString()%>, \ - start_interpolation: -1 \ - } - } - } -} - -function set_default_pose { - # Changes the pose of the rig to the the default pose without interpolation - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - - IF (has_locators || has_cameras) { - data_manager prep read - } - function ./zzz/set_default_pose -} \ No newline at end of file diff --git a/src/systems/datapackCompiler/1.21.4/animation.mcb b/src/systems/datapackCompiler/1.21.4/main.mcb similarity index 61% rename from src/systems/datapackCompiler/1.21.4/animation.mcb rename to src/systems/datapackCompiler/1.21.4/main.mcb index c20c7ad4..715c5bff 100644 --- a/src/systems/datapackCompiler/1.21.4/animation.mcb +++ b/src/systems/datapackCompiler/1.21.4/main.mcb @@ -7,26 +7,30 @@ function on_load { data modify storage <%project_storage%> rig_hash set value <%"'" + rig_hash + "'"%> - IF (use_storage_for_animation) { - REPEAT (animations) as animation { - data remove storage <%project_storage%>/animations <%animation.storage_name%> + IF (has_animations) { + IF (use_storage_for_animation) { + REPEAT (animations) as animation { + data remove storage <%project_storage%>/animations <%animation.storage_name%> + } + <%animationStorage.join('\n')%> } - <%animationStorage.join('\n')%> + <%% + animations.forEach(animation => { + emit(`scoreboard objectives add ${OBJECTIVES.FRAME(animation.storage_name)} dummy`) + }) + %%> } - <%% - animations.forEach(animation => { - emit(`scoreboard objectives add ${OBJECTIVES.FRAME(animation.storage_name)} dummy`) - }) - %%> } -function remove_animation_objectives { - <%% - animations.forEach(animation => { - emit(`scoreboard objectives remove ${OBJECTIVES.FRAME(animation.storage_name)}`) - }) - %%> - tellraw @a <%TELLRAW.UNINSTALL()%> +IF (has_animations) { + function remove_animation_objectives { + <%% + animations.forEach(animation => { + emit(`scoreboard objectives remove ${OBJECTIVES.FRAME(animation.storage_name)}`) + }) + %%> + tellraw @a <%TELLRAW.UNINSTALL()%> + } } dir root { @@ -38,26 +42,28 @@ dir root { %%> } - # animated_java:global/root/on_tick already runs this right before calling this function. - # data_manager prep read - - # Once we have more than 8 animations, calling a function only if at least one animation is playing is more efficient. - IF (animations.length > 8) { - # If no animations are playing, we can skip all animation logic. - # This helps reduce ticking commands for rigs that are idle. - execute \ - unless entity @s[<%animations.map(anim => 'tag=!' + TAGS.ANIMATION_PLAYING(blueprint_id, anim.storage_name)).join(',')%>] \ - run block tick_animations { + IF (has_animations) { + # animated_java:global/root/on_tick already runs this right before calling this function. + # data_manager prep read + + # Once we have more than 8 animations, calling a function only if at least one animation is playing is more efficient. + IF (animations.length > 8) { + # If no animations are playing, we can skip all animation logic. + # This helps reduce ticking commands for rigs that are idle. + execute \ + unless entity @s[<%animations.map(anim => 'tag=!' + TAGS.ANIMATION_PLAYING(blueprint_id, anim.storage_name)).join(',')%>] \ + run block tick_animations { + REPEAT (animations) as animation { + execute if entity @s[tag=<%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%>] run \ + function <%blueprint_id%>/animations/<%animation.storage_name%>/zzz/on_tick + } + } + } ELSE { REPEAT (animations) as animation { execute if entity @s[tag=<%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%>] run \ function <%blueprint_id%>/animations/<%animation.storage_name%>/zzz/on_tick } } - } ELSE { - REPEAT (animations) as animation { - execute if entity @s[tag=<%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%>] run \ - function <%blueprint_id%>/animations/<%animation.storage_name%>/zzz/on_tick - } } IF (auto_update_rig_orientation) { @@ -190,428 +196,436 @@ IF (!auto_update_rig_orientation) { } } -dir animations { - REPEAT (animations) as animation { - dir <%animation.storage_name%> { - function play { - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> +IF (has_animations) { + dir animations { + REPEAT (animations) as animation { + dir <%animation.storage_name%> { + function play { + debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - function <%blueprint_id%>/animations/pause_all + function <%blueprint_id%>/animations/pause_all - tag @s add <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%> - scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> 0 - tag @s add <%TAGS.TRANSFORMS_ONLY()%> - execute at @s run function ./zzz/set_frame {frame: 0} - tag @s remove <%TAGS.TRANSFORMS_ONLY()%> - } + tag @s add <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%> + scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> 0 + tag @s add <%TAGS.TRANSFORMS_ONLY()%> + execute at @s run function ./zzz/set_frame {frame: 0} + tag @s remove <%TAGS.TRANSFORMS_ONLY()%> + } - function stop { - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> + function stop { + debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - function <%blueprint_id%>/animations/pause_all + function <%blueprint_id%>/animations/pause_all - scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> 0 - tag @s add <%TAGS.TRANSFORMS_ONLY()%> - execute at @s run function ./zzz/set_frame {frame: 0} - tag @s remove <%TAGS.TRANSFORMS_ONLY()%> - } + scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> 0 + tag @s add <%TAGS.TRANSFORMS_ONLY()%> + execute at @s run function ./zzz/set_frame {frame: 0} + tag @s remove <%TAGS.TRANSFORMS_ONLY()%> + } - function pause { - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> + function pause { + debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - tag @s remove <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%> - } + tag @s remove <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%> + } - function resume { - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> + function resume { + debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - tag @s add <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%> - } + tag @s add <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%> + } - function next_frame { - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> + function next_frame { + debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - execute if score @s <%OBJECTIVES.FRAME(animation.storage_name)%> matches <%animation.duration%>.. run scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> 1 - data remove storage <%temp_storage%> args - execute store result storage <%temp_storage%> args.frame int 1 run scoreboard players get @s <%OBJECTIVES.FRAME(animation.storage_name)%> - execute at @s run function ./zzz/apply_frame with storage <%temp_storage%> args - scoreboard players add @s <%OBJECTIVES.FRAME(animation.storage_name)%> 1 - } + execute if score @s <%OBJECTIVES.FRAME(animation.storage_name)%> matches <%animation.duration%>.. run scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> 1 + data remove storage <%temp_storage%> args + execute store result storage <%temp_storage%> args.frame int 1 run scoreboard players get @s <%OBJECTIVES.FRAME(animation.storage_name)%> + execute at @s run function ./zzz/apply_frame with storage <%temp_storage%> args + scoreboard players add @s <%OBJECTIVES.FRAME(animation.storage_name)%> 1 + } - function set_frame { - # Sets the frame without interpolation - #ARGS: {frame: int} - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> + function set_frame { + # Sets the frame without interpolation + #ARGS: {frame: int} + debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - data_manager prep read + data_manager prep read - data remove storage <%temp_storage%> args - $execute store result storage <%temp_storage%> args.frame int 1 run scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> $(frame) - execute at @s run function ./zzz/set_frame with storage <%temp_storage%> args - } + data remove storage <%temp_storage%> args + $execute store result storage <%temp_storage%> args.frame int 1 run scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> $(frame) + execute at @s run function ./zzz/set_frame with storage <%temp_storage%> args + } - function apply_frame { - #ARGS: {frame: int} - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> + function apply_frame { + #ARGS: {frame: int} + debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - data_manager prep read + data_manager prep read - data remove storage <%temp_storage%> args - $execute store result storage <%temp_storage%> args.frame int 1 run scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> $(frame) - execute at @s run function ./zzz/apply_frame with storage <%temp_storage%> args - } + data remove storage <%temp_storage%> args + $execute store result storage <%temp_storage%> args.frame int 1 run scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> $(frame) + execute at @s run function ./zzz/apply_frame with storage <%temp_storage%> args + } - function tween { - # Attempts to smoothly transition from the currently playing animation into this one. - #ARGS: {duration: int, to_frame: int} - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> + function tween { + # Attempts to smoothly transition from the currently playing animation into this one. + #ARGS: {duration: int, to_frame: int} + debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - function <%blueprint_id%>/animations/pause_all + function <%blueprint_id%>/animations/pause_all - tag @s add <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%> - $scoreboard players set @s <%OBJECTIVES.TWEEN_DURATION()%> $(duration) - $scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> $(to_frame) + tag @s add <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%> + $scoreboard players set @s <%OBJECTIVES.TWEEN_DURATION()%> $(duration) + $scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> $(to_frame) - scoreboard players operation #this <%OBJECTIVES.I()%> = @s <%OBJECTIVES.TWEEN_DURATION()%> - tag @s add <%TAGS.TRANSFORMS_ONLY()%> - execute at @s run function ./zzz/apply_frame {frame: 0} - $execute at @s run function ./zzz/apply_frame {frame: $(to_frame)} - tag @s remove <%TAGS.TRANSFORMS_ONLY()%> + scoreboard players operation #this <%OBJECTIVES.I()%> = @s <%OBJECTIVES.TWEEN_DURATION()%> + tag @s add <%TAGS.TRANSFORMS_ONLY()%> + execute at @s run function ./zzz/apply_frame {frame: 0} + $execute at @s run function ./zzz/apply_frame {frame: $(to_frame)} + tag @s remove <%TAGS.TRANSFORMS_ONLY()%> - data_manager prep read - block { with storage <%temp_storage%> entry.data.uuids_by_name - REPEAT (Object.values(rig.nodes).filter(node => BONE_TYPES.includes(node.type))) as node { - $execute \ - as $(<%node.storage_name%>) \ - store result entity @s interpolation_duration int 1 \ - run scoreboard players get #this <%OBJECTIVES.I()%> + data_manager prep read + block { with storage <%temp_storage%> entry.data.uuids_by_name + REPEAT (Object.values(rig.nodes).filter(node => BONE_TYPES.includes(node.type))) as node { + $execute \ + as $(<%node.storage_name%>) \ + store result entity @s interpolation_duration int 1 \ + run scoreboard players get #this <%OBJECTIVES.I()%> + } } } - } - dir zzz { - function on_tick { - # Tweening logic - scoreboard players remove @s <%OBJECTIVES.TWEEN_DURATION()%> 1 - execute if score @s <%OBJECTIVES.TWEEN_DURATION()%> matches 1.. run return 1 - execute if score @s <%OBJECTIVES.TWEEN_DURATION()%> matches 0 run \ - block { with storage <%temp_storage%> entry.data.uuids_by_name - REPEAT (Object.values(rig.nodes).filter(node => BONE_TYPES.includes(node.type))) as node { - $data modify entity $(<%node.storage_name%>) interpolation_duration set value <%interpolation_duration%> + dir zzz { + function on_tick { + # Tweening logic + scoreboard players remove @s <%OBJECTIVES.TWEEN_DURATION()%> 1 + execute if score @s <%OBJECTIVES.TWEEN_DURATION()%> matches 1.. run return 1 + execute if score @s <%OBJECTIVES.TWEEN_DURATION()%> matches 0 run \ + block { with storage <%temp_storage%> entry.data.uuids_by_name + REPEAT (Object.values(rig.nodes).filter(node => BONE_TYPES.includes(node.type))) as node { + $data modify entity $(<%node.storage_name%>) interpolation_duration set value <%interpolation_duration%> + } } - } - # Animation logic - IF (animation.loop_mode === 'loop' && animation.loop_delay === 0) { - # Makes sure function keyframes in the last frame of the animation are activated. - execute if score @s <%OBJECTIVES.FRAME(animation.storage_name)%> matches -1 run \ - block function_keyframe_loop_patch { - function ./frames/last_frame_effects with storage <%temp_storage%> entry.data.uuids_by_name - scoreboard players add @s <%OBJECTIVES.FRAME(animation.storage_name)%> 1 + # Animation logic + IF (animation.loop_mode === 'loop' && animation.loop_delay === 0) { + # Makes sure function keyframes in the last frame of the animation are activated. + execute if score @s <%OBJECTIVES.FRAME(animation.storage_name)%> matches -1 run \ + block function_keyframe_loop_patch { + function ./frames/last_frame_effects with storage <%temp_storage%> entry.data.uuids_by_name + scoreboard players add @s <%OBJECTIVES.FRAME(animation.storage_name)%> 1 + } + } + data remove storage <%temp_storage%> args + execute store result storage <%temp_storage%> args.frame int 1 run \ + scoreboard players get @s <%OBJECTIVES.FRAME(animation.storage_name)%> + function ./apply_frame with storage <%temp_storage%> args + IF (animation.loop_mode === 'loop') { + # Loop the animation back to the start once it reaches the last frame. + # If loop_delay is 0, the animation will loop instantly, otherwise, it will wait for the specified amount of ticks. + execute \ + if score @s <%OBJECTIVES.FRAME(animation.storage_name)%> \ + matches <%animation.duration-2 + animation.loop_delay%>.. \ + run return run \ + scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> <%animation.loop_delay === 0 ? -1 : 0%> + } ELSE IF (animation.loop_mode === 'hold') { + # Pause the animation at the last frame. + execute \ + if score @s <%OBJECTIVES.FRAME(animation.storage_name)%> \ + matches <%animation.duration-1%>.. \ + run return run \ + function ../pause + } ELSE IF (animation.loop_mode === 'once') { + # Stop the animation once it reaches the last frame. + execute \ + if score @s <%OBJECTIVES.FRAME(animation.storage_name)%> \ + matches <%animation.duration-1%> \ + run return run block loop_mode_stop { + scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> 0 + tag @s add <%TAGS.TRANSFORMS_ONLY()%> + execute at @s run function ./zzz/set_frame {frame: 0} + tag @s remove <%TAGS.TRANSFORMS_ONLY()%> + tag @s remove <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%> } - } - data remove storage <%temp_storage%> args - execute store result storage <%temp_storage%> args.frame int 1 run \ - scoreboard players get @s <%OBJECTIVES.FRAME(animation.storage_name)%> - function ./apply_frame with storage <%temp_storage%> args - IF (animation.loop_mode === 'loop') { - # Loop the animation back to the start once it reaches the last frame. - # If loop_delay is 0, the animation will loop instantly, otherwise, it will wait for the specified amount of ticks. - execute \ - if score @s <%OBJECTIVES.FRAME(animation.storage_name)%> \ - matches <%animation.duration-2 + animation.loop_delay%>.. \ - run return run \ - scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> <%animation.loop_delay === 0 ? -1 : 0%> - } ELSE IF (animation.loop_mode === 'hold') { - # Pause the animation at the last frame. - execute \ - if score @s <%OBJECTIVES.FRAME(animation.storage_name)%> \ - matches <%animation.duration-1%>.. \ - run return run \ - function ../pause - } ELSE IF (animation.loop_mode === 'once') { - # Stop the animation once it reaches the last frame. - execute \ - if score @s <%OBJECTIVES.FRAME(animation.storage_name)%> \ - matches <%animation.duration-1%> \ - run return run block loop_mode_stop { - scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> 0 - tag @s add <%TAGS.TRANSFORMS_ONLY()%> - execute at @s run function ./zzz/set_frame {frame: 0} - tag @s remove <%TAGS.TRANSFORMS_ONLY()%> - tag @s remove <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%> } + scoreboard players add @s <%OBJECTIVES.FRAME(animation.storage_name)%> 1 } - scoreboard players add @s <%OBJECTIVES.FRAME(animation.storage_name)%> 1 - } - IF (use_storage_for_animation) { - function set_frame { - #ARGS: {frame: int} - $function ./apply_frame {frame: $(frame)} - block { with storage <%temp_storage%> entry.data.uuids_by_name - REPEAT (Object.values(rig.nodes).filter(node => BONE_TYPES.includes(node.type))) as node { - $data modify entity $(<%node.storage_name%>) start_interpolation set value -1 + IF (use_storage_for_animation) { + function set_frame { + #ARGS: {frame: int} + $function ./apply_frame {frame: $(frame)} + block { with storage <%temp_storage%> entry.data.uuids_by_name + REPEAT (Object.values(rig.nodes).filter(node => BONE_TYPES.includes(node.type))) as node { + $data modify entity $(<%node.storage_name%>) start_interpolation set value -1 + } } + return 1 } - return 1 - } - function apply_frame { - #ARGS: {frame: int} - - block { with storage <%temp_storage%> entry.data.uuids_by_name - REPEAT (Object.values(animation.modified_nodes).sort(nodeSorter)) as node { - IF (BONE_TYPES.includes(node.type)) { - $data modify entity $(<%node.storage_name%>) {} merge from \ - storage <%project_storage%>/animations <%animation.storage_name%>.$(frame).<%node.storage_name%> - } ELSE IF (node.type === 'locator' || node.type === 'camera') { - $data modify storage <%temp_storage%> entry.data.uuids_by_name.<%node.storage_name%> merge from \ - storage <%project_storage%>/animations <%animation.storage_name%>.$(frame).<%node.storage_name%> + function apply_frame { + #ARGS: {frame: int} + + block { with storage <%temp_storage%> entry.data.uuids_by_name + REPEAT (Object.values(animation.modified_nodes).sort(nodeSorter)) as node { + IF (BONE_TYPES.includes(node.type)) { + $data modify entity $(<%node.storage_name%>) {} merge from \ + storage <%project_storage%>/animations <%animation.storage_name%>.$(frame).<%node.storage_name%> + } ELSE IF (node.type === 'locator' || node.type === 'camera') { + $data modify storage <%temp_storage%> entry.data.uuids_by_name.<%node.storage_name%> merge from \ + storage <%project_storage%>/animations <%animation.storage_name%>.$(frame).<%node.storage_name%> + } } } - } - IF (animation.frames.some(anim => anim.variant)) { - $execute \ - if data storage <%project_storage%>/animations <%animation.storage_name%>.$(frame).variant \ - unless entity @s[tag=<%TAGS.TRANSFORMS_ONLY()%>] \ - run { with storage <%project_storage%>/animations <%animation.storage_name%>.$(frame).variant - #ARGS: {name: string, condition: string} - $execute $(condition)run function <%blueprint_id%>/variants/$(name)/apply + IF (animation.frames.some(anim => anim.variant)) { + $execute \ + if data storage <%project_storage%>/animations <%animation.storage_name%>.$(frame).variant \ + unless entity @s[tag=<%TAGS.TRANSFORMS_ONLY()%>] \ + run { with storage <%project_storage%>/animations <%animation.storage_name%>.$(frame).variant + #ARGS: {name: string, condition: string} + $execute $(condition)run function <%blueprint_id%>/variants/$(name)/apply + } } - } - return 1 - } - } ELSE { - function set_frame { - # Sets the frame without interpolation - #ARGS: {frame: int} + return 1 + } + } ELSE { + function set_frame { + # Sets the frame without interpolation + #ARGS: {frame: int} - $function ./frames/$(frame) with storage <%temp_storage%> entry.data.uuids_by_name + $function ./frames/$(frame) with storage <%temp_storage%> entry.data.uuids_by_name - block { with storage <%temp_storage%> entry.data.uuids_by_name - REPEAT (Object.values(rig.nodes).filter(node => BONE_TYPES.includes(node.type))) as node { - $data modify entity $(<%node.storage_name%>) start_interpolation set value -1 + block { with storage <%temp_storage%> entry.data.uuids_by_name + REPEAT (Object.values(rig.nodes).filter(node => BONE_TYPES.includes(node.type))) as node { + $data modify entity $(<%node.storage_name%>) start_interpolation set value -1 + } } - } - return 1 - } + return 1 + } - function apply_frame { - #ARGS: {frame: int} + function apply_frame { + #ARGS: {frame: int} - $function ./frames/$(frame) with storage <%temp_storage%> entry.data.uuids_by_name + $function ./frames/$(frame) with storage <%temp_storage%> entry.data.uuids_by_name - return 1 - } + return 1 + } - # FIXME - %NEWLINE_PATCH% is a temporary solution to temporarily fix an MCB bug where extra newlines are being added to the output. - dir frames { - <%% - global.frame = animation.frames.at(-1) - global.modified_effect_nodes = Object.values(animation.modified_nodes).filter( - node => node.type === 'locator' && global.frame.node_transforms[node.uuid] - ) - console.log(global.modified_effect_nodes) - %%> - IF(Object.keys(global.modified_effect_nodes).length > 0) { - function last_frame_effects { - REPEAT(global.modified_effect_nodes) as node { - <%% - global.transform = global.frame.node_transforms[node.uuid] - %%> - IF (node.config?.use_entity) { - $execute \ - as $(<%node.storage_name%>) \ - positioned \ - ^<%roundTo(global.transform.pos[0], 10)%> \ - ^<%roundTo(global.transform.pos[1], 10)%> \ - ^<%roundTo(global.transform.pos[2], 10)%> \ - rotated \ - ~<%roundTo(global.transform.head_rot[1], 10)%> \ - ~<%roundTo(global.transform.head_rot[0], 10)%> \ - <%global.transform.function_execute_condition ? global.transform.function_execute_condition + ' ' : ''%>run \ - function ./<%animation.duration%>_locator_<%node.storage_name%> - } ELSE { - execute \ - positioned \ - ^<%roundTo(global.transform.pos[0], 10)%> \ - ^<%roundTo(global.transform.pos[1], 10)%> \ - ^<%roundTo(global.transform.pos[2], 10)%> \ - rotated \ - ~<%roundTo(global.transform.head_rot[1], 10)%> \ - ~<%roundTo(global.transform.head_rot[0], 10)%> \ - <%global.transform.function_execute_condition ? global.transform.function_execute_condition + ' ' : ''%>run \ - function ./<%animation.duration%>_locator_<%node.storage_name%> + # FIXME - %NEWLINE_PATCH% is a temporary solution to temporarily fix an MCB bug where extra newlines are being added to the output. + dir frames { + <%% + global.frame = animation.frames.at(-1) + global.modified_effect_nodes = Object.values(animation.modified_nodes).filter( + node => node.type === 'locator' && global.frame.node_transforms[node.uuid] + ) + console.log(global.modified_effect_nodes) + %%> + IF(Object.keys(global.modified_effect_nodes).length > 0) { + function last_frame_effects { + REPEAT(global.modified_effect_nodes) as node { + <%% + global.transform = global.frame.node_transforms[node.uuid] + %%> + IF (node.config?.use_entity) { + $execute \ + as $(<%node.storage_name%>) \ + positioned \ + ^<%roundTo(global.transform.pos[0], 10)%> \ + ^<%roundTo(global.transform.pos[1], 10)%> \ + ^<%roundTo(global.transform.pos[2], 10)%> \ + rotated \ + ~<%roundTo(global.transform.head_rot[1], 10)%> \ + ~<%roundTo(global.transform.head_rot[0], 10)%> \ + <%global.transform.function_execute_condition ? global.transform.function_execute_condition + ' ' : ''%>run \ + function ./<%animation.duration%>_locator_<%node.storage_name%> + } ELSE { + execute \ + positioned \ + ^<%roundTo(global.transform.pos[0], 10)%> \ + ^<%roundTo(global.transform.pos[1], 10)%> \ + ^<%roundTo(global.transform.pos[2], 10)%> \ + rotated \ + ~<%roundTo(global.transform.head_rot[1], 10)%> \ + ~<%roundTo(global.transform.head_rot[0], 10)%> \ + <%global.transform.function_execute_condition ? global.transform.function_execute_condition + ' ' : ''%>run \ + function ./<%animation.duration%>_locator_<%node.storage_name%> + } } - } - IF (global.frame.variants?.length > 0) { - execute <%global.frame.variants_execute_condition ? global.frame.variants_execute_condition + ' ' : ''%>run \ - function <%blueprint_id%>/variants/<%global.frame.variants[0].name%>/apply - } + IF (global.frame.variants?.length > 0) { + execute <%global.frame.variants_execute_condition ? global.frame.variants_execute_condition + ' ' : ''%>run \ + function <%blueprint_id%>/variants/<%global.frame.variants[0].name%>/apply + } - IF (global.frame.function) { - execute <%global.frame.function_execute_condition ? global.frame.function_execute_condition + ' ' : ''%>run \ - block <%animation.duration%>_function_keyframe { - <%global.frame.function%> - } + IF (global.frame.function) { + execute <%global.frame.function_execute_condition ? global.frame.function_execute_condition + ' ' : ''%>run \ + block <%animation.duration%>_function_keyframe { + <%global.frame.function%> + } + } } } - } - <%% - // A record of node uuid to INodeTransform. - // Keeps track of the last time a bone was updated. - // Only used for step keyframe interpolation. - let hasFunction = false - const lastActiveFrame = {} - const modifiedNodes = Object.values(animation.modified_nodes).filter(n => n.type !== 'struct').sort(nodeSorter); - for (const [frameIndex, frame] of animation.frames.entries()) { - const to_merge = {cameras: {}, locators: {}} - let frameFunc = ``; - for (const node of modifiedNodes) { - const transform = frame.node_transforms[node.uuid] - // Skip if the node doesn't have a transform for this frame. - if (!transform) continue - switch (node.type) { - case 'bone': - case 'text_display': - case 'item_display': - case 'block_display': { - const lastFrame = lastActiveFrame[node.uuid] - const isStepInterpolation = !!(lastFrame?.interpolation === 'step') - lastActiveFrame[node.uuid] = transform - - if (transform.interpolation === 'pre-post' || isStepInterpolation) { - frameFunc += - `\n$data merge entity $(${node.storage_name})%NEWLINE_PATCH%{` - + `transformation: ${matrixToNbtFloatArray(transform.matrix).toString()},` - + `start_interpolation: ${isStepInterpolation ? -1 : 0},` - + `interpolation_duration: ${isStepInterpolation ? 0 : interpolation_duration}` - + `}` - } else { - frameFunc += - `\n$data merge entity $(${node.storage_name})%NEWLINE_PATCH%{` - + `transformation: ${matrixToNbtFloatArray(transform.matrix).toString()},` - + `start_interpolation: 0,` - + `interpolation_duration: ${interpolation_duration}` - + `}` - } - - ;hasFunction = true - break - } - case 'locator': { - const lastFrame = lastActiveFrame[node.uuid] - lastActiveFrame[node.uuid] = transform - ;if (!lastFrame || matrixToNbtFloatArray(transform.matrix).toString() !== matrixToNbtFloatArray(lastFrame.matrix).toString()) { - to_merge.locators[node.storage_name] = { - px: roundTo(transform.pos[0], 10), - py: roundTo(transform.pos[1], 10), - pz: roundTo(transform.pos[2], 10), - ry: roundTo(transform.head_rot[1], 10), - rx: roundTo(transform.head_rot[0], 10) - }; - } - - if (transform.function) { - if (node.config?.use_entity) { + <%% + // A record of node uuid to INodeTransform. + // Keeps track of the last time a bone was updated. + // Only used for step keyframe interpolation. + let hasFunction = false + const lastActiveFrame = {} + const modifiedNodes = Object.values(animation.modified_nodes).filter(n => n.type !== 'struct').sort(nodeSorter); + for (const [frameIndex, frame] of animation.frames.entries()) { + const to_merge = {cameras: {}, locators: {}} + let frameFunc = ``; + for (const node of modifiedNodes) { + const transform = frame.node_transforms[node.uuid] + // Skip if the node doesn't have a transform for this frame. + if (!transform) continue + switch (node.type) { + case 'bone': + case 'text_display': + case 'item_display': + case 'block_display': { + const lastFrame = lastActiveFrame[node.uuid] + const isStepInterpolation = !!(lastFrame?.interpolation === 'step') + lastActiveFrame[node.uuid] = transform + + if (transform.interpolation === 'pre-post' || isStepInterpolation) { frameFunc += - `\n$execute unless entity @s[tag=${TAGS.TRANSFORMS_ONLY()}] as $(${node.storage_name}) ` - + `positioned ^${roundTo(transform.pos[0], 10)} ^${roundTo(transform.pos[1], 10)} ^${roundTo(transform.pos[2], 10)} ` - + `rotated ~${roundTo(transform.head_rot[1], 10)} ~${roundTo(transform.head_rot[0], 10)} ` - + `${transform.function_execute_condition ? transform.function_execute_condition + ' ' : ''}run ` - + `block ${frameIndex}_locator_${node.storage_name}%NEWLINE_PATCH%{\n` - + `tp @s ~ ~ ~ ~ ~\n` - + `${transform.function}` - + `\n}` + `\n$data merge entity $(${node.storage_name})%NEWLINE_PATCH%{` + + `transformation: ${matrixToNbtFloatArray(transform.matrix).toString()},` + + `start_interpolation: ${isStepInterpolation ? -1 : 0},` + + `interpolation_duration: ${isStepInterpolation ? 0 : interpolation_duration}` + + `}` } else { frameFunc += - `\nexecute unless entity @s[tag=${TAGS.TRANSFORMS_ONLY()}] ` - + `positioned ^${roundTo(transform.pos[0], 10)} ^${roundTo(transform.pos[1], 10)} ^${roundTo(transform.pos[2], 10)} ` - + `rotated ~${roundTo(transform.head_rot[1], 10)} ~${roundTo(transform.head_rot[0], 10)} ` - + `${transform.function_execute_condition ? transform.function_execute_condition + ' ' : ''}run ` - + `block ${frameIndex}_locator_${node.storage_name}%NEWLINE_PATCH%{\n` - + `${transform.function}` - + `\n}` + `\n$data merge entity $(${node.storage_name})%NEWLINE_PATCH%{` + + `transformation: ${matrixToNbtFloatArray(transform.matrix).toString()},` + + `start_interpolation: 0,` + + `interpolation_duration: ${interpolation_duration}` + + `}` + } + + ;hasFunction = true + break + } + case 'locator': { + const lastFrame = lastActiveFrame[node.uuid] + lastActiveFrame[node.uuid] = transform + ;if (!lastFrame || matrixToNbtFloatArray(transform.matrix).toString() !== matrixToNbtFloatArray(lastFrame.matrix).toString()) { + to_merge.locators[node.storage_name] = { + px: roundTo(transform.pos[0], 10), + py: roundTo(transform.pos[1], 10), + pz: roundTo(transform.pos[2], 10), + ry: roundTo(transform.head_rot[1], 10), + rx: roundTo(transform.head_rot[0], 10) + }; } + + if (transform.function) { + if (node.config?.use_entity) { + frameFunc += + `\n$execute unless entity @s[tag=${TAGS.TRANSFORMS_ONLY()}] as $(${node.storage_name}) ` + + `positioned ^${roundTo(transform.pos[0], 10)} ^${roundTo(transform.pos[1], 10)} ^${roundTo(transform.pos[2], 10)} ` + + `rotated ~${roundTo(transform.head_rot[1], 10)} ~${roundTo(transform.head_rot[0], 10)} ` + + `${transform.function_execute_condition ? transform.function_execute_condition + ' ' : ''}run ` + + `block ${frameIndex}_locator_${node.storage_name}%NEWLINE_PATCH%{\n` + + `tp @s ~ ~ ~ ~ ~\n` + + `${transform.function}` + + `\n}` + } else { + frameFunc += + `\nexecute unless entity @s[tag=${TAGS.TRANSFORMS_ONLY()}] ` + + `positioned ^${roundTo(transform.pos[0], 10)} ^${roundTo(transform.pos[1], 10)} ^${roundTo(transform.pos[2], 10)} ` + + `rotated ~${roundTo(transform.head_rot[1], 10)} ~${roundTo(transform.head_rot[0], 10)} ` + + `${transform.function_execute_condition ? transform.function_execute_condition + ' ' : ''}run ` + + `block ${frameIndex}_locator_${node.storage_name}%NEWLINE_PATCH%{\n` + + `${transform.function}` + + `\n}` + } + } + break } - break - } - case 'camera': { - const lastFrame = lastActiveFrame[node.uuid] - lastActiveFrame[node.uuid] = transform - ;if (!lastFrame || matrixToNbtFloatArray(transform.matrix).toString() !== matrixToNbtFloatArray(lastFrame.matrix).toString()) { - to_merge.cameras[node.storage_name] = { - px: transform.pos[0], - py: transform.pos[1], - pz: transform.pos[2], - ry: transform.head_rot[1], - rx: transform.head_rot[0] - }; + case 'camera': { + const lastFrame = lastActiveFrame[node.uuid] + lastActiveFrame[node.uuid] = transform + ;if (!lastFrame || matrixToNbtFloatArray(transform.matrix).toString() !== matrixToNbtFloatArray(lastFrame.matrix).toString()) { + to_merge.cameras[node.storage_name] = { + px: transform.pos[0], + py: transform.pos[1], + pz: transform.pos[2], + ry: transform.head_rot[1], + rx: transform.head_rot[0] + }; + } + ;break } - ;break } } - } - if (Object.keys(to_merge.locators).length > 0 || Object.keys(to_merge.cameras).length > 0) { - frameFunc += `\ndata modify storage <%temp_storage%> entry.data merge value ${JSON.stringify(to_merge)}` - frameFunc += `\ndata_manager write` - if (!auto_update_rig_orientation) { - frameFunc += `\nfunction ${blueprint_id}/root/on_tick/transform_floating_entities` + if (Object.keys(to_merge.locators).length > 0 || Object.keys(to_merge.cameras).length > 0) { + frameFunc += `\ndata modify storage <%temp_storage%> entry.data merge value ${JSON.stringify(to_merge)}` + frameFunc += `\ndata_manager write` + if (!auto_update_rig_orientation) { + frameFunc += `\nfunction ${blueprint_id}/root/on_tick/transform_floating_entities` + } + hasFunction = true } - hasFunction = true - } - if (frame.variants?.length) { - const variant = rig.variants[frame.variants[0]] - if (!variant) { - throw new Error(`Could not find Variant with uuid "${frame.variants[0]}" while generating frame "${frameIndex}" of animation "${animation.name}".`) + if (frame.variants?.length) { + const variant = rig.variants[frame.variants[0]] + if (!variant) { + throw new Error(`Could not find Variant with uuid "${frame.variants[0]}" while generating frame "${frameIndex}" of animation "${animation.name}".`) + } + const execute_condition = frame.variants_execute_condition ? frame.variants_execute_condition + ' ' : '' + frameFunc += `\nexecute unless entity @s[tag=${TAGS.TRANSFORMS_ONLY()}] ${execute_condition}run function ${blueprint_id}/variants/${variant.name}/apply` + ;hasFunction = true } - const execute_condition = frame.variants_execute_condition ? frame.variants_execute_condition + ' ' : '' - frameFunc += `\nexecute unless entity @s[tag=${TAGS.TRANSFORMS_ONLY()}] ${execute_condition}run function ${blueprint_id}/variants/${variant.name}/apply` - ;hasFunction = true - } - // Root function keyframes. - if (frame.function) { - const execute_condition = frame.function_execute_condition ? frame.function_execute_condition + ' ' : '' - frameFunc += `\nexecute unless entity @s[tag=${TAGS.TRANSFORMS_ONLY()}] at @s ${execute_condition}run block ${frameIndex}_root_function%NEWLINE_PATCH%{\n${frame.function}\n}` - ;hasFunction = true - } - ;if (frameFunc.length > 0) { - frameFunc = `function ${frameIndex}%NEWLINE_PATCH%{${frameFunc}\n}` - emit.mcb(frameFunc.replaceAll(/%NEWLINE_PATCH%\n?/g, ' ')) + // Root function keyframes. + if (frame.function) { + const execute_condition = frame.function_execute_condition ? frame.function_execute_condition + ' ' : '' + frameFunc += `\nexecute unless entity @s[tag=${TAGS.TRANSFORMS_ONLY()}] at @s ${execute_condition}run block ${frameIndex}_root_function%NEWLINE_PATCH%{\n${frame.function}\n}` + ;hasFunction = true + } + ;if (frameFunc.length > 0) { + frameFunc = `function ${frameIndex}%NEWLINE_PATCH%{${frameFunc}\n}` + emit.mcb(frameFunc.replaceAll(/%NEWLINE_PATCH%\n?/g, ' ')) + } } - } - %%> + %%> + } } } } } - } - function pause_all { - # Pauses all animations - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> + function pause_all { + # Pauses all animations + debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - REPEAT (animations) as animation { - tag @s remove <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%> + REPEAT (animations) as animation { + tag @s remove <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%> + } } } } function summon { - #Args: {args:{variant: string, animation: string, frame: int, start_animation: boolean}} + #Args: {args:{variant?: string, animation?: string, frame?: int, start_animation?: boolean}} # frame is ignored unless animation is specified. - data modify storage <%temp_storage%> args set value {variant:'', animation:'', frame: 0} $execute store success score #success <%OBJECTIVES.I()%> run data modify storage <%temp_storage%> args set value $(args) + IF (!has_animations && debug_mode) { + execute if data storage <%temp_storage%> args.animation run return run \ + tellraw @a <%TELLRAW.ANIMATION_ARG_NO_RIG_ANIMATIONS()%> + execute if data storage <%temp_storage%> args.frame run return run \ + tellraw @a <%TELLRAW.FRAME_ARG_NO_RIG_FRAMES()%> + } + summon minecraft:item_display ~ ~ ~ { \ Tags:[ \ '<%TAGS.NEW()%>', \ @@ -656,7 +670,7 @@ function summon { type=<%locator.config.entity_type%>, \ tag=<%TAGS.PROJECT_LOCATOR_NAMED(blueprint_id, locator.storage_name)%>, \ tag=<%TAGS.NEW()%>, \ - distance=..<%Math.ceil(locator.max_distance)%> \ + distance=..<%Math.ceil(locator.max_distance + 0.5)%> \ ] \ run block as_locator/<%locator.storage_name%> { # run block ../as_locator/<%locator.storage_name%> { @@ -681,7 +695,7 @@ function summon { type=minecraft:item_display, \ tag=<%TAGS.PROJECT_CAMERA_NAMED(blueprint_id, camera.storage_name)%>, \ tag=<%TAGS.NEW()%>, \ - distance=..<%Math.ceil(camera.max_distance)%> \ + distance=..<%Math.ceil(camera.max_distance + 0.5)%> \ ] \ run block as_camera/<%camera.storage_name%> { # run block ../as_camera/<%camera.storage_name%> { @@ -757,52 +771,54 @@ function summon { } execute if score #success <%OBJECTIVES.I()%> matches 0 run return fail - # Animation Argument - # If the animation argument is provided, attempt to apply the animation. - execute if data storage <%temp_storage%> args.animation run block animation_arg/process { with storage <%temp_storage%> args - scoreboard players set #success <%OBJECTIVES.I()%> 0 - # If the animation argument is *explicitly* set to an empty string, return an error. - execute if data storage <%temp_storage%> {args:{animation:''}} run return run block if_empty { - tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('animation')%> - function <%blueprint_id%>/remove/this/without_on_remove_function - } - # Automatically set the frame argument to 0 if the frame argument is not provided. - # Takes advantage of `store result score` setting the score to 0 if the command fails. - execute \ - store result storage <%temp_storage%> args.frame int 1 \ - store result score #frame <%OBJECTIVES.I()%> \ - run \ - data get storage <%temp_storage%> args.frame - # If the frame argument is negative, return an error. - execute if score #frame <%OBJECTIVES.I()%> matches ..-1 run return run block no_negative { - # Tell the user that the frame argument cannot be negative. - tellraw @a <%TELLRAW.FRAME_CANNOT_BE_NEGATIVE()%> - function <%blueprint_id%>/remove/this/without_on_remove_function - } - # Attempt to apply the animation frame. - execute store success score #success <%OBJECTIVES.I()%> run block try_set_frame { with storage <%temp_storage%> args - # Make sure we're only applying transforms when setting the summon pose. - tag @s add <%TAGS.TRANSFORMS_ONLY()%> - $execute store success score #success <%OBJECTIVES.I()%> run function <%blueprint_id%>/animations/$(animation)/zzz/set_frame with storage <%temp_storage%> args - tag @s remove <%TAGS.TRANSFORMS_ONLY()%> - execute if score #success <%OBJECTIVES.I()%> matches 1 run return 1 - # If the set_frame function fails, the animation doesn't exist, so we return an error. - return fail - } - # If the set_frame function failed, return an error. - execute unless score #success <%OBJECTIVES.I()%> matches 1 run return run block invalid_animation { - # Tell the user that the provided animation doesn't exist, remove the rig, and list all available animations for this rig. - tellraw @a <%TELLRAW.INVALID_ANIMATION(animations)%> - function <%blueprint_id%>/remove/this/without_on_remove_function - } + IF (has_animations) { + # Animation Argument + # If the animation argument is provided, attempt to apply the animation. + execute if data storage <%temp_storage%> args.animation run block animation_arg/process { with storage <%temp_storage%> args + scoreboard players set #success <%OBJECTIVES.I()%> 0 + # If the animation argument is *explicitly* set to an empty string, return an error. + execute if data storage <%temp_storage%> {args:{animation:''}} run return run block if_empty { + tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('animation')%> + function <%blueprint_id%>/remove/this/without_on_remove_function + } + # Automatically set the frame argument to 0 if the frame argument is not provided. + # Takes advantage of `store result score` setting the score to 0 if the command fails. + execute \ + store result storage <%temp_storage%> args.frame int 1 \ + store result score #frame <%OBJECTIVES.I()%> \ + run \ + data get storage <%temp_storage%> args.frame + # If the frame argument is negative, return an error. + execute if score #frame <%OBJECTIVES.I()%> matches ..-1 run return run block no_negative { + # Tell the user that the frame argument cannot be negative. + tellraw @a <%TELLRAW.FRAME_CANNOT_BE_NEGATIVE()%> + function <%blueprint_id%>/remove/this/without_on_remove_function + } + # Attempt to apply the animation frame. + execute store success score #success <%OBJECTIVES.I()%> run block try_set_frame { with storage <%temp_storage%> args + # Make sure we're only applying transforms when setting the summon pose. + tag @s add <%TAGS.TRANSFORMS_ONLY()%> + $execute store success score #success <%OBJECTIVES.I()%> run function <%blueprint_id%>/animations/$(animation)/zzz/set_frame with storage <%temp_storage%> args + tag @s remove <%TAGS.TRANSFORMS_ONLY()%> + execute if score #success <%OBJECTIVES.I()%> matches 1 run return 1 + # If the set_frame function fails, the animation doesn't exist, so we return an error. + return fail + } + # If the set_frame function failed, return an error. + execute unless score #success <%OBJECTIVES.I()%> matches 1 run return run block invalid_animation { + # Tell the user that the provided animation doesn't exist, remove the rig, and list all available animations for this rig. + tellraw @a <%TELLRAW.INVALID_ANIMATION(animations)%> + function <%blueprint_id%>/remove/this/without_on_remove_function + } - # If the animation is successfully applied, and the start_animation argument is set to true, start the animation. - execute if data storage <%temp_storage%> {args:{start_animation: true}} run block start_animation { with storage <%temp_storage%> args - $function <%blueprint_id%>/animations/$(animation)/resume + # If the animation is successfully applied, and the start_animation argument is set to true, start the animation. + execute if data storage <%temp_storage%> {args:{start_animation: true}} run block start_animation { with storage <%temp_storage%> args + $function <%blueprint_id%>/animations/$(animation)/resume + } + scoreboard players set #success <%OBJECTIVES.I()%> 1 } - scoreboard players set #success <%OBJECTIVES.I()%> 1 + execute if score #success <%OBJECTIVES.I()%> matches 0 run return fail } - execute if score #success <%OBJECTIVES.I()%> matches 0 run return fail IF (has_locators || has_cameras) { function <%blueprint_id%>/root/on_tick/transform_floating_entities @@ -1387,16 +1403,18 @@ IF (has_locators || has_cameras) { } dir zzz { - function apply_default_pose { - IF (has_locators || has_cameras) { - function ../zzz/reset_floating_entities - } + IF (has_animations) { + function apply_default_pose { + IF (has_locators || has_cameras) { + function ../zzz/reset_floating_entities + } - block apply_default_pose_to_nodes { with storage <%temp_storage%> entry.data.uuids_by_name - REPEAT (Object.values(rig.nodes).filter(node => BONE_TYPES.includes(node.type))) as node { - $data merge entity $(<%node.storage_name%>) { \ - transformation: <%matrixToNbtFloatArray(node.default_transform.matrix).toString()%>, \ - start_interpolation: 0 \ + block apply_default_pose_to_nodes { with storage <%temp_storage%> entry.data.uuids_by_name + REPEAT (Object.values(rig.nodes).filter(node => BONE_TYPES.includes(node.type))) as node { + $data merge entity $(<%node.storage_name%>) { \ + transformation: <%matrixToNbtFloatArray(node.default_transform.matrix).toString()%>, \ + start_interpolation: 0 \ + } } } } @@ -1417,14 +1435,17 @@ dir zzz { } } } -function apply_default_pose { - # Changes the pose of the rig to the the default pose with interpolation - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - IF (has_locators || has_cameras) { - data_manager prep read +IF (has_animations) { + function apply_default_pose { + # Changes the pose of the rig to the the default pose with interpolation + debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> + + IF (has_locators || has_cameras) { + data_manager prep read + } + function ./zzz/apply_default_pose } - function ./zzz/apply_default_pose } function set_default_pose { diff --git a/src/systems/datapackCompiler/1.21.4/static.mcb b/src/systems/datapackCompiler/1.21.4/static.mcb deleted file mode 100644 index 1af994f6..00000000 --- a/src/systems/datapackCompiler/1.21.4/static.mcb +++ /dev/null @@ -1,912 +0,0 @@ -# TODO - Move all internal functions into an internal namespace, and only have user-facing functions in the main `<%blueprint_id%>` namespace. - -# DIFFERENCES FROM 1.21.2: -# - node entities are no longer passengers of the root entity for smooth rotation fix. -# - minecraft:custom_model_data is now more powerful than minecraft:item_model: item.components."minecraft:item_model" -> item.components."minecraft:custom_model_data".strings[0] - -function on_load { - data modify storage <%project_storage%> rig_hash set value <%"'" + rig_hash + "'"%> -} - -function invalid_version_warning { - # This function will contain a tellraw if the datapack is loaded in the wrong version. -} - -dir root { - function on_tick { - # Custom pre-tick function - IF (on_pre_tick_function) { - <%% - emit.mcb(on_pre_tick_function) - %%> - } - - IF (auto_update_rig_orientation) { - IF (has_locators || has_cameras) { - function <%blueprint_id%>/root/on_tick/transform_floating_entities - } - - block { with storage <%temp_storage%> entry.data.uuids_by_name - REPEAT (Object.values(rig.nodes).filter(node => BONE_TYPES.includes(node.type))) as node { - $tp $(<%node.storage_name%>) ~ ~ ~ ~ ~ - # Precise Rotation Workaround. Fixes MC-272913. - # Thanks @Triton365! (https://discord.com/channels/154777837382008833/157097006500806656/1402253905408163842) - $execute \ - as $(<%node.storage_name%>) \ - store success entity @s OnGround byte 1 \ - store success score @s <%OBJECTIVES.I()%> \ - unless score @s <%OBJECTIVES.I()%> matches 1 - } - } - } ELSE IF (has_ticking_locators) { - function <%blueprint_id%>/root/on_tick/transform_locators - } - - # Custom post-tick function - IF (on_post_tick_function) { - <%% - emit.mcb(on_post_tick_function) - %%> - } - } - - IF (has_locators || has_cameras) { - dir on_tick { - function transform_locators { - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'locator')) as locator { - block select_locator_<%locator.storage_name%> { with storage <%temp_storage%> entry.data.locators.<%locator.storage_name%> - IF (locator.config?.use_entity) { - $execute \ - as $(uuid) \ - positioned ^$(px) ^$(py) ^$(pz) \ - rotated ~$(ry) ~$(rx) \ - run block as_locator_<%locator.storage_name%> { - tp @s ~ ~ ~ ~ ~ - - IF (locator.config?.sync_passenger_rotation) { - execute on passengers run rotate @s ~ ~ - } - - IF (locator.config?.on_tick_function) { - <%% - emit.mcb(locator.config.on_tick_function) - %%> - } - } - - IF (locator.config?.sync_passenger_rotation) { - # Precise Rotation Workaround. Fixes MC-272913. - # Thanks @Triton365! (https://discord.com/channels/154777837382008833/157097006500806656/1402253905408163842) - $execute \ - as $(uuid) \ - store success entity @s OnGround byte 1 \ - store success score @s <%OBJECTIVES.I()%> \ - unless score @s <%OBJECTIVES.I()%> matches 1 - } - } ELSE IF (locator.config?.on_tick_function) { - $execute \ - positioned ^$(px) ^$(py) ^$(pz) \ - rotated ~$(ry) ~$(rx) \ - run block at_locator_<%locator.storage_name%> { - <%% - emit.mcb(locator.config.on_tick_function) - %%> - } - } - } - } - } - - function transform_floating_entities { - function ./transform_locators - - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'camera')) as camera { - block select_camera_<%camera.storage_name%> { with storage <%temp_storage%> entry.data.cameras.<%camera.storage_name%> - $execute \ - as $(uuid) \ - positioned ^$(px) ^$(py) ^$(pz) \ - rotated ~$(ry) ~$(rx) \ - run tp @s ~ ~ ~ ~ ~ - # Precise Rotation Workaround. Fixes MC-272913. - # Thanks @Triton365! (https://discord.com/channels/154777837382008833/157097006500806656/1402253905408163842) - $execute \ - as $(uuid) \ - store success entity @s OnGround byte 1 \ - store success score @s <%OBJECTIVES.I()%> \ - unless score @s <%OBJECTIVES.I()%> matches 1 - } - } - } - } - } -} - -IF (!auto_update_rig_orientation) { - function move { - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - - tp @s ~ ~ ~ ~ ~ - - data_manager prep read - IF (has_locators || has_cameras) { - function <%blueprint_id%>/root/on_tick/transform_floating_entities - } - - block { with storage <%temp_storage%> entry.data.uuids_by_name - REPEAT (Object.values(rig.nodes).filter(node => BONE_TYPES.includes(node.type))) as node { - $tp $(<%node.storage_name%>) ~ ~ ~ ~ ~ - # Precise Rotation Workaround. Fixes MC-272913. - # Thanks @Triton365! (https://discord.com/channels/154777837382008833/157097006500806656/1402253905408163842) - $execute \ - as $(<%node.storage_name%>) \ - store success entity @s OnGround byte 1 \ - store success score @s <%OBJECTIVES.I()%> \ - unless score @s <%OBJECTIVES.I()%> matches 1 - } - } - } -} ELSE { - function move { - tellraw @a <%TELLRAW.AUTO_UPDATE_RIG_ORIENTATION_MOVE_WARNING()%> - } -} - -function summon { - #Args: {args:{variant: string}} - - data modify storage <%temp_storage%> args set value {variant:''} - $execute store success score #success <%OBJECTIVES.I()%> run data modify storage <%temp_storage%> args set value $(args) - - summon minecraft:item_display ~ ~ ~ { \ - Tags:[ \ - '<%TAGS.NEW()%>', \ - '<%TAGS.GLOBAL_ENTITY()%>', \ - '<%TAGS.GLOBAL_ROOT()%>', \ - '<%TAGS.PROJECT_ENTITY(blueprint_id)%>', \ - '<%TAGS.PROJECT_ROOT(blueprint_id)%>' \ - ], \ - teleport_duration: 0, \ - interpolation_duration: <%interpolation_duration%>, \ - Passengers:<%root_entity_passengers%>, \ - CustomName: '<%ENTITY_NAMES.ROOT(blueprint_id)%>', \ - } - execute as @n[ \ - type=minecraft:item_display, \ - tag=<%TAGS.PROJECT_ROOT(blueprint_id)%>, \ - tag=<%TAGS.NEW()%>, \ - distance=..0.01 \ - ] run block zzz/summon/as_root_entity { - execute store result score @s <%OBJECTIVES.ID()%> run scoreboard players add aj.last_id <%OBJECTIVES.ID()%> 1 - - data_manager init prep read - # Data manager init runs gu:get_entity_uuid_string. So we don't need to call it again here. - # function animated_java:global/gu/get_entity_uuid_string - data modify storage <%temp_storage%> entry.data.uuids append from storage <%gu_storage%> out - data modify storage <%temp_storage%> entry.data.root_uuid set from storage <%gu_storage%> out - - data modify storage <%temp_storage%> entry.data.blueprint_id set value "<%blueprint_id%>" - data modify storage <%temp_storage%> entry.data.rig_hash set value "<%rig_hash%>" - - # Align the position and rotation of the root with the command context. - tp @s ~ ~ ~ ~ ~ - - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'locator' && node.config?.use_entity)) as locator { - summon <%locator.config.entity_type%> \ - ^<%roundTo(locator.default_transform.pos[0], 10)%> \ - ^<%roundTo(locator.default_transform.pos[1], 10)%> \ - ^<%roundTo(locator.default_transform.pos[2], 10)%> \ - {Tags:<%getNodeTags(locator, rig)%>} - execute \ - as @n[ \ - type=<%locator.config.entity_type%>, \ - tag=<%TAGS.PROJECT_LOCATOR_NAMED(blueprint_id, locator.storage_name)%>, \ - tag=<%TAGS.NEW()%>, \ - distance=..<%Math.ceil(locator.max_distance)%> \ - ] \ - run block as_locator/<%locator.storage_name%> { - # run block ../as_locator/<%locator.storage_name%> { - tag @s remove <%TAGS.NEW()%> - data modify entity @s CustomName set value '<%ENTITY_NAMES.NODE(blueprint_id, locator.type, locator.storage_name)%>' - function animated_java:global/gu/get_entity_uuid_string - scoreboard players operation @s <%OBJECTIVES.ID()%> = aj.last_id <%OBJECTIVES.ID()%> - } - data modify storage <%temp_storage%> entry.data.uuids append from storage <%gu_storage%> out - data modify storage <%temp_storage%> entry.data.uuids_by_name.<%locator.storage_name%> set from storage <%gu_storage%> out - data modify storage <%temp_storage%> entry.data.locators.<%locator.storage_name%>.uuid set from storage <%gu_storage%> out - } - - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'camera')) as camera { - summon minecraft:item_display \ - ^<%roundTo(camera.default_transform.pos[0], 10)%> \ - ^<%roundTo(camera.default_transform.pos[1], 10)%> \ - ^<%roundTo(camera.default_transform.pos[2], 10)%> \ - {Tags:<%getNodeTags(camera, rig)%>, teleport_duration: 2} - execute \ - as @n[ \ - type=minecraft:item_display, \ - tag=<%TAGS.PROJECT_CAMERA_NAMED(blueprint_id, camera.storage_name)%>, \ - tag=<%TAGS.NEW()%>, \ - distance=..<%Math.ceil(camera.max_distance)%> \ - ] \ - run block as_camera/<%camera.storage_name%> { - # run block ../as_camera/<%camera.storage_name%> { - tag @s remove <%TAGS.NEW()%> - data modify entity @s CustomName set value '<%ENTITY_NAMES.NODE(blueprint_id, camera.type, camera.storage_name)%>' - function animated_java:global/gu/get_entity_uuid_string - scoreboard players operation @s <%OBJECTIVES.ID()%> = aj.last_id <%OBJECTIVES.ID()%> - } - data modify storage <%temp_storage%> entry.data.uuids append from storage <%gu_storage%> out - data modify storage <%temp_storage%> entry.data.uuids_by_name.<%camera.storage_name%> set from storage <%gu_storage%> out - data modify storage <%temp_storage%> entry.data.cameras.<%camera.storage_name%>.uuid set from storage <%gu_storage%> out - } - - REPEAT (Object.values(rig.nodes).filter(node => BONE_TYPES.includes(node.type))) as node { - execute \ - on passengers \ - if entity @s[tag=<%TAGS.PROJECT_NODE_NAMED(blueprint_id, node.storage_name)%>] \ - run block as_node/<%node.storage_name%> { - data modify entity @s CustomName set value '<%ENTITY_NAMES.NODE(blueprint_id, node.type, node.storage_name)%>' - function animated_java:global/gu/get_entity_uuid_string - scoreboard players operation @s <%OBJECTIVES.ID()%> = aj.last_id <%OBJECTIVES.ID()%> - } - - data modify storage <%temp_storage%> entry.data.uuids append from storage <%gu_storage%> out - data modify storage <%temp_storage%> entry.data.uuids_by_name.<%node.storage_name%> set from storage <%gu_storage%> out - } - - IF (has_entity_locators) { - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'locator' && node.config?.use_entity)) as locator { - block { with storage <%temp_storage%> entry.data.locators.<%locator.storage_name%> - # Track any custom entities on the locator. - $execute at @s as $(uuid) at @s run function animated_java:global/util/get_entity_stack_uuids - } - data modify storage <%temp_storage%> entry.data.uuids append from storage <%temp_storage%> uuids - } - } - - function <%blueprint_id%>/zzz/set_default_pose - - data_manager write - - # Variant Arguement - IF (Object.keys(rig.variants).length > 1) { - execute if data storage <%temp_storage%> args.variant run block variant_arg/process { with storage <%temp_storage%> args - scoreboard players set #success <%OBJECTIVES.I()%> 0 - # If the variant argument is *explicitly* set to an empty string, return an error. - execute if data storage <%temp_storage%> {args:{variant:''}} run return run block if_empty { - # Tell the user that the variant cannot be empty. - tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('variant')%> - function <%blueprint_id%>/remove/this/without_on_remove_function - } - # Attempt to apply the requested variant. - # We get the success of the `try_apply` function in just in case the user's arguments are *very* wrong. - execute store success score #success <%OBJECTIVES.I()%> run block try_apply { with storage <%temp_storage%> args - $execute if function <%blueprint_id%>/variants/$(variant)/apply run return 1 - # If the apply function fails, the variant doesn't exist, so we return an error. - return fail - } - # If the apply function failed, return an error. - execute unless score #success <%OBJECTIVES.I()%> matches 1 run return run block invalid_variant { - # Tell the user that the provided variant doesn't exist, remove the rig, and list all available variants for this rig. - tellraw @a <%TELLRAW.INVALID_VARIANT(rig.variants)%> - function <%blueprint_id%>/remove/this/without_on_remove_function - } - scoreboard players set #success <%OBJECTIVES.I()%> 1 - } - } ELSE { - execute if data storage <%temp_storage%> args.variant run block zzz/variant_arg/no_variants_warning { - tellraw @a <%TELLRAW.NO_VARIANTS()%> - function <%blueprint_id%>/remove/this/without_on_remove_function - scoreboard players set #success <%OBJECTIVES.I()%> 0 - } - } - execute if score #success <%OBJECTIVES.I()%> matches 0 run return fail - - IF (has_locators || has_cameras) { - function <%blueprint_id%>/root/on_tick/transform_floating_entities - } - execute on passengers run rotate @s ~ ~ - - # Apply teleport duration - data modify entity @s teleport_duration set value <%teleportation_duration%> - execute on passengers run data modify entity @s teleport_duration set value <%teleportation_duration%> - - IF (has_entity_locators) { - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'locator' && node.config?.use_entity && node.config.on_summon_function)) as locator { - block { with storage <%temp_storage%> entry.data.locators.<%locator.storage_name%> - $execute at @s as $(uuid) at @s run block on_summon/custom_<%locator.type + '_' + locator.storage_name%> { - <%% - emit.mcb(locator.config.on_summon_function) - %%> - } - } - } - } - - REPEAT (Object.values(rig.nodes).filter(node => BONE_TYPES.includes(node.type) && node.on_summon_function?.trim())) as node { - execute \ - on passengers if entity @s[tag=<%TAGS.PROJECT_NODE_NAMED(blueprint_id, node.storage_name)%>] \ - run block on_summon/<%node.type + '_' + node.storage_name%> { - <%% - emit.mcb(node.on_summon_function.trim()) - %%> - } - } - - IF (on_summon_function) { - execute at @s run block on_summon/rig { - <%% - emit.mcb(on_summon_function) - %%> - } - } - - # Remove the NEW tag from the root entity, and it's passengers. - tag @s remove <%TAGS.NEW()%> - execute on passengers run tag @s remove <%TAGS.NEW()%> - # Dismount bone entities from the root entity. - execute on passengers run ride @s dismount - } -} - -function as_node { - #ARGS: {name: string, command: string} - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - data remove storage <%temp_storage%> args - $data modify storage <%temp_storage%> args merge value {name:'$(name)', command:'$(command)', uuid:'+MISSING_UUID+'} - - IF (debug_mode) { - execute if data storage <%temp_storage%> {args:{name:''}} run return run tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('name')%> - execute if data storage <%temp_storage%> {args:{command:''}} run return run tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('command')%> - } - - data_manager prep read - - block zzz/as_node/as_data { with storage <%temp_storage%> args - $data modify storage <%temp_storage%> args.uuid set from storage <%temp_storage%> entry.data.uuids_by_name.$(name) - IF (debug_mode) { - scoreboard players set #aj.check <%OBJECTIVES.I()%> 0 - } - block execute_as_uuid { with storage <%temp_storage%> args - IF (debug_mode) { - # If the function successfully instantiated, the provided command is valid. - scoreboard players set #aj.check <%OBJECTIVES.I()%> 1 - } - $execute as $(uuid) run return run $(command) - IF (debug_mode) { - # If the entity with the provided UUID doesn't exist, the node wasn't found. - tellraw @a <%TELLRAW.NODE_ENTITY_NOT_FOUND()%> - } - } - IF (debug_mode) { - execute if score #aj.check <%OBJECTIVES.I()%> matches 0 run tellraw @a <%TELLRAW.NODE_COMMAND_FAILED_TO_EXECUTE()%> - } - } -} - -IF (has_entity_locators) { - function as_locator { - #ARGS: {name: string, command: string} - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - - data remove storage <%temp_storage%> args - $data modify storage <%temp_storage%> args merge value {name:'$(name)', command:'$(command)', uuid:'+MISSING_UUID+'} - - IF (debug_mode) { - execute if data storage <%temp_storage%> {args:{name:''}} run return run tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('name')%> - execute if data storage <%temp_storage%> {args:{command:''}} run return run tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('command')%> - } - - data_manager prep read - - block zzz/as_locator/as_data { with storage <%temp_storage%> args - $data modify storage <%temp_storage%> args.uuid set from storage <%temp_storage%> entry.data.locators.$(name).uuid - IF (debug_mode) { - scoreboard players set #aj.check <%OBJECTIVES.I()%> 0 - } - block execute_as_uuid { with storage <%temp_storage%> args - IF (debug_mode) { - # If the function successfully instantiated, the provided command is valid. - scoreboard players set #aj.check <%OBJECTIVES.I()%> 1 - } - $execute as $(uuid) run return run $(command) - IF (debug_mode) { - # If the entity with the provided UUID doesn't exist, the locator wasn't found. - tellraw @a <%TELLRAW.LOCATOR_ENTITY_NOT_FOUND()%> - } - } - IF (debug_mode) { - execute if score #aj.check <%OBJECTIVES.I()%> matches 0 run tellraw @a <%TELLRAW.LOCATOR_COMMAND_FAILED_TO_EXECUTE()%> - } - } - } - - function as_at_locator { - #ARGS: {name: string, command: string} - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - - data remove storage <%temp_storage%> args - $data modify storage <%temp_storage%> args merge value {name:'$(name)', command:'$(command)', uuid:'+MISSING_UUID+'} - - IF (debug_mode) { - execute if data storage <%temp_storage%> {args:{name:''}} run return run tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('name')%> - execute if data storage <%temp_storage%> {args:{command:''}} run return run tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('command')%> - } - - data_manager prep read - - block zzz/as_locator/as_data { with storage <%temp_storage%> args - $data modify storage <%temp_storage%> args.uuid set from storage <%temp_storage%> entry.data.locators.$(name).uuid - IF (debug_mode) { - scoreboard players set #aj.check <%OBJECTIVES.I()%> 0 - } - block execute_as_uuid { with storage <%temp_storage%> args - IF (debug_mode) { - # If the function successfully instantiated, the provided command is valid. - scoreboard players set #aj.check <%OBJECTIVES.I()%> 1 - } - $execute as $(uuid) at @s run return run $(command) - IF (debug_mode) { - # If the entity with the provided UUID doesn't exist, the locator wasn't found. - tellraw @a <%TELLRAW.LOCATOR_ENTITY_NOT_FOUND()%> - } - } - IF (debug_mode) { - execute if score #aj.check <%OBJECTIVES.I()%> matches 0 run tellraw @a <%TELLRAW.LOCATOR_COMMAND_FAILED_TO_EXECUTE()%> - } - } - } - - function as_all_locators { - #ARGS: {command: string} - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - - data remove storage <%temp_storage%> args - $data modify storage <%temp_storage%> args merge value {command:'$(command)'} - - IF (debug_mode) { - execute if data storage <%temp_storage%> {args:{command:''}} run return run tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('command')%> - } - - data_manager prep read - - block zzz/as_all_locators/as_data { - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'locator' && node.config?.use_entity)) as locator { - data modify storage <%temp_storage%> args.uuid set from storage <%temp_storage%> entry.data.locators.<%locator.storage_name%>.uuid - - IF (debug_mode) { - scoreboard players set #aj.check <%OBJECTIVES.I()%> 0 - } - - block execute_as_uuid { with storage <%temp_storage%> args - IF (debug_mode) { - # If the function successfully instantiated, the provided command is valid. - scoreboard players set #aj.check <%OBJECTIVES.I()%> 1 - } - - $execute as $(uuid) run return run $(command) - } - - IF (debug_mode) { - execute if score #aj.check <%OBJECTIVES.I()%> matches 0 run tellraw @a <%TELLRAW.LOCATOR_COMMAND_FAILED_TO_EXECUTE({text: locator.storage_name, color: 'aqua'})%> - } - } - } - } - - function as_at_all_locators { - #ARGS: {command: string} - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - - data remove storage <%temp_storage%> args - $data modify storage <%temp_storage%> args merge value {command:'$(command)'} - - IF (debug_mode) { - execute if data storage <%temp_storage%> {args:{command:''}} run return run tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('command')%> - } - - data_manager prep read - - block zzz/as_all_locators/as_data { - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'locator' && node.config?.use_entity)) as locator { - data modify storage <%temp_storage%> args.uuid set from storage <%temp_storage%> entry.data.locators.<%locator.storage_name%>.uuid - - IF (debug_mode) { - scoreboard players set #aj.check <%OBJECTIVES.I()%> 0 - } - - block execute_as_uuid { with storage <%temp_storage%> args - IF (debug_mode) { - # If the function successfully instantiated, the provided command is valid. - scoreboard players set #aj.check <%OBJECTIVES.I()%> 1 - } - - $execute as $(uuid) at @s run return run $(command) - } - - IF (debug_mode) { - execute if score #aj.check <%OBJECTIVES.I()%> matches 0 run tellraw @a <%TELLRAW.LOCATOR_COMMAND_FAILED_TO_EXECUTE({text: locator.storage_name, color: 'aqua'})%> - } - } - } - } -} - -IF (has_locators) { - function at_locator { - #ARGS: {name: string, command: string} - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - - data remove storage <%temp_storage%> args - $data modify storage <%temp_storage%> args merge value {name:'$(name)', command:'$(command)'} - - IF (debug_mode) { - execute if data storage <%temp_storage%> {args:{name:''}} run return run tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('name')%> - execute if data storage <%temp_storage%> {args:{command:''}} run return run tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('command')%> - } - - data_manager prep read - - execute at @s run block zzz/at_locator/as_data { with storage <%temp_storage%> args - $data modify storage <%temp_storage%> args merge from storage <%temp_storage%> entry.data.locators.$(name) - - IF (debug_mode) { - execute unless data storage <%temp_storage%> args.px run return run tellraw @a <%TELLRAW.LOCATOR_NOT_FOUND()%> - scoreboard players set #aj.check <%OBJECTIVES.I()%> 0 - } - - block execute_at_transform { with storage <%temp_storage%> args - IF (debug_mode) { - # If the function successfully instantiated, the provided command is valid. - scoreboard players set #aj.check <%OBJECTIVES.I()%> 1 - } - - $execute \ - positioned ^$(px) ^$(py) ^$(pz) \ - rotated ~$(ry) ~$(rx) \ - run $(command) - } - - IF (debug_mode) { - execute if score #aj.check <%OBJECTIVES.I()%> matches 0 run tellraw @a <%TELLRAW.LOCATOR_COMMAND_FAILED_TO_EXECUTE()%> - } - } - } - - function at_all_locators { - #ARGS: {command: string} - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - - data remove storage <%temp_storage%> args - $data modify storage <%temp_storage%> args merge value {command:'$(command)'} - - IF (debug_mode) { - execute if data storage <%temp_storage%> {args:{command:''}} run return run tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('command')%> - } - - data_manager prep read - - block zzz/at_all_locators/as_data { - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'locator')) as locator { - data modify storage <%temp_storage%> args merge from storage <%temp_storage%> entry.data.locators.<%locator.storage_name%> - - IF (debug_mode) { - scoreboard players set #aj.check <%OBJECTIVES.I()%> 0 - } - - block execute_at_transform { with storage <%temp_storage%> args - IF (debug_mode) { - # If the function successfully instantiated, the provided command is valid. - scoreboard players set #aj.check <%OBJECTIVES.I()%> 1 - } - - $execute \ - positioned ^$(px) ^$(py) ^$(pz) \ - rotated ~$(ry) ~$(rx) \ - run $(command) - } - - IF (debug_mode) { - execute if score #aj.check <%OBJECTIVES.I()%> matches 0 run tellraw @a <%TELLRAW.LOCATOR_COMMAND_FAILED_TO_EXECUTE({text: locator.storage_name, color: 'aqua'})%> - } - } - } - } -} - -IF (has_cameras) { - function as_camera { - #ARGS: {name: string, command: string} - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - - data remove storage <%temp_storage%> args - $data modify storage <%temp_storage%> args merge value {name:'$(name)', command:'$(command)', uuid:'+MISSING_UUID+'} - - IF (debug_mode) { - execute if data storage <%temp_storage%> {args:{name:''}} run return run tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('name')%> - execute if data storage <%temp_storage%> {args:{command:''}} run return run tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('command')%> - } - - data_manager prep read - - block zzz/as_camera/as_data { with storage <%temp_storage%> args - $data modify storage <%temp_storage%> args.uuid set from storage <%temp_storage%> entry.data.cameras.$(name).uuid - - IF (debug_mode) { - scoreboard players set #aj.check <%OBJECTIVES.I()%> 0 - } - - block execute_as_uuid { with storage <%temp_storage%> args - IF (debug_mode) { - # If the function successfully instantiated, the provided command is valid. - scoreboard players set #aj.check <%OBJECTIVES.I()%> 1 - } - - $execute as $(uuid) at @s run return run $(command) - - IF (debug_mode) { - # If the entity with the provided UUID doesn't exist, the camera wasn't found. - tellraw @a <%TELLRAW.CAMERA_ENTITY_NOT_FOUND()%> - } - } - - IF (debug_mode) { - execute if score #aj.check <%OBJECTIVES.I()%> matches 0 run tellraw @a <%TELLRAW.CAMERA_COMMAND_FAILED_TO_EXECUTE()%> - } - } - } -} - -function as_root { - #ARGS: {command: string} - execute unless score @s <%OBJECTIVES.ID()%> matches <%-(2**31)%>..<%(2**31)-1%> run return run \ - tellraw @a <%TELLRAW.FUNCTION_NOT_EXECUTED_AS_ENTITY_WITH_ID_SCORE(context.functions.at(-1))%> - - data_manager prep read - - $data modify storage <%temp_storage%> args.command set value '$(command)' - data modify storage <%temp_storage%> args.root_uuid set from storage <%temp_storage%> entry.data.root_uuid - - IF (debug_mode) { - scoreboard players set #aj.check <%OBJECTIVES.I()%> 0 - } - block as_root_entity { with storage <%temp_storage%> args - $execute as $(root_uuid) run $(command) - IF (debug_mode) { - # If the function successfully instantiated, the provided command is valid. - scoreboard players set #aj.check <%OBJECTIVES.I()%> 1 - } - } - IF (debug_mode) { - execute if score #aj.check <%OBJECTIVES.I()%> matches 0 run tellraw @a <%TELLRAW.ROOT_COMMAND_FAILED_TO_EXECUTE()%> - } - -} - -dir remove { - function all { - # Removes all instances of this rig from the world. - execute as @e[type=minecraft:item_display,tag=<%TAGS.PROJECT_ROOT(blueprint_id)%>] run function <%blueprint_id%>/remove/this - } - - function entities { - # Removes all entities related to this rig from the world. - kill @e[tag=<%TAGS.PROJECT_ENTITY(blueprint_id)%>] - } - - function this { - # Removes the rig this function is executed as. - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - - <%% - if (on_remove_function) emit.mcb(on_remove_function) - %%> - - IF (has_entity_locators) { - data_manager prep read - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'locator')) as locator { - IF (locator.config?.on_remove_function) { - IF (locator.config.use_entity) { - block as_locator_<%locator.storage_name%> { with storage <%temp_storage%> entry.data.locators.<%locator.storage_name%> - $execute as $(uuid) at @s run block locator_<%locator.storage_name%>_on_remove { - <%% - emit.mcb(locator.config.on_remove_function) - %%> - } - } - } ELSE { - block at_locator_<%locator.storage_name%> { with storage <%temp_storage%> entry.data.locators.<%locator.storage_name%> - $execute \ - positioned ^$(px) ^$(py) ^$(pz) \ - rotated ~$(ry) ~$(rx) \ - run block locator_<%locator.storage_name%>_on_remove { - <%% - emit.mcb(locator.config.on_remove_function) - %%> - } - } - } - } - } - } - - function ./this/without_on_remove_function - } - - dir this { - function without_on_remove_function { - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - - data_manager prep read - - IF (has_entity_locators || has_cameras) { - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'locator' && node.config?.use_entity)) as locator { - function animated_java:global/remove/entity_stack_by_uuid with storage <%temp_storage%> entry.data.locators.<%locator.storage_name%> - } - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'camera')) as camera { - function animated_java:global/remove/entity_stack_by_uuid with storage <%temp_storage%> entry.data.cameras.<%camera.storage_name%> - } - } - - # Remove the rig using the more expensive & thorough method if the rig_hash doesn't match. - execute \ - unless data storage <%temp_storage%> {entry:{data:{rig_hash: '<%rig_hash%>'}}} \ - run function animated_java:global/remove/outdated_rig - - block { with storage <%temp_storage%> entry.data.uuids_by_name - REPEAT (Object.values(rig.nodes).filter(node => BONE_TYPES.includes(node.type))) as node { - $kill $(<%node.storage_name%>) - } - } - - function animated_java:global/remove/entity_stack - } - } -} - -IF (Object.keys(rig.variants).length > 1) { - dir variants { - REPEAT (Object.values(rig.variants)) as variant { - dir <%variant.name%> { - function apply { - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - - <%% - global.filteredNodes = Object.values(rig.nodes).filter( - node => ( - node.type === 'bone' && - !variant.excluded_nodes.includes(node.uuid) && - ( // Variant has a model override or a config override for this bone. - variant.models[node.uuid] !== undefined || - node.configs.variants[variant.uuid] !== undefined - ) - ) || ( - BONE_TYPES.includes(node.type) && - !variant.excluded_nodes.includes(node.uuid) && - // Variant has a config override for this node. - node.configs.variants[variant.uuid] !== undefined - ) - ) - %%> - - data_manager prep read - block { with storage <%temp_storage%> entry.data.uuids_by_name - REPEAT (global.filteredNodes) as node { - $execute as $(<%node.storage_name%>) run block zzz/apply_to_node_<%node.storage_name%> { - IF (node.type === 'bone' && variant.models[node.uuid] !== undefined) { - # Special case for `animated_java:empty` model. - IF (variant.models[node.uuid].model === null) { - data modify entity @s item.components."minecraft:custom_model_data".strings[0] set value "AJ_INTERNAL_EMPTY" - } ELSE { - data modify entity @s item.components."minecraft:custom_model_data".strings[0] set value "<%variant.name%>" - } - } - IF (node.configs.variants[variant.uuid]) { - <%% - global.config = DisplayEntityConfig.fromJSON(node.configs.variants[variant.uuid]) - %%> - IF (!global.config.isDefault()) { - data merge entity @s <%global.config.toNBT(undefined, variant.is_default)%> - } - IF (global.config.onApplyFunction) { - <%% - emit.mcb(global.config.onApplyFunction) - %%> - } - } - } - } - } - - # Return success to allow this function to be used in function conditions. - return 1 - } - } - } - } -} - -IF (has_locators || has_cameras) { - dir zzz { - function reset_floating_entities { - IF (has_locators) { - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'locator')) as locator { - IF (locator.config?.use_entity) { - execute at @s run block set_default_pose/as_locator_<%locator.storage_name%> { with storage <%temp_storage%> entry.data.locators.<%locator.storage_name%> - $tp $(uuid) \ - ^<%roundTo(locator.default_transform.pos[0], 10)%> \ - ^<%roundTo(locator.default_transform.pos[1], 10)%> \ - ^<%roundTo(locator.default_transform.pos[2], 10)%> \ - ~<%roundTo(locator.default_transform.head_rot[1], 10)%> \ - ~<%roundTo(locator.default_transform.head_rot[0], 10)%> - - data modify storage <%temp_storage%> entry.data.locators.<%locator.storage_name%> merge value { \ - px: <%roundTo(locator.default_transform.pos[0], 10)%>, \ - py: <%roundTo(locator.default_transform.pos[1], 10)%>, \ - pz: <%roundTo(locator.default_transform.pos[2], 10)%>, \ - ry: <%roundTo(locator.default_transform.head_rot[1], 10)%>, \ - rx: <%roundTo(locator.default_transform.head_rot[0], 10)%> \ - } - } - } ELSE { - data modify storage <%temp_storage%> entry.data.locators.<%locator.storage_name%> merge value { \ - px: <%roundTo(locator.default_transform.pos[0], 10)%>, \ - py: <%roundTo(locator.default_transform.pos[1], 10)%>, \ - pz: <%roundTo(locator.default_transform.pos[2], 10)%>, \ - ry: <%roundTo(locator.default_transform.head_rot[1], 10)%>, \ - rx: <%roundTo(locator.default_transform.head_rot[0], 10)%> \ - } - } - } - } - - IF (has_cameras) { - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'camera')) as camera { - execute at @s run block set_default_pose/as_camera_<%camera.storage_name%> { with storage <%temp_storage%> entry.data.cameras.<%camera.storage_name%> - $tp $(uuid) \ - ^<%roundTo(camera.default_transform.pos[0], 10)%> \ - ^<%roundTo(camera.default_transform.pos[1], 10)%> \ - ^<%roundTo(camera.default_transform.pos[2], 10)%> \ - ~<%roundTo(camera.default_transform.head_rot[1], 10)%> \ - ~<%roundTo(camera.default_transform.head_rot[0], 10)%> - - data modify storage <%temp_storage%> entry.data.cameras.<%camera.storage_name%> merge value { \ - px: <%roundTo(camera.default_transform.pos[0], 10)%>, \ - py: <%roundTo(camera.default_transform.pos[1], 10)%>, \ - pz: <%roundTo(camera.default_transform.pos[2], 10)%>, \ - ry: <%roundTo(camera.default_transform.head_rot[1], 10)%>, \ - rx: <%roundTo(camera.default_transform.head_rot[0], 10)%> \ - } - } - } - } - } - } -} - -dir zzz { - function set_default_pose { - IF (has_locators || has_cameras) { - function ../zzz/reset_floating_entities - } - - block set_default_pose_to_nodes { with storage <%temp_storage%> entry.data.uuids_by_name - REPEAT (Object.values(rig.nodes).filter(node => BONE_TYPES.includes(node.type))) as node { - $data merge entity $(<%node.storage_name%>) { \ - transformation: <%matrixToNbtFloatArray(node.default_transform.matrix).toString()%>, \ - start_interpolation: -1 \ - } - } - } - } -} - -function set_default_pose { - # Changes the pose of the rig to the the default pose without interpolation - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - - IF (has_locators || has_cameras) { - data_manager prep read - } - function ./zzz/set_default_pose -} \ No newline at end of file diff --git a/src/systems/datapackCompiler/1.21.5/animation.mcb b/src/systems/datapackCompiler/1.21.5/main.mcb similarity index 61% rename from src/systems/datapackCompiler/1.21.5/animation.mcb rename to src/systems/datapackCompiler/1.21.5/main.mcb index 3673d381..c4c5975b 100644 --- a/src/systems/datapackCompiler/1.21.5/animation.mcb +++ b/src/systems/datapackCompiler/1.21.5/main.mcb @@ -6,26 +6,30 @@ function on_load { data modify storage <%project_storage%> rig_hash set value <%"'" + rig_hash + "'"%> - IF (use_storage_for_animation) { - REPEAT (animations) as animation { - data remove storage <%project_storage%>/animations <%animation.storage_name%> + IF (has_animations) { + IF (use_storage_for_animation) { + REPEAT (animations) as animation { + data remove storage <%project_storage%>/animations <%animation.storage_name%> + } + <%animationStorage.join('\n')%> } - <%animationStorage.join('\n')%> + <%% + animations.forEach(animation => { + emit(`scoreboard objectives add ${OBJECTIVES.FRAME(animation.storage_name)} dummy`) + }) + %%> } - <%% - animations.forEach(animation => { - emit(`scoreboard objectives add ${OBJECTIVES.FRAME(animation.storage_name)} dummy`) - }) - %%> } -function remove_animation_objectives { - <%% - animations.forEach(animation => { - emit(`scoreboard objectives remove ${OBJECTIVES.FRAME(animation.storage_name)}`) - }) - %%> - tellraw @a <%TELLRAW.UNINSTALL()%> +IF (has_animations) { + function remove_animation_objectives { + <%% + animations.forEach(animation => { + emit(`scoreboard objectives remove ${OBJECTIVES.FRAME(animation.storage_name)}`) + }) + %%> + tellraw @a <%TELLRAW.UNINSTALL()%> + } } dir root { @@ -37,26 +41,28 @@ dir root { %%> } - # animated_java:global/root/on_tick already runs this right before calling this function. - # data_manager prep read - - # Once we have more than 8 animations, calling a function only if at least one animation is playing is more efficient. - IF (animations.length > 8) { - # If no animations are playing, we can skip all animation logic. - # This helps reduce ticking commands for rigs that are idle. - execute \ - unless entity @s[<%animations.map(anim => 'tag=!' + TAGS.ANIMATION_PLAYING(blueprint_id, anim.storage_name)).join(',')%>] \ - run block tick_animations { + IF (has_animations) { + # animated_java:global/root/on_tick already runs this right before calling this function. + # data_manager prep read + + # Once we have more than 8 animations, calling a function only if at least one animation is playing is more efficient. + IF (animations.length > 8) { + # If no animations are playing, we can skip all animation logic. + # This helps reduce ticking commands for rigs that are idle. + execute \ + unless entity @s[<%animations.map(anim => 'tag=!' + TAGS.ANIMATION_PLAYING(blueprint_id, anim.storage_name)).join(',')%>] \ + run block tick_animations { + REPEAT (animations) as animation { + execute if entity @s[tag=<%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%>] run \ + function <%blueprint_id%>/animations/<%animation.storage_name%>/zzz/on_tick + } + } + } ELSE { REPEAT (animations) as animation { execute if entity @s[tag=<%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%>] run \ function <%blueprint_id%>/animations/<%animation.storage_name%>/zzz/on_tick } } - } ELSE { - REPEAT (animations) as animation { - execute if entity @s[tag=<%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%>] run \ - function <%blueprint_id%>/animations/<%animation.storage_name%>/zzz/on_tick - } } IF (auto_update_rig_orientation) { @@ -189,428 +195,436 @@ IF (!auto_update_rig_orientation) { } } -dir animations { - REPEAT (animations) as animation { - dir <%animation.storage_name%> { - function play { - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> +IF (has_animations) { + dir animations { + REPEAT (animations) as animation { + dir <%animation.storage_name%> { + function play { + debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - function <%blueprint_id%>/animations/pause_all + function <%blueprint_id%>/animations/pause_all - tag @s add <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%> - scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> 0 - tag @s add <%TAGS.TRANSFORMS_ONLY()%> - execute at @s run function ./zzz/set_frame {frame: 0} - tag @s remove <%TAGS.TRANSFORMS_ONLY()%> - } + tag @s add <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%> + scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> 0 + tag @s add <%TAGS.TRANSFORMS_ONLY()%> + execute at @s run function ./zzz/set_frame {frame: 0} + tag @s remove <%TAGS.TRANSFORMS_ONLY()%> + } - function stop { - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> + function stop { + debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - function <%blueprint_id%>/animations/pause_all + function <%blueprint_id%>/animations/pause_all - scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> 0 - tag @s add <%TAGS.TRANSFORMS_ONLY()%> - execute at @s run function ./zzz/set_frame {frame: 0} - tag @s remove <%TAGS.TRANSFORMS_ONLY()%> - } + scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> 0 + tag @s add <%TAGS.TRANSFORMS_ONLY()%> + execute at @s run function ./zzz/set_frame {frame: 0} + tag @s remove <%TAGS.TRANSFORMS_ONLY()%> + } - function pause { - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> + function pause { + debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - tag @s remove <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%> - } + tag @s remove <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%> + } - function resume { - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> + function resume { + debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - tag @s add <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%> - } + tag @s add <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%> + } - function next_frame { - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> + function next_frame { + debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - execute if score @s <%OBJECTIVES.FRAME(animation.storage_name)%> matches <%animation.duration%>.. run scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> 1 - data remove storage <%temp_storage%> args - execute store result storage <%temp_storage%> args.frame int 1 run scoreboard players get @s <%OBJECTIVES.FRAME(animation.storage_name)%> - execute at @s run function ./zzz/apply_frame with storage <%temp_storage%> args - scoreboard players add @s <%OBJECTIVES.FRAME(animation.storage_name)%> 1 - } + execute if score @s <%OBJECTIVES.FRAME(animation.storage_name)%> matches <%animation.duration%>.. run scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> 1 + data remove storage <%temp_storage%> args + execute store result storage <%temp_storage%> args.frame int 1 run scoreboard players get @s <%OBJECTIVES.FRAME(animation.storage_name)%> + execute at @s run function ./zzz/apply_frame with storage <%temp_storage%> args + scoreboard players add @s <%OBJECTIVES.FRAME(animation.storage_name)%> 1 + } - function set_frame { - # Sets the frame without interpolation - #ARGS: {frame: int} - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> + function set_frame { + # Sets the frame without interpolation + #ARGS: {frame: int} + debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - data_manager prep read + data_manager prep read - data remove storage <%temp_storage%> args - $execute store result storage <%temp_storage%> args.frame int 1 run scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> $(frame) - execute at @s run function ./zzz/set_frame with storage <%temp_storage%> args - } + data remove storage <%temp_storage%> args + $execute store result storage <%temp_storage%> args.frame int 1 run scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> $(frame) + execute at @s run function ./zzz/set_frame with storage <%temp_storage%> args + } - function apply_frame { - #ARGS: {frame: int} - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> + function apply_frame { + #ARGS: {frame: int} + debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - data_manager prep read + data_manager prep read - data remove storage <%temp_storage%> args - $execute store result storage <%temp_storage%> args.frame int 1 run scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> $(frame) - execute at @s run function ./zzz/apply_frame with storage <%temp_storage%> args - } + data remove storage <%temp_storage%> args + $execute store result storage <%temp_storage%> args.frame int 1 run scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> $(frame) + execute at @s run function ./zzz/apply_frame with storage <%temp_storage%> args + } - function tween { - # Attempts to smoothly transition from the currently playing animation into this one. - #ARGS: {duration: int, to_frame: int} - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> + function tween { + # Attempts to smoothly transition from the currently playing animation into this one. + #ARGS: {duration: int, to_frame: int} + debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - function <%blueprint_id%>/animations/pause_all + function <%blueprint_id%>/animations/pause_all - tag @s add <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%> - $scoreboard players set @s <%OBJECTIVES.TWEEN_DURATION()%> $(duration) - $scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> $(to_frame) + tag @s add <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%> + $scoreboard players set @s <%OBJECTIVES.TWEEN_DURATION()%> $(duration) + $scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> $(to_frame) - scoreboard players operation #this <%OBJECTIVES.I()%> = @s <%OBJECTIVES.TWEEN_DURATION()%> - tag @s add <%TAGS.TRANSFORMS_ONLY()%> - execute at @s run function ./zzz/apply_frame {frame: 0} - $execute at @s run function ./zzz/apply_frame {frame: $(to_frame)} - tag @s remove <%TAGS.TRANSFORMS_ONLY()%> + scoreboard players operation #this <%OBJECTIVES.I()%> = @s <%OBJECTIVES.TWEEN_DURATION()%> + tag @s add <%TAGS.TRANSFORMS_ONLY()%> + execute at @s run function ./zzz/apply_frame {frame: 0} + $execute at @s run function ./zzz/apply_frame {frame: $(to_frame)} + tag @s remove <%TAGS.TRANSFORMS_ONLY()%> - data_manager prep read - block { with storage <%temp_storage%> entry.data.uuids_by_name - REPEAT (Object.values(rig.nodes).filter(node => BONE_TYPES.includes(node.type))) as node { - $execute \ - as $(<%node.storage_name%>) \ - store result entity @s interpolation_duration int 1 \ - run scoreboard players get #this <%OBJECTIVES.I()%> + data_manager prep read + block { with storage <%temp_storage%> entry.data.uuids_by_name + REPEAT (Object.values(rig.nodes).filter(node => BONE_TYPES.includes(node.type))) as node { + $execute \ + as $(<%node.storage_name%>) \ + store result entity @s interpolation_duration int 1 \ + run scoreboard players get #this <%OBJECTIVES.I()%> + } } } - } - dir zzz { - function on_tick { - # Tweening logic - scoreboard players remove @s <%OBJECTIVES.TWEEN_DURATION()%> 1 - execute if score @s <%OBJECTIVES.TWEEN_DURATION()%> matches 1.. run return 1 - execute if score @s <%OBJECTIVES.TWEEN_DURATION()%> matches 0 run \ - block { with storage <%temp_storage%> entry.data.uuids_by_name - REPEAT (Object.values(rig.nodes).filter(node => BONE_TYPES.includes(node.type))) as node { - $data modify entity $(<%node.storage_name%>) interpolation_duration set value <%interpolation_duration%> + dir zzz { + function on_tick { + # Tweening logic + scoreboard players remove @s <%OBJECTIVES.TWEEN_DURATION()%> 1 + execute if score @s <%OBJECTIVES.TWEEN_DURATION()%> matches 1.. run return 1 + execute if score @s <%OBJECTIVES.TWEEN_DURATION()%> matches 0 run \ + block { with storage <%temp_storage%> entry.data.uuids_by_name + REPEAT (Object.values(rig.nodes).filter(node => BONE_TYPES.includes(node.type))) as node { + $data modify entity $(<%node.storage_name%>) interpolation_duration set value <%interpolation_duration%> + } } - } - # Animation logic - IF (animation.loop_mode === 'loop' && animation.loop_delay === 0) { - # Makes sure function keyframes in the last frame of the animation are activated. - execute if score @s <%OBJECTIVES.FRAME(animation.storage_name)%> matches -1 run \ - block function_keyframe_loop_patch { - function ./frames/last_frame_effects with storage <%temp_storage%> entry.data.uuids_by_name - scoreboard players add @s <%OBJECTIVES.FRAME(animation.storage_name)%> 1 + # Animation logic + IF (animation.loop_mode === 'loop' && animation.loop_delay === 0) { + # Makes sure function keyframes in the last frame of the animation are activated. + execute if score @s <%OBJECTIVES.FRAME(animation.storage_name)%> matches -1 run \ + block function_keyframe_loop_patch { + function ./frames/last_frame_effects with storage <%temp_storage%> entry.data.uuids_by_name + scoreboard players add @s <%OBJECTIVES.FRAME(animation.storage_name)%> 1 + } + } + data remove storage <%temp_storage%> args + execute store result storage <%temp_storage%> args.frame int 1 run \ + scoreboard players get @s <%OBJECTIVES.FRAME(animation.storage_name)%> + function ./apply_frame with storage <%temp_storage%> args + IF (animation.loop_mode === 'loop') { + # Loop the animation back to the start once it reaches the last frame. + # If loop_delay is 0, the animation will loop instantly, otherwise, it will wait for the specified amount of ticks. + execute \ + if score @s <%OBJECTIVES.FRAME(animation.storage_name)%> \ + matches <%animation.duration-2 + animation.loop_delay%>.. \ + run return run \ + scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> <%animation.loop_delay === 0 ? -1 : 0%> + } ELSE IF (animation.loop_mode === 'hold') { + # Pause the animation at the last frame. + execute \ + if score @s <%OBJECTIVES.FRAME(animation.storage_name)%> \ + matches <%animation.duration-1%>.. \ + run return run \ + function ../pause + } ELSE IF (animation.loop_mode === 'once') { + # Stop the animation once it reaches the last frame. + execute \ + if score @s <%OBJECTIVES.FRAME(animation.storage_name)%> \ + matches <%animation.duration-1%> \ + run return run block loop_mode_stop { + scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> 0 + tag @s add <%TAGS.TRANSFORMS_ONLY()%> + execute at @s run function ./zzz/set_frame {frame: 0} + tag @s remove <%TAGS.TRANSFORMS_ONLY()%> + tag @s remove <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%> } - } - data remove storage <%temp_storage%> args - execute store result storage <%temp_storage%> args.frame int 1 run \ - scoreboard players get @s <%OBJECTIVES.FRAME(animation.storage_name)%> - function ./apply_frame with storage <%temp_storage%> args - IF (animation.loop_mode === 'loop') { - # Loop the animation back to the start once it reaches the last frame. - # If loop_delay is 0, the animation will loop instantly, otherwise, it will wait for the specified amount of ticks. - execute \ - if score @s <%OBJECTIVES.FRAME(animation.storage_name)%> \ - matches <%animation.duration-2 + animation.loop_delay%>.. \ - run return run \ - scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> <%animation.loop_delay === 0 ? -1 : 0%> - } ELSE IF (animation.loop_mode === 'hold') { - # Pause the animation at the last frame. - execute \ - if score @s <%OBJECTIVES.FRAME(animation.storage_name)%> \ - matches <%animation.duration-1%>.. \ - run return run \ - function ../pause - } ELSE IF (animation.loop_mode === 'once') { - # Stop the animation once it reaches the last frame. - execute \ - if score @s <%OBJECTIVES.FRAME(animation.storage_name)%> \ - matches <%animation.duration-1%> \ - run return run block loop_mode_stop { - scoreboard players set @s <%OBJECTIVES.FRAME(animation.storage_name)%> 0 - tag @s add <%TAGS.TRANSFORMS_ONLY()%> - execute at @s run function ./zzz/set_frame {frame: 0} - tag @s remove <%TAGS.TRANSFORMS_ONLY()%> - tag @s remove <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%> } + scoreboard players add @s <%OBJECTIVES.FRAME(animation.storage_name)%> 1 } - scoreboard players add @s <%OBJECTIVES.FRAME(animation.storage_name)%> 1 - } - IF (use_storage_for_animation) { - function set_frame { - #ARGS: {frame: int} - $function ./apply_frame {frame: $(frame)} - block { with storage <%temp_storage%> entry.data.uuids_by_name - REPEAT (Object.values(rig.nodes).filter(node => BONE_TYPES.includes(node.type))) as node { - $data modify entity $(<%node.storage_name%>) start_interpolation set value -1 + IF (use_storage_for_animation) { + function set_frame { + #ARGS: {frame: int} + $function ./apply_frame {frame: $(frame)} + block { with storage <%temp_storage%> entry.data.uuids_by_name + REPEAT (Object.values(rig.nodes).filter(node => BONE_TYPES.includes(node.type))) as node { + $data modify entity $(<%node.storage_name%>) start_interpolation set value -1 + } } + return 1 } - return 1 - } - function apply_frame { - #ARGS: {frame: int} - - block { with storage <%temp_storage%> entry.data.uuids_by_name - REPEAT (Object.values(animation.modified_nodes).sort(nodeSorter)) as node { - IF (BONE_TYPES.includes(node.type)) { - $data modify entity $(<%node.storage_name%>) {} merge from \ - storage <%project_storage%>/animations <%animation.storage_name%>.$(frame).<%node.storage_name%> - } ELSE IF (node.type === 'locator' || node.type === 'camera') { - $data modify storage <%temp_storage%> entry.data.uuids_by_name.<%node.storage_name%> merge from \ - storage <%project_storage%>/animations <%animation.storage_name%>.$(frame).<%node.storage_name%> + function apply_frame { + #ARGS: {frame: int} + + block { with storage <%temp_storage%> entry.data.uuids_by_name + REPEAT (Object.values(animation.modified_nodes).sort(nodeSorter)) as node { + IF (BONE_TYPES.includes(node.type)) { + $data modify entity $(<%node.storage_name%>) {} merge from \ + storage <%project_storage%>/animations <%animation.storage_name%>.$(frame).<%node.storage_name%> + } ELSE IF (node.type === 'locator' || node.type === 'camera') { + $data modify storage <%temp_storage%> entry.data.uuids_by_name.<%node.storage_name%> merge from \ + storage <%project_storage%>/animations <%animation.storage_name%>.$(frame).<%node.storage_name%> + } } } - } - IF (animation.frames.some(anim => anim.variant)) { - $execute \ - if data storage <%project_storage%>/animations <%animation.storage_name%>.$(frame).variant \ - unless entity @s[tag=<%TAGS.TRANSFORMS_ONLY()%>] \ - run { with storage <%project_storage%>/animations <%animation.storage_name%>.$(frame).variant - #ARGS: {name: string, condition: string} - $execute $(condition)run function <%blueprint_id%>/variants/$(name)/apply + IF (animation.frames.some(anim => anim.variant)) { + $execute \ + if data storage <%project_storage%>/animations <%animation.storage_name%>.$(frame).variant \ + unless entity @s[tag=<%TAGS.TRANSFORMS_ONLY()%>] \ + run { with storage <%project_storage%>/animations <%animation.storage_name%>.$(frame).variant + #ARGS: {name: string, condition: string} + $execute $(condition)run function <%blueprint_id%>/variants/$(name)/apply + } } - } - return 1 - } - } ELSE { - function set_frame { - # Sets the frame without interpolation - #ARGS: {frame: int} + return 1 + } + } ELSE { + function set_frame { + # Sets the frame without interpolation + #ARGS: {frame: int} - $function ./frames/$(frame) with storage <%temp_storage%> entry.data.uuids_by_name + $function ./frames/$(frame) with storage <%temp_storage%> entry.data.uuids_by_name - block { with storage <%temp_storage%> entry.data.uuids_by_name - REPEAT (Object.values(rig.nodes).filter(node => BONE_TYPES.includes(node.type))) as node { - $data modify entity $(<%node.storage_name%>) start_interpolation set value -1 + block { with storage <%temp_storage%> entry.data.uuids_by_name + REPEAT (Object.values(rig.nodes).filter(node => BONE_TYPES.includes(node.type))) as node { + $data modify entity $(<%node.storage_name%>) start_interpolation set value -1 + } } - } - return 1 - } + return 1 + } - function apply_frame { - #ARGS: {frame: int} + function apply_frame { + #ARGS: {frame: int} - $function ./frames/$(frame) with storage <%temp_storage%> entry.data.uuids_by_name + $function ./frames/$(frame) with storage <%temp_storage%> entry.data.uuids_by_name - return 1 - } + return 1 + } - # FIXME - %NEWLINE_PATCH% is a temporary solution to temporarily fix an MCB bug where extra newlines are being added to the output. - dir frames { - <%% - global.frame = animation.frames.at(-1) - global.modified_effect_nodes = Object.values(animation.modified_nodes).filter( - node => node.type === 'locator' && global.frame.node_transforms[node.uuid] - ) - console.log(global.modified_effect_nodes) - %%> - IF(Object.keys(global.modified_effect_nodes).length > 0) { - function last_frame_effects { - REPEAT(global.modified_effect_nodes) as node { - <%% - global.transform = global.frame.node_transforms[node.uuid] - %%> - IF (node.config?.use_entity) { - $execute \ - as $(<%node.storage_name%>) \ - positioned \ - ^<%roundTo(global.transform.pos[0], 10)%> \ - ^<%roundTo(global.transform.pos[1], 10)%> \ - ^<%roundTo(global.transform.pos[2], 10)%> \ - rotated \ - ~<%roundTo(global.transform.head_rot[1], 10)%> \ - ~<%roundTo(global.transform.head_rot[0], 10)%> \ - <%global.transform.function_execute_condition ? global.transform.function_execute_condition + ' ' : ''%>run \ - function ./<%animation.duration%>_locator_<%node.storage_name%> - } ELSE { - execute \ - positioned \ - ^<%roundTo(global.transform.pos[0], 10)%> \ - ^<%roundTo(global.transform.pos[1], 10)%> \ - ^<%roundTo(global.transform.pos[2], 10)%> \ - rotated \ - ~<%roundTo(global.transform.head_rot[1], 10)%> \ - ~<%roundTo(global.transform.head_rot[0], 10)%> \ - <%global.transform.function_execute_condition ? global.transform.function_execute_condition + ' ' : ''%>run \ - function ./<%animation.duration%>_locator_<%node.storage_name%> + # FIXME - %NEWLINE_PATCH% is a temporary solution to temporarily fix an MCB bug where extra newlines are being added to the output. + dir frames { + <%% + global.frame = animation.frames.at(-1) + global.modified_effect_nodes = Object.values(animation.modified_nodes).filter( + node => node.type === 'locator' && global.frame.node_transforms[node.uuid] + ) + console.log(global.modified_effect_nodes) + %%> + IF(Object.keys(global.modified_effect_nodes).length > 0) { + function last_frame_effects { + REPEAT(global.modified_effect_nodes) as node { + <%% + global.transform = global.frame.node_transforms[node.uuid] + %%> + IF (node.config?.use_entity) { + $execute \ + as $(<%node.storage_name%>) \ + positioned \ + ^<%roundTo(global.transform.pos[0], 10)%> \ + ^<%roundTo(global.transform.pos[1], 10)%> \ + ^<%roundTo(global.transform.pos[2], 10)%> \ + rotated \ + ~<%roundTo(global.transform.head_rot[1], 10)%> \ + ~<%roundTo(global.transform.head_rot[0], 10)%> \ + <%global.transform.function_execute_condition ? global.transform.function_execute_condition + ' ' : ''%>run \ + function ./<%animation.duration%>_locator_<%node.storage_name%> + } ELSE { + execute \ + positioned \ + ^<%roundTo(global.transform.pos[0], 10)%> \ + ^<%roundTo(global.transform.pos[1], 10)%> \ + ^<%roundTo(global.transform.pos[2], 10)%> \ + rotated \ + ~<%roundTo(global.transform.head_rot[1], 10)%> \ + ~<%roundTo(global.transform.head_rot[0], 10)%> \ + <%global.transform.function_execute_condition ? global.transform.function_execute_condition + ' ' : ''%>run \ + function ./<%animation.duration%>_locator_<%node.storage_name%> + } } - } - IF (global.frame.variants?.length > 0) { - execute <%global.frame.variants_execute_condition ? global.frame.variants_execute_condition + ' ' : ''%>run \ - function <%blueprint_id%>/variants/<%global.frame.variants[0].name%>/apply - } + IF (global.frame.variants?.length > 0) { + execute <%global.frame.variants_execute_condition ? global.frame.variants_execute_condition + ' ' : ''%>run \ + function <%blueprint_id%>/variants/<%global.frame.variants[0].name%>/apply + } - IF (global.frame.function) { - execute <%global.frame.function_execute_condition ? global.frame.function_execute_condition + ' ' : ''%>run \ - block <%animation.duration%>_function_keyframe { - <%global.frame.function%> - } + IF (global.frame.function) { + execute <%global.frame.function_execute_condition ? global.frame.function_execute_condition + ' ' : ''%>run \ + block <%animation.duration%>_function_keyframe { + <%global.frame.function%> + } + } } } - } - <%% - // A record of node uuid to INodeTransform. - // Keeps track of the last time a bone was updated. - // Only used for step keyframe interpolation. - let hasFunction = false - const lastActiveFrame = {} - const modifiedNodes = Object.values(animation.modified_nodes).filter(n => n.type !== 'struct').sort(nodeSorter); - for (const [frameIndex, frame] of animation.frames.entries()) { - const to_merge = {cameras: {}, locators: {}} - let frameFunc = ``; - for (const node of modifiedNodes) { - const transform = frame.node_transforms[node.uuid] - // Skip if the node doesn't have a transform for this frame. - if (!transform) continue - switch (node.type) { - case 'bone': - case 'text_display': - case 'item_display': - case 'block_display': { - const lastFrame = lastActiveFrame[node.uuid] - const isStepInterpolation = !!(lastFrame?.interpolation === 'step') - lastActiveFrame[node.uuid] = transform - - if (transform.interpolation === 'pre-post' || isStepInterpolation) { - frameFunc += - `\n$data merge entity $(${node.storage_name})%NEWLINE_PATCH%{` - + `transformation: ${matrixToNbtFloatArray(transform.matrix).toString()},` - + `start_interpolation: ${isStepInterpolation ? -1 : 0},` - + `interpolation_duration: ${isStepInterpolation ? 0 : interpolation_duration}` - + `}` - } else { - frameFunc += - `\n$data merge entity $(${node.storage_name})%NEWLINE_PATCH%{` - + `transformation: ${matrixToNbtFloatArray(transform.matrix).toString()},` - + `start_interpolation: 0,` - + `interpolation_duration: ${interpolation_duration}` - + `}` - } - - ;hasFunction = true - break - } - case 'locator': { - const lastFrame = lastActiveFrame[node.uuid] - lastActiveFrame[node.uuid] = transform - ;if (!lastFrame || matrixToNbtFloatArray(transform.matrix).toString() !== matrixToNbtFloatArray(lastFrame.matrix).toString()) { - to_merge.locators[node.storage_name] = { - px: roundTo(transform.pos[0], 10), - py: roundTo(transform.pos[1], 10), - pz: roundTo(transform.pos[2], 10), - ry: roundTo(transform.head_rot[1], 10), - rx: roundTo(transform.head_rot[0], 10) - }; - } - - if (transform.function) { - if (node.config?.use_entity) { + <%% + // A record of node uuid to INodeTransform. + // Keeps track of the last time a bone was updated. + // Only used for step keyframe interpolation. + let hasFunction = false + const lastActiveFrame = {} + const modifiedNodes = Object.values(animation.modified_nodes).filter(n => n.type !== 'struct').sort(nodeSorter); + for (const [frameIndex, frame] of animation.frames.entries()) { + const to_merge = {cameras: {}, locators: {}} + let frameFunc = ``; + for (const node of modifiedNodes) { + const transform = frame.node_transforms[node.uuid] + // Skip if the node doesn't have a transform for this frame. + if (!transform) continue + switch (node.type) { + case 'bone': + case 'text_display': + case 'item_display': + case 'block_display': { + const lastFrame = lastActiveFrame[node.uuid] + const isStepInterpolation = !!(lastFrame?.interpolation === 'step') + lastActiveFrame[node.uuid] = transform + + if (transform.interpolation === 'pre-post' || isStepInterpolation) { frameFunc += - `\n$execute unless entity @s[tag=${TAGS.TRANSFORMS_ONLY()}] as $(${node.storage_name}) ` - + `positioned ^${roundTo(transform.pos[0], 10)} ^${roundTo(transform.pos[1], 10)} ^${roundTo(transform.pos[2], 10)} ` - + `rotated ~${roundTo(transform.head_rot[1], 10)} ~${roundTo(transform.head_rot[0], 10)} ` - + `${transform.function_execute_condition ? transform.function_execute_condition + ' ' : ''}run ` - + `block ${frameIndex}_locator_${node.storage_name}%NEWLINE_PATCH%{\n` - + `tp @s ~ ~ ~ ~ ~\n` - + `${transform.function}` - + `\n}` + `\n$data merge entity $(${node.storage_name})%NEWLINE_PATCH%{` + + `transformation: ${matrixToNbtFloatArray(transform.matrix).toString()},` + + `start_interpolation: ${isStepInterpolation ? -1 : 0},` + + `interpolation_duration: ${isStepInterpolation ? 0 : interpolation_duration}` + + `}` } else { frameFunc += - `\nexecute unless entity @s[tag=${TAGS.TRANSFORMS_ONLY()}] ` - + `positioned ^${roundTo(transform.pos[0], 10)} ^${roundTo(transform.pos[1], 10)} ^${roundTo(transform.pos[2], 10)} ` - + `rotated ~${roundTo(transform.head_rot[1], 10)} ~${roundTo(transform.head_rot[0], 10)} ` - + `${transform.function_execute_condition ? transform.function_execute_condition + ' ' : ''}run ` - + `block ${frameIndex}_locator_${node.storage_name}%NEWLINE_PATCH%{\n` - + `${transform.function}` - + `\n}` + `\n$data merge entity $(${node.storage_name})%NEWLINE_PATCH%{` + + `transformation: ${matrixToNbtFloatArray(transform.matrix).toString()},` + + `start_interpolation: 0,` + + `interpolation_duration: ${interpolation_duration}` + + `}` + } + + ;hasFunction = true + break + } + case 'locator': { + const lastFrame = lastActiveFrame[node.uuid] + lastActiveFrame[node.uuid] = transform + ;if (!lastFrame || matrixToNbtFloatArray(transform.matrix).toString() !== matrixToNbtFloatArray(lastFrame.matrix).toString()) { + to_merge.locators[node.storage_name] = { + px: roundTo(transform.pos[0], 10), + py: roundTo(transform.pos[1], 10), + pz: roundTo(transform.pos[2], 10), + ry: roundTo(transform.head_rot[1], 10), + rx: roundTo(transform.head_rot[0], 10) + }; } + + if (transform.function) { + if (node.config?.use_entity) { + frameFunc += + `\n$execute unless entity @s[tag=${TAGS.TRANSFORMS_ONLY()}] as $(${node.storage_name}) ` + + `positioned ^${roundTo(transform.pos[0], 10)} ^${roundTo(transform.pos[1], 10)} ^${roundTo(transform.pos[2], 10)} ` + + `rotated ~${roundTo(transform.head_rot[1], 10)} ~${roundTo(transform.head_rot[0], 10)} ` + + `${transform.function_execute_condition ? transform.function_execute_condition + ' ' : ''}run ` + + `block ${frameIndex}_locator_${node.storage_name}%NEWLINE_PATCH%{\n` + + `tp @s ~ ~ ~ ~ ~\n` + + `${transform.function}` + + `\n}` + } else { + frameFunc += + `\nexecute unless entity @s[tag=${TAGS.TRANSFORMS_ONLY()}] ` + + `positioned ^${roundTo(transform.pos[0], 10)} ^${roundTo(transform.pos[1], 10)} ^${roundTo(transform.pos[2], 10)} ` + + `rotated ~${roundTo(transform.head_rot[1], 10)} ~${roundTo(transform.head_rot[0], 10)} ` + + `${transform.function_execute_condition ? transform.function_execute_condition + ' ' : ''}run ` + + `block ${frameIndex}_locator_${node.storage_name}%NEWLINE_PATCH%{\n` + + `${transform.function}` + + `\n}` + } + } + break } - break - } - case 'camera': { - const lastFrame = lastActiveFrame[node.uuid] - lastActiveFrame[node.uuid] = transform - ;if (!lastFrame || matrixToNbtFloatArray(transform.matrix).toString() !== matrixToNbtFloatArray(lastFrame.matrix).toString()) { - to_merge.cameras[node.storage_name] = { - px: transform.pos[0], - py: transform.pos[1], - pz: transform.pos[2], - ry: transform.head_rot[1], - rx: transform.head_rot[0] - }; + case 'camera': { + const lastFrame = lastActiveFrame[node.uuid] + lastActiveFrame[node.uuid] = transform + ;if (!lastFrame || matrixToNbtFloatArray(transform.matrix).toString() !== matrixToNbtFloatArray(lastFrame.matrix).toString()) { + to_merge.cameras[node.storage_name] = { + px: transform.pos[0], + py: transform.pos[1], + pz: transform.pos[2], + ry: transform.head_rot[1], + rx: transform.head_rot[0] + }; + } + ;break } - ;break } } - } - if (Object.keys(to_merge.locators).length > 0 || Object.keys(to_merge.cameras).length > 0) { - frameFunc += `\ndata modify storage <%temp_storage%> entry.data merge value ${JSON.stringify(to_merge)}` - frameFunc += `\ndata_manager write` - if (!auto_update_rig_orientation) { - frameFunc += `\nfunction ${blueprint_id}/root/on_tick/transform_floating_entities` + if (Object.keys(to_merge.locators).length > 0 || Object.keys(to_merge.cameras).length > 0) { + frameFunc += `\ndata modify storage <%temp_storage%> entry.data merge value ${JSON.stringify(to_merge)}` + frameFunc += `\ndata_manager write` + if (!auto_update_rig_orientation) { + frameFunc += `\nfunction ${blueprint_id}/root/on_tick/transform_floating_entities` + } + hasFunction = true } - hasFunction = true - } - if (frame.variants?.length) { - const variant = rig.variants[frame.variants[0]] - if (!variant) { - throw new Error(`Could not find Variant with uuid "${frame.variants[0]}" while generating frame "${frameIndex}" of animation "${animation.name}".`) + if (frame.variants?.length) { + const variant = rig.variants[frame.variants[0]] + if (!variant) { + throw new Error(`Could not find Variant with uuid "${frame.variants[0]}" while generating frame "${frameIndex}" of animation "${animation.name}".`) + } + const execute_condition = frame.variants_execute_condition ? frame.variants_execute_condition + ' ' : '' + frameFunc += `\nexecute unless entity @s[tag=${TAGS.TRANSFORMS_ONLY()}] ${execute_condition}run function ${blueprint_id}/variants/${variant.name}/apply` + ;hasFunction = true } - const execute_condition = frame.variants_execute_condition ? frame.variants_execute_condition + ' ' : '' - frameFunc += `\nexecute unless entity @s[tag=${TAGS.TRANSFORMS_ONLY()}] ${execute_condition}run function ${blueprint_id}/variants/${variant.name}/apply` - ;hasFunction = true - } - // Root function keyframes. - if (frame.function) { - const execute_condition = frame.function_execute_condition ? frame.function_execute_condition + ' ' : '' - frameFunc += `\nexecute unless entity @s[tag=${TAGS.TRANSFORMS_ONLY()}] at @s ${execute_condition}run block ${frameIndex}_root_function%NEWLINE_PATCH%{\n${frame.function}\n}` - ;hasFunction = true - } - ;if (frameFunc.length > 0) { - frameFunc = `function ${frameIndex}%NEWLINE_PATCH%{${frameFunc}\n}` - emit.mcb(frameFunc.replaceAll(/%NEWLINE_PATCH%\n?/g, ' ')) + // Root function keyframes. + if (frame.function) { + const execute_condition = frame.function_execute_condition ? frame.function_execute_condition + ' ' : '' + frameFunc += `\nexecute unless entity @s[tag=${TAGS.TRANSFORMS_ONLY()}] at @s ${execute_condition}run block ${frameIndex}_root_function%NEWLINE_PATCH%{\n${frame.function}\n}` + ;hasFunction = true + } + ;if (frameFunc.length > 0) { + frameFunc = `function ${frameIndex}%NEWLINE_PATCH%{${frameFunc}\n}` + emit.mcb(frameFunc.replaceAll(/%NEWLINE_PATCH%\n?/g, ' ')) + } } - } - %%> + %%> + } } } } } - } - function pause_all { - # Pauses all animations - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> + function pause_all { + # Pauses all animations + debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - REPEAT (animations) as animation { - tag @s remove <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%> + REPEAT (animations) as animation { + tag @s remove <%TAGS.ANIMATION_PLAYING(blueprint_id, animation.storage_name)%> + } } } } function summon { - #Args: {args:{variant: string, animation: string, frame: int, start_animation: boolean}} + #Args: {args:{variant?: string, animation?: string, frame?: int, start_animation?: boolean}} # frame is ignored unless animation is specified. - data modify storage <%temp_storage%> args set value {variant:'', animation:'', frame: 0} $execute store success score #success <%OBJECTIVES.I()%> run data modify storage <%temp_storage%> args set value $(args) + IF (!has_animations && debug_mode) { + execute if data storage <%temp_storage%> args.animation run return run \ + tellraw @a <%TELLRAW.ANIMATION_ARG_NO_RIG_ANIMATIONS()%> + execute if data storage <%temp_storage%> args.frame run return run \ + tellraw @a <%TELLRAW.FRAME_ARG_NO_RIG_FRAMES()%> + } + summon minecraft:item_display ~ ~ ~ { \ Tags:[ \ '<%TAGS.NEW()%>', \ @@ -756,52 +770,54 @@ function summon { } execute if score #success <%OBJECTIVES.I()%> matches 0 run return fail - # Animation Argument - # If the animation argument is provided, attempt to apply the animation. - execute if data storage <%temp_storage%> args.animation run block animation_arg/process { with storage <%temp_storage%> args - scoreboard players set #success <%OBJECTIVES.I()%> 0 - # If the animation argument is *explicitly* set to an empty string, return an error. - execute if data storage <%temp_storage%> {args:{animation:''}} run return run block if_empty { - tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('animation')%> - function <%blueprint_id%>/remove/this/without_on_remove_function - } - # Automatically set the frame argument to 0 if the frame argument is not provided. - # Takes advantage of `store result score` setting the score to 0 if the command fails. - execute \ - store result storage <%temp_storage%> args.frame int 1 \ - store result score #frame <%OBJECTIVES.I()%> \ - run \ - data get storage <%temp_storage%> args.frame - # If the frame argument is negative, return an error. - execute if score #frame <%OBJECTIVES.I()%> matches ..-1 run return run block no_negative { - # Tell the user that the frame argument cannot be negative. - tellraw @a <%TELLRAW.FRAME_CANNOT_BE_NEGATIVE()%> - function <%blueprint_id%>/remove/this/without_on_remove_function - } - # Attempt to apply the animation frame. - execute store success score #success <%OBJECTIVES.I()%> run block try_set_frame { with storage <%temp_storage%> args - # Make sure we're only applying transforms when setting the summon pose. - tag @s add <%TAGS.TRANSFORMS_ONLY()%> - $execute store success score #success <%OBJECTIVES.I()%> run function <%blueprint_id%>/animations/$(animation)/zzz/set_frame with storage <%temp_storage%> args - tag @s remove <%TAGS.TRANSFORMS_ONLY()%> - execute if score #success <%OBJECTIVES.I()%> matches 1 run return 1 - # If the set_frame function fails, the animation doesn't exist, so we return an error. - return fail - } - # If the set_frame function failed, return an error. - execute unless score #success <%OBJECTIVES.I()%> matches 1 run return run block invalid_animation { - # Tell the user that the provided animation doesn't exist, remove the rig, and list all available animations for this rig. - tellraw @a <%TELLRAW.INVALID_ANIMATION(animations)%> - function <%blueprint_id%>/remove/this/without_on_remove_function - } + IF (has_animations) { + # Animation Argument + # If the animation argument is provided, attempt to apply the animation. + execute if data storage <%temp_storage%> args.animation run block animation_arg/process { with storage <%temp_storage%> args + scoreboard players set #success <%OBJECTIVES.I()%> 0 + # If the animation argument is *explicitly* set to an empty string, return an error. + execute if data storage <%temp_storage%> {args:{animation:''}} run return run block if_empty { + tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('animation')%> + function <%blueprint_id%>/remove/this/without_on_remove_function + } + # Automatically set the frame argument to 0 if the frame argument is not provided. + # Takes advantage of `store result score` setting the score to 0 if the command fails. + execute \ + store result storage <%temp_storage%> args.frame int 1 \ + store result score #frame <%OBJECTIVES.I()%> \ + run \ + data get storage <%temp_storage%> args.frame + # If the frame argument is negative, return an error. + execute if score #frame <%OBJECTIVES.I()%> matches ..-1 run return run block no_negative { + # Tell the user that the frame argument cannot be negative. + tellraw @a <%TELLRAW.FRAME_CANNOT_BE_NEGATIVE()%> + function <%blueprint_id%>/remove/this/without_on_remove_function + } + # Attempt to apply the animation frame. + execute store success score #success <%OBJECTIVES.I()%> run block try_set_frame { with storage <%temp_storage%> args + # Make sure we're only applying transforms when setting the summon pose. + tag @s add <%TAGS.TRANSFORMS_ONLY()%> + $execute store success score #success <%OBJECTIVES.I()%> run function <%blueprint_id%>/animations/$(animation)/zzz/set_frame with storage <%temp_storage%> args + tag @s remove <%TAGS.TRANSFORMS_ONLY()%> + execute if score #success <%OBJECTIVES.I()%> matches 1 run return 1 + # If the set_frame function fails, the animation doesn't exist, so we return an error. + return fail + } + # If the set_frame function failed, return an error. + execute unless score #success <%OBJECTIVES.I()%> matches 1 run return run block invalid_animation { + # Tell the user that the provided animation doesn't exist, remove the rig, and list all available animations for this rig. + tellraw @a <%TELLRAW.INVALID_ANIMATION(animations)%> + function <%blueprint_id%>/remove/this/without_on_remove_function + } - # If the animation is successfully applied, and the start_animation argument is set to true, start the animation. - execute if data storage <%temp_storage%> {args:{start_animation: true}} run block start_animation { with storage <%temp_storage%> args - $function <%blueprint_id%>/animations/$(animation)/resume + # If the animation is successfully applied, and the start_animation argument is set to true, start the animation. + execute if data storage <%temp_storage%> {args:{start_animation: true}} run block start_animation { with storage <%temp_storage%> args + $function <%blueprint_id%>/animations/$(animation)/resume + } + scoreboard players set #success <%OBJECTIVES.I()%> 1 } - scoreboard players set #success <%OBJECTIVES.I()%> 1 + execute if score #success <%OBJECTIVES.I()%> matches 0 run return fail } - execute if score #success <%OBJECTIVES.I()%> matches 0 run return fail IF (has_locators || has_cameras) { function <%blueprint_id%>/root/on_tick/transform_floating_entities @@ -1386,16 +1402,18 @@ IF (has_locators || has_cameras) { } dir zzz { - function apply_default_pose { - IF (has_locators || has_cameras) { - function ../zzz/reset_floating_entities - } + IF (has_animations) { + function apply_default_pose { + IF (has_locators || has_cameras) { + function ../zzz/reset_floating_entities + } - block apply_default_pose_to_nodes { with storage <%temp_storage%> entry.data.uuids_by_name - REPEAT (Object.values(rig.nodes).filter(node => BONE_TYPES.includes(node.type))) as node { - $data merge entity $(<%node.storage_name%>) { \ - transformation: <%matrixToNbtFloatArray(node.default_transform.matrix).toString()%>, \ - start_interpolation: 0 \ + block apply_default_pose_to_nodes { with storage <%temp_storage%> entry.data.uuids_by_name + REPEAT (Object.values(rig.nodes).filter(node => BONE_TYPES.includes(node.type))) as node { + $data merge entity $(<%node.storage_name%>) { \ + transformation: <%matrixToNbtFloatArray(node.default_transform.matrix).toString()%>, \ + start_interpolation: 0 \ + } } } } @@ -1416,14 +1434,17 @@ dir zzz { } } } -function apply_default_pose { - # Changes the pose of the rig to the the default pose with interpolation - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - IF (has_locators || has_cameras) { - data_manager prep read +IF (has_animations) { + function apply_default_pose { + # Changes the pose of the rig to the the default pose with interpolation + debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> + + IF (has_locators || has_cameras) { + data_manager prep read + } + function ./zzz/apply_default_pose } - function ./zzz/apply_default_pose } function set_default_pose { diff --git a/src/systems/datapackCompiler/1.21.5/static.mcb b/src/systems/datapackCompiler/1.21.5/static.mcb deleted file mode 100644 index 207b1af4..00000000 --- a/src/systems/datapackCompiler/1.21.5/static.mcb +++ /dev/null @@ -1,907 +0,0 @@ -# TODO - Move all internal functions into an internal namespace, and only have user-facing functions in the main `<%blueprint_id%>` namespace. - -# DIFFERENCES FROM 1.21.4: -# - JSON text components are now stored as NBT in entities. - -function on_load { - data modify storage <%project_storage%> rig_hash set value <%"'" + rig_hash + "'"%> -} - -dir root { - function on_tick { - # Custom pre-tick function - IF (on_pre_tick_function) { - <%% - emit.mcb(on_pre_tick_function) - %%> - } - - IF (auto_update_rig_orientation) { - IF (has_locators || has_cameras) { - function <%blueprint_id%>/root/on_tick/transform_floating_entities - } - - block { with storage <%temp_storage%> entry.data.uuids_by_name - REPEAT (Object.values(rig.nodes).filter(node => BONE_TYPES.includes(node.type))) as node { - $tp $(<%node.storage_name%>) ~ ~ ~ ~ ~ - # Precise Rotation Workaround. Fixes MC-272913. - # Thanks @Triton365! (https://discord.com/channels/154777837382008833/157097006500806656/1402253905408163842) - $execute \ - as $(<%node.storage_name%>) \ - store success entity @s OnGround byte 1 \ - store success score @s <%OBJECTIVES.I()%> \ - unless score @s <%OBJECTIVES.I()%> matches 1 - } - } - } ELSE IF (has_ticking_locators) { - function <%blueprint_id%>/root/on_tick/transform_locators - } - - # Custom post-tick function - IF (on_post_tick_function) { - <%% - emit.mcb(on_post_tick_function) - %%> - } - } - - IF (has_locators || has_cameras) { - dir on_tick { - function transform_locators { - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'locator')) as locator { - block select_locator_<%locator.storage_name%> { with storage <%temp_storage%> entry.data.locators.<%locator.storage_name%> - IF (locator.config?.use_entity) { - $execute \ - as $(uuid) \ - positioned ^$(px) ^$(py) ^$(pz) \ - rotated ~$(ry) ~$(rx) \ - run block as_locator_<%locator.storage_name%> { - tp @s ~ ~ ~ ~ ~ - - IF (locator.config?.sync_passenger_rotation) { - execute on passengers run rotate @s ~ ~ - } - - IF (locator.config?.on_tick_function) { - <%% - emit.mcb(locator.config.on_tick_function) - %%> - } - } - - IF (locator.config?.sync_passenger_rotation) { - # Precise Rotation Workaround. Fixes MC-272913. - # Thanks @Triton365! (https://discord.com/channels/154777837382008833/157097006500806656/1402253905408163842) - $execute \ - as $(uuid) \ - store success entity @s OnGround byte 1 \ - store success score @s <%OBJECTIVES.I()%> \ - unless score @s <%OBJECTIVES.I()%> matches 1 - } - } ELSE IF (locator.config?.on_tick_function) { - $execute \ - positioned ^$(px) ^$(py) ^$(pz) \ - rotated ~$(ry) ~$(rx) \ - run block at_locator_<%locator.storage_name%> { - <%% - emit.mcb(locator.config.on_tick_function) - %%> - } - } - } - } - } - - function transform_floating_entities { - function ./transform_locators - - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'camera')) as camera { - block select_camera_<%camera.storage_name%> { with storage <%temp_storage%> entry.data.cameras.<%camera.storage_name%> - $execute \ - as $(uuid) \ - positioned ^$(px) ^$(py) ^$(pz) \ - rotated ~$(ry) ~$(rx) \ - run tp @s ~ ~ ~ ~ ~ - # Precise Rotation Workaround. Fixes MC-272913. - # Thanks @Triton365! (https://discord.com/channels/154777837382008833/157097006500806656/1402253905408163842) - $execute \ - as $(uuid) \ - store success entity @s OnGround byte 1 \ - store success score @s <%OBJECTIVES.I()%> \ - unless score @s <%OBJECTIVES.I()%> matches 1 - } - } - } - } - } -} - -IF (!auto_update_rig_orientation) { - function move { - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - - tp @s ~ ~ ~ ~ ~ - - data_manager prep read - IF (has_locators || has_cameras) { - function <%blueprint_id%>/root/on_tick/transform_floating_entities - } - - block { with storage <%temp_storage%> entry.data.uuids_by_name - REPEAT (Object.values(rig.nodes).filter(node => BONE_TYPES.includes(node.type))) as node { - $tp $(<%node.storage_name%>) ~ ~ ~ ~ ~ - # Precise Rotation Workaround. Fixes MC-272913. - # Thanks @Triton365! (https://discord.com/channels/154777837382008833/157097006500806656/1402253905408163842) - $execute \ - as $(<%node.storage_name%>) \ - store success entity @s OnGround byte 1 \ - store success score @s <%OBJECTIVES.I()%> \ - unless score @s <%OBJECTIVES.I()%> matches 1 - } - } - } -} ELSE { - function move { - tellraw @a <%TELLRAW.AUTO_UPDATE_RIG_ORIENTATION_MOVE_WARNING()%> - } -} - -function summon { - #Args: {args:{variant: string}} - - data modify storage <%temp_storage%> args set value {variant:''} - $execute store success score #success <%OBJECTIVES.I()%> run data modify storage <%temp_storage%> args set value $(args) - - summon minecraft:item_display ~ ~ ~ { \ - Tags:[ \ - '<%TAGS.NEW()%>', \ - '<%TAGS.GLOBAL_ENTITY()%>', \ - '<%TAGS.GLOBAL_ROOT()%>', \ - '<%TAGS.PROJECT_ENTITY(blueprint_id)%>', \ - '<%TAGS.PROJECT_ROOT(blueprint_id)%>' \ - ], \ - teleport_duration: 0, \ - interpolation_duration: <%interpolation_duration%>, \ - Passengers:<%root_entity_passengers%>, \ - CustomName: <%ENTITY_NAMES.ROOT(blueprint_id)%>, \ - } - execute as @n[ \ - type=minecraft:item_display, \ - tag=<%TAGS.PROJECT_ROOT(blueprint_id)%>, \ - tag=<%TAGS.NEW()%>, \ - distance=..0.01 \ - ] run block zzz/summon/as_root_entity { - execute store result score @s <%OBJECTIVES.ID()%> run scoreboard players add aj.last_id <%OBJECTIVES.ID()%> 1 - - data_manager init prep read - # Data manager init runs gu:get_entity_uuid_string. So we don't need to call it again here. - # function animated_java:global/gu/get_entity_uuid_string - data modify storage <%temp_storage%> entry.data.uuids append from storage <%gu_storage%> out - data modify storage <%temp_storage%> entry.data.root_uuid set from storage <%gu_storage%> out - - data modify storage <%temp_storage%> entry.data.blueprint_id set value "<%blueprint_id%>" - data modify storage <%temp_storage%> entry.data.rig_hash set value "<%rig_hash%>" - - # Align the position and rotation of the root with the command context. - tp @s ~ ~ ~ ~ ~ - - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'locator' && node.config?.use_entity)) as locator { - summon <%locator.config.entity_type%> \ - ^<%roundTo(locator.default_transform.pos[0], 10)%> \ - ^<%roundTo(locator.default_transform.pos[1], 10)%> \ - ^<%roundTo(locator.default_transform.pos[2], 10)%> \ - {Tags:<%getNodeTags(locator, rig)%>} - execute \ - as @n[ \ - type=<%locator.config.entity_type%>, \ - tag=<%TAGS.PROJECT_LOCATOR_NAMED(blueprint_id, locator.storage_name)%>, \ - tag=<%TAGS.NEW()%>, \ - distance=..<%Math.ceil(locator.max_distance + 0.5)%> \ - ] \ - run block as_locator/<%locator.storage_name%> { - # run block ../as_locator/<%locator.storage_name%> { - tag @s remove <%TAGS.NEW()%> - data modify entity @s CustomName set value <%ENTITY_NAMES.NODE(blueprint_id, locator.type, locator.storage_name)%> - function animated_java:global/gu/get_entity_uuid_string - scoreboard players operation @s <%OBJECTIVES.ID()%> = aj.last_id <%OBJECTIVES.ID()%> - } - data modify storage <%temp_storage%> entry.data.uuids append from storage <%gu_storage%> out - data modify storage <%temp_storage%> entry.data.uuids_by_name.<%locator.storage_name%> set from storage <%gu_storage%> out - data modify storage <%temp_storage%> entry.data.locators.<%locator.storage_name%>.uuid set from storage <%gu_storage%> out - } - - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'camera')) as camera { - summon minecraft:item_display \ - ^<%roundTo(camera.default_transform.pos[0], 10)%> \ - ^<%roundTo(camera.default_transform.pos[1], 10)%> \ - ^<%roundTo(camera.default_transform.pos[2], 10)%> \ - {Tags:<%getNodeTags(camera, rig)%>, teleport_duration: 2} - execute \ - as @n[ \ - type=minecraft:item_display, \ - tag=<%TAGS.PROJECT_CAMERA_NAMED(blueprint_id, camera.storage_name)%>, \ - tag=<%TAGS.NEW()%>, \ - distance=..<%Math.ceil(camera.max_distance + 0.5)%> \ - ] \ - run block as_camera/<%camera.storage_name%> { - # run block ../as_camera/<%camera.storage_name%> { - tag @s remove <%TAGS.NEW()%> - data modify entity @s CustomName set value <%ENTITY_NAMES.NODE(blueprint_id, camera.type, camera.storage_name)%> - function animated_java:global/gu/get_entity_uuid_string - scoreboard players operation @s <%OBJECTIVES.ID()%> = aj.last_id <%OBJECTIVES.ID()%> - } - data modify storage <%temp_storage%> entry.data.uuids append from storage <%gu_storage%> out - data modify storage <%temp_storage%> entry.data.uuids_by_name.<%camera.storage_name%> set from storage <%gu_storage%> out - data modify storage <%temp_storage%> entry.data.cameras.<%camera.storage_name%>.uuid set from storage <%gu_storage%> out - } - - REPEAT (Object.values(rig.nodes).filter(node => BONE_TYPES.includes(node.type))) as node { - execute \ - on passengers \ - if entity @s[tag=<%TAGS.PROJECT_NODE_NAMED(blueprint_id, node.storage_name)%>] \ - run block as_node/<%node.storage_name%> { - data modify entity @s CustomName set value <%ENTITY_NAMES.NODE(blueprint_id, node.type, node.storage_name)%> - function animated_java:global/gu/get_entity_uuid_string - scoreboard players operation @s <%OBJECTIVES.ID()%> = aj.last_id <%OBJECTIVES.ID()%> - } - - data modify storage <%temp_storage%> entry.data.uuids append from storage <%gu_storage%> out - data modify storage <%temp_storage%> entry.data.uuids_by_name.<%node.storage_name%> set from storage <%gu_storage%> out - } - - IF (has_entity_locators) { - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'locator' && node.config?.use_entity)) as locator { - block { with storage <%temp_storage%> entry.data.locators.<%locator.storage_name%> - # Track any custom entities on the locator. - $execute at @s as $(uuid) at @s run function animated_java:global/util/get_entity_stack_uuids - } - data modify storage <%temp_storage%> entry.data.uuids append from storage <%temp_storage%> uuids - } - } - - function <%blueprint_id%>/zzz/set_default_pose - - data_manager write - - # Variant Arguement - IF (Object.keys(rig.variants).length > 1) { - execute if data storage <%temp_storage%> args.variant run block variant_arg/process { with storage <%temp_storage%> args - scoreboard players set #success <%OBJECTIVES.I()%> 0 - # If the variant argument is *explicitly* set to an empty string, return an error. - execute if data storage <%temp_storage%> {args:{variant:''}} run return run block if_empty { - # Tell the user that the variant cannot be empty. - tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('variant')%> - function <%blueprint_id%>/remove/this/without_on_remove_function - } - # Attempt to apply the requested variant. - # We get the success of the `try_apply` function in just in case the user's arguments are *very* wrong. - execute store success score #success <%OBJECTIVES.I()%> run block try_apply { with storage <%temp_storage%> args - $execute if function <%blueprint_id%>/variants/$(variant)/apply run return 1 - # If the apply function fails, the variant doesn't exist, so we return an error. - return fail - } - # If the apply function failed, return an error. - execute unless score #success <%OBJECTIVES.I()%> matches 1 run return run block invalid_variant { - # Tell the user that the provided variant doesn't exist, remove the rig, and list all available variants for this rig. - tellraw @a <%TELLRAW.INVALID_VARIANT(rig.variants)%> - function <%blueprint_id%>/remove/this/without_on_remove_function - } - scoreboard players set #success <%OBJECTIVES.I()%> 1 - } - } ELSE { - execute if data storage <%temp_storage%> args.variant run block zzz/variant_arg/no_variants_warning { - tellraw @a <%TELLRAW.NO_VARIANTS()%> - function <%blueprint_id%>/remove/this/without_on_remove_function - scoreboard players set #success <%OBJECTIVES.I()%> 0 - } - } - execute if score #success <%OBJECTIVES.I()%> matches 0 run return fail - - IF (has_locators || has_cameras) { - function <%blueprint_id%>/root/on_tick/transform_floating_entities - } - execute on passengers run rotate @s ~ ~ - - # Apply teleport duration - data modify entity @s teleport_duration set value <%teleportation_duration%> - execute on passengers run data modify entity @s teleport_duration set value <%teleportation_duration%> - - IF (has_entity_locators) { - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'locator' && node.config?.use_entity && node.config.on_summon_function)) as locator { - block { with storage <%temp_storage%> entry.data.locators.<%locator.storage_name%> - $execute at @s as $(uuid) at @s run block on_summon/custom_<%locator.type + '_' + locator.storage_name%> { - <%% - emit.mcb(locator.config.on_summon_function) - %%> - } - } - } - } - - REPEAT (Object.values(rig.nodes).filter(node => BONE_TYPES.includes(node.type) && node.on_summon_function?.trim())) as node { - execute \ - on passengers if entity @s[tag=<%TAGS.PROJECT_NODE_NAMED(blueprint_id, node.storage_name)%>] \ - run block on_summon/<%node.type + '_' + node.storage_name%> { - <%% - emit.mcb(node.on_summon_function.trim()) - %%> - } - } - - IF (on_summon_function) { - execute at @s run block on_summon/rig { - <%% - emit.mcb(on_summon_function) - %%> - } - } - - # Remove the NEW tag from the root entity, and it's passengers. - tag @s remove <%TAGS.NEW()%> - execute on passengers run tag @s remove <%TAGS.NEW()%> - # Dismount bone entities from the root entity. - execute on passengers run ride @s dismount - } -} - -function as_node { - #ARGS: {name: string, command: string} - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - data remove storage <%temp_storage%> args - $data modify storage <%temp_storage%> args merge value {name:'$(name)', command:'$(command)', uuid:'+MISSING_UUID+'} - - IF (debug_mode) { - execute if data storage <%temp_storage%> {args:{name:''}} run return run tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('name')%> - execute if data storage <%temp_storage%> {args:{command:''}} run return run tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('command')%> - } - - data_manager prep read - - block zzz/as_node/as_data { with storage <%temp_storage%> args - $data modify storage <%temp_storage%> args.uuid set from storage <%temp_storage%> entry.data.uuids_by_name.$(name) - IF (debug_mode) { - scoreboard players set #aj.check <%OBJECTIVES.I()%> 0 - } - block execute_as_uuid { with storage <%temp_storage%> args - IF (debug_mode) { - # If the function successfully instantiated, the provided command is valid. - scoreboard players set #aj.check <%OBJECTIVES.I()%> 1 - } - $execute as $(uuid) run return run $(command) - IF (debug_mode) { - # If the entity with the provided UUID doesn't exist, the node wasn't found. - tellraw @a <%TELLRAW.NODE_ENTITY_NOT_FOUND()%> - } - } - IF (debug_mode) { - execute if score #aj.check <%OBJECTIVES.I()%> matches 0 run tellraw @a <%TELLRAW.NODE_COMMAND_FAILED_TO_EXECUTE()%> - } - } -} - -IF (has_entity_locators) { - function as_locator { - #ARGS: {name: string, command: string} - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - - data remove storage <%temp_storage%> args - $data modify storage <%temp_storage%> args merge value {name:'$(name)', command:'$(command)', uuid:'+MISSING_UUID+'} - - IF (debug_mode) { - execute if data storage <%temp_storage%> {args:{name:''}} run return run tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('name')%> - execute if data storage <%temp_storage%> {args:{command:''}} run return run tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('command')%> - } - - data_manager prep read - - block zzz/as_locator/as_data { with storage <%temp_storage%> args - $data modify storage <%temp_storage%> args.uuid set from storage <%temp_storage%> entry.data.locators.$(name).uuid - IF (debug_mode) { - scoreboard players set #aj.check <%OBJECTIVES.I()%> 0 - } - block execute_as_uuid { with storage <%temp_storage%> args - IF (debug_mode) { - # If the function successfully instantiated, the provided command is valid. - scoreboard players set #aj.check <%OBJECTIVES.I()%> 1 - } - $execute as $(uuid) run return run $(command) - IF (debug_mode) { - # If the entity with the provided UUID doesn't exist, the locator wasn't found. - tellraw @a <%TELLRAW.LOCATOR_ENTITY_NOT_FOUND()%> - } - } - IF (debug_mode) { - execute if score #aj.check <%OBJECTIVES.I()%> matches 0 run tellraw @a <%TELLRAW.LOCATOR_COMMAND_FAILED_TO_EXECUTE()%> - } - } - } - - function as_at_locator { - #ARGS: {name: string, command: string} - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - - data remove storage <%temp_storage%> args - $data modify storage <%temp_storage%> args merge value {name:'$(name)', command:'$(command)', uuid:'+MISSING_UUID+'} - - IF (debug_mode) { - execute if data storage <%temp_storage%> {args:{name:''}} run return run tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('name')%> - execute if data storage <%temp_storage%> {args:{command:''}} run return run tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('command')%> - } - - data_manager prep read - - block zzz/as_locator/as_data { with storage <%temp_storage%> args - $data modify storage <%temp_storage%> args.uuid set from storage <%temp_storage%> entry.data.locators.$(name).uuid - IF (debug_mode) { - scoreboard players set #aj.check <%OBJECTIVES.I()%> 0 - } - block execute_as_uuid { with storage <%temp_storage%> args - IF (debug_mode) { - # If the function successfully instantiated, the provided command is valid. - scoreboard players set #aj.check <%OBJECTIVES.I()%> 1 - } - $execute as $(uuid) at @s run return run $(command) - IF (debug_mode) { - # If the entity with the provided UUID doesn't exist, the locator wasn't found. - tellraw @a <%TELLRAW.LOCATOR_ENTITY_NOT_FOUND()%> - } - } - IF (debug_mode) { - execute if score #aj.check <%OBJECTIVES.I()%> matches 0 run tellraw @a <%TELLRAW.LOCATOR_COMMAND_FAILED_TO_EXECUTE()%> - } - } - } - - function as_all_locators { - #ARGS: {command: string} - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - - data remove storage <%temp_storage%> args - $data modify storage <%temp_storage%> args merge value {command:'$(command)'} - - IF (debug_mode) { - execute if data storage <%temp_storage%> {args:{command:''}} run return run tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('command')%> - } - - data_manager prep read - - block zzz/as_all_locators/as_data { - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'locator' && node.config?.use_entity)) as locator { - data modify storage <%temp_storage%> args.uuid set from storage <%temp_storage%> entry.data.locators.<%locator.storage_name%>.uuid - - IF (debug_mode) { - scoreboard players set #aj.check <%OBJECTIVES.I()%> 0 - } - - block execute_as_uuid { with storage <%temp_storage%> args - IF (debug_mode) { - # If the function successfully instantiated, the provided command is valid. - scoreboard players set #aj.check <%OBJECTIVES.I()%> 1 - } - - $execute as $(uuid) run return run $(command) - } - - IF (debug_mode) { - execute if score #aj.check <%OBJECTIVES.I()%> matches 0 run tellraw @a <%TELLRAW.LOCATOR_COMMAND_FAILED_TO_EXECUTE({text: locator.storage_name, color: 'aqua'})%> - } - } - } - } - - function as_at_all_locators { - #ARGS: {command: string} - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - - data remove storage <%temp_storage%> args - $data modify storage <%temp_storage%> args merge value {command:'$(command)'} - - IF (debug_mode) { - execute if data storage <%temp_storage%> {args:{command:''}} run return run tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('command')%> - } - - data_manager prep read - - block zzz/as_all_locators/as_data { - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'locator' && node.config?.use_entity)) as locator { - data modify storage <%temp_storage%> args.uuid set from storage <%temp_storage%> entry.data.locators.<%locator.storage_name%>.uuid - - IF (debug_mode) { - scoreboard players set #aj.check <%OBJECTIVES.I()%> 0 - } - - block execute_as_uuid { with storage <%temp_storage%> args - IF (debug_mode) { - # If the function successfully instantiated, the provided command is valid. - scoreboard players set #aj.check <%OBJECTIVES.I()%> 1 - } - - $execute as $(uuid) at @s run return run $(command) - } - - IF (debug_mode) { - execute if score #aj.check <%OBJECTIVES.I()%> matches 0 run tellraw @a <%TELLRAW.LOCATOR_COMMAND_FAILED_TO_EXECUTE({text: locator.storage_name, color: 'aqua'})%> - } - } - } - } -} - -IF (has_locators) { - function at_locator { - #ARGS: {name: string, command: string} - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - - data remove storage <%temp_storage%> args - $data modify storage <%temp_storage%> args merge value {name:'$(name)', command:'$(command)'} - - IF (debug_mode) { - execute if data storage <%temp_storage%> {args:{name:''}} run return run tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('name')%> - execute if data storage <%temp_storage%> {args:{command:''}} run return run tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('command')%> - } - - data_manager prep read - - execute at @s run block zzz/at_locator/as_data { with storage <%temp_storage%> args - $data modify storage <%temp_storage%> args merge from storage <%temp_storage%> entry.data.locators.$(name) - - IF (debug_mode) { - execute unless data storage <%temp_storage%> args.px run return run tellraw @a <%TELLRAW.LOCATOR_NOT_FOUND()%> - scoreboard players set #aj.check <%OBJECTIVES.I()%> 0 - } - - block execute_at_transform { with storage <%temp_storage%> args - IF (debug_mode) { - # If the function successfully instantiated, the provided command is valid. - scoreboard players set #aj.check <%OBJECTIVES.I()%> 1 - } - - $execute \ - positioned ^$(px) ^$(py) ^$(pz) \ - rotated ~$(ry) ~$(rx) \ - run $(command) - } - - IF (debug_mode) { - execute if score #aj.check <%OBJECTIVES.I()%> matches 0 run tellraw @a <%TELLRAW.LOCATOR_COMMAND_FAILED_TO_EXECUTE()%> - } - } - } - - function at_all_locators { - #ARGS: {command: string} - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - - data remove storage <%temp_storage%> args - $data modify storage <%temp_storage%> args merge value {command:'$(command)'} - - IF (debug_mode) { - execute if data storage <%temp_storage%> {args:{command:''}} run return run tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('command')%> - } - - data_manager prep read - - block zzz/at_all_locators/as_data { - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'locator')) as locator { - data modify storage <%temp_storage%> args merge from storage <%temp_storage%> entry.data.locators.<%locator.storage_name%> - - IF (debug_mode) { - scoreboard players set #aj.check <%OBJECTIVES.I()%> 0 - } - - block execute_at_transform { with storage <%temp_storage%> args - IF (debug_mode) { - # If the function successfully instantiated, the provided command is valid. - scoreboard players set #aj.check <%OBJECTIVES.I()%> 1 - } - - $execute \ - positioned ^$(px) ^$(py) ^$(pz) \ - rotated ~$(ry) ~$(rx) \ - run $(command) - } - - IF (debug_mode) { - execute if score #aj.check <%OBJECTIVES.I()%> matches 0 run tellraw @a <%TELLRAW.LOCATOR_COMMAND_FAILED_TO_EXECUTE({text: locator.storage_name, color: 'aqua'})%> - } - } - } - } -} - -IF (has_cameras) { - function as_camera { - #ARGS: {name: string, command: string} - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - - data remove storage <%temp_storage%> args - $data modify storage <%temp_storage%> args merge value {name:'$(name)', command:'$(command)', uuid:'+MISSING_UUID+'} - - IF (debug_mode) { - execute if data storage <%temp_storage%> {args:{name:''}} run return run tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('name')%> - execute if data storage <%temp_storage%> {args:{command:''}} run return run tellraw @a <%TELLRAW.ARGUMENT_CANNOT_BE_EMPTY('command')%> - } - - data_manager prep read - - block zzz/as_camera/as_data { with storage <%temp_storage%> args - $data modify storage <%temp_storage%> args.uuid set from storage <%temp_storage%> entry.data.cameras.$(name).uuid - - IF (debug_mode) { - scoreboard players set #aj.check <%OBJECTIVES.I()%> 0 - } - - block execute_as_uuid { with storage <%temp_storage%> args - IF (debug_mode) { - # If the function successfully instantiated, the provided command is valid. - scoreboard players set #aj.check <%OBJECTIVES.I()%> 1 - } - - $execute as $(uuid) at @s run return run $(command) - - IF (debug_mode) { - # If the entity with the provided UUID doesn't exist, the camera wasn't found. - tellraw @a <%TELLRAW.CAMERA_ENTITY_NOT_FOUND()%> - } - } - - IF (debug_mode) { - execute if score #aj.check <%OBJECTIVES.I()%> matches 0 run tellraw @a <%TELLRAW.CAMERA_COMMAND_FAILED_TO_EXECUTE()%> - } - } - } -} - -function as_root { - #ARGS: {command: string} - execute unless score @s <%OBJECTIVES.ID()%> matches <%-(2**31)%>..<%(2**31)-1%> run return run \ - tellraw @a <%TELLRAW.FUNCTION_NOT_EXECUTED_AS_ENTITY_WITH_ID_SCORE(context.functions.at(-1))%> - - data_manager prep read - - $data modify storage <%temp_storage%> args.command set value '$(command)' - data modify storage <%temp_storage%> args.root_uuid set from storage <%temp_storage%> entry.data.root_uuid - - IF (debug_mode) { - scoreboard players set #aj.check <%OBJECTIVES.I()%> 0 - } - block as_root_entity { with storage <%temp_storage%> args - $execute as $(root_uuid) run $(command) - IF (debug_mode) { - # If the function successfully instantiated, the provided command is valid. - scoreboard players set #aj.check <%OBJECTIVES.I()%> 1 - } - } - IF (debug_mode) { - execute if score #aj.check <%OBJECTIVES.I()%> matches 0 run tellraw @a <%TELLRAW.ROOT_COMMAND_FAILED_TO_EXECUTE()%> - } - -} - -dir remove { - function all { - # Removes all instances of this rig from the world. - execute as @e[type=minecraft:item_display,tag=<%TAGS.PROJECT_ROOT(blueprint_id)%>] run function <%blueprint_id%>/remove/this - } - - function entities { - # Removes all entities related to this rig from the world. - kill @e[tag=<%TAGS.PROJECT_ENTITY(blueprint_id)%>] - } - - function this { - # Removes the rig this function is executed as. - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - - <%% - if (on_remove_function) emit.mcb(on_remove_function) - %%> - - IF (has_entity_locators) { - data_manager prep read - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'locator')) as locator { - IF (locator.config?.on_remove_function) { - IF (locator.config.use_entity) { - block as_locator_<%locator.storage_name%> { with storage <%temp_storage%> entry.data.locators.<%locator.storage_name%> - $execute as $(uuid) at @s run block locator_<%locator.storage_name%>_on_remove { - <%% - emit.mcb(locator.config.on_remove_function) - %%> - } - } - } ELSE { - block at_locator_<%locator.storage_name%> { with storage <%temp_storage%> entry.data.locators.<%locator.storage_name%> - $execute \ - positioned ^$(px) ^$(py) ^$(pz) \ - rotated ~$(ry) ~$(rx) \ - run block locator_<%locator.storage_name%>_on_remove { - <%% - emit.mcb(locator.config.on_remove_function) - %%> - } - } - } - } - } - } - - function ./this/without_on_remove_function - } - - dir this { - function without_on_remove_function { - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - - data_manager prep read - - IF (has_entity_locators || has_cameras) { - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'locator' && node.config?.use_entity)) as locator { - function animated_java:global/remove/entity_stack_by_uuid with storage <%temp_storage%> entry.data.locators.<%locator.storage_name%> - } - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'camera')) as camera { - function animated_java:global/remove/entity_stack_by_uuid with storage <%temp_storage%> entry.data.cameras.<%camera.storage_name%> - } - } - - # Remove the rig using the more expensive & thorough method if the rig_hash doesn't match. - execute \ - unless data storage <%temp_storage%> {entry:{data:{rig_hash: '<%rig_hash%>'}}} \ - run function animated_java:global/remove/outdated_rig - - block { with storage <%temp_storage%> entry.data.uuids_by_name - REPEAT (Object.values(rig.nodes).filter(node => BONE_TYPES.includes(node.type))) as node { - $kill $(<%node.storage_name%>) - } - } - - function animated_java:global/remove/entity_stack - } - } -} - -IF (Object.keys(rig.variants).length > 1) { - dir variants { - REPEAT (Object.values(rig.variants)) as variant { - dir <%variant.name%> { - function apply { - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - - <%% - global.filteredNodes = Object.values(rig.nodes).filter( - node => ( - node.type === 'bone' && - !variant.excluded_nodes.includes(node.uuid) && - ( // Variant has a model override or a config override for this bone. - variant.models[node.uuid] !== undefined || - node.configs.variants[variant.uuid] !== undefined - ) - ) || ( - BONE_TYPES.includes(node.type) && - !variant.excluded_nodes.includes(node.uuid) && - // Variant has a config override for this node. - node.configs.variants[variant.uuid] !== undefined - ) - ) - %%> - - data_manager prep read - block { with storage <%temp_storage%> entry.data.uuids_by_name - REPEAT (global.filteredNodes) as node { - $execute as $(<%node.storage_name%>) run block zzz/apply_to_node_<%node.storage_name%> { - IF (node.type === 'bone' && variant.models[node.uuid] !== undefined) { - # Special case for `animated_java:empty` model. - IF (variant.models[node.uuid].model === null) { - data modify entity @s item.components."minecraft:custom_model_data".strings[0] set value "AJ_INTERNAL_EMPTY" - } ELSE { - data modify entity @s item.components."minecraft:custom_model_data".strings[0] set value "<%variant.name%>" - } - } - IF (node.configs.variants[variant.uuid]) { - <%% - global.config = DisplayEntityConfig.fromJSON(node.configs.variants[variant.uuid]) - %%> - IF (!global.config.isDefault()) { - data merge entity @s <%global.config.toNBT(undefined, variant.is_default)%> - } - IF (global.config.onApplyFunction) { - <%% - emit.mcb(global.config.onApplyFunction) - %%> - } - } - } - } - } - - # Return success to allow this function to be used in function conditions. - return 1 - } - } - } - } -} - -IF (has_locators || has_cameras) { - dir zzz { - function reset_floating_entities { - IF (has_locators) { - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'locator')) as locator { - IF (locator.config?.use_entity) { - execute at @s run block set_default_pose/as_locator_<%locator.storage_name%> { with storage <%temp_storage%> entry.data.locators.<%locator.storage_name%> - $tp $(uuid) \ - ^<%roundTo(locator.default_transform.pos[0], 10)%> \ - ^<%roundTo(locator.default_transform.pos[1], 10)%> \ - ^<%roundTo(locator.default_transform.pos[2], 10)%> \ - ~<%roundTo(locator.default_transform.head_rot[1], 10)%> \ - ~<%roundTo(locator.default_transform.head_rot[0], 10)%> - - data modify storage <%temp_storage%> entry.data.locators.<%locator.storage_name%> merge value { \ - px: <%roundTo(locator.default_transform.pos[0], 10)%>, \ - py: <%roundTo(locator.default_transform.pos[1], 10)%>, \ - pz: <%roundTo(locator.default_transform.pos[2], 10)%>, \ - ry: <%roundTo(locator.default_transform.head_rot[1], 10)%>, \ - rx: <%roundTo(locator.default_transform.head_rot[0], 10)%> \ - } - } - } ELSE { - data modify storage <%temp_storage%> entry.data.locators.<%locator.storage_name%> merge value { \ - px: <%roundTo(locator.default_transform.pos[0], 10)%>, \ - py: <%roundTo(locator.default_transform.pos[1], 10)%>, \ - pz: <%roundTo(locator.default_transform.pos[2], 10)%>, \ - ry: <%roundTo(locator.default_transform.head_rot[1], 10)%>, \ - rx: <%roundTo(locator.default_transform.head_rot[0], 10)%> \ - } - } - } - } - - IF (has_cameras) { - REPEAT (Object.values(rig.nodes).filter(node => node.type === 'camera')) as camera { - execute at @s run block set_default_pose/as_camera_<%camera.storage_name%> { with storage <%temp_storage%> entry.data.cameras.<%camera.storage_name%> - $tp $(uuid) \ - ^<%roundTo(camera.default_transform.pos[0], 10)%> \ - ^<%roundTo(camera.default_transform.pos[1], 10)%> \ - ^<%roundTo(camera.default_transform.pos[2], 10)%> \ - ~<%roundTo(camera.default_transform.head_rot[1], 10)%> \ - ~<%roundTo(camera.default_transform.head_rot[0], 10)%> - - data modify storage <%temp_storage%> entry.data.cameras.<%camera.storage_name%> merge value { \ - px: <%roundTo(camera.default_transform.pos[0], 10)%>, \ - py: <%roundTo(camera.default_transform.pos[1], 10)%>, \ - pz: <%roundTo(camera.default_transform.pos[2], 10)%>, \ - ry: <%roundTo(camera.default_transform.head_rot[1], 10)%>, \ - rx: <%roundTo(camera.default_transform.head_rot[0], 10)%> \ - } - } - } - } - } - } -} - -dir zzz { - function set_default_pose { - IF (has_locators || has_cameras) { - function ../zzz/reset_floating_entities - } - - block set_default_pose_to_nodes { with storage <%temp_storage%> entry.data.uuids_by_name - REPEAT (Object.values(rig.nodes).filter(node => BONE_TYPES.includes(node.type))) as node { - $data merge entity $(<%node.storage_name%>) { \ - transformation: <%matrixToNbtFloatArray(node.default_transform.matrix).toString()%>, \ - start_interpolation: -1 \ - } - } - } - } -} - -function set_default_pose { - # Changes the pose of the rig to the the default pose without interpolation - debug assert executed_as_root_entity <%TAGS.PROJECT_ROOT(blueprint_id)%> - - IF (has_locators || has_cameras) { - data_manager prep read - } - function ./zzz/set_default_pose -} \ No newline at end of file diff --git a/src/systems/datapackCompiler/index.ts b/src/systems/datapackCompiler/index.ts index 6c2a511c..1e8c769c 100644 --- a/src/systems/datapackCompiler/index.ts +++ b/src/systems/datapackCompiler/index.ts @@ -594,7 +594,7 @@ const dataPackCompiler: DataPackCompiler = async ({ Object.values(rig.nodes).filter(n => n.type === 'locator' && n.config?.on_tick_function) .length > 0, has_cameras: Object.values(rig.nodes).filter(n => n.type === 'camera').length > 0, - is_static: isStatic, + has_animations: animations.length > 0, getNodeTags, BONE_TYPES, project_storage: `${aj.blueprint_id}`, @@ -612,8 +612,7 @@ const dataPackCompiler: DataPackCompiler = async ({ 'src/global.mcbt': mcbFiles.globalTemplates, 'src/animated_java.mcb': mcbFiles.global, [`src/${parsed.fullPath}.mcb`]: - `import ${relativePathToSrc}/global.mcbt\n` + - (isStatic ? mcbFiles.static : mcbFiles.animation), + `import ${relativePathToSrc}/global.mcbt\n` + mcbFiles.main, }, destPath: '.', variables, diff --git a/src/systems/datapackCompiler/mcbFiles.ts b/src/systems/datapackCompiler/mcbFiles.ts index 0796dcc8..26f73d16 100644 --- a/src/systems/datapackCompiler/mcbFiles.ts +++ b/src/systems/datapackCompiler/mcbFiles.ts @@ -1,32 +1,25 @@ // FIXME - Figure out how to import these files dynamically and generate the MCB_FILES object automatically. -import ANIMATION_1_20_4 from './1.20.4/animation.mcb' import GLOBAL_1_20_4 from './1.20.4/global.mcb' import GLOBAL_TEMPLATES_1_20_4 from './1.20.4/global.mcbt' -import STATIC_1_20_4 from './1.20.4/static.mcb' +import MAIN_1_20_4 from './1.20.4/main.mcb' -import ANIMATION_1_20_5 from './1.20.5/animation.mcb' -import STATIC_1_20_5 from './1.20.5/static.mcb' +import MAIN_1_20_5 from './1.20.5/main.mcb' -import ANIMATION_1_21_0 from './1.21.0/animation.mcb' import GLOBAL_1_21_0 from './1.21.0/global.mcb' -import STATIC_1_21_0 from './1.21.0/static.mcb' +import MAIN_1_21_0 from './1.21.0/main.mcb' -import ANIMATION_1_21_2 from './1.21.2/animation.mcb' -import STATIC_1_21_2 from './1.21.2/static.mcb' +import MAIN_1_21_2 from './1.21.2/main.mcb' -import ANIMATION_1_21_4 from './1.21.4/animation.mcb' -import STATIC_1_21_4 from './1.21.4/static.mcb' +import MAIN_1_21_4 from './1.21.4/main.mcb' -import ANIMATION_1_21_5 from './1.21.5/animation.mcb' import GLOBAL_1_21_5 from './1.21.5/global.mcb' -import STATIC_1_21_5 from './1.21.5/static.mcb' +import MAIN_1_21_5 from './1.21.5/main.mcb' // The core is content that always goes in the `data` folder directly, // while other files are in the `animated_java/data` folder to be overlayed when the correct version is loaded. interface MCBFiles { - animation: string - static: string + main: string global: string globalTemplates: string } @@ -35,8 +28,7 @@ export function getMCBFilesByVersion(version: string): MCBFiles { switch (true) { case VersionUtil.compare(version, '>=', '1.21.11'): { return { - animation: ANIMATION_1_21_5, - static: STATIC_1_21_5, + main: MAIN_1_21_5, global: GLOBAL_1_21_5, globalTemplates: GLOBAL_TEMPLATES_1_20_4, } @@ -44,8 +36,7 @@ export function getMCBFilesByVersion(version: string): MCBFiles { case VersionUtil.compare(version, '>=', '1.21.9'): { return { - animation: ANIMATION_1_21_5, - static: STATIC_1_21_5, + main: MAIN_1_21_5, global: GLOBAL_1_21_5, globalTemplates: GLOBAL_TEMPLATES_1_20_4, } @@ -53,8 +44,7 @@ export function getMCBFilesByVersion(version: string): MCBFiles { case VersionUtil.compare(version, '>=', '1.21.6'): { return { - animation: ANIMATION_1_21_5, - static: STATIC_1_21_5, + main: MAIN_1_21_5, global: GLOBAL_1_21_5, globalTemplates: GLOBAL_TEMPLATES_1_20_4, } @@ -62,8 +52,7 @@ export function getMCBFilesByVersion(version: string): MCBFiles { case VersionUtil.compare(version, '>=', '1.21.5'): { return { - animation: ANIMATION_1_21_5, - static: STATIC_1_21_5, + main: MAIN_1_21_5, global: GLOBAL_1_21_5, globalTemplates: GLOBAL_TEMPLATES_1_20_4, } @@ -71,8 +60,7 @@ export function getMCBFilesByVersion(version: string): MCBFiles { case VersionUtil.compare(version, '>=', '1.21.4'): { return { - animation: ANIMATION_1_21_4, - static: STATIC_1_21_4, + main: MAIN_1_21_4, global: GLOBAL_1_21_0, globalTemplates: GLOBAL_TEMPLATES_1_20_4, } @@ -80,8 +68,7 @@ export function getMCBFilesByVersion(version: string): MCBFiles { case VersionUtil.compare(version, '>=', '1.21.2'): { return { - animation: ANIMATION_1_21_2, - static: STATIC_1_21_2, + main: MAIN_1_21_2, global: GLOBAL_1_21_0, globalTemplates: GLOBAL_TEMPLATES_1_20_4, } @@ -89,8 +76,7 @@ export function getMCBFilesByVersion(version: string): MCBFiles { case VersionUtil.compare(version, '>=', '1.21.0'): { return { - animation: ANIMATION_1_21_0, - static: STATIC_1_21_0, + main: MAIN_1_21_0, global: GLOBAL_1_21_0, globalTemplates: GLOBAL_TEMPLATES_1_20_4, } @@ -98,8 +84,7 @@ export function getMCBFilesByVersion(version: string): MCBFiles { case VersionUtil.compare(version, '>=', '1.20.5'): { return { - animation: ANIMATION_1_20_5, - static: STATIC_1_20_5, + main: MAIN_1_20_5, global: GLOBAL_1_20_4, globalTemplates: GLOBAL_TEMPLATES_1_20_4, } @@ -107,8 +92,7 @@ export function getMCBFilesByVersion(version: string): MCBFiles { case VersionUtil.compare(version, '>=', '1.20.4'): { return { - animation: ANIMATION_1_20_4, - static: STATIC_1_20_4, + main: MAIN_1_20_4, global: GLOBAL_1_20_4, globalTemplates: GLOBAL_TEMPLATES_1_20_4, } diff --git a/src/systems/datapackCompiler/tellraw.ts b/src/systems/datapackCompiler/tellraw.ts index dff46064..c6779c2b 100644 --- a/src/systems/datapackCompiler/tellraw.ts +++ b/src/systems/datapackCompiler/tellraw.ts @@ -240,6 +240,18 @@ namespace TELLRAW { ), ]) + export const FRAME_ARG_NO_RIG_FRAMES = () => + TELLRAW_ERROR('Frame Argument Invalid - No Rig Animations', [ + 'This Blueprint has no animations to play, and therefore no frames to switch between.', + '\n Please ensure that the rig has animations, or avoid using the frame argument in your summon function.', + ]) + + export const ANIMATION_ARG_NO_RIG_ANIMATIONS = () => + TELLRAW_ERROR('Animation Argument Invalid - No Rig Animations', [ + 'This Blueprint has no animations to play.', + '\n Please ensure that the rig has animations, or avoid using the animation argument in your summon function.', + ]) + export const NO_VARIANTS = () => TELLRAW_ERROR('No Variants', ['This Blueprint has no variants to switch between.']) From aa78e0b737647225cce92e2fdf55e7c28513978a Mon Sep 17 00:00:00 2001 From: SnaveSutit Date: Sun, 3 May 2026 07:13:57 -0400 Subject: [PATCH 10/17] =?UTF-8?q?=F0=9F=8E=A8=20Simplify=20plugin=20packag?= =?UTF-8?q?er?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .scripts/plugins/packagerPlugin.ts | 174 +++++++++-------------------- 1 file changed, 55 insertions(+), 119 deletions(-) diff --git a/.scripts/plugins/packagerPlugin.ts b/.scripts/plugins/packagerPlugin.ts index 73fd8bed..689d562b 100644 --- a/.scripts/plugins/packagerPlugin.ts +++ b/.scripts/plugins/packagerPlugin.ts @@ -2,8 +2,6 @@ import type { Plugin } from 'esbuild' import * as fs from 'fs' import { readFileSync, writeFileSync } from 'fs' import { basename, join } from 'node:path' -import { Octokit } from 'octokit' -import * as prettier from 'prettier' import { sveltePreprocess } from 'svelte-preprocess' // @ts-expect-error - Types are broken in nodenext for this package, but it works fine. import { typescript } from 'svelte-preprocess-esbuild' @@ -13,16 +11,12 @@ import { render } from 'svelte/server' // @ts-expect-error - Svelte's internal server-side rendering API is not typed, but we need it to render the about.svelte file at build time. import * as svelteInternalServer from 'svelte/internal/server' -const OCTO_KIT = new Octokit({}) - const PACKAGE = JSON.parse(fs.readFileSync('./package.json', 'utf-8')) const PLUGIN_PACKAGE_PATH = './src/pluginPackage/' const SVELTE_FILE = './src/pluginPackage/about.svelte' const README_DIST_PATH = './dist/pluginPackage/about.md' const DIST_PATH = './dist/' const DIST_PACKAGE_PATH = './dist/pluginPackage/' -const PLUGIN_REPO_PATH = 'D:/github-repos/snavesutit/blockbench-plugins/plugins/animated_java' -const PLUGIN_MANIFEST_PATH = 'D:/github-repos/snavesutit/blockbench-plugins/plugins.json' const CHANGELOG_PATH = './src/pluginPackage/changelog.json' const RELEASE_NOTES_TEMPLATES = './.scripts/plugins/releaseNoteTemplates/' const URL_REGEX = @@ -32,18 +26,6 @@ function replaceTemplateVars(str: string, items: Record) { return str.replace(/\{(.+?)\}/g, str => items[str.replace(/[\{\}]/g, '')] ?? str) } -const VERSION_REGEX = /(\d+)\.(\d+)\.(\d+)(?:-([a-zA-Z0-9]+))?/ - -function getVersionNumbers(version: string) { - const match = VERSION_REGEX.exec(version) - if (!match) return null - const major = parseInt(match[1]) - const minor = parseInt(match[2]) - const patch = parseInt(match[3]) - const preRelease = match[4] ?? null - return { major, minor, patch, preRelease } -} - /** * Convert a warning or error emitted from the svelte compiler for esbuild. */ @@ -160,114 +142,68 @@ function plugin(): Plugin { fs.unlinkSync(join(DIST_PACKAGE_PATH, 'about.svelte')) if (process.env.NODE_ENV === 'production') { - try { - console.log('📝 Creating changelogs...') - const rawChangelog = fs.readFileSync(CHANGELOG_PATH, 'utf-8') - const changelog = JSON.parse(rawChangelog) - for (const file of fs.readdirSync(RELEASE_NOTES_TEMPLATES)) { - let content = fs.readFileSync( - join(RELEASE_NOTES_TEMPLATES, file), - 'utf-8' - ) - let pings = '' - const version = getVersionNumbers(PACKAGE.version) - if (!version) { - throw new Error( - `Version ${PACKAGE.version} in package.json is not valid semver!` - ) - } - const latestRelease = getVersionNumbers( - ( - await OCTO_KIT.request('GET /repos/{owner}/{repo}/releases', { - owner: 'animated-java', - repo: 'animated-java', - per_page: 1, - headers: { - accept: 'application/vnd.github+json', - 'X-GitHub-Api-Version': '2022-11-28', - }, - }) - ).data[0].tag_name + console.log('📝 Creating changelogs...') + const rawChangelog = fs.readFileSync(CHANGELOG_PATH, 'utf-8') + const changelog = JSON.parse(rawChangelog) + for (const file of fs.readdirSync(RELEASE_NOTES_TEMPLATES)) { + let content = fs.readFileSync(join(RELEASE_NOTES_TEMPLATES, file), 'utf-8') + + const versionChangelog = changelog[PACKAGE.version] + if (!versionChangelog) { + console.warn( + `⚠️ No changelog found for version ${PACKAGE.version} in ${CHANGELOG_PATH}` ) - if (!latestRelease) { - throw new Error('No latest release found on github!') - } - if (version.major > latestRelease.major) { - pings += `@Major Release Ping` - } - if (version.minor > latestRelease.minor) { - pings += ` @Minor Release Ping` - } - if (version.patch > latestRelease.patch) { - pings += ` @Patch Release Ping` - } - if (latestRelease.preRelease) { - pings += ` @Pre-Release Ping` - } - if (rawChangelog.includes('[BREAKING]')) { - pings += ` @Breaking Changes Ping` - } - - const versionChangelog = changelog[PACKAGE.version] - if (!versionChangelog) { - throw new Error( - `No changelog found for version ${PACKAGE.version} in ${CHANGELOG_PATH}` - ) - } - - let categories = '' - for (const category of versionChangelog.categories) { - categories += - `\n\n### ${category.title}\n\n` + - category.list - .map((v: string) => '- ' + v) - .join('\n') - .replaceAll('[BREAKING]', '⚠️ **BREAKING** —') - } + return + } - content = replaceTemplateVars(content, { - version: PACKAGE.version, - categories: categories.trim(), - pings: pings.trim(), - }) + let categories = '' + for (const category of versionChangelog.categories) { + categories += + `\n\n### ${category.title}\n\n` + + category.list + .map((v: string) => '- ' + v) + .join('\n') + .replaceAll('[BREAKING]', '⚠️ **BREAKING** —') + } - if (content.includes('[[ESCAPE_URLS]]')) { - content = content - .replace('[[ESCAPE_URLS]]', '') - .replaceAll(URL_REGEX, (match: string) => '<' + match + '>') - } + content = replaceTemplateVars(content, { + version: PACKAGE.version, + categories: categories.trim(), + }) - fs.writeFileSync(join(DIST_PATH, file), content) + if (content.includes('[[ESCAPE_URLS]]')) { + content = content + .replace('[[ESCAPE_URLS]]', '') + .replaceAll(URL_REGEX, (match: string) => '<' + match + '>') } - } catch (e) { - console.error('Error creating changelogs:', e) - throw e - } - - if (fs.existsSync(PLUGIN_REPO_PATH)) { - fs.rmSync(PLUGIN_REPO_PATH, { recursive: true, force: true }) - fs.cpSync(DIST_PACKAGE_PATH, PLUGIN_REPO_PATH, { recursive: true }) - const manifest = JSON.parse(fs.readFileSync(PLUGIN_MANIFEST_PATH, 'utf-8')) - manifest.animated_java.title = PACKAGE.title - manifest.animated_java.author = PACKAGE.author.name - manifest.animated_java.icon = PACKAGE.icon - manifest.animated_java.description = PACKAGE.description - manifest.animated_java.version = PACKAGE.version - manifest.animated_java.min_version = PACKAGE.min_blockbench_version - manifest.animated_java.max_version = PACKAGE.max_blockbench_version - manifest.animated_java.variant = PACKAGE.variant - manifest.animated_java.tags = PACKAGE.tags - manifest.animated_java.has_changelog = true - fs.writeFileSync( - PLUGIN_MANIFEST_PATH, - await prettier.format(JSON.stringify(manifest, null, '\t'), { - useTabs: true, - parser: 'json', - }) - ) - console.log('📋 Copied to Plugin Repo!') + fs.writeFileSync(join(DIST_PATH, file), content) } + + // if (fs.existsSync(PLUGIN_REPO_PATH)) { + // fs.rmSync(PLUGIN_REPO_PATH, { recursive: true, force: true }) + // fs.cpSync(DIST_PACKAGE_PATH, PLUGIN_REPO_PATH, { recursive: true }) + // const manifest = JSON.parse(fs.readFileSync(PLUGIN_MANIFEST_PATH, 'utf-8')) + // manifest.animated_java.title = PACKAGE.title + // manifest.animated_java.author = PACKAGE.author.name + // manifest.animated_java.icon = PACKAGE.icon + // manifest.animated_java.description = PACKAGE.description + // manifest.animated_java.version = PACKAGE.version + // manifest.animated_java.min_version = PACKAGE.min_blockbench_version + // manifest.animated_java.max_version = PACKAGE.max_blockbench_version + // manifest.animated_java.variant = PACKAGE.variant + // manifest.animated_java.tags = PACKAGE.tags + // manifest.animated_java.has_changelog = true + + // fs.writeFileSync( + // PLUGIN_MANIFEST_PATH, + // await prettier.format(JSON.stringify(manifest, null, '\t'), { + // useTabs: true, + // parser: 'json', + // }) + // ) + // console.log('📋 Copied to Plugin Repo!') + // } } }) }, From 12c04becbeb7cb9da8b92825bbfef9425b4de99c Mon Sep 17 00:00:00 2001 From: SnaveSutit Date: Sun, 3 May 2026 07:15:25 -0400 Subject: [PATCH 11/17] =?UTF-8?q?=E2=9C=A8=20Add=20`Rig`=20page=20to=20Blu?= =?UTF-8?q?eprint=20settings?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../blueprintSettings/blueprintSettings.ts | 19 ++++++--- .../blueprintSettings/pages/datapack.svelte | 23 ---------- .../blueprintSettings/pages/rig.svelte | 42 +++++++++++++++++++ src/lang/en.yml | 18 +++++++- 4 files changed, 73 insertions(+), 29 deletions(-) create mode 100644 src/dialogs/blueprintSettings/pages/rig.svelte diff --git a/src/dialogs/blueprintSettings/blueprintSettings.ts b/src/dialogs/blueprintSettings/blueprintSettings.ts index 3be25454..92222760 100644 --- a/src/dialogs/blueprintSettings/blueprintSettings.ts +++ b/src/dialogs/blueprintSettings/blueprintSettings.ts @@ -15,6 +15,7 @@ import GeneralComponent from './pages/general.svelte' import MiscComponent from './pages/misc.svelte' import PluginComponent from './pages/plugin.svelte' import ResourcepackComponent from './pages/resourcepack.svelte' +import RigComponent from './pages/rig.svelte' const localize = createScopedTranslator('dialog.blueprint_settings') @@ -28,17 +29,25 @@ export function openBlueprintSettings() { label: localize('pages.general.title'), icon: 'settings', }, + resourcepack: { + component: ResourcepackComponent, + condition: () => Project.pluginMode.get() === false, + label: localize('pages.resource_pack.title'), + icon: 'image', + }, datapack: { component: DatapackComponent, condition: () => Project.pluginMode.get() === false, label: localize('pages.datapack.title'), icon: 'database', }, - resourcepack: { - component: ResourcepackComponent, - condition: () => Project.pluginMode.get() === false, - label: localize('pages.resource_pack.title'), - icon: 'image', + rig: { + component: RigComponent, + label: localize('pages.rig.title'), + icon: 'fa-person', + condition: () => + Project.pluginMode.get() === false && + Project.animated_java.data_pack_export_mode !== 'none', }, eventFunctions: { component: EventFunctionsComponent, diff --git a/src/dialogs/blueprintSettings/pages/datapack.svelte b/src/dialogs/blueprintSettings/pages/datapack.svelte index 27f294ff..6427bf52 100644 --- a/src/dialogs/blueprintSettings/pages/datapack.svelte +++ b/src/dialogs/blueprintSettings/pages/datapack.svelte @@ -3,7 +3,6 @@ import { validateDataPackFolder, validateZipPath } from '../../../formats/blueprint/settings' import BoxSelect from '../../../svelteComponents/sidebarDialogItems/boxSelect.svelte' import Checkbox from '../../../svelteComponents/sidebarDialogItems/checkbox.svelte' - import NumberSlider from '../../../svelteComponents/sidebarDialogItems/numberSlider.svelte' import SelectFile from '../../../svelteComponents/sidebarDialogItems/selectFile.svelte' import SelectFolder from '../../../svelteComponents/sidebarDialogItems/selectFolder.svelte' import { createScopedTranslator } from '../../../util/lang' @@ -15,16 +14,12 @@ let animationSystem = $state( Project.animated_java.use_storage_for_animation ? 'storage' : 'functions' ) - let interpolationDuration = $state(Project.animated_java.interpolation_duration) - let teleportationDuration = $state(Project.animated_java.teleportation_duration) let autoUpdateRigOrientation = $state(Project.animated_java.auto_update_rig_orientation) onDestroy(() => { Project.animated_java.data_pack_export_mode = dataPackExportFormat Project.animated_java.data_pack = dataPackLocation Project.animated_java.use_storage_for_animation = animationSystem === 'storage' - Project.animated_java.interpolation_duration = interpolationDuration - Project.animated_java.teleportation_duration = teleportationDuration Project.animated_java.auto_update_rig_orientation = autoUpdateRigOrientation }) @@ -71,24 +66,6 @@ {/if} {#if dataPackExportFormat !== 'none'} - - - - + import { onDestroy } from 'svelte' + import Checkbox from '../../../svelteComponents/sidebarDialogItems/checkbox.svelte' + import NumberSlider from '../../../svelteComponents/sidebarDialogItems/numberSlider.svelte' + import { createScopedTranslator } from '../../../util/lang' + + const localize = createScopedTranslator('dialog.blueprint_settings') + + let interpolationDuration = $state(Project.animated_java.interpolation_duration) + let teleportationDuration = $state(Project.animated_java.teleportation_duration) + let useEntityStacking = $state(Project.animated_java.use_entity_stacking) + + onDestroy(() => { + Project.animated_java.interpolation_duration = interpolationDuration + Project.animated_java.teleportation_duration = teleportationDuration + Project.animated_java.use_entity_stacking = useEntityStacking + }) + + + + + + + diff --git a/src/lang/en.yml b/src/lang/en.yml index b6ca849b..a90ce90f 100644 --- a/src/lang/en.yml +++ b/src/lang/en.yml @@ -114,6 +114,7 @@ animated_java: general.title: General resource_pack.title: Resource Pack datapack.title: Data Pack + rig.title: Rig event_functions.title: Event Functions plugin.title: Plugin misc.title: Misc @@ -325,7 +326,22 @@ animated_java: [Markdown] The default [teleport duration](https://minecraft.wiki/w/Display#Entity_data) of the rig. - Higher values make large movements smoother but less responsive. + use_entity_stacking: + title: Use Entity Stacking + description: |- + [Markdown] + Whether or not to use entity stacking for the rig's bone entities. + + When **enabled**: + - All bone entities will be mounted on the root entity. + - Bone rotations will be less precise. (limited to integer degrees) + - Bone entities can be selected via `on passengers` when executing `as` the root entity. + + When **disabled**: + - Bone entities will not be mounted on the root entity. + - Bone rotations will be *much* more precise, enabling much smoother movement when teleporting the rig around. + - Bone entities cannot be selected via `on passengers`, but can still be accessed via `as_node`. + auto_update_rig_orientation: title: Auto Update Rig Orientation description: |- From 9630f944d492028e005ece63efd2242f0c62a4ed Mon Sep 17 00:00:00 2001 From: SnaveSutit Date: Sun, 3 May 2026 07:16:14 -0400 Subject: [PATCH 12/17] =?UTF-8?q?=E2=9C=A8=20Add=20`Use=20Entity=20Stackin?= =?UTF-8?q?g`=20option=20to=20Blueprint=20rig=20settings?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/formats/blueprint/settings.ts | 3 +- src/mods/globalCssMod.css | 10 ++ src/systems/datapackCompiler/1.21.4/main.mcb | 104 ++++++++++++------- src/systems/datapackCompiler/1.21.5/main.mcb | 104 ++++++++++++------- src/systems/datapackCompiler/index.ts | 2 +- 5 files changed, 141 insertions(+), 82 deletions(-) diff --git a/src/formats/blueprint/settings.ts b/src/formats/blueprint/settings.ts index 9ced70b7..142fb4ae 100644 --- a/src/formats/blueprint/settings.ts +++ b/src/formats/blueprint/settings.ts @@ -37,6 +37,7 @@ export interface BlueprintSettings { teleportation_duration: number auto_update_rig_orientation: boolean use_storage_for_animation: boolean + use_entity_stacking: boolean // Plugin Settings baked_animations: boolean json_file: string @@ -75,7 +76,7 @@ export const defaultValues: BlueprintSettings = { auto_update_rig_orientation: true, use_storage_for_animation: false, - + use_entity_stacking: false, // Plugin Settings baked_animations: true, json_file: '', diff --git a/src/mods/globalCssMod.css b/src/mods/globalCssMod.css index 1abcb1c6..102ebd42 100644 --- a/src/mods/globalCssMod.css +++ b/src/mods/globalCssMod.css @@ -26,3 +26,13 @@ dialog.dialog pre:has(code) { white-space: nowrap !important; max-width: 75% !important; } + +div.base-sidebar-dialog-item p.description ul { + padding-left: 2em; +} +div.base-sidebar-dialog-item p.description li { + list-style: disc; +} +div.base-sidebar-dialog-item p.description code { + background: var(--color-back); +} diff --git a/src/systems/datapackCompiler/1.21.4/main.mcb b/src/systems/datapackCompiler/1.21.4/main.mcb index 715c5bff..e5ad389e 100644 --- a/src/systems/datapackCompiler/1.21.4/main.mcb +++ b/src/systems/datapackCompiler/1.21.4/main.mcb @@ -70,17 +70,20 @@ dir root { IF (has_locators || has_cameras) { function <%blueprint_id%>/root/on_tick/transform_floating_entities } - - block { with storage <%temp_storage%> entry.data.uuids_by_name - REPEAT (Object.values(rig.nodes).filter(node => BONE_TYPES.includes(node.type))) as node { - $tp $(<%node.storage_name%>) ~ ~ ~ ~ ~ - # Precise Rotation Workaround. Fixes MC-272913. - # Thanks @Triton365! (https://discord.com/channels/154777837382008833/157097006500806656/1402253905408163842) - $execute \ - as $(<%node.storage_name%>) \ - store success entity @s OnGround byte 1 \ - store success score @s <%OBJECTIVES.I()%> \ - unless score @s <%OBJECTIVES.I()%> matches 1 + IF (use_entity_stacking) { + execute on passengers run rotate @s ~ ~ + } ELSE { + block { with storage <%temp_storage%> entry.data.uuids_by_name + REPEAT (Object.values(rig.nodes).filter(node => BONE_TYPES.includes(node.type))) as node { + $tp $(<%node.storage_name%>) ~ ~ ~ ~ ~ + # Precise Rotation Workaround. Fixes MC-272913. + # Thanks @Triton365! (https://discord.com/channels/154777837382008833/157097006500806656/1402253905408163842) + $execute \ + as $(<%node.storage_name%>) \ + store success entity @s OnGround byte 1 \ + store success score @s <%OBJECTIVES.I()%> \ + unless score @s <%OBJECTIVES.I()%> matches 1 + } } } } ELSE IF (has_ticking_locators) { @@ -176,17 +179,20 @@ IF (!auto_update_rig_orientation) { IF (has_locators || has_cameras) { function <%blueprint_id%>/root/on_tick/transform_floating_entities } - - block { with storage <%temp_storage%> entry.data.uuids_by_name - REPEAT (Object.values(rig.nodes).filter(node => BONE_TYPES.includes(node.type))) as node { - $tp $(<%node.storage_name%>) ~ ~ ~ ~ ~ - # Precise Rotation Workaround. Fixes MC-272913. - # Thanks @Triton365! (https://discord.com/channels/154777837382008833/157097006500806656/1402253905408163842) - $execute \ - as $(<%node.storage_name%>) \ - store success entity @s OnGround byte 1 \ - store success score @s <%OBJECTIVES.I()%> \ - unless score @s <%OBJECTIVES.I()%> matches 1 + IF (use_entity_stacking) { + execute at @s on passengers run rotate @s ~ ~ + } ELSE { + block { with storage <%temp_storage%> entry.data.uuids_by_name + REPEAT (Object.values(rig.nodes).filter(node => BONE_TYPES.includes(node.type))) as node { + $tp $(<%node.storage_name%>) ~ ~ ~ ~ ~ + # Precise Rotation Workaround. Fixes MC-272913. + # Thanks @Triton365! (https://discord.com/channels/154777837382008833/157097006500806656/1402253905408163842) + $execute \ + as $(<%node.storage_name%>) \ + store success entity @s OnGround byte 1 \ + store success score @s <%OBJECTIVES.I()%> \ + unless score @s <%OBJECTIVES.I()%> matches 1 + } } } } @@ -285,13 +291,17 @@ IF (has_animations) { $execute at @s run function ./zzz/apply_frame {frame: $(to_frame)} tag @s remove <%TAGS.TRANSFORMS_ONLY()%> - data_manager prep read - block { with storage <%temp_storage%> entry.data.uuids_by_name - REPEAT (Object.values(rig.nodes).filter(node => BONE_TYPES.includes(node.type))) as node { - $execute \ - as $(<%node.storage_name%>) \ - store result entity @s interpolation_duration int 1 \ - run scoreboard players get #this <%OBJECTIVES.I()%> + IF (use_entity_stacking) { + execute on passengers store result entity @s interpolation_duration int 1 run scoreboard players get #this <%OBJECTIVES.I()%> + } ELSE { + data_manager prep read + block { with storage <%temp_storage%> entry.data.uuids_by_name + REPEAT (Object.values(rig.nodes).filter(node => BONE_TYPES.includes(node.type))) as node { + $execute \ + as $(<%node.storage_name%>) \ + store result entity @s interpolation_duration int 1 \ + run scoreboard players get #this <%OBJECTIVES.I()%> + } } } } @@ -301,12 +311,17 @@ IF (has_animations) { # Tweening logic scoreboard players remove @s <%OBJECTIVES.TWEEN_DURATION()%> 1 execute if score @s <%OBJECTIVES.TWEEN_DURATION()%> matches 1.. run return 1 - execute if score @s <%OBJECTIVES.TWEEN_DURATION()%> matches 0 run \ - block { with storage <%temp_storage%> entry.data.uuids_by_name - REPEAT (Object.values(rig.nodes).filter(node => BONE_TYPES.includes(node.type))) as node { - $data modify entity $(<%node.storage_name%>) interpolation_duration set value <%interpolation_duration%> + IF (use_entity_stacking) { + execute if score @s <%OBJECTIVES.TWEEN_DURATION()%> matches 0 on passengers run \ + data modify entity @s interpolation_duration set value <%interpolation_duration%> + } ELSE { + execute if score @s <%OBJECTIVES.TWEEN_DURATION()%> matches 0 run \ + block { with storage <%temp_storage%> entry.data.uuids_by_name + REPEAT (Object.values(rig.nodes).filter(node => BONE_TYPES.includes(node.type))) as node { + $data modify entity $(<%node.storage_name%>) interpolation_duration set value <%interpolation_duration%> + } } - } + } # Animation logic IF (animation.loop_mode === 'loop' && animation.loop_delay === 0) { @@ -356,9 +371,13 @@ IF (has_animations) { function set_frame { #ARGS: {frame: int} $function ./apply_frame {frame: $(frame)} - block { with storage <%temp_storage%> entry.data.uuids_by_name - REPEAT (Object.values(rig.nodes).filter(node => BONE_TYPES.includes(node.type))) as node { - $data modify entity $(<%node.storage_name%>) start_interpolation set value -1 + IF (use_entity_stacking) { + execute on passengers run data modify entity @s start_interpolation set value -1 + } ELSE { + block { with storage <%temp_storage%> entry.data.uuids_by_name + REPEAT (Object.values(rig.nodes).filter(node => BONE_TYPES.includes(node.type))) as node { + $data modify entity $(<%node.storage_name%>) start_interpolation set value -1 + } } } return 1 @@ -398,9 +417,14 @@ IF (has_animations) { $function ./frames/$(frame) with storage <%temp_storage%> entry.data.uuids_by_name - block { with storage <%temp_storage%> entry.data.uuids_by_name - REPEAT (Object.values(rig.nodes).filter(node => BONE_TYPES.includes(node.type))) as node { - $data modify entity $(<%node.storage_name%>) start_interpolation set value -1 + IF (use_entity_stacking) { + execute on passengers run \ + data modify entity @s start_interpolation set value -1 + } ELSE { + block { with storage <%temp_storage%> entry.data.uuids_by_name + REPEAT (Object.values(rig.nodes).filter(node => BONE_TYPES.includes(node.type))) as node { + $data modify entity $(<%node.storage_name%>) start_interpolation set value -1 + } } } diff --git a/src/systems/datapackCompiler/1.21.5/main.mcb b/src/systems/datapackCompiler/1.21.5/main.mcb index c4c5975b..2d95bfe1 100644 --- a/src/systems/datapackCompiler/1.21.5/main.mcb +++ b/src/systems/datapackCompiler/1.21.5/main.mcb @@ -69,17 +69,20 @@ dir root { IF (has_locators || has_cameras) { function <%blueprint_id%>/root/on_tick/transform_floating_entities } - - block { with storage <%temp_storage%> entry.data.uuids_by_name - REPEAT (Object.values(rig.nodes).filter(node => BONE_TYPES.includes(node.type))) as node { - $tp $(<%node.storage_name%>) ~ ~ ~ ~ ~ - # Precise Rotation Workaround. Fixes MC-272913. - # Thanks @Triton365! (https://discord.com/channels/154777837382008833/157097006500806656/1402253905408163842) - $execute \ - as $(<%node.storage_name%>) \ - store success entity @s OnGround byte 1 \ - store success score @s <%OBJECTIVES.I()%> \ - unless score @s <%OBJECTIVES.I()%> matches 1 + IF (use_entity_stacking) { + execute on passengers run rotate @s ~ ~ + } ELSE { + block { with storage <%temp_storage%> entry.data.uuids_by_name + REPEAT (Object.values(rig.nodes).filter(node => BONE_TYPES.includes(node.type))) as node { + $tp $(<%node.storage_name%>) ~ ~ ~ ~ ~ + # Precise Rotation Workaround. Fixes MC-272913. + # Thanks @Triton365! (https://discord.com/channels/154777837382008833/157097006500806656/1402253905408163842) + $execute \ + as $(<%node.storage_name%>) \ + store success entity @s OnGround byte 1 \ + store success score @s <%OBJECTIVES.I()%> \ + unless score @s <%OBJECTIVES.I()%> matches 1 + } } } } ELSE IF (has_ticking_locators) { @@ -175,17 +178,20 @@ IF (!auto_update_rig_orientation) { IF (has_locators || has_cameras) { function <%blueprint_id%>/root/on_tick/transform_floating_entities } - - block { with storage <%temp_storage%> entry.data.uuids_by_name - REPEAT (Object.values(rig.nodes).filter(node => BONE_TYPES.includes(node.type))) as node { - $tp $(<%node.storage_name%>) ~ ~ ~ ~ ~ - # Precise Rotation Workaround. Fixes MC-272913. - # Thanks @Triton365! (https://discord.com/channels/154777837382008833/157097006500806656/1402253905408163842) - $execute \ - as $(<%node.storage_name%>) \ - store success entity @s OnGround byte 1 \ - store success score @s <%OBJECTIVES.I()%> \ - unless score @s <%OBJECTIVES.I()%> matches 1 + IF (use_entity_stacking) { + execute at @s on passengers run rotate @s ~ ~ + } ELSE { + block { with storage <%temp_storage%> entry.data.uuids_by_name + REPEAT (Object.values(rig.nodes).filter(node => BONE_TYPES.includes(node.type))) as node { + $tp $(<%node.storage_name%>) ~ ~ ~ ~ ~ + # Precise Rotation Workaround. Fixes MC-272913. + # Thanks @Triton365! (https://discord.com/channels/154777837382008833/157097006500806656/1402253905408163842) + $execute \ + as $(<%node.storage_name%>) \ + store success entity @s OnGround byte 1 \ + store success score @s <%OBJECTIVES.I()%> \ + unless score @s <%OBJECTIVES.I()%> matches 1 + } } } } @@ -284,13 +290,17 @@ IF (has_animations) { $execute at @s run function ./zzz/apply_frame {frame: $(to_frame)} tag @s remove <%TAGS.TRANSFORMS_ONLY()%> - data_manager prep read - block { with storage <%temp_storage%> entry.data.uuids_by_name - REPEAT (Object.values(rig.nodes).filter(node => BONE_TYPES.includes(node.type))) as node { - $execute \ - as $(<%node.storage_name%>) \ - store result entity @s interpolation_duration int 1 \ - run scoreboard players get #this <%OBJECTIVES.I()%> + IF (use_entity_stacking) { + execute on passengers store result entity @s interpolation_duration int 1 run scoreboard players get #this <%OBJECTIVES.I()%> + } ELSE { + data_manager prep read + block { with storage <%temp_storage%> entry.data.uuids_by_name + REPEAT (Object.values(rig.nodes).filter(node => BONE_TYPES.includes(node.type))) as node { + $execute \ + as $(<%node.storage_name%>) \ + store result entity @s interpolation_duration int 1 \ + run scoreboard players get #this <%OBJECTIVES.I()%> + } } } } @@ -300,12 +310,17 @@ IF (has_animations) { # Tweening logic scoreboard players remove @s <%OBJECTIVES.TWEEN_DURATION()%> 1 execute if score @s <%OBJECTIVES.TWEEN_DURATION()%> matches 1.. run return 1 - execute if score @s <%OBJECTIVES.TWEEN_DURATION()%> matches 0 run \ - block { with storage <%temp_storage%> entry.data.uuids_by_name - REPEAT (Object.values(rig.nodes).filter(node => BONE_TYPES.includes(node.type))) as node { - $data modify entity $(<%node.storage_name%>) interpolation_duration set value <%interpolation_duration%> + IF (use_entity_stacking) { + execute if score @s <%OBJECTIVES.TWEEN_DURATION()%> matches 0 on passengers run \ + data modify entity @s interpolation_duration set value <%interpolation_duration%> + } ELSE { + execute if score @s <%OBJECTIVES.TWEEN_DURATION()%> matches 0 run \ + block { with storage <%temp_storage%> entry.data.uuids_by_name + REPEAT (Object.values(rig.nodes).filter(node => BONE_TYPES.includes(node.type))) as node { + $data modify entity $(<%node.storage_name%>) interpolation_duration set value <%interpolation_duration%> + } } - } + } # Animation logic IF (animation.loop_mode === 'loop' && animation.loop_delay === 0) { @@ -355,9 +370,13 @@ IF (has_animations) { function set_frame { #ARGS: {frame: int} $function ./apply_frame {frame: $(frame)} - block { with storage <%temp_storage%> entry.data.uuids_by_name - REPEAT (Object.values(rig.nodes).filter(node => BONE_TYPES.includes(node.type))) as node { - $data modify entity $(<%node.storage_name%>) start_interpolation set value -1 + IF (use_entity_stacking) { + execute on passengers run data modify entity @s start_interpolation set value -1 + } ELSE { + block { with storage <%temp_storage%> entry.data.uuids_by_name + REPEAT (Object.values(rig.nodes).filter(node => BONE_TYPES.includes(node.type))) as node { + $data modify entity $(<%node.storage_name%>) start_interpolation set value -1 + } } } return 1 @@ -397,9 +416,14 @@ IF (has_animations) { $function ./frames/$(frame) with storage <%temp_storage%> entry.data.uuids_by_name - block { with storage <%temp_storage%> entry.data.uuids_by_name - REPEAT (Object.values(rig.nodes).filter(node => BONE_TYPES.includes(node.type))) as node { - $data modify entity $(<%node.storage_name%>) start_interpolation set value -1 + IF (use_entity_stacking) { + execute on passengers run \ + data modify entity @s start_interpolation set value -1 + } ELSE { + block { with storage <%temp_storage%> entry.data.uuids_by_name + REPEAT (Object.values(rig.nodes).filter(node => BONE_TYPES.includes(node.type))) as node { + $data modify entity $(<%node.storage_name%>) start_interpolation set value -1 + } } } diff --git a/src/systems/datapackCompiler/index.ts b/src/systems/datapackCompiler/index.ts index 1e8c769c..651be4b9 100644 --- a/src/systems/datapackCompiler/index.ts +++ b/src/systems/datapackCompiler/index.ts @@ -547,7 +547,6 @@ const dataPackCompiler: DataPackCompiler = async ({ TextComponent.defaultMinecraftVersion = version const aj = Project!.animated_java - const isStatic = animations.length === 0 const parsed = parseResourceLocation(aj.blueprint_id) const relativePathToSrc = parsed.path @@ -603,6 +602,7 @@ const dataPackCompiler: DataPackCompiler = async ({ data_storage: `animated_java:data`, auto_update_rig_orientation: aj.auto_update_rig_orientation, debug_mode: debugMode, + use_entity_stacking: aj.use_entity_stacking, } const mcbFiles = getMCBFilesByVersion(version) From fa7353727b82ade35d0f932da3c21e37dd5eb30f Mon Sep 17 00:00:00 2001 From: SnaveSutit Date: Sun, 3 May 2026 07:16:58 -0400 Subject: [PATCH 13/17] =?UTF-8?q?=E2=AC=86=EF=B8=8F=20Update=20`blockbench?= =?UTF-8?q?-patch-manager`=20and=20`book-and-quill`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bun.lock | 8 ++++---- package.json | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/bun.lock b/bun.lock index 8e0bdae3..e8bf283a 100644 --- a/bun.lock +++ b/bun.lock @@ -24,8 +24,8 @@ "@types/websocket": "^1.0.10", "@typescript-eslint/eslint-plugin": "^5.54.0", "@typescript-eslint/parser": "^5.54.0", - "blockbench-patch-manager": "^1.0.2", - "book-and-quill": "^1.0.8", + "blockbench-patch-manager": "^1.1.0", + "book-and-quill": "^1.0.9", "esbuild": "^0.17.10", "esbuild-plugin-import-folder": "^1.0.1", "esbuild-plugin-import-glob": "^0.1.1", @@ -499,11 +499,11 @@ "before-after-hook": ["before-after-hook@4.0.0", "", {}, "sha512-q6tR3RPqIB1pMiTRMFcZwuG5T8vwp+vUvEG0vuI6B+Rikh5BfPp2fQ82c925FOs+b0lcFQ8CFrL+KbilfZFhOQ=="], - "blockbench-patch-manager": ["blockbench-patch-manager@1.0.2", "", { "dependencies": { "blockbench-types": "^5.0.6", "simple-subpub": "^1.2.0", "svelte": "^5.46.3", "svelte-observable-store": "^1.0.1", "svelte-preprocess": "^6.0.3", "svelte-preprocess-esbuild": "^3.0.1" }, "peerDependencies": { "typescript": "^5" } }, "sha512-u72CF1AyqWaIMHYqnhhYQjf1SbAtJAhJLKkPu9j+n2dGBLZYNmMTZRqHGCRPZl7ZEHWwuX0mUuP1Gq2B8rmUfg=="], + "blockbench-patch-manager": ["blockbench-patch-manager@1.1.0", "", { "dependencies": { "blockbench-types": "^5.1.0-beta.1", "simple-subpub": "^1.2.0", "svelte": "^5.46.3", "svelte-observable-store": "^1.0.1", "svelte-preprocess": "^6.0.3", "svelte-preprocess-esbuild": "^3.0.1" }, "peerDependencies": { "typescript": "^5" } }, "sha512-68FXezYJ3HdkVcam90r/MY8W2gS8jZeitfUz3XXnC/XyDkHJZlLr8dpFJmJrrUqUSBVRG7wweOhbs/tn+znotQ=="], "blockbench-types": ["blockbench-types@5.1.0", "", { "dependencies": { "@babel/types": "^7.20.7", "@types/dompurify": "^3.0.5", "@types/jquery": "^3.5.32", "@types/prismjs": "^1.26.0", "@types/three": "^0.129.2", "@types/tinycolor2": "^1.4.6", "dompurify": "^3.0.1", "electron": "^40.8.0", "prismjs": "^1.29.0", "tinycolor2": "^1.6.0", "typescript": "^5.8.3", "vue": "2.7.14", "wintersky": "^1.3.0" } }, "sha512-JLMHJZ+2J7aFQwSacfW4N/rvd56JRqvaBsHNH2R6sjyxkwKPuNPKYIeav/WtRXnq3dmlsEoH3rtg09s7yhe3sg=="], - "book-and-quill": ["book-and-quill@1.0.8", "", { "dependencies": { "@types/node": "^25.3.3", "tinycolor2": "^1.6.0" }, "peerDependencies": { "typescript": "^5" } }, "sha512-lN6I+l/1fJ1OB4LM8wkm9jxOxBD+sgwoSRQjdfcsekwFcPRBC8TJckbgnp+mgvGGz/c14z7fkj6yhJh+opsy4Q=="], + "book-and-quill": ["book-and-quill@1.0.9", "", { "dependencies": { "@types/node": "^25.3.3", "tinycolor2": "^1.6.0" }, "peerDependencies": { "typescript": "^5" } }, "sha512-5jpj2ziHTMzeS7YTPqV8IcvaRkRn71A+kcvhSsxruK6JBM14jnqIjgdiKlDfuA/YzV5P6APwH9lNcC5yWOBn5A=="], "boolean": ["boolean@3.2.0", "", {}, "sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw=="], diff --git a/package.json b/package.json index 2423e259..36de8c76 100644 --- a/package.json +++ b/package.json @@ -92,8 +92,8 @@ "@types/websocket": "^1.0.10", "@typescript-eslint/eslint-plugin": "^5.54.0", "@typescript-eslint/parser": "^5.54.0", - "blockbench-patch-manager": "^1.0.2", - "book-and-quill": "^1.0.8", + "blockbench-patch-manager": "^1.1.0", + "book-and-quill": "^1.0.9", "esbuild": "^0.17.10", "esbuild-plugin-import-folder": "^1.0.1", "esbuild-plugin-import-glob": "^0.1.1", From f5da72acc6c3395f75df48dcfa269ec2211080bd Mon Sep 17 00:00:00 2001 From: SnaveSutit Date: Sun, 3 May 2026 07:30:48 -0400 Subject: [PATCH 14/17] =?UTF-8?q?=E2=9C=A8=20Add=20`Custom=20Rig=20Entity?= =?UTF-8?q?=20Tags`=20option=20to=20blueprint=20rig=20settings?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/dialogs/blueprintSettings/pages/rig.svelte | 9 +++++++++ src/formats/blueprint/settings.ts | 2 ++ src/lang/en.yml | 9 ++++++++- src/systems/datapackCompiler/1.20.4/main.mcb | 8 +------- src/systems/datapackCompiler/1.20.5/main.mcb | 8 +------- src/systems/datapackCompiler/1.21.0/main.mcb | 8 +------- src/systems/datapackCompiler/1.21.2/main.mcb | 8 +------- src/systems/datapackCompiler/1.21.4/main.mcb | 8 +------- src/systems/datapackCompiler/1.21.5/main.mcb | 8 +------- src/systems/datapackCompiler/index.ts | 3 ++- src/systems/datapackCompiler/tags.ts | 17 ++++++++++++++++- 11 files changed, 43 insertions(+), 45 deletions(-) diff --git a/src/dialogs/blueprintSettings/pages/rig.svelte b/src/dialogs/blueprintSettings/pages/rig.svelte index d17a0e63..2726384c 100644 --- a/src/dialogs/blueprintSettings/pages/rig.svelte +++ b/src/dialogs/blueprintSettings/pages/rig.svelte @@ -1,22 +1,31 @@ + + ', \ - '<%TAGS.GLOBAL_ENTITY()%>', \ - '<%TAGS.GLOBAL_ROOT()%>', \ - '<%TAGS.PROJECT_ENTITY(blueprint_id)%>', \ - '<%TAGS.PROJECT_ROOT(blueprint_id)%>' \ - ], \ + Tags:<%root_entity_tags%>, \ teleport_duration: 0, \ interpolation_duration: <%interpolation_duration%>, \ Passengers:<%root_entity_passengers%>, \ diff --git a/src/systems/datapackCompiler/1.20.5/main.mcb b/src/systems/datapackCompiler/1.20.5/main.mcb index 4cbe5f48..20636c01 100644 --- a/src/systems/datapackCompiler/1.20.5/main.mcb +++ b/src/systems/datapackCompiler/1.20.5/main.mcb @@ -562,13 +562,7 @@ function summon { } summon minecraft:item_display ~ ~ ~ { \ - Tags:[ \ - '<%TAGS.NEW()%>', \ - '<%TAGS.GLOBAL_ENTITY()%>', \ - '<%TAGS.GLOBAL_ROOT()%>', \ - '<%TAGS.PROJECT_ENTITY(blueprint_id)%>', \ - '<%TAGS.PROJECT_ROOT(blueprint_id)%>' \ - ], \ + Tags:<%root_entity_tags%>, \ teleport_duration: 0, \ interpolation_duration: <%interpolation_duration%>, \ Passengers:<%root_entity_passengers%>, \ diff --git a/src/systems/datapackCompiler/1.21.0/main.mcb b/src/systems/datapackCompiler/1.21.0/main.mcb index e927e04a..82d9014a 100644 --- a/src/systems/datapackCompiler/1.21.0/main.mcb +++ b/src/systems/datapackCompiler/1.21.0/main.mcb @@ -563,13 +563,7 @@ function summon { } summon minecraft:item_display ~ ~ ~ { \ - Tags:[ \ - '<%TAGS.NEW()%>', \ - '<%TAGS.GLOBAL_ENTITY()%>', \ - '<%TAGS.GLOBAL_ROOT()%>', \ - '<%TAGS.PROJECT_ENTITY(blueprint_id)%>', \ - '<%TAGS.PROJECT_ROOT(blueprint_id)%>' \ - ], \ + Tags:<%root_entity_tags%>, \ teleport_duration: 0, \ interpolation_duration: <%interpolation_duration%>, \ Passengers:<%root_entity_passengers%>, \ diff --git a/src/systems/datapackCompiler/1.21.2/main.mcb b/src/systems/datapackCompiler/1.21.2/main.mcb index 310f992e..9aacd4ac 100644 --- a/src/systems/datapackCompiler/1.21.2/main.mcb +++ b/src/systems/datapackCompiler/1.21.2/main.mcb @@ -562,13 +562,7 @@ function summon { } summon minecraft:item_display ~ ~ ~ { \ - Tags:[ \ - '<%TAGS.NEW()%>', \ - '<%TAGS.GLOBAL_ENTITY()%>', \ - '<%TAGS.GLOBAL_ROOT()%>', \ - '<%TAGS.PROJECT_ENTITY(blueprint_id)%>', \ - '<%TAGS.PROJECT_ROOT(blueprint_id)%>' \ - ], \ + Tags:<%root_entity_tags%>, \ teleport_duration: 0, \ interpolation_duration: <%interpolation_duration%>, \ Passengers:<%root_entity_passengers%>, \ diff --git a/src/systems/datapackCompiler/1.21.4/main.mcb b/src/systems/datapackCompiler/1.21.4/main.mcb index e5ad389e..2b14954f 100644 --- a/src/systems/datapackCompiler/1.21.4/main.mcb +++ b/src/systems/datapackCompiler/1.21.4/main.mcb @@ -651,13 +651,7 @@ function summon { } summon minecraft:item_display ~ ~ ~ { \ - Tags:[ \ - '<%TAGS.NEW()%>', \ - '<%TAGS.GLOBAL_ENTITY()%>', \ - '<%TAGS.GLOBAL_ROOT()%>', \ - '<%TAGS.PROJECT_ENTITY(blueprint_id)%>', \ - '<%TAGS.PROJECT_ROOT(blueprint_id)%>' \ - ], \ + Tags:<%root_entity_tags%>, \ teleport_duration: 0, \ interpolation_duration: <%interpolation_duration%>, \ Passengers:<%root_entity_passengers%>, \ diff --git a/src/systems/datapackCompiler/1.21.5/main.mcb b/src/systems/datapackCompiler/1.21.5/main.mcb index 2d95bfe1..6a80dac0 100644 --- a/src/systems/datapackCompiler/1.21.5/main.mcb +++ b/src/systems/datapackCompiler/1.21.5/main.mcb @@ -650,13 +650,7 @@ function summon { } summon minecraft:item_display ~ ~ ~ { \ - Tags:[ \ - '<%TAGS.NEW()%>', \ - '<%TAGS.GLOBAL_ENTITY()%>', \ - '<%TAGS.GLOBAL_ROOT()%>', \ - '<%TAGS.PROJECT_ENTITY(blueprint_id)%>', \ - '<%TAGS.PROJECT_ROOT(blueprint_id)%>' \ - ], \ + Tags:<%root_entity_tags%>, \ teleport_duration: 0, \ interpolation_duration: <%interpolation_duration%>, \ Passengers:<%root_entity_passengers%>, \ diff --git a/src/systems/datapackCompiler/index.ts b/src/systems/datapackCompiler/index.ts index 651be4b9..1dde6841 100644 --- a/src/systems/datapackCompiler/index.ts +++ b/src/systems/datapackCompiler/index.ts @@ -37,7 +37,7 @@ import { import ENTITY_NAMES from './entityNames' import { compileMcbProject } from './mcbCompiler' import OBJECTIVES from './objectives' -import TAGS, { getNodeTags } from './tags' +import TAGS, { getNodeTags, getRootEntityTags } from './tags' import TELLRAW from './tellraw' const BONE_TYPES = ['bone', 'text_display', 'item_display', 'block_display'] @@ -603,6 +603,7 @@ const dataPackCompiler: DataPackCompiler = async ({ auto_update_rig_orientation: aj.auto_update_rig_orientation, debug_mode: debugMode, use_entity_stacking: aj.use_entity_stacking, + root_entity_tags: getRootEntityTags().toString(), } const mcbFiles = getMCBFilesByVersion(version) diff --git a/src/systems/datapackCompiler/tags.ts b/src/systems/datapackCompiler/tags.ts index 4625663e..57810978 100644 --- a/src/systems/datapackCompiler/tags.ts +++ b/src/systems/datapackCompiler/tags.ts @@ -173,9 +173,24 @@ namespace TAGS { export default TAGS +export function getRootEntityTags(): NbtList { + const tags: string[] = [ + ...Project!.animated_java.custom_rig_entity_tags.split(',').map(t => t.trim()), + TAGS.NEW(), + TAGS.GLOBAL_ENTITY(), + TAGS.GLOBAL_ROOT(), + TAGS.PROJECT_ENTITY(Project!.animated_java.blueprint_id), + TAGS.PROJECT_ROOT(Project!.animated_java.blueprint_id), + ] + + return new NbtList(tags.sort().map(v => new NbtString(v))) +} + // region getNodeTags export function getNodeTags(node: AnyRenderedNode, rig: IRenderedRig): NbtList { - const tags: string[] = [] + const tags: string[] = [ + ...Project!.animated_java.custom_rig_entity_tags.split(',').map(t => t.trim()), + ] const parentNames: Array<{ name: string; type: string }> = [] From e3beca4b2f974aef56ba7946a97b5902ff34dcf3 Mon Sep 17 00:00:00 2001 From: SnaveSutit Date: Sun, 3 May 2026 07:32:11 -0400 Subject: [PATCH 15/17] =?UTF-8?q?=F0=9F=A9=B9=20Disable=20bounding=20boxes?= =?UTF-8?q?=20temporarily?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/formats/blueprint/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/formats/blueprint/index.ts b/src/formats/blueprint/index.ts index 85ac29d4..32163e5d 100644 --- a/src/formats/blueprint/index.ts +++ b/src/formats/blueprint/index.ts @@ -373,7 +373,7 @@ export const BLUEPRINT_FORMAT = registerDeletableHandlerPatch({ single_texture: false, texture_folder: false, texture_meshes: false, - bounding_boxes: true, + // bounding_boxes: true, uv_rotation: true, vertex_color_ambient_occlusion: true, java_cube_shading_properties: true, From 941c6237b2268680923b8b33ff6af5398725e8db Mon Sep 17 00:00:00 2001 From: SnaveSutit Date: Sun, 3 May 2026 07:37:44 -0400 Subject: [PATCH 16/17] =?UTF-8?q?=F0=9F=94=96=20v1.10.0-beta.6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 +- src/pluginPackage/changelog.json | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 36de8c76..0df6b361 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "title": "Animated Java", "icon": "icon.svg", "description": "Effortlessly craft complex animations for Minecraft: Java Edition", - "version": "1.10.0-beta.5", + "version": "1.10.0-beta.6", "min_blockbench_version": "5.1.4", "variant": "desktop", "tags": [ diff --git a/src/pluginPackage/changelog.json b/src/pluginPackage/changelog.json index f5bef75a..4b110bdb 100644 --- a/src/pluginPackage/changelog.json +++ b/src/pluginPackage/changelog.json @@ -697,5 +697,28 @@ "list": ["Fixed \"infinite loading popup\" issue."] } ] + }, + "1.10.0-beta.6": { + "title": "v1.10.0-beta.6", + "author": "Titus Evans (SnaveSutit)", + "date": "2026-05-04", + "categories": [ + { + "title": "Changes", + "list": [ + "Added `Rig` page to Blueprint settings.", + "Added `Custom Rig Entity Tags` option to Blueprint settings.", + "Added `Use Entity Stacking` option to Blueprint settings." + ] + }, + { + "title": "Fixes", + "list": [ + "Fixed Blueprints failing to save due to missing `fs` global.", + "Fixed Animated Java failing to reload correctly when plugins are reloaded.", + "Fixed JSON Text Components failing to add quotes around strings that start with numeric characters." + ] + } + ] } } From 5ef56e4af911520e02939b211b71e4275018a580 Mon Sep 17 00:00:00 2001 From: SnaveSutit Date: Sun, 3 May 2026 07:39:16 -0400 Subject: [PATCH 17/17] =?UTF-8?q?=E2=9A=99=EF=B8=8F=20Fix=20build=20workfl?= =?UTF-8?q?ow?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 64b14c85..8f790875 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -23,7 +23,7 @@ jobs: run: bun install --frozen-lockfile - name: Build - run: bun run build + run: bun run prod - name: Run tests run: bun test