incanto 0.69.0 → 0.71.0
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/bin/_behaviors-loader.mjs +22 -0
- package/bin/_read-json.mjs +28 -0
- package/bin/incanto-assets.mjs +5 -4
- package/bin/incanto-check.mjs +58 -31
- package/bin/incanto-editor.mjs +128 -5
- package/bin/incanto-env.mjs +3 -2
- package/bin/incanto-feel.mjs +24 -13
- package/bin/incanto-frame.mjs +8 -1
- package/bin/incanto-multiplay.mjs +11 -9
- package/bin/incanto-new.mjs +105 -10
- package/bin/incanto-play.mjs +158 -16
- package/bin/incanto-playtest.mjs +66 -23
- package/bin/incanto-skills.mjs +14 -2
- package/bin/incanto-verify.mjs +121 -102
- package/bin/incanto.mjs +3 -2
- package/dist/2d.d.ts +296 -34
- package/dist/2d.js +4 -4
- package/dist/3d.d.ts +157 -9
- package/dist/3d.js +8 -8
- package/dist/{agent8-CvsfVskX.js → agent8-Cfmd3ar_.js} +61 -8
- package/dist/{audio-player-C0j2k-yB.d.ts → audio-player-L8yccdMP.d.ts} +2 -2
- package/dist/{behavior-rm8vVzu_.d.ts → behavior-Dcz0fr1S.d.ts} +755 -46
- package/dist/{create-game-CwxEDlCm.js → create-game-CH4kt78v.js} +143 -60
- package/dist/{create-game-CvJ1wSRP.js → create-game-LCHBLfA4.js} +98 -48
- package/dist/debug.d.ts +1 -1
- package/dist/debug.js +2 -3
- package/dist/diagnostics-Cu85N3tL.d.ts +12 -0
- package/dist/{editor-switch-CnIOiyNJ.d.ts → editor-switch-CFU9mCec.d.ts} +22 -13
- package/dist/editor.js +1088 -882
- package/dist/env.d.ts +1 -1
- package/dist/env.js +5 -3
- package/dist/{environment-presets-BO-7XoFV.js → environment-presets-99BzP_L-.js} +298 -45
- package/dist/{frame-report-Dlq13Gyj.js → frame-report-D-_7YF2G.js} +1 -1
- package/dist/{gameplay-D1KixWK8.js → gameplay-CNULJvwh.js} +914 -214
- package/dist/gameplay.d.ts +254 -10
- package/dist/gameplay.js +2 -2
- package/dist/{heightmap-CRK0M4jT.js → heightmap-BYgD5Edk.js} +1 -1
- package/dist/index.d.ts +179 -13
- package/dist/index.js +10 -12
- package/dist/json-CfTjpvW8.js +67 -0
- package/dist/{loader-DadV2QCT.d.ts → loader-8-IHvbKD.d.ts} +2 -2
- package/dist/net.d.ts +27 -3
- package/dist/net.js +2 -2
- package/dist/{noise-CGUMx44x.js → noise-D3nPpmFg.js} +1 -1
- package/dist/{physics-2d-CF5yyjbj.js → physics-2d-FhrXUc6B.js} +136 -11
- package/dist/{physics-3d-DbYaEcZy.js → physics-3d-CFEGxBXZ.js} +104 -23
- package/dist/{teardown-CMqFVxO9.js → picking-DVo7fI13.js} +104 -13
- package/dist/react.d.ts +2 -2
- package/dist/react.js +2 -2
- package/dist/{register-DbVArsns.js → register-BYQCBySi.js} +429 -28
- package/dist/{register-mmfugpaQ.js → register-DuVdzxbq.js} +594 -831
- package/dist/{replay-BEHLDcQV.js → replay-DEvp3kyV.js} +224 -14
- package/dist/{replay-BQfkX4x7.d.ts → replay-F7IZHdFR.d.ts} +20 -3
- package/dist/{schema-B6ugCV1Q.d.ts → rng-Bb-IutXB.d.ts} +38 -21
- package/dist/{rng-DP-SR7eg.js → rng-CDOMybym.js} +22 -0
- package/dist/{loader-DZE7B07H.js → save-slots-Bvuh2p_r.js} +4619 -2318
- package/dist/{split-screen-Cg76MCV5.d.ts → split-screen-CIYf1zSf.d.ts} +36 -4
- package/dist/{split-screen-CauMwu6y.js → split-screen-eULetcg-.js} +159 -26
- package/dist/{sprite-animation-CY-mrr1L.js → sprite-animation-CqR2o3SA.js} +39 -8
- package/dist/{src-CYEu-_S9.js → src-_jk0qLsS.js} +2 -17
- package/dist/test-CmN54kWv.js +4264 -0
- package/dist/test.d.ts +639 -30
- package/dist/test.js +3 -3
- package/dist/touch-BnCyPA0G.js +519 -0
- package/dist/vite.d.ts +20 -37
- package/dist/vite.js +177 -7
- package/dist/{webgl-unavailable-Z5_g8x9H.js → webgl-unavailable-C8aDbGmR.js} +44 -0
- package/editor/assets/agent8-yLIEYHbd.js +1 -0
- package/editor/assets/{debug-CMULinBW.js → debug-u31w_yhq.js} +2 -2
- package/editor/assets/index-DK9xMGpW.js +11046 -0
- package/editor/index.html +1 -1
- package/package.json +4 -14
- package/schemas/scene.schema.json +34 -3
- package/skills/incanto-3d-character.md +14 -1
- package/skills/incanto-3d-models.md +12 -0
- package/skills/incanto-assets.md +9 -1
- package/skills/incanto-audio.md +8 -2
- package/skills/incanto-behaviors-and-scripts.md +105 -7
- package/skills/incanto-building-2d-games.md +97 -10
- package/skills/incanto-building-3d-games.md +58 -4
- package/skills/incanto-editor.md +46 -7
- package/skills/incanto-environment.md +19 -1
- package/skills/incanto-game-feel.md +70 -0
- package/skills/incanto-gameplay-behaviors.md +172 -20
- package/skills/incanto-hud.md +142 -7
- package/skills/incanto-localization.md +13 -5
- package/skills/incanto-multiplayer.md +83 -3
- package/skills/incanto-node-reference.md +239 -59
- package/skills/incanto-performance.md +52 -0
- package/skills/incanto-physics-and-input.md +123 -24
- package/skills/incanto-playtesting.md +112 -2
- package/skills/incanto-save-slots.md +217 -7
- package/skills/incanto-scene-json-authoring.md +69 -12
- package/skills/incanto-verifying-your-game.md +207 -10
- package/skills/incanto-web-integration.md +28 -0
- package/skills/incanto-your-first-game.md +3 -1
- package/templates-app/beacon-isle-3d/generate-world.ts +77 -9
- package/templates-app/beacon-isle-3d/package.json +2 -2
- package/templates-app/beacon-isle-3d/src/behaviors.ts +22 -0
- package/templates-app/beacon-isle-3d/src/game.scene.json +143 -600
- package/templates-app/beacon-isle-3d/src/main.ts +11 -1
- package/templates-app/beacon-isle-3d/tsconfig.json +1 -1
- package/templates-app/beacon-isle-3d/verify.ts +3 -1
- package/templates-app/molehill-2d/.incanto/playtest/lost-seed1.json +4277 -0
- package/templates-app/molehill-2d/PROJECT/Context.md +58 -0
- package/templates-app/molehill-2d/PROJECT/Requirements.md +39 -0
- package/templates-app/molehill-2d/PROJECT/Status.md +27 -0
- package/templates-app/molehill-2d/PROJECT/Structure.md +48 -0
- package/templates-app/molehill-2d/docs/project-2d-rules.md +44 -0
- package/templates-app/molehill-2d/index.html +73 -0
- package/templates-app/molehill-2d/package.json +23 -0
- package/templates-app/molehill-2d/src/behaviors.ts +198 -0
- package/templates-app/molehill-2d/src/game.scene.json +1205 -0
- package/templates-app/molehill-2d/src/main.ts +41 -0
- package/templates-app/molehill-2d/tsconfig.json +13 -0
- package/templates-app/molehill-2d/verify.ts +247 -0
- package/templates-app/molehill-2d/vite.config.ts +12 -0
- package/templates-app/platformer-2d/package.json +2 -2
- package/templates-app/platformer-2d/src/game.scene.json +178 -986
- package/templates-app/platformer-2d/src/main.ts +11 -1
- package/templates-app/platformer-2d/tsconfig.json +1 -1
- package/templates-app/star-survivor/package.json +2 -2
- package/templates-app/star-survivor/src/game.scene.json +43 -216
- package/templates-app/star-survivor/src/main.ts +11 -1
- package/templates-app/star-survivor/tsconfig.json +1 -1
- package/templates-app/tps-3d/PROJECT/Context.md +1 -1
- package/templates-app/tps-3d/package.json +2 -2
- package/templates-app/tps-3d/src/behaviors.ts +19 -1
- package/templates-app/tps-3d/src/game.scene.json +66 -263
- package/templates-app/tps-3d/src/main.ts +13 -2
- package/templates-app/tps-3d/tsconfig.json +1 -1
- package/templates-app/village-quest-3d/.incanto/playtest/swapped-seed1.json +1735 -0
- package/templates-app/village-quest-3d/package.json +2 -2
- package/templates-app/village-quest-3d/src/behaviors.ts +42 -4
- package/templates-app/village-quest-3d/src/grove.scene.json +68 -306
- package/templates-app/village-quest-3d/src/main.ts +11 -1
- package/templates-app/village-quest-3d/src/village.scene.json +202 -863
- package/templates-app/village-quest-3d/tsconfig.json +1 -1
- package/templates-app/village-quest-3d/verify.ts +14 -1
- package/dist/duplicate-Dj4L-5AA.js +0 -22
- package/dist/json-CwwhxQgb.js +0 -36
- package/dist/registry-CF70EArN.js +0 -212
- package/dist/rolldown-runtime-D7D4PA-g.js +0 -13
- package/dist/test-D6ISmuFE.js +0 -2383
- package/dist/touch-DEAmqGdf.js +0 -225
- package/editor/assets/agent8-BDvaZMQJ.js +0 -1
- package/editor/assets/index-CZIRr5EL.js +0 -10958
|
@@ -62,6 +62,16 @@ function walkTo(
|
|
|
62
62
|
const inputToWorld = Math.atan2(after[1] - before[1], after[0] - before[0]);
|
|
63
63
|
|
|
64
64
|
for (let f = 0; f < budget && dist() > within; f++) {
|
|
65
|
+
/*
|
|
66
|
+
* A frozen clock is an ANSWER, not a slow walk.
|
|
67
|
+
*
|
|
68
|
+
* `GameFlow` sets `timeScale = 0` the moment the run is won or lost, and
|
|
69
|
+
* `engine.step()` then advances nothing. Without this the loop burns its
|
|
70
|
+
* whole budget on no-ops and the harness reports "the player cannot reach
|
|
71
|
+
* it on foot" about a player who has already WON — measured, 1100 of 1200
|
|
72
|
+
* steps were no-ops and the run ended `flow=won` one metre short.
|
|
73
|
+
*/
|
|
74
|
+
if (ctx.engine.timeScale === 0) break;
|
|
65
75
|
const here = at();
|
|
66
76
|
const want = Math.atan2(target[1] - here[1], target[0] - here[0]);
|
|
67
77
|
const aim = want - inputToWorld;
|
|
@@ -69,6 +79,7 @@ function walkTo(
|
|
|
69
79
|
ctx.engine.step();
|
|
70
80
|
}
|
|
71
81
|
ctx.engine.input.setActionVector('move', 0, 0);
|
|
82
|
+
if (ctx.engine.timeScale === 0) return; // the run ended while we were walking
|
|
72
83
|
for (let i = 0; i < 10; i++) ctx.engine.step();
|
|
73
84
|
if (dist() > within) {
|
|
74
85
|
throw new Error(
|
|
@@ -273,7 +284,9 @@ const ok = (label: string, cond: boolean): void => {
|
|
|
273
284
|
resetQuest();
|
|
274
285
|
const boot = async (): Promise<Engine> => {
|
|
275
286
|
const engine = new Engine({ seed: 42, scheduler: () => () => {} });
|
|
276
|
-
engine.setScene(
|
|
287
|
+
engine.setScene(
|
|
288
|
+
loadScene(structuredClone(villageJson) as Parameters<typeof loadScene>[0], { engine }),
|
|
289
|
+
);
|
|
277
290
|
await enablePhysics3D(engine);
|
|
278
291
|
return engine;
|
|
279
292
|
};
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { a as serializeNode, t as buildNodeJson } from "./loader-DZE7B07H.js";
|
|
2
|
-
//#region src/core/scene/duplicate.ts
|
|
3
|
-
function stripUids(json) {
|
|
4
|
-
const { uid: _uid, ...rest } = json;
|
|
5
|
-
return {
|
|
6
|
-
...rest,
|
|
7
|
-
children: json.children?.map(stripUids)
|
|
8
|
-
};
|
|
9
|
-
}
|
|
10
|
-
/**
|
|
11
|
-
* Deep-clone a node subtree (detached — add it wherever you like; sibling
|
|
12
|
-
* auto-rename applies on attach). Implemented as serialize → rebuild so a
|
|
13
|
-
* duplicate is exactly what would survive a save/load round-trip — EXCEPT
|
|
14
|
-
* uids: clones are new entities and get a fresh identity (no uid), so
|
|
15
|
-
* duplicating a uid'd template can never mint colliding ids. Names ARE
|
|
16
|
-
* kept — rename clones you need to look up individually.
|
|
17
|
-
*/
|
|
18
|
-
function duplicateNode(node) {
|
|
19
|
-
return buildNodeJson(stripUids(serializeNode(node)));
|
|
20
|
-
}
|
|
21
|
-
//#endregion
|
|
22
|
-
export { duplicateNode as t };
|
package/dist/json-CwwhxQgb.js
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
|
|
2
|
-
//#region src/core/json.ts
|
|
3
|
-
var json_exports = /* @__PURE__ */ __exportAll({
|
|
4
|
-
jsonClone: () => jsonClone,
|
|
5
|
-
jsonEquals: () => jsonEquals,
|
|
6
|
-
jsonKind: () => jsonKind
|
|
7
|
-
});
|
|
8
|
-
function jsonKind(value) {
|
|
9
|
-
if (value === null) return "null";
|
|
10
|
-
if (Array.isArray(value)) return "array";
|
|
11
|
-
const t = typeof value;
|
|
12
|
-
if (t === "string" || t === "number" || t === "boolean") return t;
|
|
13
|
-
return "object";
|
|
14
|
-
}
|
|
15
|
-
/** Deep structural equality over JSON values (used for delta-only serialization). */
|
|
16
|
-
function jsonEquals(a, b) {
|
|
17
|
-
if (a === b) return true;
|
|
18
|
-
if (Array.isArray(a) && Array.isArray(b)) return a.length === b.length && a.every((v, i) => jsonEquals(v, b[i]));
|
|
19
|
-
if (a !== null && b !== null && typeof a === "object" && typeof b === "object") {
|
|
20
|
-
if (Array.isArray(a) || Array.isArray(b)) return false;
|
|
21
|
-
const ka = Object.keys(a);
|
|
22
|
-
const kb = Object.keys(b);
|
|
23
|
-
return ka.length === kb.length && ka.every((k) => k in b && jsonEquals(a[k], b[k]));
|
|
24
|
-
}
|
|
25
|
-
return false;
|
|
26
|
-
}
|
|
27
|
-
/**
|
|
28
|
-
* Deep clone of JSON-safe data (defaults must never be shared between
|
|
29
|
-
* instances). The value must contain only JSON types.
|
|
30
|
-
*/
|
|
31
|
-
function jsonClone(value) {
|
|
32
|
-
if (value === null || typeof value !== "object") return value;
|
|
33
|
-
return JSON.parse(JSON.stringify(value));
|
|
34
|
-
}
|
|
35
|
-
//#endregion
|
|
36
|
-
export { json_exports as i, jsonEquals as n, jsonKind as r, jsonClone as t };
|
|
@@ -1,212 +0,0 @@
|
|
|
1
|
-
import { t as IncantoError } from "./errors-BpWbnbb_.js";
|
|
2
|
-
import { r as jsonKind, t as jsonClone } from "./json-CwwhxQgb.js";
|
|
3
|
-
//#region src/core/prop-range.ts
|
|
4
|
-
function describe(range) {
|
|
5
|
-
const { min, max, exclusiveMin, allow } = range;
|
|
6
|
-
let body;
|
|
7
|
-
if (min !== void 0 && max !== void 0) body = `${min}..${max}`;
|
|
8
|
-
else if (min !== void 0) body = exclusiveMin ? `greater than ${min}` : `at least ${min}`;
|
|
9
|
-
else if (max !== void 0) body = `at most ${max}`;
|
|
10
|
-
else body = "a finite number";
|
|
11
|
-
return allow && allow.length > 0 ? `${body} (or ${allow.join(", ")})` : body;
|
|
12
|
-
}
|
|
13
|
-
/**
|
|
14
|
-
* Throws `PROP_TYPE_MISMATCH` when a number falls outside its documented range.
|
|
15
|
-
*
|
|
16
|
-
* A non-number is ignored: the kind check has already run and reporting the
|
|
17
|
-
* same value twice, under two codes, tells its reader nothing new.
|
|
18
|
-
*
|
|
19
|
-
* @param value the authored value
|
|
20
|
-
* @param label `Type.prop`, for the message
|
|
21
|
-
* @param range what the prop documents
|
|
22
|
-
*/
|
|
23
|
-
function validatePropRange(value, label, range) {
|
|
24
|
-
if (typeof value !== "number") return;
|
|
25
|
-
if (range.allow?.includes(value)) return;
|
|
26
|
-
if (!Number.isFinite(value)) throw new IncantoError("PROP_TYPE_MISMATCH", `Prop '${label}' must be a finite number, got ${value}.`, { prop: label });
|
|
27
|
-
const belowMin = range.min !== void 0 && (range.exclusiveMin ? value <= range.min : value < range.min);
|
|
28
|
-
const aboveMax = range.max !== void 0 && value > range.max;
|
|
29
|
-
if (!belowMin && !aboveMax) return;
|
|
30
|
-
throw new IncantoError("PROP_TYPE_MISMATCH", `Prop '${label}' must be ${describe(range)}, got ${value}.`, { prop: label });
|
|
31
|
-
}
|
|
32
|
-
//#endregion
|
|
33
|
-
//#region src/core/registry.ts
|
|
34
|
-
/**
|
|
35
|
-
* Validate a prop value against its schema default:
|
|
36
|
-
* - JSON kind must match (unless the default is null = "any")
|
|
37
|
-
* - numbers must be finite (NaN/Infinity corrupt JSON files)
|
|
38
|
-
* - non-empty default arrays are FIXED templates: same length, element-wise match
|
|
39
|
-
* (empty default arrays are unconstrained — variable-length lists)
|
|
40
|
-
*/
|
|
41
|
-
function validatePropValue(value, def, at, options) {
|
|
42
|
-
if (options && typeof value === "string" && !options.includes(value)) throw new IncantoError("PROP_TYPE_MISMATCH", `Prop '${at}' is ${JSON.stringify(value)}, which is not one of: ${options.map((o) => JSON.stringify(o)).join(", ")}.`, {
|
|
43
|
-
prop: at,
|
|
44
|
-
validOptions: [...options]
|
|
45
|
-
});
|
|
46
|
-
const expected = jsonKind(def);
|
|
47
|
-
if (expected === "null") return;
|
|
48
|
-
const actual = jsonKind(value);
|
|
49
|
-
if (actual !== expected) throw new IncantoError("PROP_TYPE_MISMATCH", `Prop '${at}' expects ${expected} (default ${JSON.stringify(def)}), got ${actual} (${JSON.stringify(value)}).`, { prop: at });
|
|
50
|
-
if (typeof value === "number" && !Number.isFinite(value)) throw new IncantoError("PROP_TYPE_MISMATCH", `Prop '${at}' is ${value} — props must be finite numbers.`, { prop: at });
|
|
51
|
-
if (Array.isArray(def) && Array.isArray(value) && def.length > 0) {
|
|
52
|
-
if (value.length !== def.length) throw new IncantoError("PROP_TYPE_MISMATCH", `Prop '${at}' expects an array of length ${def.length} (default ${JSON.stringify(def)}), got length ${value.length}.`, { prop: at });
|
|
53
|
-
for (let i = 0; i < def.length; i++) validatePropValue(value[i], def[i], `${at}[${i}]`);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
/**
|
|
57
|
-
* Global node-type registry (Godot's ClassDB role).
|
|
58
|
-
*
|
|
59
|
-
* Registration is EXPLICIT — never an import-time side effect, so
|
|
60
|
-
* `sideEffects: false` tree-shaking can never silently drop node types.
|
|
61
|
-
*/
|
|
62
|
-
const types = /* @__PURE__ */ new Map();
|
|
63
|
-
function registerNode(ctor, opts) {
|
|
64
|
-
const existing = types.get(ctor.typeName);
|
|
65
|
-
if (existing && existing !== ctor && !opts?.replace) throw new IncantoError("DUPLICATE_NODE_TYPE", `Node type '${ctor.typeName}' is already registered by a different class. Replacing an implementation (e.g. under hot reload) needs registerNode(ctor, { replace: true }).`, { nodeType: ctor.typeName });
|
|
66
|
-
types.set(ctor.typeName, ctor);
|
|
67
|
-
}
|
|
68
|
-
function getNodeType(typeName) {
|
|
69
|
-
const ctor = types.get(typeName);
|
|
70
|
-
if (!ctor) {
|
|
71
|
-
const registered = [...types.keys()];
|
|
72
|
-
throw new IncantoError("UNKNOWN_NODE_TYPE", `Unknown node type '${typeName}'. Registered types: [${registered.join(", ")}].` + missingRegistrarHint(typeName), {
|
|
73
|
-
nodeType: typeName,
|
|
74
|
-
validOptions: registered
|
|
75
|
-
});
|
|
76
|
-
}
|
|
77
|
-
return ctor;
|
|
78
|
-
}
|
|
79
|
-
/**
|
|
80
|
-
* "Unknown node type 'Node2D'" next to a list with no 2D types in it is the
|
|
81
|
-
* most confusing error this engine can produce: the type is not misspelled and
|
|
82
|
-
* not missing — a REGISTRAR was never called. Say which one.
|
|
83
|
-
*
|
|
84
|
-
* The case that produced this: the multiplayer boot registers `registerNodesNet()`
|
|
85
|
-
* and loads a 2D scene, which dies on its own root node.
|
|
86
|
-
*/
|
|
87
|
-
function missingRegistrarHint(typeName) {
|
|
88
|
-
const suffix = typeName.endsWith("2D") ? "2D" : typeName.endsWith("3D") ? "3D" : "";
|
|
89
|
-
if (!suffix || types.has(`Node${suffix}`)) return "";
|
|
90
|
-
const dim = suffix.toLowerCase();
|
|
91
|
-
return ` '${typeName}' is a ${dim} node and no ${dim} type is registered: call registerNodes${suffix}() (from 'incanto/${dim}') before loading the scene — createGame${suffix}() does it for you. Registrars compose: a multiplayer game calls registerNodes${suffix}() AND registerNodesNet().`;
|
|
92
|
-
}
|
|
93
|
-
function registeredTypes() {
|
|
94
|
-
return [...types.keys()];
|
|
95
|
-
}
|
|
96
|
-
/** Test isolation helper. */
|
|
97
|
-
function clearRegistry() {
|
|
98
|
-
types.clear();
|
|
99
|
-
}
|
|
100
|
-
/**
|
|
101
|
-
* Effective prop schema for a type: own static `props` merged over every
|
|
102
|
-
* ancestor's (subclass keys win).
|
|
103
|
-
*/
|
|
104
|
-
function getNodeSchema(typeName) {
|
|
105
|
-
return mergeStaticProps(getNodeType(typeName));
|
|
106
|
-
}
|
|
107
|
-
/** Walk a constructor's prototype chain collecting static `signals` (deduped). */
|
|
108
|
-
function mergeStaticSignals(ctor) {
|
|
109
|
-
const out = [];
|
|
110
|
-
let current = ctor;
|
|
111
|
-
while (current) {
|
|
112
|
-
if (Object.hasOwn(current, "signals") && current.signals) out.unshift(...current.signals);
|
|
113
|
-
const parent = Object.getPrototypeOf(current);
|
|
114
|
-
current = typeof parent === "function" ? parent : null;
|
|
115
|
-
}
|
|
116
|
-
return [...new Set(out)];
|
|
117
|
-
}
|
|
118
|
-
/** Every signal a registered type declares (its own + inherited). */
|
|
119
|
-
function getNodeSignals(typeName) {
|
|
120
|
-
return mergeStaticSignals(getNodeType(typeName));
|
|
121
|
-
}
|
|
122
|
-
/** Walk a constructor's prototype chain merging static `props` (subclass wins). */
|
|
123
|
-
function mergeStaticProps(ctor) {
|
|
124
|
-
const chain = [];
|
|
125
|
-
let current = ctor;
|
|
126
|
-
while (current) {
|
|
127
|
-
if (Object.hasOwn(current, "props") && current.props) chain.unshift(current.props);
|
|
128
|
-
const parent = Object.getPrototypeOf(current);
|
|
129
|
-
current = typeof parent === "function" ? parent : null;
|
|
130
|
-
}
|
|
131
|
-
return Object.assign({}, ...chain);
|
|
132
|
-
}
|
|
133
|
-
/** Walk a constructor's prototype chain merging static `propAliases` (legacy
|
|
134
|
-
* prop key → its current canonical key; subclass wins). Lets a renamed prop keep
|
|
135
|
-
* loading old scenes (e.g. 2D `zIndex` → `renderOrder`) without a format bump. */
|
|
136
|
-
function mergeStaticAliases(ctor) {
|
|
137
|
-
const chain = [];
|
|
138
|
-
let current = ctor;
|
|
139
|
-
while (current) {
|
|
140
|
-
if (Object.hasOwn(current, "propAliases") && current.propAliases) chain.unshift(current.propAliases);
|
|
141
|
-
const parent = Object.getPrototypeOf(current);
|
|
142
|
-
current = typeof parent === "function" ? parent : null;
|
|
143
|
-
}
|
|
144
|
-
return Object.assign({}, ...chain);
|
|
145
|
-
}
|
|
146
|
-
/**
|
|
147
|
-
* Assign schema defaults (cloned) then the given props onto a target,
|
|
148
|
-
* hard-validating every key and JSON kind. Shared by nodes and behaviors.
|
|
149
|
-
* `aliases` maps legacy keys onto current ones (back-compat for renamed props).
|
|
150
|
-
*/
|
|
151
|
-
function applySchemaProps(target, schema, props, label, aliases = {}, extraOptions = {}) {
|
|
152
|
-
for (const [key, def] of Object.entries(schema)) target[key] = jsonClone(def.default);
|
|
153
|
-
if (props) applyGivenProps(target, schema, props, label, aliases, extraOptions);
|
|
154
|
-
requireNonEmpty(target, schema, label);
|
|
155
|
-
}
|
|
156
|
-
function applyGivenProps(target, schema, props, label, aliases, extraOptions) {
|
|
157
|
-
for (const [rawKey, value] of Object.entries(props)) {
|
|
158
|
-
const key = schema[rawKey] ? rawKey : aliases[rawKey] ?? rawKey;
|
|
159
|
-
const def = schema[key];
|
|
160
|
-
if (!def) {
|
|
161
|
-
const valid = Object.keys(schema);
|
|
162
|
-
throw new IncantoError("UNKNOWN_PROP", `Unknown prop '${rawKey}' on '${label}'. Valid props: [${valid.join(", ")}].`, {
|
|
163
|
-
prop: rawKey,
|
|
164
|
-
nodeType: label,
|
|
165
|
-
validOptions: valid
|
|
166
|
-
});
|
|
167
|
-
}
|
|
168
|
-
const extra = extraOptions[key];
|
|
169
|
-
const options = def.options && extra && extra.length > 0 ? [...def.options, ...extra] : def.options;
|
|
170
|
-
validatePropValue(value, def.default, `${label}.${key}`, options);
|
|
171
|
-
if (def.range) validatePropRange(value, `${label}.${key}`, def.range);
|
|
172
|
-
target[key] = jsonClone(value);
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
function requireNonEmpty(target, schema, label) {
|
|
176
|
-
for (const [key, def] of Object.entries(schema)) {
|
|
177
|
-
if (!def.required) continue;
|
|
178
|
-
if (!isEmptyValue(target[key])) continue;
|
|
179
|
-
throw new IncantoError("PROP_TYPE_MISMATCH", `'${label}' needs a "${key}" — it is empty.`, {
|
|
180
|
-
prop: key,
|
|
181
|
-
nodeType: label
|
|
182
|
-
});
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
/**
|
|
186
|
-
* "Not a configuration" — what `required` refuses.
|
|
187
|
-
*
|
|
188
|
-
* The first cut only knew about `''`, which is what the two props that
|
|
189
|
-
* introduced the flag hold. Three of the ones declared since default to an
|
|
190
|
-
* ARRAY — `MoveTo.to`, `Patrol.points`, `WaveSpawner.waves` — and for those the
|
|
191
|
-
* flag was inert: a `MoveTo` with no `to` loaded clean and moved nowhere, which
|
|
192
|
-
* is exactly the failure the flag was added to stop. Found by running the
|
|
193
|
-
* shipped package as a consumer instead of trusting the declaration.
|
|
194
|
-
*/
|
|
195
|
-
function isEmptyValue(value) {
|
|
196
|
-
if (value === "" || value === void 0 || value === null) return true;
|
|
197
|
-
if (Array.isArray(value)) return value.length === 0;
|
|
198
|
-
if (typeof value === "object") return Object.keys(value).length === 0;
|
|
199
|
-
return false;
|
|
200
|
-
}
|
|
201
|
-
/**
|
|
202
|
-
* Instantiate a registered type, assign schema defaults (cloned), then the
|
|
203
|
-
* given props — validating every key and its JSON kind against the default.
|
|
204
|
-
*/
|
|
205
|
-
function createNode(typeName, props, extraOptions) {
|
|
206
|
-
const ctor = getNodeType(typeName);
|
|
207
|
-
const node = new ctor();
|
|
208
|
-
applySchemaProps(node, getNodeSchema(typeName), props, typeName, mergeStaticAliases(ctor), extraOptions);
|
|
209
|
-
return node;
|
|
210
|
-
}
|
|
211
|
-
//#endregion
|
|
212
|
-
export { getNodeSignals as a, mergeStaticSignals as c, getNodeSchema as i, registerNode as l, clearRegistry as n, getNodeType as o, createNode as r, mergeStaticProps as s, applySchemaProps as t, registeredTypes as u };
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
//#region \0rolldown/runtime.js
|
|
2
|
-
var __defProp = Object.defineProperty;
|
|
3
|
-
var __exportAll = (all, no_symbols) => {
|
|
4
|
-
let target = {};
|
|
5
|
-
for (var name in all) __defProp(target, name, {
|
|
6
|
-
get: all[name],
|
|
7
|
-
enumerable: true
|
|
8
|
-
});
|
|
9
|
-
if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
|
|
10
|
-
return target;
|
|
11
|
-
};
|
|
12
|
-
//#endregion
|
|
13
|
-
export { __exportAll as t };
|