minerender 2.1.0-alpha.139 → 2.1.0-alpha.140
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser/esm/index.browser.d.mts +10 -1
- package/dist/browser/esm/scene/SceneDocument.mjs +18 -3
- package/dist/browser/esm/scene/SceneDocument.mjs.map +1 -1
- package/dist/browser/esm/scene/SceneDocumentLoader.mjs +13 -3
- package/dist/browser/esm/scene/SceneDocumentLoader.mjs.map +1 -1
- package/dist/browser/index.d.ts +10 -1
- package/dist/browser/index.js +31 -6
- package/dist/browser/index.js.map +1 -1
- package/dist/bundle.js +31 -6
- package/dist/bundle.js.map +1 -1
- package/dist/node/index.d.mts +10 -1
- package/dist/node/index.d.ts +10 -1
- package/dist/node/index.js +31 -6
- package/dist/node/index.js.map +1 -1
- package/dist/node/index.mjs +31 -6
- package/dist/node/index.mjs.map +1 -1
- package/package.json +1 -1
|
@@ -3491,8 +3491,17 @@ interface SceneEntityDefinition extends SceneObjectDefinitionBase {
|
|
|
3491
3491
|
wireframe?: boolean;
|
|
3492
3492
|
tints?: Record<string, string | number>;
|
|
3493
3493
|
};
|
|
3494
|
-
|
|
3494
|
+
/** Plays one named clip or blends clips with weights defaulting to 1, without normalization. */
|
|
3495
|
+
animation?: ({
|
|
3495
3496
|
name: string;
|
|
3497
|
+
clips?: never;
|
|
3498
|
+
} | {
|
|
3499
|
+
name?: never;
|
|
3500
|
+
clips: {
|
|
3501
|
+
name: string;
|
|
3502
|
+
weight?: number;
|
|
3503
|
+
}[];
|
|
3504
|
+
}) & {
|
|
3496
3505
|
loop?: boolean;
|
|
3497
3506
|
speed?: number;
|
|
3498
3507
|
time?: number;
|
|
@@ -95,6 +95,23 @@ var itemContext = (withDisplayContext) => (value, path) => {
|
|
|
95
95
|
}
|
|
96
96
|
});
|
|
97
97
|
};
|
|
98
|
+
function entityAnimation(value, path) {
|
|
99
|
+
const animation = object(value, path);
|
|
100
|
+
if (["name", "clips"].filter((key) => animation[key] !== void 0).length !== 1) {
|
|
101
|
+
fail(path, "expected exactly one of name or clips");
|
|
102
|
+
}
|
|
103
|
+
fields(value, path, { name: text, clips: (value2, path2) => {
|
|
104
|
+
list((value3, path3) => {
|
|
105
|
+
fields(value3, path3, { name: text, weight: nonnegative }, ["name"]);
|
|
106
|
+
})(value2, path2);
|
|
107
|
+
if (!value2.length) fail(path2, "expected at least one clip");
|
|
108
|
+
const names = /* @__PURE__ */ new Set();
|
|
109
|
+
for (const [index, clip] of value2.entries()) {
|
|
110
|
+
if (names.has(clip.name)) fail(`${path2}[${index}].name`, `duplicate clip "${clip.name}"`);
|
|
111
|
+
names.add(clip.name);
|
|
112
|
+
}
|
|
113
|
+
}, loop: boolean, speed: nonnegative, time: nonnegative, paused: boolean });
|
|
114
|
+
}
|
|
98
115
|
function guiLayer(value, path) {
|
|
99
116
|
const layer = object(value, path);
|
|
100
117
|
if (["texture", "item", "text"].filter((key) => layer[key] !== void 0).length !== 1) {
|
|
@@ -197,9 +214,7 @@ function validateObject(value, path) {
|
|
|
197
214
|
})
|
|
198
215
|
});
|
|
199
216
|
},
|
|
200
|
-
animation:
|
|
201
|
-
fields(value2, path2, { name: text, loop: boolean, speed: nonnegative, time: nonnegative, paused: boolean }, ["name"]);
|
|
202
|
-
}
|
|
217
|
+
animation: entityAnimation
|
|
203
218
|
}, [...required, "asset"]);
|
|
204
219
|
if (Array.isArray(input.layers) && !input.layers.length) fail(`${path}.layers`, "expected at least one layer");
|
|
205
220
|
break;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/scene/SceneDocument.ts"],"sourcesContent":["import type { CapeLayout } from \"../skin/CapeLayout\";\nimport { SKIN_PARTS } from \"../skin/SkinPart\";\nimport type { TripleArray } from \"../model/Model\";\nimport { DISPLAY_POSITIONS, DisplayPosition } from \"../model/DisplayPosition\";\nimport type { GuiItemLayer, GuiTextLayer, GuiTextureLayer } from \"../gui/GuiLayer\";\n\n/** Portable scene setup. Positions use model units (16 per block); rotations use radians. */\nexport interface SceneDocument {\n format: \"minerender-scene\";\n version: 1;\n minecraftVersion?: string;\n camera?: { position: TripleArray; target: TripleArray };\n objects: SceneObjectDefinition[];\n}\n\nexport interface SceneObjectDefinitionBase {\n id: string;\n name?: string;\n position?: TripleArray;\n rotation?: TripleArray;\n scale?: TripleArray;\n visible?: boolean;\n}\n\nexport type SceneSkinPosePart = \"head\" | \"body\" | \"rightArm\" | \"leftArm\" | \"rightLeg\" | \"leftLeg\" | \"cape\";\n\nexport interface SceneSkinDefinition extends SceneObjectDefinitionBase {\n type: \"skin\";\n /** Texture URL, Minecraft username, or UUID. Omit for Steve, or Alex with slim: true, from the active asset version. */\n skin?: string;\n cape?: { texture: string; layout?: CapeLayout };\n options?: { slim?: boolean; legacy?: boolean };\n /** Mesh names from SkinPart; hiding a base part does not hide its overlay. */\n hiddenParts?: string[];\n /** Absolute local XYZ joint rotations in radians; omitted joints keep their default pose. */\n pose?: Partial<Record<SceneSkinPosePart, TripleArray>>;\n}\n\nexport interface SceneBlockDefinition extends SceneObjectDefinitionBase {\n type: \"block\";\n asset: string;\n state?: Record<string, string>;\n options?: { wireframe?: boolean; tints?: Record<number, number> };\n}\n\n/** Supplied item state; see ItemModelContext. Item references are item IDs such as minecraft:apple. */\nexport interface SceneItemContext {\n displayContext?: DisplayPosition | \"none\";\n properties?: Record<string, boolean | string | number>;\n components?: Record<string, unknown>;\n count?: number;\n itemReferences?: Record<string, string>;\n}\n\nexport interface SceneModelDefinition extends SceneObjectDefinitionBase {\n type: \"item\" | \"model\";\n asset: string;\n options?: { wireframe?: boolean; displayPosition?: DisplayPosition; tints?: Record<number, number> };\n /** Item state for `type: \"item\"` definitions only. */\n context?: SceneItemContext;\n}\n\nexport interface SceneEntityDefinition extends SceneObjectDefinitionBase {\n type: \"entity\";\n asset: string;\n texture?: string;\n layers?: string[];\n when?: string[];\n textures?: Record<string, string>;\n options?: { flip?: boolean; wireframe?: boolean; tints?: Record<string, string | number> };\n animation?: { name: string; loop?: boolean; speed?: number; time?: number; paused?: boolean };\n}\n\nexport type SceneGuiLayer = (Omit<GuiTextureLayer, \"texture\"> & { texture: string })\n | (Omit<GuiItemLayer, \"item\" | \"context\"> & { item: string; context?: Omit<SceneItemContext, \"displayContext\"> })\n | (Omit<GuiTextLayer, \"font\"> & { font?: string });\n\nexport interface SceneGuiDefinition extends SceneObjectDefinitionBase {\n type: \"gui\";\n layers: SceneGuiLayer[];\n}\n\nexport type SceneObjectDefinition = SceneSkinDefinition | SceneBlockDefinition | SceneModelDefinition\n | SceneEntityDefinition | SceneGuiDefinition;\n\ntype JsonObject = Record<string, unknown>;\ntype Validator = (value: unknown, path: string) => void;\n\nfunction fail(path: string, message: string): never {\n throw new Error(`${path}: ${message}`);\n}\n\nfunction object(value: unknown, path: string): JsonObject {\n if (!value || typeof value !== \"object\" || Array.isArray(value)\n || ![Object.prototype, null].includes(Object.getPrototypeOf(value))) fail(path, \"expected a JSON object\");\n for (const key of Object.keys(value)) {\n if ([\"__proto__\", \"prototype\", \"constructor\"].includes(key)) fail(`${path}.${key}`, \"unsupported property\");\n }\n return value as JsonObject;\n}\n\nfunction fields(value: unknown, path: string, allowed: Record<string, Validator>, required: string[] = []): JsonObject {\n const input = object(value, path);\n for (const key of required) if (input[key] === undefined) fail(`${path}.${key}`, \"required\");\n for (const [key, entry] of Object.entries(input)) {\n if (!Object.prototype.hasOwnProperty.call(allowed, key)) fail(`${path}.${key}`, \"unsupported property\");\n if (entry !== undefined) allowed[key](entry, `${path}.${key}`);\n }\n return input;\n}\n\nconst text: Validator = (value, path) => {\n if (typeof value !== \"string\" || !value.trim()) fail(path, \"expected a nonempty string\");\n};\nconst literalText: Validator = (value, path) => {\n if (typeof value !== \"string\") fail(path, \"expected a string\");\n};\nconst boolean: Validator = (value, path) => {\n if (typeof value !== \"boolean\") fail(path, \"expected a boolean\");\n};\nconst number: Validator = (value, path) => {\n if (typeof value !== \"number\" || !Number.isFinite(value)) fail(path, \"expected a finite number\");\n};\nconst positive: Validator = (value, path) => {\n number(value, path);\n if ((value as number) <= 0) fail(path, \"expected a positive number\");\n};\nconst nonnegative: Validator = (value, path) => {\n number(value, path);\n if ((value as number) < 0) fail(path, \"expected a nonnegative number\");\n};\nconst color: Validator = (value, path) => {\n number(value, path);\n if (!Number.isInteger(value) || (value as number) < 0 || (value as number) > 0xffffff) {\n fail(path, \"expected an RGB integer from 0 to 16777215\");\n }\n};\nconst asset: Validator = (value, path) => {\n text(value, path);\n if (!/^(?:[a-z0-9_.-]+:)?[a-z0-9_./-]+$/.test(value as string)\n || (value as string).split(/[:/]/).some(part => !part || part === \".\" || part === \"..\")) {\n fail(path, \"expected a resource ID such as minecraft:stone\");\n }\n};\nconst version: Validator = (value, path) => {\n text(value, path);\n if (!/^[a-zA-Z0-9._-]+$/.test(value as string)) fail(path, \"expected a Minecraft version without slashes\");\n};\nconst tuple = (size: number, item: Validator = number): Validator => (value, path) => {\n if (!Array.isArray(value) || value.length !== size) fail(path, `expected ${size} numbers`);\n for (let index = 0; index < size; index++) item(value[index], `${path}[${index}]`);\n};\nconst list = (item: Validator): Validator => (value, path) => {\n if (!Array.isArray(value)) fail(path, \"expected an array\");\n for (let index = 0; index < value.length; index++) item(value[index], `${path}[${index}]`);\n};\nconst dictionary = (item: Validator, numericKeys = false): Validator => (value, path) => {\n for (const [key, entry] of Object.entries(object(value, path))) {\n if (numericKeys && !/^\\d+$/.test(key)) fail(`${path}.${key}`, \"expected a nonnegative tint index\");\n item(entry, `${path}.${key}`);\n }\n};\nconst enumeration = (values: readonly string[]): Validator => (value, path) => {\n if (!values.includes(value as string)) fail(path, `expected one of: ${values.join(\", \")}`);\n};\nconst textStyle = { color, bold: boolean, italic: boolean };\nconst jsonValue: Validator = (value, path) => {\n if (value === null || typeof value === \"boolean\" || typeof value === \"string\") return;\n if (typeof value === \"number\") number(value, path);\n else if (Array.isArray(value)) list(jsonValue)(value, path);\n else dictionary(jsonValue)(value, path);\n};\nconst propertyValue: Validator = (value, path) => {\n if (typeof value === \"boolean\" || typeof value === \"string\") return;\n if (typeof value !== \"number\" || !Number.isFinite(value)) fail(path, \"expected a boolean, string, or finite number\");\n};\nconst itemContext = (withDisplayContext: boolean): Validator => (value, path) => {\n fields(value, path, {\n ...(withDisplayContext ? { displayContext: enumeration([...DISPLAY_POSITIONS, \"none\"]) } : {}),\n properties: dictionary(propertyValue), components: dictionary(jsonValue), itemReferences: dictionary(asset),\n count: (value, path) => { if (!Number.isInteger(value) || (value as number) < 0) fail(path, \"expected a nonnegative integer\"); }\n });\n};\n\nfunction guiLayer(value: unknown, path: string): void {\n const layer = object(value, path);\n if ([\"texture\", \"item\", \"text\"].filter(key => layer[key] !== undefined).length !== 1) {\n fail(path, \"expected exactly one of texture, item, or text\");\n }\n const layout = { name: text, position: tuple(2), size: tuple(2, positive) };\n if (layer.texture !== undefined) {\n fields(value, path, { ...layout, texture: asset, crop: (value, path) => {\n tuple(4)(value, path);\n const [x, y, width, height] = value as number[];\n nonnegative(x, `${path}[0]`); nonnegative(y, `${path}[1]`);\n positive(width, `${path}[2]`); positive(height, `${path}[3]`);\n } });\n } else if (layer.item !== undefined) {\n fields(value, path, { ...layout, item: asset, context: itemContext(false), tints: dictionary(color, true) });\n } else {\n fields(value, path, { ...layout, ...textStyle, font: asset, shadow: boolean, maxWidth: positive, lineHeight: positive,\n text: (value, path) => {\n if (typeof value === \"string\") return;\n list((run, path) => { fields(run, path, { text: literalText, ...textStyle }, [\"text\"]); })(value, path);\n }\n });\n }\n}\n\nfunction validateObject(value: unknown, path: string): void {\n const input = object(value, path);\n const common = { id: text, name: text, type: text, position: tuple(3), rotation: tuple(3), scale: tuple(3), visible: boolean };\n const required = [\"id\", \"type\"];\n const renderOptions = { wireframe: boolean };\n switch (input.type) {\n case \"skin\":\n fields(value, path, { ...common, skin: text,\n cape: (value, path) => { fields(value, path, { texture: text, layout: enumeration([\"minecraft\", \"optifine\", \"labymod\"]) }, [\"texture\"]); },\n hiddenParts: list(enumeration(SKIN_PARTS)),\n pose: (value, path) => { fields(value, path, {\n head: tuple(3), body: tuple(3), rightArm: tuple(3), leftArm: tuple(3),\n rightLeg: tuple(3), leftLeg: tuple(3), cape: tuple(3)\n }); },\n options: (value, path) => { fields(value, path, { slim: boolean, legacy: boolean }); }\n }, required);\n break;\n case \"block\":\n fields(value, path, { ...common, asset, state: dictionary(text),\n options: (value, path) => { fields(value, path, { ...renderOptions, tints: dictionary(color, true) }); }\n }, [...required, \"asset\"]);\n break;\n case \"item\":\n case \"model\":\n fields(value, path, { ...common, asset, ...(input.type === \"item\" ? { context: itemContext(true) } : {}),\n options: (value, path) => { fields(value, path, { ...renderOptions, displayPosition: enumeration(DISPLAY_POSITIONS), tints: dictionary(color, true) }); }\n }, [...required, \"asset\"]);\n break;\n case \"entity\":\n fields(value, path, { ...common, asset, texture: asset, layers: list(text), when: list(text), textures: dictionary(asset),\n options: (value, path) => { fields(value, path, { ...renderOptions, flip: boolean,\n tints: dictionary((value, path) => { typeof value === \"string\" ? text(value, path) : color(value, path); }) }); },\n animation: (value, path) => { fields(value, path, { name: text, loop: boolean, speed: nonnegative, time: nonnegative, paused: boolean }, [\"name\"]); }\n }, [...required, \"asset\"]);\n if (Array.isArray(input.layers) && !input.layers.length) fail(`${path}.layers`, \"expected at least one layer\");\n break;\n case \"gui\":\n fields(value, path, { ...common, layers: list(guiLayer) }, [...required, \"layers\"]);\n break;\n default:\n fail(`${path}.type`, \"expected skin, block, item, entity, model, or gui\");\n }\n}\n\n/** Validates and copies a scene document without requesting assets or changing the active asset version. */\nexport function parseSceneDocument(value: unknown): SceneDocument {\n if (typeof value === \"string\") {\n try { value = JSON.parse(value); }\n catch { fail(\"scene\", \"invalid JSON\"); }\n }\n const input = fields(value, \"scene\", {\n format: enumeration([\"minerender-scene\"]),\n version: (value, path) => { if (value !== 1) fail(path, \"only scene document version 1 is supported\"); },\n minecraftVersion: version,\n camera: (value, path) => { fields(value, path, { position: tuple(3), target: tuple(3) }, [\"position\", \"target\"]); },\n objects: list(validateObject)\n }, [\"format\", \"version\", \"objects\"]);\n const ids = new Set<string>();\n for (const [index, entry] of (input.objects as SceneObjectDefinition[]).entries()) {\n if (ids.has(entry.id)) fail(`scene.objects[${index}].id`, `duplicate object ID \"${entry.id}\"`);\n ids.add(entry.id);\n }\n return JSON.parse(JSON.stringify(input)) as SceneDocument;\n}\n"],"mappings":"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","names":["value","path"]}
|
|
1
|
+
{"version":3,"sources":["../../../../src/scene/SceneDocument.ts"],"sourcesContent":["import type { CapeLayout } from \"../skin/CapeLayout\";\nimport { SKIN_PARTS } from \"../skin/SkinPart\";\nimport type { TripleArray } from \"../model/Model\";\nimport { DISPLAY_POSITIONS, DisplayPosition } from \"../model/DisplayPosition\";\nimport type { GuiItemLayer, GuiTextLayer, GuiTextureLayer } from \"../gui/GuiLayer\";\n\n/** Portable scene setup. Positions use model units (16 per block); rotations use radians. */\nexport interface SceneDocument {\n format: \"minerender-scene\";\n version: 1;\n minecraftVersion?: string;\n camera?: { position: TripleArray; target: TripleArray };\n objects: SceneObjectDefinition[];\n}\n\nexport interface SceneObjectDefinitionBase {\n id: string;\n name?: string;\n position?: TripleArray;\n rotation?: TripleArray;\n scale?: TripleArray;\n visible?: boolean;\n}\n\nexport type SceneSkinPosePart = \"head\" | \"body\" | \"rightArm\" | \"leftArm\" | \"rightLeg\" | \"leftLeg\" | \"cape\";\n\nexport interface SceneSkinDefinition extends SceneObjectDefinitionBase {\n type: \"skin\";\n /** Texture URL, Minecraft username, or UUID. Omit for Steve, or Alex with slim: true, from the active asset version. */\n skin?: string;\n cape?: { texture: string; layout?: CapeLayout };\n options?: { slim?: boolean; legacy?: boolean };\n /** Mesh names from SkinPart; hiding a base part does not hide its overlay. */\n hiddenParts?: string[];\n /** Absolute local XYZ joint rotations in radians; omitted joints keep their default pose. */\n pose?: Partial<Record<SceneSkinPosePart, TripleArray>>;\n}\n\nexport interface SceneBlockDefinition extends SceneObjectDefinitionBase {\n type: \"block\";\n asset: string;\n state?: Record<string, string>;\n options?: { wireframe?: boolean; tints?: Record<number, number> };\n}\n\n/** Supplied item state; see ItemModelContext. Item references are item IDs such as minecraft:apple. */\nexport interface SceneItemContext {\n displayContext?: DisplayPosition | \"none\";\n properties?: Record<string, boolean | string | number>;\n components?: Record<string, unknown>;\n count?: number;\n itemReferences?: Record<string, string>;\n}\n\nexport interface SceneModelDefinition extends SceneObjectDefinitionBase {\n type: \"item\" | \"model\";\n asset: string;\n options?: { wireframe?: boolean; displayPosition?: DisplayPosition; tints?: Record<number, number> };\n /** Item state for `type: \"item\"` definitions only. */\n context?: SceneItemContext;\n}\n\nexport interface SceneEntityDefinition extends SceneObjectDefinitionBase {\n type: \"entity\";\n asset: string;\n texture?: string;\n layers?: string[];\n when?: string[];\n textures?: Record<string, string>;\n options?: { flip?: boolean; wireframe?: boolean; tints?: Record<string, string | number> };\n /** Plays one named clip or blends clips with weights defaulting to 1, without normalization. */\n animation?: ({ name: string; clips?: never } | { name?: never; clips: { name: string; weight?: number }[] })\n & { loop?: boolean; speed?: number; time?: number; paused?: boolean };\n}\n\nexport type SceneGuiLayer = (Omit<GuiTextureLayer, \"texture\"> & { texture: string })\n | (Omit<GuiItemLayer, \"item\" | \"context\"> & { item: string; context?: Omit<SceneItemContext, \"displayContext\"> })\n | (Omit<GuiTextLayer, \"font\"> & { font?: string });\n\nexport interface SceneGuiDefinition extends SceneObjectDefinitionBase {\n type: \"gui\";\n layers: SceneGuiLayer[];\n}\n\nexport type SceneObjectDefinition = SceneSkinDefinition | SceneBlockDefinition | SceneModelDefinition\n | SceneEntityDefinition | SceneGuiDefinition;\n\ntype JsonObject = Record<string, unknown>;\ntype Validator = (value: unknown, path: string) => void;\n\nfunction fail(path: string, message: string): never {\n throw new Error(`${path}: ${message}`);\n}\n\nfunction object(value: unknown, path: string): JsonObject {\n if (!value || typeof value !== \"object\" || Array.isArray(value)\n || ![Object.prototype, null].includes(Object.getPrototypeOf(value))) fail(path, \"expected a JSON object\");\n for (const key of Object.keys(value)) {\n if ([\"__proto__\", \"prototype\", \"constructor\"].includes(key)) fail(`${path}.${key}`, \"unsupported property\");\n }\n return value as JsonObject;\n}\n\nfunction fields(value: unknown, path: string, allowed: Record<string, Validator>, required: string[] = []): JsonObject {\n const input = object(value, path);\n for (const key of required) if (input[key] === undefined) fail(`${path}.${key}`, \"required\");\n for (const [key, entry] of Object.entries(input)) {\n if (!Object.prototype.hasOwnProperty.call(allowed, key)) fail(`${path}.${key}`, \"unsupported property\");\n if (entry !== undefined) allowed[key](entry, `${path}.${key}`);\n }\n return input;\n}\n\nconst text: Validator = (value, path) => {\n if (typeof value !== \"string\" || !value.trim()) fail(path, \"expected a nonempty string\");\n};\nconst literalText: Validator = (value, path) => {\n if (typeof value !== \"string\") fail(path, \"expected a string\");\n};\nconst boolean: Validator = (value, path) => {\n if (typeof value !== \"boolean\") fail(path, \"expected a boolean\");\n};\nconst number: Validator = (value, path) => {\n if (typeof value !== \"number\" || !Number.isFinite(value)) fail(path, \"expected a finite number\");\n};\nconst positive: Validator = (value, path) => {\n number(value, path);\n if ((value as number) <= 0) fail(path, \"expected a positive number\");\n};\nconst nonnegative: Validator = (value, path) => {\n number(value, path);\n if ((value as number) < 0) fail(path, \"expected a nonnegative number\");\n};\nconst color: Validator = (value, path) => {\n number(value, path);\n if (!Number.isInteger(value) || (value as number) < 0 || (value as number) > 0xffffff) {\n fail(path, \"expected an RGB integer from 0 to 16777215\");\n }\n};\nconst asset: Validator = (value, path) => {\n text(value, path);\n if (!/^(?:[a-z0-9_.-]+:)?[a-z0-9_./-]+$/.test(value as string)\n || (value as string).split(/[:/]/).some(part => !part || part === \".\" || part === \"..\")) {\n fail(path, \"expected a resource ID such as minecraft:stone\");\n }\n};\nconst version: Validator = (value, path) => {\n text(value, path);\n if (!/^[a-zA-Z0-9._-]+$/.test(value as string)) fail(path, \"expected a Minecraft version without slashes\");\n};\nconst tuple = (size: number, item: Validator = number): Validator => (value, path) => {\n if (!Array.isArray(value) || value.length !== size) fail(path, `expected ${size} numbers`);\n for (let index = 0; index < size; index++) item(value[index], `${path}[${index}]`);\n};\nconst list = (item: Validator): Validator => (value, path) => {\n if (!Array.isArray(value)) fail(path, \"expected an array\");\n for (let index = 0; index < value.length; index++) item(value[index], `${path}[${index}]`);\n};\nconst dictionary = (item: Validator, numericKeys = false): Validator => (value, path) => {\n for (const [key, entry] of Object.entries(object(value, path))) {\n if (numericKeys && !/^\\d+$/.test(key)) fail(`${path}.${key}`, \"expected a nonnegative tint index\");\n item(entry, `${path}.${key}`);\n }\n};\nconst enumeration = (values: readonly string[]): Validator => (value, path) => {\n if (!values.includes(value as string)) fail(path, `expected one of: ${values.join(\", \")}`);\n};\nconst textStyle = { color, bold: boolean, italic: boolean };\nconst jsonValue: Validator = (value, path) => {\n if (value === null || typeof value === \"boolean\" || typeof value === \"string\") return;\n if (typeof value === \"number\") number(value, path);\n else if (Array.isArray(value)) list(jsonValue)(value, path);\n else dictionary(jsonValue)(value, path);\n};\nconst propertyValue: Validator = (value, path) => {\n if (typeof value === \"boolean\" || typeof value === \"string\") return;\n if (typeof value !== \"number\" || !Number.isFinite(value)) fail(path, \"expected a boolean, string, or finite number\");\n};\nconst itemContext = (withDisplayContext: boolean): Validator => (value, path) => {\n fields(value, path, {\n ...(withDisplayContext ? { displayContext: enumeration([...DISPLAY_POSITIONS, \"none\"]) } : {}),\n properties: dictionary(propertyValue), components: dictionary(jsonValue), itemReferences: dictionary(asset),\n count: (value, path) => { if (!Number.isInteger(value) || (value as number) < 0) fail(path, \"expected a nonnegative integer\"); }\n });\n};\n\nfunction entityAnimation(value: unknown, path: string): void {\n const animation = object(value, path);\n if ([\"name\", \"clips\"].filter(key => animation[key] !== undefined).length !== 1) {\n fail(path, \"expected exactly one of name or clips\");\n }\n fields(value, path, { name: text, clips: (value, path) => {\n list((value, path) => { fields(value, path, { name: text, weight: nonnegative }, [\"name\"]); })(value, path);\n if (!(value as unknown[]).length) fail(path, \"expected at least one clip\");\n const names = new Set<string>();\n for (const [index, clip] of (value as { name: string }[]).entries()) {\n if (names.has(clip.name)) fail(`${path}[${index}].name`, `duplicate clip \"${clip.name}\"`);\n names.add(clip.name);\n }\n }, loop: boolean, speed: nonnegative, time: nonnegative, paused: boolean });\n}\n\nfunction guiLayer(value: unknown, path: string): void {\n const layer = object(value, path);\n if ([\"texture\", \"item\", \"text\"].filter(key => layer[key] !== undefined).length !== 1) {\n fail(path, \"expected exactly one of texture, item, or text\");\n }\n const layout = { name: text, position: tuple(2), size: tuple(2, positive) };\n if (layer.texture !== undefined) {\n fields(value, path, { ...layout, texture: asset, crop: (value, path) => {\n tuple(4)(value, path);\n const [x, y, width, height] = value as number[];\n nonnegative(x, `${path}[0]`); nonnegative(y, `${path}[1]`);\n positive(width, `${path}[2]`); positive(height, `${path}[3]`);\n } });\n } else if (layer.item !== undefined) {\n fields(value, path, { ...layout, item: asset, context: itemContext(false), tints: dictionary(color, true) });\n } else {\n fields(value, path, { ...layout, ...textStyle, font: asset, shadow: boolean, maxWidth: positive, lineHeight: positive,\n text: (value, path) => {\n if (typeof value === \"string\") return;\n list((run, path) => { fields(run, path, { text: literalText, ...textStyle }, [\"text\"]); })(value, path);\n }\n });\n }\n}\n\nfunction validateObject(value: unknown, path: string): void {\n const input = object(value, path);\n const common = { id: text, name: text, type: text, position: tuple(3), rotation: tuple(3), scale: tuple(3), visible: boolean };\n const required = [\"id\", \"type\"];\n const renderOptions = { wireframe: boolean };\n switch (input.type) {\n case \"skin\":\n fields(value, path, { ...common, skin: text,\n cape: (value, path) => { fields(value, path, { texture: text, layout: enumeration([\"minecraft\", \"optifine\", \"labymod\"]) }, [\"texture\"]); },\n hiddenParts: list(enumeration(SKIN_PARTS)),\n pose: (value, path) => { fields(value, path, {\n head: tuple(3), body: tuple(3), rightArm: tuple(3), leftArm: tuple(3),\n rightLeg: tuple(3), leftLeg: tuple(3), cape: tuple(3)\n }); },\n options: (value, path) => { fields(value, path, { slim: boolean, legacy: boolean }); }\n }, required);\n break;\n case \"block\":\n fields(value, path, { ...common, asset, state: dictionary(text),\n options: (value, path) => { fields(value, path, { ...renderOptions, tints: dictionary(color, true) }); }\n }, [...required, \"asset\"]);\n break;\n case \"item\":\n case \"model\":\n fields(value, path, { ...common, asset, ...(input.type === \"item\" ? { context: itemContext(true) } : {}),\n options: (value, path) => { fields(value, path, { ...renderOptions, displayPosition: enumeration(DISPLAY_POSITIONS), tints: dictionary(color, true) }); }\n }, [...required, \"asset\"]);\n break;\n case \"entity\":\n fields(value, path, { ...common, asset, texture: asset, layers: list(text), when: list(text), textures: dictionary(asset),\n options: (value, path) => { fields(value, path, { ...renderOptions, flip: boolean,\n tints: dictionary((value, path) => { typeof value === \"string\" ? text(value, path) : color(value, path); }) }); },\n animation: entityAnimation\n }, [...required, \"asset\"]);\n if (Array.isArray(input.layers) && !input.layers.length) fail(`${path}.layers`, \"expected at least one layer\");\n break;\n case \"gui\":\n fields(value, path, { ...common, layers: list(guiLayer) }, [...required, \"layers\"]);\n break;\n default:\n fail(`${path}.type`, \"expected skin, block, item, entity, model, or gui\");\n }\n}\n\n/** Validates and copies a scene document without requesting assets or changing the active asset version. */\nexport function parseSceneDocument(value: unknown): SceneDocument {\n if (typeof value === \"string\") {\n try { value = JSON.parse(value); }\n catch { fail(\"scene\", \"invalid JSON\"); }\n }\n const input = fields(value, \"scene\", {\n format: enumeration([\"minerender-scene\"]),\n version: (value, path) => { if (value !== 1) fail(path, \"only scene document version 1 is supported\"); },\n minecraftVersion: version,\n camera: (value, path) => { fields(value, path, { position: tuple(3), target: tuple(3) }, [\"position\", \"target\"]); },\n objects: list(validateObject)\n }, [\"format\", \"version\", \"objects\"]);\n const ids = new Set<string>();\n for (const [index, entry] of (input.objects as SceneObjectDefinition[]).entries()) {\n if (ids.has(entry.id)) fail(`scene.objects[${index}].id`, `duplicate object ID \"${entry.id}\"`);\n ids.add(entry.id);\n }\n return JSON.parse(JSON.stringify(input)) as SceneDocument;\n}\n"],"mappings":"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","names":["value","path"]}
|
|
@@ -161,10 +161,20 @@ var SceneDocumentLoader = class {
|
|
|
161
161
|
const entity = await content.addEntity(model, { ...definition.options, instanceMeshes: false });
|
|
162
162
|
object = entity;
|
|
163
163
|
if (definition.animation) {
|
|
164
|
+
const animation = definition.animation;
|
|
164
165
|
const animations = await Entities.getAnimations(key);
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
166
|
+
if (animation.name !== void 0) {
|
|
167
|
+
const clip = animations && Object.prototype.hasOwnProperty.call(animations, animation.name) ? animations[animation.name] : void 0;
|
|
168
|
+
if (!clip) throw new Error(`Entity ${definition.asset} has no animation "${animation.name}"`);
|
|
169
|
+
entity.playAnimation(clip, animation);
|
|
170
|
+
} else {
|
|
171
|
+
const clips = animation.clips.map(({ name }) => {
|
|
172
|
+
const clip = animations && Object.prototype.hasOwnProperty.call(animations, name) ? animations[name] : void 0;
|
|
173
|
+
if (!clip) throw new Error(`Entity ${definition.asset} has no animation "${name}"`);
|
|
174
|
+
return clip;
|
|
175
|
+
});
|
|
176
|
+
entity.playAnimations(clips, { ...animation, weights: animation.clips.map((clip) => clip.weight ?? 1) });
|
|
177
|
+
}
|
|
168
178
|
}
|
|
169
179
|
break;
|
|
170
180
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/scene/SceneDocumentLoader.ts"],"sourcesContent":["import { Group } from \"three\";\nimport type { Object3D } from \"three\";\nimport { AssetKey } from \"../assets/AssetKey\";\nimport { AssetLoader } from \"../assets/AssetLoader\";\nimport { BlockStates } from \"../assets/BlockStates\";\nimport { Entities } from \"../assets/Entities\";\nimport { ItemModelContext, Models } from \"../assets/Models\";\nimport type { BasicMinecraftAsset } from \"../MinecraftAsset\";\nimport { DisplayPosition } from \"../model/DisplayPosition\";\nimport { MineRenderScene } from \"../renderer/MineRenderScene\";\nimport { isSceneObject, SceneObject } from \"../renderer/SceneObject\";\nimport type { SceneObjectOptions } from \"../renderer/SceneObjectOptions\";\nimport { EntityObject } from \"../entity/scene/EntityObject\";\nimport { SkinObject } from \"../skin/scene/SkinObject\";\nimport { Skins } from \"../skin/Skins\";\nimport { GuiObject } from \"../gui/scene/GuiObject\";\nimport type { GuiLayer } from \"../gui/GuiLayer\";\nimport { parseSceneDocument, SceneDocument, SceneItemContext, SceneObjectDefinition } from \"./SceneDocument\";\n\nfunction itemKey(asset: string): AssetKey {\n const key = AssetKey.parse(\"models\", asset);\n return key.type === \"item\" ? key : new AssetKey(key.namespace, key.getFullPath(), \"models\", \"item\");\n}\n\nfunction itemContext(context: SceneItemContext | undefined): ItemModelContext {\n const { itemReferences, ...rest } = context ?? {};\n return itemReferences\n ? { ...rest, itemReferences: Object.fromEntries(Object.entries(itemReferences).map(([id, item]) => [id, itemKey(item)])) }\n : rest;\n}\n\nexport interface LoadedSceneObject {\n readonly root: Group;\n readonly object: SceneObject;\n readonly definition: SceneObjectDefinition;\n /** Advances entity playback in seconds unless the definition has paused it. */\n advanceAnimation(delta: number): void;\n /** Removes this object and releases its owned resources. Safe to call more than once. */\n dispose(): void;\n}\n\nexport interface LoadedSceneDocument {\n readonly root: Group;\n readonly objects: LoadedSceneObject[];\n readonly definition: SceneDocument;\n advanceAnimations(delta: number): void;\n dispose(): void;\n}\n\n// Blocks create models and block entities through their scene, without forwarding a parent.\n// A nested scene keeps those visuals inside the object's transform group, including after state changes.\nclass DocumentObjectScene extends MineRenderScene {\n public async addSceneObject<A extends BasicMinecraftAsset, T extends SceneObject, O extends SceneObjectOptions>(\n _asset: A, supplier: () => T | Promise<T>, _options?: Partial<O>, parent: Object3D = this\n ): Promise<T> {\n const object = await supplier();\n return this.initialize(object, parent);\n }\n\n public async initialize<T extends SceneObject>(object: T, parent: Object3D = this): Promise<T> {\n object.scene = this;\n try {\n await object.init();\n parent.add(object);\n return object;\n } catch (error) {\n object.dispose();\n object.removeFromParent();\n throw error;\n }\n }\n\n public dispose(): void {\n for (const child of [...this.children]) {\n if (child.parent !== this) continue;\n if (isSceneObject(child)) child.dispose();\n child.removeFromParent();\n }\n }\n}\n\nasync function skinTexture(value: string, cape = false): Promise<string> {\n if (!/^[a-zA-Z0-9_-]{1,36}$/.test(value)) return value;\n const texture = await (cape ? Skins.capeFromUuidOrUsername(value) : Skins.fromUuidOrUsername(value));\n if (!texture) throw new Error(`Could not find ${cape ? \"cape\" : \"skin\"} for \"${value}\"`);\n return texture;\n}\n\n/** Loads portable scene documents using the asset sources already configured by the caller. */\nexport class SceneDocumentLoader {\n public static parse(value: unknown): SceneDocument {\n return parseSceneDocument(value);\n }\n\n /**\n * Loads objects concurrently and attaches them in document order after every load succeeds.\n * A failure waits for all loads, disposes staged objects, and reports the first error in document order.\n */\n public static async load(scene: MineRenderScene, value: unknown, parent: Object3D = scene): Promise<LoadedSceneDocument> {\n const definition = this.parse(value);\n if (definition.minecraftVersion !== undefined && definition.minecraftVersion !== AssetLoader.version) {\n throw new Error(`Scene requires Minecraft ${definition.minecraftVersion}; call AssetLoader.setVersion(\"${definition.minecraftVersion}\") before loading it`);\n }\n const root = new Group();\n root.name = \"MineRender scene document\";\n const objects: LoadedSceneObject[] = [];\n let disposed = false;\n const loaded: LoadedSceneDocument = {\n root, objects, definition,\n advanceAnimations: delta => { if (!disposed) for (const object of objects) object.advanceAnimation(delta); },\n dispose: () => {\n if (disposed) return;\n disposed = true;\n root.removeFromParent();\n for (const object of objects) object.dispose();\n root.clear();\n scene.dirty = true;\n }\n };\n try {\n const results = await Promise.allSettled(definition.objects.map(object => this.loadValidatedObject(scene, object)));\n for (const result of results) if (result.status === \"fulfilled\") objects.push(result.value);\n const failure = results.find((result): result is PromiseRejectedResult => result.status === \"rejected\");\n if (failure) throw failure.reason;\n for (const object of objects) root.add(object.root);\n parent.add(root);\n scene.dirty = true;\n return loaded;\n } catch (error) {\n loaded.dispose();\n throw error;\n }\n }\n\n /** Loads an independently editable object. Its root owns the document's position, rotation, and scale. */\n public static async loadObject(scene: MineRenderScene, value: SceneObjectDefinition, parent: Object3D = scene): Promise<LoadedSceneObject> {\n const definition = this.parse({ format: \"minerender-scene\", version: 1, objects: [value] }).objects[0];\n return this.loadValidatedObject(scene, definition, parent);\n }\n\n private static async loadValidatedObject(scene: MineRenderScene, definition: SceneObjectDefinition, parent?: Object3D): Promise<LoadedSceneObject> {\n const root = new Group();\n root.name = definition.name ?? definition.id;\n root.userData.sceneObjectId = definition.id;\n root.position.fromArray(definition.position ?? [0, 0, 0]);\n root.rotation.set(...(definition.rotation ?? [0, 0, 0]));\n root.scale.fromArray(definition.scale ?? [1, 1, 1]);\n root.visible = definition.visible ?? true;\n const content = new DocumentObjectScene();\n root.add(content);\n let object: SceneObject | undefined;\n try {\n switch (definition.type) {\n case \"skin\": {\n const skin = new SkinObject({ ...definition.options, instanceMeshes: false });\n object = skin;\n const texture = definition.skin ? await skinTexture(definition.skin)\n : `${AssetLoader.ROOT}/assets/minecraft/textures/entity/player/${definition.options?.slim ? \"slim/alex\" : \"wide/steve\"}.png`;\n await skin.setSkinTexture(texture);\n await content.initialize(skin);\n if (definition.cape) await skin.setCapeTexture(await skinTexture(definition.cape.texture, true), definition.cape.layout);\n for (const [part, rotation] of Object.entries(definition.pose ?? {})) {\n skin.getGroupByName(part)?.rotation.set(...rotation, \"XYZ\");\n }\n for (const part of definition.hiddenParts ?? []) {\n const mesh = skin.getMeshByName(part);\n if (mesh) mesh.visible = false;\n }\n break;\n }\n case \"block\": {\n const state = await BlockStates.get(AssetKey.parse(\"blockstates\", definition.asset));\n if (!state) throw new Error(`Could not load block ${definition.asset}`);\n object = await content.addBlock(state, { ...definition.options, initialState: definition.state, instanceMeshes: false }) as SceneObject;\n break;\n }\n case \"item\":\n case \"model\": {\n const key = definition.type === \"item\" ? itemKey(definition.asset) : AssetKey.parse(\"models\", definition.asset);\n const model = await Models.getMerged(key, definition.type === \"item\" ? itemContext(definition.context) : {});\n if (!model) throw new Error(`Could not load ${definition.type} ${definition.asset}`);\n object = await content.addModel(model, { ...(definition.type === \"item\" ? { displayPosition: DisplayPosition.GUI } : {}),\n ...definition.options, instanceMeshes: false }) as SceneObject;\n break;\n }\n case \"entity\": {\n const key = AssetKey.parse(\"entity-models\", definition.asset);\n const model = await Entities.getEntity(key, definition.texture ? AssetKey.parse(\"textures\", definition.texture) : undefined, {\n layers: definition.layers, when: definition.when,\n textures: definition.textures && Object.fromEntries(Object.entries(definition.textures).map(([name, texture]) => [name, AssetKey.parse(\"textures\", texture)]))\n });\n if (!model) throw new Error(`Could not load entity ${definition.asset}`);\n const entity = await content.addEntity(model, { ...definition.options, instanceMeshes: false }) as EntityObject;\n object = entity;\n if (definition.animation) {\n const animations = await Entities.getAnimations(key);\n const clip = animations?.[definition.animation.name];\n if (!clip) throw new Error(`Entity ${definition.asset} has no animation \"${definition.animation.name}\"`);\n entity.playAnimation(clip, definition.animation);\n }\n break;\n }\n case \"gui\":\n object = await content.initialize(new GuiObject(definition.layers.map((layer): GuiLayer =>\n \"item\" in layer ? { ...layer, context: layer.context && itemContext(layer.context) } : layer)));\n break;\n }\n let disposed = false;\n const loaded: LoadedSceneObject = {\n root, object, definition,\n advanceAnimation: delta => {\n if (!disposed && definition.type === \"entity\" && !definition.animation?.paused) (object as EntityObject).advanceAnimation(delta);\n },\n dispose: () => {\n if (disposed) return;\n disposed = true;\n root.removeFromParent();\n object!.dispose();\n object!.removeFromParent();\n content.dispose();\n root.clear();\n scene.dirty = true;\n }\n };\n parent?.add(root);\n scene.dirty = true;\n return loaded;\n } catch (error) {\n object?.dispose();\n object?.removeFromParent();\n content.dispose();\n root.removeFromParent();\n root.clear();\n throw new Error(`Scene object \"${definition.name ?? definition.id}\": ${error instanceof Error ? error.message : String(error)}`);\n }\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../../src/scene/SceneDocumentLoader.ts"],"sourcesContent":["import { Group } from \"three\";\nimport type { Object3D } from \"three\";\nimport { AssetKey } from \"../assets/AssetKey\";\nimport { AssetLoader } from \"../assets/AssetLoader\";\nimport { BlockStates } from \"../assets/BlockStates\";\nimport { Entities } from \"../assets/Entities\";\nimport { ItemModelContext, Models } from \"../assets/Models\";\nimport type { BasicMinecraftAsset } from \"../MinecraftAsset\";\nimport { DisplayPosition } from \"../model/DisplayPosition\";\nimport { MineRenderScene } from \"../renderer/MineRenderScene\";\nimport { isSceneObject, SceneObject } from \"../renderer/SceneObject\";\nimport type { SceneObjectOptions } from \"../renderer/SceneObjectOptions\";\nimport { EntityObject } from \"../entity/scene/EntityObject\";\nimport { SkinObject } from \"../skin/scene/SkinObject\";\nimport { Skins } from \"../skin/Skins\";\nimport { GuiObject } from \"../gui/scene/GuiObject\";\nimport type { GuiLayer } from \"../gui/GuiLayer\";\nimport { parseSceneDocument, SceneDocument, SceneItemContext, SceneObjectDefinition } from \"./SceneDocument\";\n\nfunction itemKey(asset: string): AssetKey {\n const key = AssetKey.parse(\"models\", asset);\n return key.type === \"item\" ? key : new AssetKey(key.namespace, key.getFullPath(), \"models\", \"item\");\n}\n\nfunction itemContext(context: SceneItemContext | undefined): ItemModelContext {\n const { itemReferences, ...rest } = context ?? {};\n return itemReferences\n ? { ...rest, itemReferences: Object.fromEntries(Object.entries(itemReferences).map(([id, item]) => [id, itemKey(item)])) }\n : rest;\n}\n\nexport interface LoadedSceneObject {\n readonly root: Group;\n readonly object: SceneObject;\n readonly definition: SceneObjectDefinition;\n /** Advances entity playback in seconds unless the definition has paused it. */\n advanceAnimation(delta: number): void;\n /** Removes this object and releases its owned resources. Safe to call more than once. */\n dispose(): void;\n}\n\nexport interface LoadedSceneDocument {\n readonly root: Group;\n readonly objects: LoadedSceneObject[];\n readonly definition: SceneDocument;\n advanceAnimations(delta: number): void;\n dispose(): void;\n}\n\n// Blocks create models and block entities through their scene, without forwarding a parent.\n// A nested scene keeps those visuals inside the object's transform group, including after state changes.\nclass DocumentObjectScene extends MineRenderScene {\n public async addSceneObject<A extends BasicMinecraftAsset, T extends SceneObject, O extends SceneObjectOptions>(\n _asset: A, supplier: () => T | Promise<T>, _options?: Partial<O>, parent: Object3D = this\n ): Promise<T> {\n const object = await supplier();\n return this.initialize(object, parent);\n }\n\n public async initialize<T extends SceneObject>(object: T, parent: Object3D = this): Promise<T> {\n object.scene = this;\n try {\n await object.init();\n parent.add(object);\n return object;\n } catch (error) {\n object.dispose();\n object.removeFromParent();\n throw error;\n }\n }\n\n public dispose(): void {\n for (const child of [...this.children]) {\n if (child.parent !== this) continue;\n if (isSceneObject(child)) child.dispose();\n child.removeFromParent();\n }\n }\n}\n\nasync function skinTexture(value: string, cape = false): Promise<string> {\n if (!/^[a-zA-Z0-9_-]{1,36}$/.test(value)) return value;\n const texture = await (cape ? Skins.capeFromUuidOrUsername(value) : Skins.fromUuidOrUsername(value));\n if (!texture) throw new Error(`Could not find ${cape ? \"cape\" : \"skin\"} for \"${value}\"`);\n return texture;\n}\n\n/** Loads portable scene documents using the asset sources already configured by the caller. */\nexport class SceneDocumentLoader {\n public static parse(value: unknown): SceneDocument {\n return parseSceneDocument(value);\n }\n\n /**\n * Loads objects concurrently and attaches them in document order after every load succeeds.\n * A failure waits for all loads, disposes staged objects, and reports the first error in document order.\n */\n public static async load(scene: MineRenderScene, value: unknown, parent: Object3D = scene): Promise<LoadedSceneDocument> {\n const definition = this.parse(value);\n if (definition.minecraftVersion !== undefined && definition.minecraftVersion !== AssetLoader.version) {\n throw new Error(`Scene requires Minecraft ${definition.minecraftVersion}; call AssetLoader.setVersion(\"${definition.minecraftVersion}\") before loading it`);\n }\n const root = new Group();\n root.name = \"MineRender scene document\";\n const objects: LoadedSceneObject[] = [];\n let disposed = false;\n const loaded: LoadedSceneDocument = {\n root, objects, definition,\n advanceAnimations: delta => { if (!disposed) for (const object of objects) object.advanceAnimation(delta); },\n dispose: () => {\n if (disposed) return;\n disposed = true;\n root.removeFromParent();\n for (const object of objects) object.dispose();\n root.clear();\n scene.dirty = true;\n }\n };\n try {\n const results = await Promise.allSettled(definition.objects.map(object => this.loadValidatedObject(scene, object)));\n for (const result of results) if (result.status === \"fulfilled\") objects.push(result.value);\n const failure = results.find((result): result is PromiseRejectedResult => result.status === \"rejected\");\n if (failure) throw failure.reason;\n for (const object of objects) root.add(object.root);\n parent.add(root);\n scene.dirty = true;\n return loaded;\n } catch (error) {\n loaded.dispose();\n throw error;\n }\n }\n\n /** Loads an independently editable object. Its root owns the document's position, rotation, and scale. */\n public static async loadObject(scene: MineRenderScene, value: SceneObjectDefinition, parent: Object3D = scene): Promise<LoadedSceneObject> {\n const definition = this.parse({ format: \"minerender-scene\", version: 1, objects: [value] }).objects[0];\n return this.loadValidatedObject(scene, definition, parent);\n }\n\n private static async loadValidatedObject(scene: MineRenderScene, definition: SceneObjectDefinition, parent?: Object3D): Promise<LoadedSceneObject> {\n const root = new Group();\n root.name = definition.name ?? definition.id;\n root.userData.sceneObjectId = definition.id;\n root.position.fromArray(definition.position ?? [0, 0, 0]);\n root.rotation.set(...(definition.rotation ?? [0, 0, 0]));\n root.scale.fromArray(definition.scale ?? [1, 1, 1]);\n root.visible = definition.visible ?? true;\n const content = new DocumentObjectScene();\n root.add(content);\n let object: SceneObject | undefined;\n try {\n switch (definition.type) {\n case \"skin\": {\n const skin = new SkinObject({ ...definition.options, instanceMeshes: false });\n object = skin;\n const texture = definition.skin ? await skinTexture(definition.skin)\n : `${AssetLoader.ROOT}/assets/minecraft/textures/entity/player/${definition.options?.slim ? \"slim/alex\" : \"wide/steve\"}.png`;\n await skin.setSkinTexture(texture);\n await content.initialize(skin);\n if (definition.cape) await skin.setCapeTexture(await skinTexture(definition.cape.texture, true), definition.cape.layout);\n for (const [part, rotation] of Object.entries(definition.pose ?? {})) {\n skin.getGroupByName(part)?.rotation.set(...rotation, \"XYZ\");\n }\n for (const part of definition.hiddenParts ?? []) {\n const mesh = skin.getMeshByName(part);\n if (mesh) mesh.visible = false;\n }\n break;\n }\n case \"block\": {\n const state = await BlockStates.get(AssetKey.parse(\"blockstates\", definition.asset));\n if (!state) throw new Error(`Could not load block ${definition.asset}`);\n object = await content.addBlock(state, { ...definition.options, initialState: definition.state, instanceMeshes: false }) as SceneObject;\n break;\n }\n case \"item\":\n case \"model\": {\n const key = definition.type === \"item\" ? itemKey(definition.asset) : AssetKey.parse(\"models\", definition.asset);\n const model = await Models.getMerged(key, definition.type === \"item\" ? itemContext(definition.context) : {});\n if (!model) throw new Error(`Could not load ${definition.type} ${definition.asset}`);\n object = await content.addModel(model, { ...(definition.type === \"item\" ? { displayPosition: DisplayPosition.GUI } : {}),\n ...definition.options, instanceMeshes: false }) as SceneObject;\n break;\n }\n case \"entity\": {\n const key = AssetKey.parse(\"entity-models\", definition.asset);\n const model = await Entities.getEntity(key, definition.texture ? AssetKey.parse(\"textures\", definition.texture) : undefined, {\n layers: definition.layers, when: definition.when,\n textures: definition.textures && Object.fromEntries(Object.entries(definition.textures).map(([name, texture]) => [name, AssetKey.parse(\"textures\", texture)]))\n });\n if (!model) throw new Error(`Could not load entity ${definition.asset}`);\n const entity = await content.addEntity(model, { ...definition.options, instanceMeshes: false }) as EntityObject;\n object = entity;\n if (definition.animation) {\n const animation = definition.animation;\n const animations = await Entities.getAnimations(key);\n if (animation.name !== undefined) {\n const clip = animations && Object.prototype.hasOwnProperty.call(animations, animation.name) ? animations[animation.name] : undefined;\n if (!clip) throw new Error(`Entity ${definition.asset} has no animation \"${animation.name}\"`);\n entity.playAnimation(clip, animation);\n } else {\n const clips = animation.clips.map(({ name }) => {\n const clip = animations && Object.prototype.hasOwnProperty.call(animations, name) ? animations[name] : undefined;\n if (!clip) throw new Error(`Entity ${definition.asset} has no animation \"${name}\"`);\n return clip;\n });\n entity.playAnimations(clips, { ...animation, weights: animation.clips.map(clip => clip.weight ?? 1) });\n }\n }\n break;\n }\n case \"gui\":\n object = await content.initialize(new GuiObject(definition.layers.map((layer): GuiLayer =>\n \"item\" in layer ? { ...layer, context: layer.context && itemContext(layer.context) } : layer)));\n break;\n }\n let disposed = false;\n const loaded: LoadedSceneObject = {\n root, object, definition,\n advanceAnimation: delta => {\n if (!disposed && definition.type === \"entity\" && !definition.animation?.paused) (object as EntityObject).advanceAnimation(delta);\n },\n dispose: () => {\n if (disposed) return;\n disposed = true;\n root.removeFromParent();\n object!.dispose();\n object!.removeFromParent();\n content.dispose();\n root.clear();\n scene.dirty = true;\n }\n };\n parent?.add(root);\n scene.dirty = true;\n return loaded;\n } catch (error) {\n object?.dispose();\n object?.removeFromParent();\n content.dispose();\n root.removeFromParent();\n root.clear();\n throw new Error(`Scene object \"${definition.name ?? definition.id}\": ${error instanceof Error ? error.message : String(error)}`);\n }\n }\n}\n"],"mappings":"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","names":[]}
|
package/dist/browser/index.d.ts
CHANGED
|
@@ -3491,8 +3491,17 @@ interface SceneEntityDefinition extends SceneObjectDefinitionBase {
|
|
|
3491
3491
|
wireframe?: boolean;
|
|
3492
3492
|
tints?: Record<string, string | number>;
|
|
3493
3493
|
};
|
|
3494
|
-
|
|
3494
|
+
/** Plays one named clip or blends clips with weights defaulting to 1, without normalization. */
|
|
3495
|
+
animation?: ({
|
|
3495
3496
|
name: string;
|
|
3497
|
+
clips?: never;
|
|
3498
|
+
} | {
|
|
3499
|
+
name?: never;
|
|
3500
|
+
clips: {
|
|
3501
|
+
name: string;
|
|
3502
|
+
weight?: number;
|
|
3503
|
+
}[];
|
|
3504
|
+
}) & {
|
|
3496
3505
|
loop?: boolean;
|
|
3497
3506
|
speed?: number;
|
|
3498
3507
|
time?: number;
|
package/dist/browser/index.js
CHANGED
|
@@ -16741,6 +16741,23 @@ var itemContext = (withDisplayContext) => (value, path) => {
|
|
|
16741
16741
|
}
|
|
16742
16742
|
});
|
|
16743
16743
|
};
|
|
16744
|
+
function entityAnimation(value, path) {
|
|
16745
|
+
const animation = object3(value, path);
|
|
16746
|
+
if (["name", "clips"].filter((key) => animation[key] !== void 0).length !== 1) {
|
|
16747
|
+
fail(path, "expected exactly one of name or clips");
|
|
16748
|
+
}
|
|
16749
|
+
fields(value, path, { name: text, clips: (value2, path2) => {
|
|
16750
|
+
list((value3, path3) => {
|
|
16751
|
+
fields(value3, path3, { name: text, weight: nonnegative }, ["name"]);
|
|
16752
|
+
})(value2, path2);
|
|
16753
|
+
if (!value2.length) fail(path2, "expected at least one clip");
|
|
16754
|
+
const names = /* @__PURE__ */ new Set();
|
|
16755
|
+
for (const [index, clip] of value2.entries()) {
|
|
16756
|
+
if (names.has(clip.name)) fail(`${path2}[${index}].name`, `duplicate clip "${clip.name}"`);
|
|
16757
|
+
names.add(clip.name);
|
|
16758
|
+
}
|
|
16759
|
+
}, loop: boolean, speed: nonnegative, time: nonnegative, paused: boolean });
|
|
16760
|
+
}
|
|
16744
16761
|
function guiLayer(value, path) {
|
|
16745
16762
|
const layer = object3(value, path);
|
|
16746
16763
|
if (["texture", "item", "text"].filter((key) => layer[key] !== void 0).length !== 1) {
|
|
@@ -16843,9 +16860,7 @@ function validateObject(value, path) {
|
|
|
16843
16860
|
})
|
|
16844
16861
|
});
|
|
16845
16862
|
},
|
|
16846
|
-
animation:
|
|
16847
|
-
fields(value2, path2, { name: text, loop: boolean, speed: nonnegative, time: nonnegative, paused: boolean }, ["name"]);
|
|
16848
|
-
}
|
|
16863
|
+
animation: entityAnimation
|
|
16849
16864
|
}, [...required, "asset"]);
|
|
16850
16865
|
if (Array.isArray(input.layers) && !input.layers.length) fail(`${path}.layers`, "expected at least one layer");
|
|
16851
16866
|
break;
|
|
@@ -17112,10 +17127,20 @@ var SceneDocumentLoader = class {
|
|
|
17112
17127
|
const entity = await content.addEntity(model, { ...definition.options, instanceMeshes: false });
|
|
17113
17128
|
object4 = entity;
|
|
17114
17129
|
if (definition.animation) {
|
|
17130
|
+
const animation = definition.animation;
|
|
17115
17131
|
const animations = await Entities.getAnimations(key);
|
|
17116
|
-
|
|
17117
|
-
|
|
17118
|
-
|
|
17132
|
+
if (animation.name !== void 0) {
|
|
17133
|
+
const clip = animations && Object.prototype.hasOwnProperty.call(animations, animation.name) ? animations[animation.name] : void 0;
|
|
17134
|
+
if (!clip) throw new Error(`Entity ${definition.asset} has no animation "${animation.name}"`);
|
|
17135
|
+
entity.playAnimation(clip, animation);
|
|
17136
|
+
} else {
|
|
17137
|
+
const clips = animation.clips.map(({ name }) => {
|
|
17138
|
+
const clip = animations && Object.prototype.hasOwnProperty.call(animations, name) ? animations[name] : void 0;
|
|
17139
|
+
if (!clip) throw new Error(`Entity ${definition.asset} has no animation "${name}"`);
|
|
17140
|
+
return clip;
|
|
17141
|
+
});
|
|
17142
|
+
entity.playAnimations(clips, { ...animation, weights: animation.clips.map((clip) => clip.weight ?? 1) });
|
|
17143
|
+
}
|
|
17119
17144
|
}
|
|
17120
17145
|
break;
|
|
17121
17146
|
}
|