incanto 0.71.0 → 0.73.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/incanto-check.mjs +114 -42
- package/bin/incanto-editor.mjs +15 -9
- package/bin/incanto-feel.mjs +11 -1
- package/bin/incanto-play.mjs +11 -1
- package/bin/incanto-playtest.mjs +11 -1
- package/bin/incanto-verify.mjs +9 -2
- package/dist/2d.d.ts +29 -4
- package/dist/2d.js +3 -3
- package/dist/3d.d.ts +137 -15
- package/dist/3d.js +6 -6
- package/dist/{agent8-Cfmd3ar_.js → agent8-CHTT4unP.js} +1 -1
- package/dist/{audio-player-L8yccdMP.d.ts → audio-player-BOrk4eQx.d.ts} +1 -1
- package/dist/{behavior-Dcz0fr1S.d.ts → behavior-J1cmVah0.d.ts} +9 -1
- package/dist/{create-game-LCHBLfA4.js → create-game-CAu-ucHg.js} +8 -7
- package/dist/{create-game-CH4kt78v.js → create-game-CbTLFjis.js} +37 -13
- package/dist/debug.d.ts +1 -1
- package/dist/debug.js +1 -1
- package/dist/editor.js +1036 -930
- package/dist/{environment-presets-99BzP_L-.js → environment-presets-BsFJM3v0.js} +277 -60
- package/dist/{gameplay-CNULJvwh.js → gameplay-CRte0OVf.js} +589 -35
- package/dist/gameplay.d.ts +136 -4
- package/dist/gameplay.js +2 -2
- package/dist/index.d.ts +6 -4
- package/dist/index.js +6 -6
- package/dist/{loader-8-IHvbKD.d.ts → loader-BAeWMYfF.d.ts} +10 -3
- package/dist/net.d.ts +2 -2
- package/dist/net.js +2 -2
- package/dist/{physics-2d-FhrXUc6B.js → physics-2d-CovokK7s.js} +94 -11
- package/dist/{physics-3d-CFEGxBXZ.js → physics-3d-BiK6Emwn.js} +202 -15
- package/dist/{picking-DVo7fI13.js → picking-Dtd8JInh.js} +2 -2
- package/dist/react.d.ts +1 -1
- package/dist/react.js +1 -1
- package/dist/{register-BYQCBySi.js → register-CY9QCCZs.js} +45 -9
- package/dist/{register-DuVdzxbq.js → register-CjociOtt.js} +19 -4
- package/dist/{replay-DEvp3kyV.js → replay-B6BbgGM_.js} +55 -12
- package/dist/{replay-F7IZHdFR.d.ts → replay-wZK5Ok5c.d.ts} +2 -2
- package/dist/{save-slots-Bvuh2p_r.js → save-slots-CEUGeLuB.js} +57 -3
- package/dist/{split-screen-eULetcg-.js → split-screen-BxZ5rBe7.js} +4 -4
- package/dist/{split-screen-CIYf1zSf.d.ts → split-screen-D6sx8z3Z.d.ts} +2 -2
- package/dist/{sprite-animation-CqR2o3SA.js → sprite-animation-Bz3DHD_4.js} +1 -1
- package/dist/{src-_jk0qLsS.js → src-D-dnVrFY.js} +1 -1
- package/dist/{test-CmN54kWv.js → test-DZmCFz0Q.js} +162 -30
- package/dist/test.d.ts +56 -5
- package/dist/test.js +2 -2
- package/dist/{touch-BnCyPA0G.js → touch-CioTZB-y.js} +1 -1
- package/dist/vite.d.ts +8 -1
- package/dist/vite.js +22 -5
- package/editor/assets/{agent8-yLIEYHbd.js → agent8-GuZ5u5bi.js} +1 -1
- package/editor/assets/{debug-u31w_yhq.js → debug-BbxionO2.js} +1 -1
- package/editor/assets/{index-DK9xMGpW.js → index-CNlTzQbm.js} +92 -92
- package/editor/index.html +1 -1
- package/package.json +1 -1
- package/schemas/scene.schema.json +634 -10
- package/skills/incanto-3d-character.md +113 -5
- package/skills/incanto-assets.md +9 -3
- package/skills/incanto-behaviors-and-scripts.md +26 -2
- package/skills/incanto-building-2d-games.md +15 -0
- package/skills/incanto-building-3d-games.md +45 -0
- package/skills/incanto-editor.md +10 -1
- package/skills/incanto-environment.md +7 -2
- package/skills/incanto-game-feel.md +16 -11
- package/skills/incanto-gameplay-behaviors.md +174 -15
- package/skills/incanto-node-reference.md +122 -45
- package/skills/incanto-physics-and-input.md +67 -5
- package/skills/incanto-scene-json-authoring.md +37 -1
- package/skills/incanto-verifying-your-game.md +19 -2
- package/templates-app/beacon-isle-3d/PROJECT/Status.md +8 -0
- package/templates-app/beacon-isle-3d/PROJECT/Structure.md +3 -0
- package/templates-app/beacon-isle-3d/package.json +1 -1
- package/templates-app/beacon-isle-3d/src/game.scene.json +512 -184
- package/templates-app/beacon-isle-3d/verify.ts +144 -0
- package/templates-app/molehill-2d/package.json +1 -1
- package/templates-app/platformer-2d/PROJECT/Status.md +7 -0
- package/templates-app/platformer-2d/PROJECT/Structure.md +3 -0
- package/templates-app/platformer-2d/package.json +1 -1
- package/templates-app/platformer-2d/src/game.scene.json +319 -93
- package/templates-app/platformer-2d/verify.ts +54 -0
- package/templates-app/star-survivor/package.json +1 -1
- package/templates-app/star-survivor/src/game.scene.json +18 -9
- package/templates-app/tps-3d/PROJECT/Context.md +1 -1
- package/templates-app/tps-3d/PROJECT/Status.md +40 -1
- package/templates-app/tps-3d/PROJECT/Structure.md +19 -0
- package/templates-app/tps-3d/package.json +1 -1
- package/templates-app/tps-3d/src/behaviors.ts +9 -0
- package/templates-app/tps-3d/src/cover.scene.json +26 -0
- package/templates-app/tps-3d/src/game.scene.json +379 -80
- package/templates-app/tps-3d/src/main.ts +14 -0
- package/templates-app/tps-3d/src/pillar.scene.json +25 -0
- package/templates-app/tps-3d/verify.ts +582 -3
- package/templates-app/village-quest-3d/package.json +1 -1
- package/templates-app/village-quest-3d/src/grove.scene.json +98 -46
- package/templates-app/village-quest-3d/src/village.scene.json +449 -223
package/bin/incanto-check.mjs
CHANGED
|
@@ -86,7 +86,7 @@ function collectScenes(entry) {
|
|
|
86
86
|
* not. A WARNING, not an error: a url can legitimately be produced at runtime,
|
|
87
87
|
* and refusing to load a scene over a guess would be worse than the bug.
|
|
88
88
|
*/
|
|
89
|
-
function missingArt(file, json) {
|
|
89
|
+
async function missingArt(file, json) {
|
|
90
90
|
const assets = json && typeof json === 'object' ? json.assets : null;
|
|
91
91
|
const sceneDir = dirname(file);
|
|
92
92
|
const root = projectRoot(sceneDir);
|
|
@@ -112,9 +112,17 @@ function missingArt(file, json) {
|
|
|
112
112
|
url: u.url,
|
|
113
113
|
})),
|
|
114
114
|
];
|
|
115
|
+
const remote = [];
|
|
115
116
|
for (const { what, kind, url } of named) {
|
|
116
117
|
if (typeof url !== 'string' || url === '') continue;
|
|
117
|
-
//
|
|
118
|
+
// A remote url is not guessed about — it is ASKED. A melee arena built from
|
|
119
|
+
// the tarball named a model at a path that does not exist on the CDN, and
|
|
120
|
+
// `incanto-verify` printed "its assets resolve" over a 404 only the browser
|
|
121
|
+
// ever reported. Inline (`data:`) and protocol-relative urls stay unchecked.
|
|
122
|
+
if (/^https?:\/\//i.test(url)) {
|
|
123
|
+
remote.push({ what, kind, url });
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
118
126
|
if (/^[a-z][a-z0-9+.-]*:/i.test(url) || url.startsWith('//')) continue;
|
|
119
127
|
const rel = url.replace(/^\//, '');
|
|
120
128
|
const candidates = [
|
|
@@ -139,6 +147,68 @@ function missingArt(file, json) {
|
|
|
139
147
|
`, and beside the scene). It will ${kind === 'audio' ? 'be silent' : 'draw nothing'}.`,
|
|
140
148
|
);
|
|
141
149
|
}
|
|
150
|
+
out.push(...(await missingRemoteArt(remote)));
|
|
151
|
+
return out;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/** One answer per url per run — a corpus names the same model in every scene. */
|
|
155
|
+
const probed = new Map();
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Does the server have it? A HEAD with a short deadline; servers that refuse
|
|
159
|
+
* HEAD get one ranged GET. Only the answer "no" (404/410) is a warning: an
|
|
160
|
+
* unreachable host is a NOTE on stdout and nothing else, because a check that
|
|
161
|
+
* fails offline is a check people turn off.
|
|
162
|
+
*/
|
|
163
|
+
async function probeUrl(url) {
|
|
164
|
+
if (probed.has(url)) return probed.get(url);
|
|
165
|
+
const ask = async (method) => {
|
|
166
|
+
const ctl = new AbortController();
|
|
167
|
+
const timer = setTimeout(() => ctl.abort(), 4000);
|
|
168
|
+
try {
|
|
169
|
+
const res = await fetch(url, {
|
|
170
|
+
method,
|
|
171
|
+
redirect: 'follow',
|
|
172
|
+
signal: ctl.signal,
|
|
173
|
+
headers: method === 'GET' ? { range: 'bytes=0-0' } : {},
|
|
174
|
+
});
|
|
175
|
+
if (method === 'GET') await res.body?.cancel?.();
|
|
176
|
+
return { status: res.status };
|
|
177
|
+
} catch (e) {
|
|
178
|
+
return {
|
|
179
|
+
error:
|
|
180
|
+
e?.name === 'AbortError'
|
|
181
|
+
? 'timed out after 4 s'
|
|
182
|
+
: (e?.cause?.code ?? e?.message ?? String(e)),
|
|
183
|
+
};
|
|
184
|
+
} finally {
|
|
185
|
+
clearTimeout(timer);
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
let answer = await ask('HEAD');
|
|
189
|
+
if (answer.status === 405 || answer.status === 403 || answer.status === 501)
|
|
190
|
+
answer = await ask('GET');
|
|
191
|
+
probed.set(url, answer);
|
|
192
|
+
return answer;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
async function missingRemoteArt(remote) {
|
|
196
|
+
const answers = await Promise.all(
|
|
197
|
+
remote.map(async (r) => ({ ...r, ...(await probeUrl(r.url)) })),
|
|
198
|
+
);
|
|
199
|
+
const out = [];
|
|
200
|
+
for (const { what, kind, url, status, error } of answers) {
|
|
201
|
+
if (status === 404 || status === 410) {
|
|
202
|
+
out.push(
|
|
203
|
+
`${what} → ${url} is not found on its server (HTTP ${status}). It will ` +
|
|
204
|
+
`${kind === 'audio' ? 'be silent' : 'draw nothing'}.`,
|
|
205
|
+
);
|
|
206
|
+
} else if (error !== undefined) {
|
|
207
|
+
console.log(
|
|
208
|
+
` note: ${what} → ${url} could not be reached from here (${error}) — not checked.`,
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
142
212
|
return out;
|
|
143
213
|
}
|
|
144
214
|
|
|
@@ -266,49 +336,51 @@ for (const file of files) {
|
|
|
266
336
|
|
|
267
337
|
const instanced = instancedScenes(corpus, (from, ref) => resolve(dirname(from), ref));
|
|
268
338
|
|
|
269
|
-
const results =
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
339
|
+
const results = await Promise.all(
|
|
340
|
+
files.map(async (file) => {
|
|
341
|
+
let json;
|
|
342
|
+
try {
|
|
343
|
+
json = readJson(file);
|
|
344
|
+
} catch (e) {
|
|
345
|
+
return { file, ok: false, code: 'BAD_JSON', message: String(e?.message ?? e) };
|
|
346
|
+
}
|
|
347
|
+
const res = validateScene(json, {
|
|
348
|
+
strictBehaviors: args.strict,
|
|
349
|
+
/*
|
|
350
|
+
* `validateScene` has always taken `behaviors`; this bin had no way to pass
|
|
351
|
+
* any. So `--strict-behaviors` could only ever FAIL on a project with a
|
|
352
|
+
* behaviour of its own — which is every project past its first hour:
|
|
353
|
+
*
|
|
354
|
+
* [UNKNOWN_BEHAVIOR] Unknown behavior 'Hunter'. … Did you forget
|
|
355
|
+
* registerBehavior('Hunter', Hunter)?
|
|
356
|
+
* 0/1 scene(s) valid EXIT=1
|
|
357
|
+
*
|
|
358
|
+
* A flag whose only outcome is failure is a flag nobody uses, and the check
|
|
359
|
+
* it gates — a script name that resolves nowhere — is worth having.
|
|
360
|
+
*/
|
|
361
|
+
behaviors,
|
|
362
|
+
declaredAssets,
|
|
363
|
+
resolveScene: (p) => readJson(resolve(dirname(file), p)),
|
|
364
|
+
});
|
|
365
|
+
if (res.ok) {
|
|
366
|
+
return {
|
|
367
|
+
file,
|
|
368
|
+
ok: true,
|
|
369
|
+
warnings: [
|
|
370
|
+
...auditScene(json, { declaredElsewhere, instanced: instanced.has(resolve(file)) }),
|
|
371
|
+
...(await missingArt(file, json)),
|
|
372
|
+
],
|
|
373
|
+
};
|
|
374
|
+
}
|
|
295
375
|
return {
|
|
296
376
|
file,
|
|
297
|
-
ok:
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
],
|
|
377
|
+
ok: false,
|
|
378
|
+
code: res.error?.code,
|
|
379
|
+
message: res.error?.message,
|
|
380
|
+
details: res.error?.details,
|
|
302
381
|
};
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
file,
|
|
306
|
-
ok: false,
|
|
307
|
-
code: res.error?.code,
|
|
308
|
-
message: res.error?.message,
|
|
309
|
-
details: res.error?.details,
|
|
310
|
-
};
|
|
311
|
-
});
|
|
382
|
+
}),
|
|
383
|
+
);
|
|
312
384
|
|
|
313
385
|
const failed = results.filter((r) => !r.ok);
|
|
314
386
|
const warned = results.reduce((n, r) => n + (r.warnings?.length ?? 0), 0);
|
package/bin/incanto-editor.mjs
CHANGED
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
import { existsSync, mkdirSync, readdirSync, readFileSync, statSync, writeFileSync } from 'node:fs';
|
|
31
31
|
import { createServer } from 'node:http';
|
|
32
32
|
import { basename, dirname, extname, join, normalize, relative, resolve, sep } from 'node:path';
|
|
33
|
-
import { fileURLToPath } from 'node:url';
|
|
33
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
34
34
|
import { readJson } from './_read-json.mjs';
|
|
35
35
|
|
|
36
36
|
const PKG_ROOT = join(dirname(fileURLToPath(import.meta.url)), '..');
|
|
@@ -463,7 +463,7 @@ const server = createServer((req, res) => {
|
|
|
463
463
|
if (!originAllowed(req)) {
|
|
464
464
|
return send(res, 403, JSON.stringify({ error: 'cross-origin write rejected' }));
|
|
465
465
|
}
|
|
466
|
-
readBody(req, res, (body) => {
|
|
466
|
+
readBody(req, res, async (body) => {
|
|
467
467
|
// a path with no extension means the usual thing, so `levels/arena` works
|
|
468
468
|
const wanted =
|
|
469
469
|
typeof body?.path === 'string' && body.path && !body.path.endsWith('.json')
|
|
@@ -495,14 +495,20 @@ const server = createServer((req, res) => {
|
|
|
495
495
|
*/
|
|
496
496
|
const asked = body?.dimension === '3d' || body?.dimension === '2d' ? body.dimension : null;
|
|
497
497
|
const dimension = asked ?? projectDimension() ?? '2d';
|
|
498
|
-
const scene = {
|
|
499
|
-
format: 1,
|
|
500
|
-
type: 'scene',
|
|
501
|
-
dimension,
|
|
502
|
-
name,
|
|
503
|
-
root: { name, type: dimension === '3d' ? 'Node3D' : 'Node2D' },
|
|
504
|
-
};
|
|
505
498
|
try {
|
|
499
|
+
// uid at CREATION, like every node the editor makes: without it the
|
|
500
|
+
// first save backfills one and the diff carries a line nobody wrote.
|
|
501
|
+
// Imported here rather than at the top so starting the editor never
|
|
502
|
+
// pays for `dist` it may not otherwise need — inside the try, so a
|
|
503
|
+
// missing build is a 400 and not a dead server.
|
|
504
|
+
const { newUid } = await import(pathToFileURL(join(PKG_ROOT, 'dist', 'index.js')).href);
|
|
505
|
+
const scene = {
|
|
506
|
+
format: 1,
|
|
507
|
+
type: 'scene',
|
|
508
|
+
dimension,
|
|
509
|
+
name,
|
|
510
|
+
root: { name, type: dimension === '3d' ? 'Node3D' : 'Node2D', uid: newUid() },
|
|
511
|
+
};
|
|
506
512
|
mkdirSync(dirname(abs), { recursive: true });
|
|
507
513
|
writeFileSync(abs, formatSceneJson(scene));
|
|
508
514
|
return send(res, 201, JSON.stringify({ rel: relative(ROOT, abs), abs }));
|
package/bin/incanto-feel.mjs
CHANGED
|
@@ -60,7 +60,17 @@ if (args.help || !args.scene) {
|
|
|
60
60
|
pushed +x/-y/+y/-x until the player moves)
|
|
61
61
|
--jump ACTION the button to jump with (default: "jump")
|
|
62
62
|
--json the report as JSON instead of prose`);
|
|
63
|
-
|
|
63
|
+
/*
|
|
64
|
+
* `--help` is a REQUEST, and the answer is the text above.
|
|
65
|
+
*
|
|
66
|
+
* The rule used to be "0 only if a scene was also named", so the exact thing
|
|
67
|
+
* an agent types first — `incanto-playtest --help` — printed the usage and
|
|
68
|
+
* exited 1, while thirteen sibling bins exited 0 for the same input. A
|
|
69
|
+
* non-zero exit says "you did it wrong" to someone who did the documented
|
|
70
|
+
* thing, and under `set -e` it stops the script. A typo still exits 1
|
|
71
|
+
* (`invalid`), and so does a missing scene when help was not asked for.
|
|
72
|
+
*/
|
|
73
|
+
process.exit(args.help && !args.invalid ? 0 : 1);
|
|
64
74
|
}
|
|
65
75
|
|
|
66
76
|
const { facingReport, facingText, feelReport, feelText } = await import(
|
package/bin/incanto-play.mjs
CHANGED
|
@@ -69,7 +69,17 @@ if (args.help || !args.scene) {
|
|
|
69
69
|
|
|
70
70
|
Headless play: stdin commands (step/press/release/vector/key/mouse/pointer/
|
|
71
71
|
wheel/capture/describe/framing/logs/quit), JSON-line responses on stdout.`);
|
|
72
|
-
|
|
72
|
+
/*
|
|
73
|
+
* `--help` is a REQUEST, and the answer is the text above.
|
|
74
|
+
*
|
|
75
|
+
* The rule used to be "0 only if a scene was also named", so the exact thing
|
|
76
|
+
* an agent types first — `incanto-playtest --help` — printed the usage and
|
|
77
|
+
* exited 1, while thirteen sibling bins exited 0 for the same input. A
|
|
78
|
+
* non-zero exit says "you did it wrong" to someone who did the documented
|
|
79
|
+
* thing, and under `set -e` it stops the script. A typo still exits 1
|
|
80
|
+
* (`invalid`), and so does a missing scene when help was not asked for.
|
|
81
|
+
*/
|
|
82
|
+
process.exit(args.help && !args.invalid ? 0 : 1);
|
|
73
83
|
}
|
|
74
84
|
|
|
75
85
|
const out = (obj) => process.stdout.write(`${JSON.stringify(obj)}\n`);
|
package/bin/incanto-playtest.mjs
CHANGED
|
@@ -92,7 +92,17 @@ if (args.help || !args.scene) {
|
|
|
92
92
|
Exits 1 when a run THREW or left the world, or when a win is declared and no
|
|
93
93
|
run reached it. A scene that declares no win, or has nobody to drive, exits 0 —
|
|
94
94
|
the report marks those · rather than ✗, and the exit code says the same.`);
|
|
95
|
-
|
|
95
|
+
/*
|
|
96
|
+
* `--help` is a REQUEST, and the answer is the text above.
|
|
97
|
+
*
|
|
98
|
+
* The rule used to be "0 only if a scene was also named", so the exact thing
|
|
99
|
+
* an agent types first — `incanto-playtest --help` — printed the usage and
|
|
100
|
+
* exited 1, while thirteen sibling bins exited 0 for the same input. A
|
|
101
|
+
* non-zero exit says "you did it wrong" to someone who did the documented
|
|
102
|
+
* thing, and under `set -e` it stops the script. A typo still exits 1
|
|
103
|
+
* (`invalid`), and so does a missing scene when help was not asked for.
|
|
104
|
+
*/
|
|
105
|
+
process.exit(args.help && !args.invalid ? 0 : 1);
|
|
96
106
|
}
|
|
97
107
|
|
|
98
108
|
const { playtest, playtestText, playtestFailed, failingReplays } = await import(
|
package/bin/incanto-verify.mjs
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*
|
|
5
5
|
* bunx incanto-verify # finds your scene
|
|
6
6
|
* bunx incanto-verify src/game.scene.json --behaviors src/behaviors.ts
|
|
7
|
+
* bunx incanto-verify src/game.scene.json --runs 16 # more seeds for the plays rung
|
|
7
8
|
*
|
|
8
9
|
* The rungs already existed and were used one at a time, because using them
|
|
9
10
|
* together means knowing three things nobody writes down: the order, that the
|
|
@@ -31,8 +32,14 @@ const { feelsRung, firstLine, ladderText, ladderVerdict, saysRung, unmeasuredPla
|
|
|
31
32
|
|
|
32
33
|
const argv = process.argv.slice(2);
|
|
33
34
|
const asJson = argv.includes('--json');
|
|
35
|
+
// `--runs N` for the plays rung. Eight seeds see a one-in-eight event 64% of
|
|
36
|
+
// the time; a starter is where a rare fall costs the most, so the sweep asks
|
|
37
|
+
// the six that ship for sixteen. The default stays 8 — every example, every
|
|
38
|
+
// campaign, and the sweep's seven minutes are the reason.
|
|
39
|
+
const runsAt = argv.indexOf('--runs');
|
|
40
|
+
const RUNS = runsAt >= 0 && /^\d+$/.test(argv[runsAt + 1] ?? '') ? argv[runsAt + 1] : '8';
|
|
34
41
|
if (argv.includes('--help') || argv.includes('-h')) {
|
|
35
|
-
console.log(`Usage: incanto verify [scene.json] [--behaviors FILE[,FILE...]] [--json]
|
|
42
|
+
console.log(`Usage: incanto verify [scene.json] [--behaviors FILE[,FILE...]] [--runs N] [--json]
|
|
36
43
|
|
|
37
44
|
Walks the whole ladder and tells you the ONE thing to do next:
|
|
38
45
|
|
|
@@ -223,7 +230,7 @@ let botPlayed = true;
|
|
|
223
230
|
|
|
224
231
|
// ---- plays ---------------------------------------------------------------
|
|
225
232
|
if (rungs[0].status === 'pass') {
|
|
226
|
-
const args = [scene, '--json', '--runs',
|
|
233
|
+
const args = [scene, '--json', '--runs', RUNS];
|
|
227
234
|
if (behaviors) args.push('--behaviors', behaviors);
|
|
228
235
|
const r = run('playtest', args);
|
|
229
236
|
const out = safeJson(r.stdout);
|
package/dist/2d.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { c as showBootFailure, i as ParticleSim, o as ParticleView, r as SpatialPose, s as isWebGLAvailable } from "./audio-player-
|
|
2
|
-
import { P as Scene$1, S as Scheduler, T as RendererStats, b as Engine, d as PropSchema, jt as Node, n as BehaviorCtor, w as GameStats, x as EngineOptions } from "./behavior-
|
|
1
|
+
import { c as showBootFailure, i as ParticleSim, o as ParticleView, r as SpatialPose, s as isWebGLAvailable } from "./audio-player-BOrk4eQx.js";
|
|
2
|
+
import { P as Scene$1, S as Scheduler, T as RendererStats, b as Engine, d as PropSchema, jt as Node, n as BehaviorCtor, w as GameStats, x as EngineOptions } from "./behavior-J1cmVah0.js";
|
|
3
3
|
import { t as DiagnosticSink } from "./diagnostics-Cu85N3tL.js";
|
|
4
4
|
import { a as SceneJson, s as JsonObject } from "./rng-Bb-IutXB.js";
|
|
5
5
|
import { t as EditorSwitchOptions } from "./editor-switch-CFU9mCec.js";
|
|
6
6
|
import { r as FrameStats } from "./frame-report-DNxDAb1w.js";
|
|
7
|
-
import { t as LoadSceneOptions } from "./loader-
|
|
7
|
+
import { t as LoadSceneOptions } from "./loader-BAeWMYfF.js";
|
|
8
8
|
import { n as AnimationEntry } from "./sprite-animation-CMr6f1K2.js";
|
|
9
9
|
import { Group, Mesh, Object3D, Scene, Texture } from "three";
|
|
10
10
|
import * as RapierNs from "@dimforge/rapier2d-compat";
|
|
@@ -159,9 +159,24 @@ declare class PhysicsBody2D extends Node2D {
|
|
|
159
159
|
/** @internal Set by Physics2D when the body is created. */
|
|
160
160
|
_physics: Physics2D | null;
|
|
161
161
|
}
|
|
162
|
-
/**
|
|
162
|
+
/**
|
|
163
|
+
* Immovable collider (ground, walls, platforms).
|
|
164
|
+
*
|
|
165
|
+
* It also carries the SURFACE it is: `friction` and `restitution` used to
|
|
166
|
+
* live on `RigidBody2D` alone, so a trampoline, an ice patch or a sticky
|
|
167
|
+
* landing could not be written in scene JSON, and Rapier's AVERAGE rule
|
|
168
|
+
* halved whatever a ball brought to a plain floor. A static body's authored
|
|
169
|
+
* value WINS the pair — restitution above 0 combines by Max, friction below
|
|
170
|
+
* the default by Min and above it by Max — so the pad decides, whatever lands
|
|
171
|
+
* on it. Left at the defaults, nothing changes for any existing scene.
|
|
172
|
+
*/
|
|
163
173
|
declare class StaticBody2D extends PhysicsBody2D {
|
|
164
174
|
static override readonly typeName: string;
|
|
175
|
+
static override readonly props: PropSchema;
|
|
176
|
+
/** 0.5 plain · 0 ice (slides on and on) · 1+ glue. Away from 0.5 it wins the pair. */
|
|
177
|
+
friction: number;
|
|
178
|
+
/** 0 dead · 1 trampoline. Above 0 it wins the pair: a dead ball still bounces. */
|
|
179
|
+
restitution: number;
|
|
165
180
|
}
|
|
166
181
|
/**
|
|
167
182
|
* Sensor volume. Emits `triggerEnter(other)` / `triggerExit(other)` — the
|
|
@@ -184,6 +199,10 @@ declare class RigidBody2D extends PhysicsBody2D {
|
|
|
184
199
|
fixedRotation: boolean;
|
|
185
200
|
friction: number;
|
|
186
201
|
restitution: number;
|
|
202
|
+
/** Drag, per second: velocity decays by `e^(-linearDamping·t)`. `0` = none. */
|
|
203
|
+
linearDamping: number;
|
|
204
|
+
/** Rolling resistance, per second, on the spin — see `RigidBody3D.angularDamping`. */
|
|
205
|
+
angularDamping: number;
|
|
187
206
|
/** px/s, y-down. Read back every step; write to launch. */
|
|
188
207
|
linearVelocity: number[];
|
|
189
208
|
/**
|
|
@@ -250,6 +269,8 @@ declare class CharacterBody2D extends PhysicsBody2D {
|
|
|
250
269
|
* `0` restores the old behaviour.
|
|
251
270
|
*/
|
|
252
271
|
stepHeight: number;
|
|
272
|
+
/** See CharacterBody3D.collideWithCharacters — off, a crowd ignores itself and costs nothing. */
|
|
273
|
+
collideWithCharacters: boolean;
|
|
253
274
|
/** @internal Updated by Physics2D.moveAndSlide. */
|
|
254
275
|
_grounded: boolean;
|
|
255
276
|
moveAndSlide(): void;
|
|
@@ -359,6 +380,10 @@ declare class Physics2D {
|
|
|
359
380
|
*/
|
|
360
381
|
/** Drop one node from the overlap map, both as a key and as a member. */
|
|
361
382
|
private forgetOverlaps;
|
|
383
|
+
/** Every overlap `node` is in ends now — the exits Rapier does not send for a disabled collider. */
|
|
384
|
+
private releaseOverlaps;
|
|
385
|
+
/** Every body the armed sensor is inside of RIGHT NOW enters it — the starts Rapier does not send for a re-enabled collider. */
|
|
386
|
+
private armOverlaps;
|
|
362
387
|
private pruneOverlaps;
|
|
363
388
|
/** The bodies currently overlapping `node`. Freed nodes are dropped on read. */
|
|
364
389
|
overlapping(node: PhysicsBody2D): PhysicsBody2D[];
|
package/dist/2d.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { t as IncantoError } from "./errors-BpWbnbb_.js";
|
|
2
2
|
import { t as showBootFailure } from "./boot-failure-CKYrEcGF.js";
|
|
3
3
|
import { t as isWebGLAvailable } from "./webgl-unavailable-C8aDbGmR.js";
|
|
4
|
-
import { a as AssetStore2D, i as syncTree2D, r as Renderer2D, t as createGame2D } from "./create-game-
|
|
5
|
-
import { _ as RigidBody2D, a as parseCells, c as ColorRect2D, d as AnimatedSprite2D, f as Sprite2D, g as PhysicsBody2D, h as CharacterBody2D, i as mergeSolidRects, l as CharacterController2D, m as Area2D, n as UILayer, o as Particles2D, p as Joint2D, r as TileMap2D, s as Label, t as registerNodes2D, u as Camera2D, v as StaticBody2D, y as Node2D } from "./register-
|
|
6
|
-
import { n as enablePhysics2D, t as Physics2D } from "./physics-2d-
|
|
4
|
+
import { a as AssetStore2D, i as syncTree2D, r as Renderer2D, t as createGame2D } from "./create-game-CbTLFjis.js";
|
|
5
|
+
import { _ as RigidBody2D, a as parseCells, c as ColorRect2D, d as AnimatedSprite2D, f as Sprite2D, g as PhysicsBody2D, h as CharacterBody2D, i as mergeSolidRects, l as CharacterController2D, m as Area2D, n as UILayer, o as Particles2D, p as Joint2D, r as TileMap2D, s as Label, t as registerNodes2D, u as Camera2D, v as StaticBody2D, y as Node2D } from "./register-CY9QCCZs.js";
|
|
6
|
+
import { n as enablePhysics2D, t as Physics2D } from "./physics-2d-CovokK7s.js";
|
|
7
7
|
//#region src/2d/library-sprite.ts
|
|
8
8
|
/**
|
|
9
9
|
* What a `CharacterController2D`/`3D` will ask a skin to play, and the clip in
|
package/dist/3d.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { c as showBootFailure, i as ParticleSim, o as ParticleView, r as SpatialPose, s as isWebGLAvailable } from "./audio-player-
|
|
2
|
-
import { D as QualityCaps, P as Scene$1, S as Scheduler, T as RendererStats, b as Engine, d as PropSchema, jt as Node, n as BehaviorCtor, w as GameStats, x as EngineOptions } from "./behavior-
|
|
1
|
+
import { c as showBootFailure, i as ParticleSim, o as ParticleView, r as SpatialPose, s as isWebGLAvailable } from "./audio-player-BOrk4eQx.js";
|
|
2
|
+
import { D as QualityCaps, P as Scene$1, S as Scheduler, T as RendererStats, b as Engine, d as PropSchema, jt as Node, n as BehaviorCtor, w as GameStats, x as EngineOptions } from "./behavior-J1cmVah0.js";
|
|
3
3
|
import { t as DiagnosticSink } from "./diagnostics-Cu85N3tL.js";
|
|
4
4
|
import { a as SceneJson$1, s as JsonObject } from "./rng-Bb-IutXB.js";
|
|
5
5
|
import { t as EditorSwitchOptions } from "./editor-switch-CFU9mCec.js";
|
|
6
6
|
import { a as GridCell, c as diffText, d as frameText, i as FrameStatsOptions, l as frameSignature, n as FrameSignature, o as SIGNATURE_GRID, r as FrameStats, s as diffSignatures, t as FrameDiff, u as frameStats } from "./frame-report-DNxDAb1w.js";
|
|
7
|
-
import { t as LoadSceneOptions } from "./loader-
|
|
7
|
+
import { t as LoadSceneOptions } from "./loader-BAeWMYfF.js";
|
|
8
8
|
import { n as PathGrid } from "./pathfinding-_fGrCFmH.js";
|
|
9
9
|
import { AnimationClip, AnimationMixer, BufferGeometry, Color, DirectionalLight, Group, InstancedMesh, Mesh, MeshPhysicalMaterial, Object3D, PerspectiveCamera, Scene, ShaderMaterial, Texture, Vector3, WebGLRenderer } from "three";
|
|
10
10
|
import { VRM } from "@pixiv/three-vrm";
|
|
@@ -391,9 +391,24 @@ declare class PhysicsBody3D extends Node3D {
|
|
|
391
391
|
/** @internal Set by Physics3D when the body is created. */
|
|
392
392
|
_physics: Physics3D | null;
|
|
393
393
|
}
|
|
394
|
-
/**
|
|
394
|
+
/**
|
|
395
|
+
* Immovable collider (ground, walls, platforms).
|
|
396
|
+
*
|
|
397
|
+
* It also carries the SURFACE it is: `friction` and `restitution` used to
|
|
398
|
+
* live on `RigidBody3D` alone, so a trampoline, an ice patch or a sticky
|
|
399
|
+
* landing could not be written in scene JSON, and Rapier's AVERAGE rule
|
|
400
|
+
* halved whatever a ball brought to a plain floor. A static body's authored
|
|
401
|
+
* value WINS the pair — restitution above 0 combines by Max, friction below
|
|
402
|
+
* the default by Min and above it by Max — so the pad decides, whatever lands
|
|
403
|
+
* on it. Left at the defaults, nothing changes for any existing scene.
|
|
404
|
+
*/
|
|
395
405
|
declare class StaticBody3D extends PhysicsBody3D {
|
|
396
406
|
static override readonly typeName: string;
|
|
407
|
+
static override readonly props: PropSchema;
|
|
408
|
+
/** 0.5 plain · 0 ice (slides on and on) · 1+ glue. Away from 0.5 it wins the pair. */
|
|
409
|
+
friction: number;
|
|
410
|
+
/** 0 dead · 1 trampoline. Above 0 it wins the pair: a dead ball still bounces. */
|
|
411
|
+
restitution: number;
|
|
397
412
|
}
|
|
398
413
|
/** Sensor volume emitting `triggerEnter(other)` / `triggerExit(other)`. */
|
|
399
414
|
declare class Area3D extends PhysicsBody3D {
|
|
@@ -435,6 +450,17 @@ declare class RigidBody3D extends PhysicsBody3D {
|
|
|
435
450
|
fixedRotation: boolean;
|
|
436
451
|
friction: number;
|
|
437
452
|
restitution: number;
|
|
453
|
+
/**
|
|
454
|
+
* Drag, per second: velocity decays by `e^(-linearDamping·t)`. `0` = none.
|
|
455
|
+
* A body flying through nothing keeps its speed forever otherwise.
|
|
456
|
+
*/
|
|
457
|
+
linearDamping: number;
|
|
458
|
+
/**
|
|
459
|
+
* Rolling resistance, per second, on the spin. Rapier has none by itself:
|
|
460
|
+
* friction only converts slip into spin, so a rolling ball is a wheel and a
|
|
461
|
+
* golf ball rolled to the edge of the world. `1`–`3` stops a ball on a green.
|
|
462
|
+
*/
|
|
463
|
+
angularDamping: number;
|
|
438
464
|
/** m/s, y-up. Read back every step; write to launch. */
|
|
439
465
|
linearVelocity: number[];
|
|
440
466
|
/**
|
|
@@ -481,6 +507,16 @@ declare class CharacterBody3D extends PhysicsBody3D {
|
|
|
481
507
|
/** Max climbable slope angle. */
|
|
482
508
|
slopeLimitDeg: number;
|
|
483
509
|
/**
|
|
510
|
+
* Whether OTHER characters are obstacles to this one. On (default), a
|
|
511
|
+
* character is a wall to every other character — Godot's answer, and what a
|
|
512
|
+
* few enemies want. Off, the controller ignores every other kinematic body
|
|
513
|
+
* and a crowd costs what the floor and the walls cost: eighty chasers around
|
|
514
|
+
* a player cost 64–286 ms a step with this on (each slide shape-casts
|
|
515
|
+
* against every neighbour, O(n²) in the crowd) and under a millisecond off.
|
|
516
|
+
* A survivor's horde overlaps itself and nobody minds.
|
|
517
|
+
*/
|
|
518
|
+
collideWithCharacters: boolean;
|
|
519
|
+
/**
|
|
484
520
|
* How high a step this body walks UP without jumping (0 = none).
|
|
485
521
|
*
|
|
486
522
|
* Rapier's character controller does not autostep unless asked, and nothing
|
|
@@ -637,7 +673,12 @@ declare class Physics3D {
|
|
|
637
673
|
* off ONE fixed body — they never move, so there is nothing to step — and the
|
|
638
674
|
* whole set is rebuilt only when the tree's shape changes.
|
|
639
675
|
*/
|
|
640
|
-
/**
|
|
676
|
+
/**
|
|
677
|
+
* Where each live scatter field was when its colliders were built — and what
|
|
678
|
+
* they were built FROM. Rows and place were remembered from the start; the
|
|
679
|
+
* stone itself (`mesh`, `size`, the `collider` spec) was not, so a field
|
|
680
|
+
* grown at runtime, or resized in the inspector, collided as the old stones.
|
|
681
|
+
*/
|
|
641
682
|
private readonly scatterState;
|
|
642
683
|
/**
|
|
643
684
|
* Has any scatter field moved, or had its rows replaced, since the build?
|
|
@@ -650,6 +691,24 @@ declare class Physics3D {
|
|
|
650
691
|
private syncScatters;
|
|
651
692
|
private syncBodies;
|
|
652
693
|
/**
|
|
694
|
+
* The stamp an auto body is compared against, reused across every body and
|
|
695
|
+
* step: the walk writes here instead of returning an object, because it runs
|
|
696
|
+
* once per auto body per step and a village of crates must not allocate.
|
|
697
|
+
*/
|
|
698
|
+
private readonly stamp;
|
|
699
|
+
/** An auto body whose carried mesh (or mounted model) is not what it was built from. */
|
|
700
|
+
private autoReshaped;
|
|
701
|
+
private rememberAutoShape;
|
|
702
|
+
/**
|
|
703
|
+
* The same choice `meshesUnder` makes — the FIRST carried mesh in tree
|
|
704
|
+
* order, else the first mounted model — reduced to the numbers the collider
|
|
705
|
+
* was built from, so a change in any of them is visible without a rebuild.
|
|
706
|
+
*/
|
|
707
|
+
private stampAutoShape;
|
|
708
|
+
private walkAutoShape;
|
|
709
|
+
/** A heightfield body whose Terrain3D regenerated its grid since the build. */
|
|
710
|
+
private heightfieldReshaped;
|
|
711
|
+
/**
|
|
653
712
|
* Null while a `{"shape":"auto"}` body is waiting on its model — the shape
|
|
654
713
|
* lives in the model's triangles, and there is nothing honest to guess in the
|
|
655
714
|
* meantime. syncBodies runs every step, so the body appears the moment the
|
|
@@ -676,6 +735,10 @@ declare class Physics3D {
|
|
|
676
735
|
*/
|
|
677
736
|
/** Drop one node from the overlap map, both as a key and as a member. */
|
|
678
737
|
private forgetOverlaps;
|
|
738
|
+
/** Every overlap `node` is in ends now — the exits Rapier does not send for a disabled collider. */
|
|
739
|
+
private releaseOverlaps;
|
|
740
|
+
/** Every body the armed sensor is inside of RIGHT NOW enters it — the starts Rapier does not send for a re-enabled collider. */
|
|
741
|
+
private armOverlaps;
|
|
679
742
|
private pruneOverlaps;
|
|
680
743
|
/**
|
|
681
744
|
* The bodies currently overlapping `node` — the standing answer behind
|
|
@@ -1424,12 +1487,8 @@ declare class Camera3D extends Node3D {
|
|
|
1424
1487
|
current: boolean;
|
|
1425
1488
|
lookAt: string;
|
|
1426
1489
|
/**
|
|
1427
|
-
* Aim, every frame, whenever `lookAt` names something
|
|
1428
|
-
*
|
|
1429
|
-
* In `update` and not `_syncObject3D`: the second is the renderer's copy pass
|
|
1430
|
-
* and a static node is pruned from it, which silently freezes anything driven
|
|
1431
|
-
* there. `rotation` is written as an ordinary prop, so the editor, the
|
|
1432
|
-
* serializer and `describeFraming` all see what the camera is actually doing.
|
|
1490
|
+
* Aim, every frame, whenever `lookAt` names something — see `aimAt`, which
|
|
1491
|
+
* the spot light shares.
|
|
1433
1492
|
*/
|
|
1434
1493
|
/** The `lookAt` path already reported as unlookable — cleared by a new one. */
|
|
1435
1494
|
private warnedLookAt;
|
|
@@ -1470,6 +1529,17 @@ declare class CharacterController3D extends Node3D {
|
|
|
1470
1529
|
jumpCutMultiplier: number;
|
|
1471
1530
|
maxJumps: number;
|
|
1472
1531
|
airControl: number;
|
|
1532
|
+
/**
|
|
1533
|
+
* `[away, up]` m/s: airborne and pressing into a wall, `jump` kicks off it —
|
|
1534
|
+
* away along the wall's normal, up. `[0, 0]` (default) = no wall-jumps.
|
|
1535
|
+
* The controller owns this because a kick written from outside lasted three
|
|
1536
|
+
* frames: the jump cut halved its rise on release and air control steered
|
|
1537
|
+
* the horizontal straight back into the wall. After a kick, air control
|
|
1538
|
+
* stands down for `WALL_LOCKOUT` so the kick lands.
|
|
1539
|
+
*/
|
|
1540
|
+
wallJumpImpulse: number[];
|
|
1541
|
+
/** Max fall speed (m/s) while pressing into a wall; 0 = no wall slide. */
|
|
1542
|
+
wallSlideSpeed: number;
|
|
1473
1543
|
fallGravity: number;
|
|
1474
1544
|
floatHeight: number;
|
|
1475
1545
|
/**
|
|
@@ -1568,6 +1638,10 @@ declare class CharacterController3D extends Node3D {
|
|
|
1568
1638
|
private rising;
|
|
1569
1639
|
/** Between the jump impulse and the landing — the animation's clock. */
|
|
1570
1640
|
private jumping;
|
|
1641
|
+
/** Seconds of air control still suppressed after a wall kick. */
|
|
1642
|
+
private wallLockout;
|
|
1643
|
+
/** The outward normal of the wall being pressed into this step, if any. */
|
|
1644
|
+
private wallNormal;
|
|
1571
1645
|
private get body();
|
|
1572
1646
|
override onEnterTree(): void;
|
|
1573
1647
|
override fixedUpdate(dt: number): void;
|
|
@@ -2169,6 +2243,44 @@ declare class OmniLight3D extends Node3D {
|
|
|
2169
2243
|
protected override _createObject3D(): Object3D;
|
|
2170
2244
|
override _syncObject3D(): void;
|
|
2171
2245
|
}
|
|
2246
|
+
/**
|
|
2247
|
+
* A cone of light — a flashlight, a searchlight, a car's headlights, a stage
|
|
2248
|
+
* spot, a guard's torch.
|
|
2249
|
+
*
|
|
2250
|
+
* It AIMS down the node's local −Z, exactly like a camera: at rest it points
|
|
2251
|
+
* along −Z, `rotation: [-90, 0, 0]` points it at the floor, and a headlamp
|
|
2252
|
+
* mounted on a +Z-forward skin wants `rotation: [0, 180, 0]`. `coneDeg` is the
|
|
2253
|
+
* FULL angle of the cone (a "30° beam" is 30), converted to three's half-angle
|
|
2254
|
+
* here so nobody has to halve it by hand. `intensity` is in the same physical
|
|
2255
|
+
* units as `OmniLight3D` — tens, not ones. Shadows are a perspective map from
|
|
2256
|
+
* the cone's apex, so `castShadow` costs one extra render per frame per light.
|
|
2257
|
+
*/
|
|
2258
|
+
declare class SpotLight3D extends Node3D {
|
|
2259
|
+
static override readonly typeName: string;
|
|
2260
|
+
static override readonly props: PropSchema;
|
|
2261
|
+
color: string;
|
|
2262
|
+
intensity: number;
|
|
2263
|
+
/** 0 = unlimited (three `distance` semantics). */
|
|
2264
|
+
range: number;
|
|
2265
|
+
/** Full cone angle in degrees, exclusive of 0 and 180. */
|
|
2266
|
+
coneDeg: number;
|
|
2267
|
+
/** 0 = hard edge, 1 = the whole cone is falloff. */
|
|
2268
|
+
penumbra: number;
|
|
2269
|
+
castShadow: boolean;
|
|
2270
|
+
shadowMapSize: number;
|
|
2271
|
+
/**
|
|
2272
|
+
* A node path to AIM at, every frame — the camera's prop, for the same
|
|
2273
|
+
* reason: a searchlight that tracks the player, a stage spot on the boss.
|
|
2274
|
+
* Aiming by hand is Euler arithmetic in XYZ order, where a yaw on the same
|
|
2275
|
+
* node as a pitch swings the cone sideways (at yaw 180 a −55° pitch points
|
|
2276
|
+
* UP). Empty = the authored `rotation` is the aim.
|
|
2277
|
+
*/
|
|
2278
|
+
lookAt: string;
|
|
2279
|
+
private warnedLookAt;
|
|
2280
|
+
override update(_dt: number): void;
|
|
2281
|
+
protected override _createObject3D(): Object3D;
|
|
2282
|
+
override _syncObject3D(): void;
|
|
2283
|
+
}
|
|
2172
2284
|
//#endregion
|
|
2173
2285
|
//#region src/3d/nodes/loft-mesh-3d.d.ts
|
|
2174
2286
|
/**
|
|
@@ -3395,9 +3507,19 @@ declare class VoxelGrid3D extends Node3D {
|
|
|
3395
3507
|
* hard-fails at load; this one silently truncated.
|
|
3396
3508
|
*/
|
|
3397
3509
|
static validateJson(node: Node): void;
|
|
3398
|
-
|
|
3399
|
-
|
|
3400
|
-
|
|
3510
|
+
private _voxels;
|
|
3511
|
+
/**
|
|
3512
|
+
* JSON-authored blocks as [x, y, z, tile] tuples (generated terrains bake
|
|
3513
|
+
* these). The seed lands WHEN THE PROP DOES — at load, before the tree
|
|
3514
|
+
* readies — not on the first `update()` as it used to: a sibling that
|
|
3515
|
+
* builds chunk colliders from `blocks()` at ready (the minecraft template's
|
|
3516
|
+
* Builder) saw an empty map and a baked hut was walked through, and the
|
|
3517
|
+
* late `setBlocks` then WIPED whatever a generator had built at ready.
|
|
3518
|
+
* Now a generator calling `setBlocks` after load is the author replacing
|
|
3519
|
+
* the seed, never the seed replacing the author.
|
|
3520
|
+
*/
|
|
3521
|
+
get voxels(): number[][];
|
|
3522
|
+
set voxels(rows: number[][]);
|
|
3401
3523
|
/** Said once per node: a runtime overflow must not spam a frame loop. */
|
|
3402
3524
|
private reportedOverflow;
|
|
3403
3525
|
private readonly map;
|
|
@@ -4278,4 +4400,4 @@ declare function createNavDebugNode(nav: TerrainNav, opts?: {
|
|
|
4278
4400
|
name?: string;
|
|
4279
4401
|
}): InstancedMesh3D;
|
|
4280
4402
|
//#endregion
|
|
4281
|
-
export { Area3D, AssetStore3D, type BedSampler, Billboard3D, type BillboardGroupMode, BoneAttachment3D, BoneLookAt3D, Camera3D, CharacterBody3D, CharacterController3D, type CreateGame3DOptions, DEFAULT_TERRAIN_TEXTURE_BASE, DirectionalLight3D, type DownhillTraceOptions, Environment3D, type Environment3DConfig, DENSITY_PRESETS as FLOWER_DENSITY_PRESETS, FLOWER_VARIETIES, type FlowerVariety, Flowers3D, type FogEnvironment, Foliage3D, type FoliageKind, type FoliageStyle, type FrameDiff, type FrameSignature, type FrameStats, type FrameStatsOptions, type Game3D, type GridCell, type HeightSampler, type Heightmap, type HeightmapOptions, InstancedMesh3D, Joint3D, type JointType3D, LoftMesh3D, type LoftSection, MeshInstance3D, type MeshKind, type MeshMaterialProps, type ModelEntry, type ModelFacts, ModelInstance3D, type ModelVerdict, Node3D, OmniLight3D, Particles3D, Physics3D, type Physics3DOptions, PhysicsBody3D, QUARTER_PITCH, type RenderContext3D, type RenderHook3D, Renderer3D, type Renderer3DOptions, type Rig, type RigView, RigidBody3D, type Ripple, River3D, type RiverCarveOptions, type RiverCoverageGap, type RiverHit, type RiverRing, type RiverRingOptions, SIGNATURE_GRID, type SceneJson, type ShadowsEnvironment, type SkyEnvironment, StaticBody3D, type SunConsumer3D, type SyncOptions, type SyncResult, TERRAIN_THEMES, Terrain3D, type TerrainLayer, type TerrainNav, type TerrainNavOptions, type TerrainTheme, TextureCache3D, type TextureSpec, Trail3D, Tree3D, type TreeTier, type TreeType, VOXEL_PALETTE, type VoxelBlock, VoxelGrid3D, WATER_CUTOUT_MAX, WATER_MAX_RIPPLES, Water3D, WaterCutout3D, acquireOwnTexture, acquireTexture, applyQualityTier3D, buildHeightmap, buildRiverRings, buildTerrainNav, cameraRelative, createGame3D, createNavDebugNode, diffSignatures, diffText, enablePhysics3D, findRiverCoverageGaps, frameSignature, frameStats, frameText, horizonColorFromSky, isWebGLAvailable, keyboardIntensity, modelVerdict, movementState, parseEnvironment3D, projectToRiver, registerNodes3D, resolveFlowerDensity, rigPose, riverCarveChannels, riverStepFor, setEnvironment3D, showBootFailure, smoothCourse, splatWeights, sunDirectionFromElevationAzimuth, sunDirectionFromSky, syncTree, terrainThemeLayers, traceDownhillPath, verdictText };
|
|
4403
|
+
export { Area3D, AssetStore3D, type BedSampler, Billboard3D, type BillboardGroupMode, BoneAttachment3D, BoneLookAt3D, Camera3D, CharacterBody3D, CharacterController3D, type CreateGame3DOptions, DEFAULT_TERRAIN_TEXTURE_BASE, DirectionalLight3D, type DownhillTraceOptions, Environment3D, type Environment3DConfig, DENSITY_PRESETS as FLOWER_DENSITY_PRESETS, FLOWER_VARIETIES, type FlowerVariety, Flowers3D, type FogEnvironment, Foliage3D, type FoliageKind, type FoliageStyle, type FrameDiff, type FrameSignature, type FrameStats, type FrameStatsOptions, type Game3D, type GridCell, type HeightSampler, type Heightmap, type HeightmapOptions, InstancedMesh3D, Joint3D, type JointType3D, LoftMesh3D, type LoftSection, MeshInstance3D, type MeshKind, type MeshMaterialProps, type ModelEntry, type ModelFacts, ModelInstance3D, type ModelVerdict, Node3D, OmniLight3D, Particles3D, Physics3D, type Physics3DOptions, PhysicsBody3D, QUARTER_PITCH, type RenderContext3D, type RenderHook3D, Renderer3D, type Renderer3DOptions, type Rig, type RigView, RigidBody3D, type Ripple, River3D, type RiverCarveOptions, type RiverCoverageGap, type RiverHit, type RiverRing, type RiverRingOptions, SIGNATURE_GRID, type SceneJson, type ShadowsEnvironment, type SkyEnvironment, SpotLight3D, StaticBody3D, type SunConsumer3D, type SyncOptions, type SyncResult, TERRAIN_THEMES, Terrain3D, type TerrainLayer, type TerrainNav, type TerrainNavOptions, type TerrainTheme, TextureCache3D, type TextureSpec, Trail3D, Tree3D, type TreeTier, type TreeType, VOXEL_PALETTE, type VoxelBlock, VoxelGrid3D, WATER_CUTOUT_MAX, WATER_MAX_RIPPLES, Water3D, WaterCutout3D, acquireOwnTexture, acquireTexture, applyQualityTier3D, buildHeightmap, buildRiverRings, buildTerrainNav, cameraRelative, createGame3D, createNavDebugNode, diffSignatures, diffText, enablePhysics3D, findRiverCoverageGaps, frameSignature, frameStats, frameText, horizonColorFromSky, isWebGLAvailable, keyboardIntensity, modelVerdict, movementState, parseEnvironment3D, projectToRiver, registerNodes3D, resolveFlowerDensity, rigPose, riverCarveChannels, riverStepFor, setEnvironment3D, showBootFailure, smoothCourse, splatWeights, sunDirectionFromElevationAzimuth, sunDirectionFromSky, syncTree, terrainThemeLayers, traceDownhillPath, verdictText };
|