incanto 0.66.0 → 0.67.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 +87 -0
- package/bin/incanto-editor.mjs +39 -2
- package/bin/incanto-feel.mjs +4 -1
- package/bin/incanto-frame.mjs +52 -3
- package/bin/incanto-logs.mjs +33 -3
- package/bin/incanto-multiplay.mjs +50 -1
- package/bin/incanto-play.mjs +3 -1
- package/bin/incanto-playtest.mjs +3 -25
- package/bin/incanto-verify.mjs +15 -2
- package/dist/2d.d.ts +41 -4
- package/dist/2d.js +3 -3
- package/dist/3d.d.ts +86 -14
- package/dist/3d.js +6 -6
- package/dist/{audio-player-_UAcHxnC.d.ts → audio-player-BNUHo0JF.d.ts} +1 -1
- package/dist/{behavior-BXNLfIJk.d.ts → behavior-ZnfzKDo3.d.ts} +39 -1
- package/dist/{create-game-Dd7H4bJV.js → create-game-DMetd3vR.js} +14 -8
- package/dist/{create-game-DYJCIzO0.js → create-game-FAXdHta3.js} +77 -11
- package/dist/debug.d.ts +1 -1
- package/dist/debug.js +3 -2
- package/dist/{duplicate-CqSAtdrh.js → duplicate-B8QnX2-r.js} +1 -1
- package/dist/editor.js +7 -2
- package/dist/{environment-presets-BlPsEmq6.js → environment-presets-C-5g2pMh.js} +46 -6
- package/dist/{gameplay-D1RADWu3.js → gameplay-CGSv-9XR.js} +28 -5
- package/dist/gameplay.d.ts +25 -4
- package/dist/gameplay.js +1 -1
- package/dist/index.d.ts +50 -6
- package/dist/index.js +7 -6
- package/dist/{loader-Cga7FVP4.d.ts → loader-DyT30ArB.d.ts} +1 -1
- package/dist/{loader-lQDCwNag.js → loader-KZESOZmE.js} +148 -1
- package/dist/net.d.ts +2 -2
- package/dist/net.js +1 -1
- package/dist/{physics-2d-Cji5A6sX.js → physics-2d-_B6zj3zU.js} +29 -2
- package/dist/{physics-3d-BkHjwJgI.js → physics-3d-i1IeAY0F.js} +30 -3
- package/dist/react.d.ts +1 -1
- package/dist/react.js +1 -1
- package/dist/{register-BmuqYTiY.js → register-Cs53CY7s.js} +81 -16
- package/dist/{register-D0CxCveZ.js → register-vIxU3Xbv.js} +3 -3
- package/dist/rendering-options-ByAdi8PF.js +184 -0
- package/dist/{replay-IsZbNu6d.js → replay-BkpDV51O.js} +4 -3
- package/dist/{replay-BHoB6fCU.d.ts → replay-D0GcEHYU.d.ts} +1 -1
- package/dist/{split-screen-eJUFjhi1.d.ts → split-screen-DD5eYIgW.d.ts} +2 -2
- package/dist/{split-screen-D_i7GRcY.js → split-screen-DS8RaUV_.js} +2 -2
- package/dist/{src-BTLbXFPZ.js → src-BLlsGJW9.js} +1 -1
- package/dist/{teardown-byR9USax.js → teardown-LB9cTnXJ.js} +2 -2
- package/dist/{test-DgrD0jHD.js → test-81uZ967a.js} +127 -24
- package/dist/test.d.ts +7 -5
- package/dist/test.js +2 -2
- package/dist/{touch-DESwnpOc.js → touch-DEAmqGdf.js} +30 -186
- package/dist/vite.d.ts +0 -7
- package/dist/vite.js +13 -3
- package/editor/assets/{agent8-9N-Pd_YS.js → agent8-C2jtNKbx.js} +1 -1
- package/editor/assets/debug-DoU3KeqS.js +3 -0
- package/editor/assets/{index-CeDhIPTC.js → index-CNqHojcC.js} +92 -92
- package/editor/index.html +1 -1
- package/package.json +1 -1
- package/schemas/scene.schema.json +1 -1
- package/skills/incanto-building-3d-games.md +19 -0
- package/skills/incanto-editor.md +5 -1
- package/skills/incanto-environment.md +2 -2
- package/skills/incanto-gameplay-behaviors.md +1 -1
- package/skills/incanto-hud.md +14 -1
- package/skills/incanto-multiplayer.md +14 -0
- package/skills/incanto-node-reference.md +1 -1
- package/skills/incanto-performance.md +35 -0
- package/skills/incanto-playtesting.md +15 -1
- package/skills/incanto-save-slots.md +21 -1
- package/skills/incanto-verifying-your-game.md +19 -0
- package/skills/incanto-your-first-game.md +4 -4
- package/templates-app/beacon-isle-3d/package.json +1 -1
- package/templates-app/beacon-isle-3d/src/game.scene.json +38 -19
- package/templates-app/platformer-2d/package.json +1 -1
- package/templates-app/platformer-2d/src/game.scene.json +99 -53
- package/templates-app/star-survivor/package.json +1 -1
- package/templates-app/star-survivor/src/game.scene.json +31 -17
- package/templates-app/tps-3d/package.json +1 -1
- package/templates-app/tps-3d/src/game.scene.json +14 -8
- package/templates-app/village-quest-3d/package.json +1 -1
- package/templates-app/village-quest-3d/src/grove.scene.json +20 -11
- package/templates-app/village-quest-3d/src/village.scene.json +10 -7
- package/editor/assets/debug-CkbJICYp.js +0 -3
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { O as Node, P as Behavior, _ as SaveSlots, k as diagnose, n as loadScene, w as effectiveOrder, z as registerBehavior } from "./loader-
|
|
1
|
+
import { O as Node, P as Behavior, _ as SaveSlots, k as diagnose, n as loadScene, w as effectiveOrder, z as registerBehavior } from "./loader-KZESOZmE.js";
|
|
2
2
|
import { t as IncantoError } from "./errors-BpWbnbb_.js";
|
|
3
3
|
import { t as jsonClone } from "./json-CwwhxQgb.js";
|
|
4
|
-
import { t as duplicateNode } from "./duplicate-
|
|
4
|
+
import { t as duplicateNode } from "./duplicate-B8QnX2-r.js";
|
|
5
5
|
import { Color, CubeCamera, DepthTexture, DoubleSide, Euler, FloatType, Frustum, HalfFloatType, LinearMipmapLinearFilter, MathUtils, Matrix4, Mesh, MeshDepthMaterial, Object3D, PerspectiveCamera, Plane, PlaneGeometry, Quaternion, ShaderMaterial, Sphere, Vector2, Vector3, Vector4, WebGLCubeRenderTarget, WebGLRenderTarget } from "three";
|
|
6
6
|
//#region src/3d/frustum.ts
|
|
7
7
|
const scratchFrustum = new Frustum();
|
|
@@ -5016,11 +5016,19 @@ var Health = class extends Behavior {
|
|
|
5016
5016
|
* unlosable. Every checker was green on it, and `incanto-playtest` even
|
|
5017
5017
|
* reported `lost in 19/20` because a single `died` reads as a loss.
|
|
5018
5018
|
*
|
|
5019
|
-
* Wire
|
|
5019
|
+
* **Wire `reviveFull`, not this, to `lifeLost`.** `ScoreKeeper.loseLife()`
|
|
5020
|
+
* emits `lifeLost` WITH the remaining life count, and this method's first
|
|
5021
|
+
* parameter is the HP to come back at — so the documented recipe revived at
|
|
5022
|
+
* 2 HP, then 1, then 0, and nothing warned (the wire-arity guard fires only
|
|
5023
|
+
* when a handler is UNDER-fed, and `hp` is optional):
|
|
5020
5024
|
*
|
|
5021
|
-
* ```json
|
|
5022
|
-
* { "signal": "lifeLost", "from": "Score", "to": "Player", "handler": "revive" }
|
|
5023
5025
|
* ```
|
|
5026
|
+
* death 1: lives=2 hp=2
|
|
5027
|
+
* death 2: lives=1 hp=1
|
|
5028
|
+
* death 3: lives=0 hp=0 dead=false <- alive at zero HP
|
|
5029
|
+
* ```
|
|
5030
|
+
*
|
|
5031
|
+
* Reach for `revive(hp)` when your game genuinely wants a partial comeback.
|
|
5024
5032
|
*
|
|
5025
5033
|
* A no-op on the living — reviving someone who never died would silently
|
|
5026
5034
|
* refill their health, which is a different feature and not this one.
|
|
@@ -5033,6 +5041,21 @@ var Health = class extends Behavior {
|
|
|
5033
5041
|
this.invulnTimer = this.invulnerableFor;
|
|
5034
5042
|
this.emit("revived", this.current);
|
|
5035
5043
|
}
|
|
5044
|
+
/**
|
|
5045
|
+
* Bring a dead one back at FULL health — the handler a life-lost wire wants.
|
|
5046
|
+
*
|
|
5047
|
+
* It exists because `revive` takes an optional `hp` and `lifeLost` carries the
|
|
5048
|
+
* life count, so wiring the two silently made "you have 2 lives left" mean
|
|
5049
|
+
* "come back at 2 HP". This takes no arguments, so no signal's payload can
|
|
5050
|
+
* ever change what it means.
|
|
5051
|
+
*
|
|
5052
|
+
* ```json
|
|
5053
|
+
* { "signal": "lifeLost", "from": "Score", "to": "Player", "handler": "reviveFull" }
|
|
5054
|
+
* ```
|
|
5055
|
+
*/
|
|
5056
|
+
reviveFull() {
|
|
5057
|
+
this.revive();
|
|
5058
|
+
}
|
|
5036
5059
|
/** Drop to 0 and die immediately (ignores i-frames). */
|
|
5037
5060
|
kill() {
|
|
5038
5061
|
if (this.dead) return;
|
package/dist/gameplay.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { b as Engine, d as PropSchema, jt as Node, n as BehaviorCtor, t as Behavior } from "./behavior-
|
|
1
|
+
import { b as Engine, d as PropSchema, jt as Node, n as BehaviorCtor, t as Behavior } from "./behavior-ZnfzKDo3.js";
|
|
2
2
|
import { c as JsonValue, s as JsonObject } from "./schema-CFeioQRE.js";
|
|
3
3
|
|
|
4
4
|
//#region src/gameplay/chase.d.ts
|
|
@@ -143,16 +143,37 @@ declare class Health extends Behavior {
|
|
|
143
143
|
* unlosable. Every checker was green on it, and `incanto-playtest` even
|
|
144
144
|
* reported `lost in 19/20` because a single `died` reads as a loss.
|
|
145
145
|
*
|
|
146
|
-
* Wire
|
|
146
|
+
* **Wire `reviveFull`, not this, to `lifeLost`.** `ScoreKeeper.loseLife()`
|
|
147
|
+
* emits `lifeLost` WITH the remaining life count, and this method's first
|
|
148
|
+
* parameter is the HP to come back at — so the documented recipe revived at
|
|
149
|
+
* 2 HP, then 1, then 0, and nothing warned (the wire-arity guard fires only
|
|
150
|
+
* when a handler is UNDER-fed, and `hp` is optional):
|
|
147
151
|
*
|
|
148
|
-
* ```json
|
|
149
|
-
* { "signal": "lifeLost", "from": "Score", "to": "Player", "handler": "revive" }
|
|
150
152
|
* ```
|
|
153
|
+
* death 1: lives=2 hp=2
|
|
154
|
+
* death 2: lives=1 hp=1
|
|
155
|
+
* death 3: lives=0 hp=0 dead=false <- alive at zero HP
|
|
156
|
+
* ```
|
|
157
|
+
*
|
|
158
|
+
* Reach for `revive(hp)` when your game genuinely wants a partial comeback.
|
|
151
159
|
*
|
|
152
160
|
* A no-op on the living — reviving someone who never died would silently
|
|
153
161
|
* refill their health, which is a different feature and not this one.
|
|
154
162
|
*/
|
|
155
163
|
revive(hp?: number): void;
|
|
164
|
+
/**
|
|
165
|
+
* Bring a dead one back at FULL health — the handler a life-lost wire wants.
|
|
166
|
+
*
|
|
167
|
+
* It exists because `revive` takes an optional `hp` and `lifeLost` carries the
|
|
168
|
+
* life count, so wiring the two silently made "you have 2 lives left" mean
|
|
169
|
+
* "come back at 2 HP". This takes no arguments, so no signal's payload can
|
|
170
|
+
* ever change what it means.
|
|
171
|
+
*
|
|
172
|
+
* ```json
|
|
173
|
+
* { "signal": "lifeLost", "from": "Score", "to": "Player", "handler": "reviveFull" }
|
|
174
|
+
* ```
|
|
175
|
+
*/
|
|
176
|
+
reviveFull(): void;
|
|
156
177
|
/** Drop to 0 and die immediately (ignores i-frames). */
|
|
157
178
|
kill(): void;
|
|
158
179
|
/**
|
package/dist/gameplay.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { A as DamageOnContact, C as restartScene, D as FaceTarget, E as FloatAway, M as Currency, N as Collector, O as DayNight, P as Chase, S as goToScene, T as FollowCamera, _ as Cooldown, a as Wander, b as Interactable, c as SavePoint, d as Patrol, f as PathFollow, g as CameraShake, h as Lifetime, i as WaveSpawner, j as Health, k as phaseOf, l as Projectile, m as MoveTo, n as registerGameplayBehaviors, o as Spawner, p as Oscillate, r as ZombieAI, s as ScoreKeeper, t as GAMEPLAY_BEHAVIORS, u as Pickup, v as hitStop, x as GameFlow, y as screenFlash } from "./gameplay-
|
|
1
|
+
import { A as DamageOnContact, C as restartScene, D as FaceTarget, E as FloatAway, M as Currency, N as Collector, O as DayNight, P as Chase, S as goToScene, T as FollowCamera, _ as Cooldown, a as Wander, b as Interactable, c as SavePoint, d as Patrol, f as PathFollow, g as CameraShake, h as Lifetime, i as WaveSpawner, j as Health, k as phaseOf, l as Projectile, m as MoveTo, n as registerGameplayBehaviors, o as Spawner, p as Oscillate, r as ZombieAI, s as ScoreKeeper, t as GAMEPLAY_BEHAVIORS, u as Pickup, v as hitStop, x as GameFlow, y as screenFlash } from "./gameplay-CGSv-9XR.js";
|
|
2
2
|
export { CameraShake, Chase, Collector, Cooldown, Currency, DamageOnContact, DayNight, FaceTarget, FloatAway, FollowCamera, GAMEPLAY_BEHAVIORS, GameFlow, Health, Interactable, Lifetime, MoveTo, Oscillate, PathFollow, Patrol, Pickup, Projectile, SavePoint, ScoreKeeper, Spawner, Wander, WaveSpawner, ZombieAI, goToScene, hitStop, phaseOf, registerGameplayBehaviors, restartScene, screenFlash };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { $ as T_PREFIX, A as SettingsValues, At as BusName, B as captureBehaviors, C as EngineStats, Ct as sfxDuration, Dt as MusicTrack, E as DeviceHints, Et as MusicManager, F as BehaviorState, Ft as LogLevel, G as ORDER_GROUP_BASE, H as savesWithoutUid, I as RestoreReport, It as LogManager, J as effectiveOrder, K as OrderGroup, L as SaveSlot, Lt as Signal, M as readDeviceHints, Mt as NodeLifecycle, N as suggestQuality, Nt as SceneTree, O as QualityTier, Ot as PlayMusicOptions, P as Scene, Pt as LogEntry, Q as Localization, R as SaveSlots, Rt as SignalListener, S as Scheduler, St as SynthOptions, T as RendererStats, Tt as MusicBackend, U as SaveStore, V as restoreBehaviors, W as createSaveStore, X as BASE_LOCALE, Y as resolveOrderGroups, Z as LocaleTables, _ as mergeStaticSignals, _t as spatialPan, a as clearBehaviors, at as EffectLog, b as Engine, bt as SfxParams, c as registeredBehaviors, ct as isAudioContextAvailable, d as PropSchema, dt as Listener, et as suggestLocale, f as clearRegistry, ft as ROLLOFF_MODELS, g as getNodeType, gt as spatialGain, h as getNodeSignals, ht as Vec3, i as behaviorSignals, it as EffectKind, j as qualityEnvironment, jt as Node, k as Settings, kt as AudioBuses, l as NodeCtor, lt as Voice, m as getNodeSchema, mt as SpatialParams, n as BehaviorCtor, nt as InputMap, o as getBehavior, ot as SfxEngine, p as createNode, pt as RolloffModel, q as OrderGroupTable, r as behaviorSchema, rt as EffectEvent, s as registerBehavior, st as SfxPlayOptions, t as Behavior, tt as translationKey, u as PropDef, ut as VoicePreset, v as registerNode, vt as SFX_PRESETS, w as GameStats, wt as synthSfx, x as EngineOptions, xt as SfxWave, y as registeredTypes, yt as SFX_PRESET_NAMES, z as behaviorsWithoutSave } from "./behavior-
|
|
1
|
+
import { $ as T_PREFIX, A as SettingsValues, At as BusName, B as captureBehaviors, C as EngineStats, Ct as sfxDuration, Dt as MusicTrack, E as DeviceHints, Et as MusicManager, F as BehaviorState, Ft as LogLevel, G as ORDER_GROUP_BASE, H as savesWithoutUid, I as RestoreReport, It as LogManager, J as effectiveOrder, K as OrderGroup, L as SaveSlot, Lt as Signal, M as readDeviceHints, Mt as NodeLifecycle, N as suggestQuality, Nt as SceneTree, O as QualityTier, Ot as PlayMusicOptions, P as Scene, Pt as LogEntry, Q as Localization, R as SaveSlots, Rt as SignalListener, S as Scheduler, St as SynthOptions, T as RendererStats, Tt as MusicBackend, U as SaveStore, V as restoreBehaviors, W as createSaveStore, X as BASE_LOCALE, Y as resolveOrderGroups, Z as LocaleTables, _ as mergeStaticSignals, _t as spatialPan, a as clearBehaviors, at as EffectLog, b as Engine, bt as SfxParams, c as registeredBehaviors, ct as isAudioContextAvailable, d as PropSchema, dt as Listener, et as suggestLocale, f as clearRegistry, ft as ROLLOFF_MODELS, g as getNodeType, gt as spatialGain, h as getNodeSignals, ht as Vec3, i as behaviorSignals, it as EffectKind, j as qualityEnvironment, jt as Node, k as Settings, kt as AudioBuses, l as NodeCtor, lt as Voice, m as getNodeSchema, mt as SpatialParams, n as BehaviorCtor, nt as InputMap, o as getBehavior, ot as SfxEngine, p as createNode, pt as RolloffModel, q as OrderGroupTable, r as behaviorSchema, rt as EffectEvent, s as registerBehavior, st as SfxPlayOptions, t as Behavior, tt as translationKey, u as PropDef, ut as VoicePreset, v as registerNode, vt as SFX_PRESETS, w as GameStats, wt as synthSfx, x as EngineOptions, xt as SfxWave, y as registeredTypes, yt as SFX_PRESET_NAMES, z as behaviorsWithoutSave } from "./behavior-ZnfzKDo3.js";
|
|
2
2
|
import { a as Rng, c as JsonValue, d as jsonKind, i as SceneJson, l as jsonClone, n as NodeJson, o as JsonKind, r as SCENE_FORMAT, s as JsonObject, t as ConnectionJson, u as jsonEquals } from "./schema-CFeioQRE.js";
|
|
3
|
-
import { n as loadScene, t as LoadSceneOptions } from "./loader-
|
|
3
|
+
import { n as loadScene, t as LoadSceneOptions } from "./loader-DyT30ArB.js";
|
|
4
4
|
import { i as resolveFrames, n as AnimationEntry, r as resolveAnimation, t as AnimationDef } from "./sprite-animation-CMr6f1K2.js";
|
|
5
|
-
import { a as ParticleSimConfig, i as ParticleSim, n as AudioPlayer, o as ParticleView, t as AudioElementLike } from "./audio-player-
|
|
5
|
+
import { a as ParticleSimConfig, i as ParticleSim, n as AudioPlayer, o as ParticleView, t as AudioElementLike } from "./audio-player-BNUHo0JF.js";
|
|
6
6
|
import { i as gridFromRows, n as PathGrid, r as findPath, t as FindPathOptions } from "./pathfinding-_fGrCFmH.js";
|
|
7
|
-
import { a as startRecording, c as IncantoErrorDetails, i as replay, l as auditScene, n as ReplayEvent, o as IncantoError, r as ReplayJson, s as IncantoErrorCode, t as Recorder } from "./replay-
|
|
7
|
+
import { a as startRecording, c as IncantoErrorDetails, i as replay, l as auditScene, n as ReplayEvent, o as IncantoError, r as ReplayJson, s as IncantoErrorCode, t as Recorder } from "./replay-D0GcEHYU.js";
|
|
8
8
|
|
|
9
9
|
//#region src/core/audio/crossfade.d.ts
|
|
10
10
|
/**
|
|
@@ -313,8 +313,24 @@ declare class HudLayer extends Node {
|
|
|
313
313
|
* play resumes.
|
|
314
314
|
*/
|
|
315
315
|
private stepFocus;
|
|
316
|
-
/**
|
|
317
|
-
|
|
316
|
+
/**
|
|
317
|
+
* Focusable widgets under this layer, in tree order — **on screen only**.
|
|
318
|
+
*
|
|
319
|
+
* This filtered on each widget's OWN `visible` and recursed into hidden
|
|
320
|
+
* containers anyway, so arrow-keys walked into closed panels and Enter really
|
|
321
|
+
* pressed what it found. Measured on a title screen: 23 focus stops, 21 of
|
|
322
|
+
* them under an ancestor with `visible = false`, and
|
|
323
|
+
*
|
|
324
|
+
* gold before = 150 -> Enter on the hidden Shop/Row0/Buy -> gold 120,
|
|
325
|
+
* screen still 'title'
|
|
326
|
+
*
|
|
327
|
+
* The layer's own visibility was not a gate either. It is now: a HUD nobody
|
|
328
|
+
* can see has no ring, and a subtree nobody can see is not walked.
|
|
329
|
+
*
|
|
330
|
+
* PUBLIC, because a game that wants to know what its ring contains could not
|
|
331
|
+
* ask — and "why is focus on that" is exactly the question this answers.
|
|
332
|
+
*/
|
|
333
|
+
focusables(): HudWidgetBase[];
|
|
318
334
|
/** Move focus to a widget by hand — opening a menu should start somewhere. */
|
|
319
335
|
focus(widget: HudWidgetBase | null): void;
|
|
320
336
|
/** @internal Widgets mount into per-anchor flex columns. */
|
|
@@ -377,6 +393,11 @@ declare abstract class HudWidgetBase extends Node {
|
|
|
377
393
|
private host;
|
|
378
394
|
override onExitTree(): void;
|
|
379
395
|
override update(_dt: number): void;
|
|
396
|
+
/**
|
|
397
|
+
* The display this widget's own css asks for while shown — `grid` for a grid
|
|
398
|
+
* panel, `flex` for a row, `''` for a widget that never says.
|
|
399
|
+
*/
|
|
400
|
+
private _shownDisplay;
|
|
380
401
|
/** Which anchor slot this widget was mounted into. */
|
|
381
402
|
private mountedAnchor;
|
|
382
403
|
/**
|
|
@@ -607,6 +628,29 @@ declare class UiDialogue extends HudWidgetBase {
|
|
|
607
628
|
/** Queue a line; optional `choices` renders buttons after the line types out. */
|
|
608
629
|
say(speaker: string, text: string, choices?: string[]): void;
|
|
609
630
|
/**
|
|
631
|
+
* A dialogue takes focus while it is up.
|
|
632
|
+
*
|
|
633
|
+
* It paints a focus ring and the generated reference advertises the prop, and
|
|
634
|
+
* it was inert: choices are raw DOM buttons inside the widget, so
|
|
635
|
+
* `HudLayer.focusables()` can never see them, and this class — unlike
|
|
636
|
+
* `UiButton` a hundred lines above it — never overrode `_activate`. Eleven
|
|
637
|
+
* keys and eight pad codes did nothing to a waiting choice while the same
|
|
638
|
+
* Enter pressed a sibling button. Native Tab worked, and is closed by any
|
|
639
|
+
* game that binds Tab; a pad has no Tab at all.
|
|
640
|
+
*/
|
|
641
|
+
override focusable: boolean;
|
|
642
|
+
/** Which choice the keyboard/pad is on. Reset by every new line. */
|
|
643
|
+
private cursor;
|
|
644
|
+
/**
|
|
645
|
+
* Enter / A, and left / right between the options.
|
|
646
|
+
*
|
|
647
|
+
* `dir` is 0 for "activate" and ±1 for a nudge, the same shape `UiSelect`
|
|
648
|
+
* uses — so one key layout drives a menu, a slider and a conversation.
|
|
649
|
+
*/
|
|
650
|
+
override _activate(dir: number): void;
|
|
651
|
+
/** Show which option the keyboard is on — a ring nobody can see is not one. */
|
|
652
|
+
private paintCursor;
|
|
653
|
+
/**
|
|
610
654
|
* Player pressed "next": mid-typing reveals the whole line; a fully-typed
|
|
611
655
|
* line without choices advances (choice lines wait for `choose`).
|
|
612
656
|
*/
|
package/dist/index.js
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import { A as describeRefProblem, B as registeredBehaviors, C as ORDER_GROUP_BASE, E as InputMap, F as behaviorSchema, I as behaviorSignals, L as clearBehaviors, M as resolveRefInJson, N as parseNodePath, O as Node, P as Behavior, R as getBehavior, S as createSaveStore, T as resolveOrderGroups, V as Signal, _ as SaveSlots, a as serializeNode, b as restoreBehaviors, d as computeViewport, f as resolveViewport, g as resolveConstants, h as isConstRef, i as Scene, j as nodeRefWarnings, m as CONST_REF_KEY, n as loadScene, o as SCENE_FORMAT, p as SceneTree, v as behaviorsWithoutSave, w as effectiveOrder, x as savesWithoutUid, y as captureBehaviors, z as registerBehavior } from "./loader-
|
|
2
|
-
import { A as UiBanner, B as isAudioContextAvailable, D as EffectLog, E as LogManager, F as T_PREFIX, G as SFX_PRESET_NAMES, H as spatialGain, I as suggestLocale, J as MusicManager, K as sfxDuration, M as UiText, N as BASE_LOCALE, O as HudLayer, P as Localization, Q as AudioBuses, R as translationKey, S as qualityEnvironment, T as suggestQuality, U as spatialPan, V as ROLLOFF_MODELS, W as SFX_PRESETS, X as crossfadeGains, Y as WebAudioMusicBackend, Z as fadeGain, _ as AudioPlayer, a as UiMuteToggle, b as Settings, c as UiRenderScaleSelect, d as UiToggle, f as UiVolumeSlider, g as UiDialogue, h as UiButton, i as UiLanguageSelect, j as UiBar, l as UiSelect, m as Respawn, n as UiFrameCapSelect, o as UiPanel, p as Timer, q as synthSfx, r as UiImage, s as UiQualitySelect, t as registerCoreNodes, u as UiSlider, v as Engine, w as readDeviceHints, z as SfxEngine } from "./register-
|
|
1
|
+
import { A as describeRefProblem, B as registeredBehaviors, C as ORDER_GROUP_BASE, E as InputMap, F as behaviorSchema, I as behaviorSignals, L as clearBehaviors, M as resolveRefInJson, N as parseNodePath, O as Node, P as Behavior, R as getBehavior, S as createSaveStore, T as resolveOrderGroups, V as Signal, _ as SaveSlots, a as serializeNode, b as restoreBehaviors, d as computeViewport, f as resolveViewport, g as resolveConstants, h as isConstRef, i as Scene, j as nodeRefWarnings, m as CONST_REF_KEY, n as loadScene, o as SCENE_FORMAT, p as SceneTree, v as behaviorsWithoutSave, w as effectiveOrder, x as savesWithoutUid, y as captureBehaviors, z as registerBehavior } from "./loader-KZESOZmE.js";
|
|
2
|
+
import { A as UiBanner, B as isAudioContextAvailable, D as EffectLog, E as LogManager, F as T_PREFIX, G as SFX_PRESET_NAMES, H as spatialGain, I as suggestLocale, J as MusicManager, K as sfxDuration, M as UiText, N as BASE_LOCALE, O as HudLayer, P as Localization, Q as AudioBuses, R as translationKey, S as qualityEnvironment, T as suggestQuality, U as spatialPan, V as ROLLOFF_MODELS, W as SFX_PRESETS, X as crossfadeGains, Y as WebAudioMusicBackend, Z as fadeGain, _ as AudioPlayer, a as UiMuteToggle, b as Settings, c as UiRenderScaleSelect, d as UiToggle, f as UiVolumeSlider, g as UiDialogue, h as UiButton, i as UiLanguageSelect, j as UiBar, l as UiSelect, m as Respawn, n as UiFrameCapSelect, o as UiPanel, p as Timer, q as synthSfx, r as UiImage, s as UiQualitySelect, t as registerCoreNodes, u as UiSlider, v as Engine, w as readDeviceHints, z as SfxEngine } from "./register-Cs53CY7s.js";
|
|
3
3
|
import { t as IncantoError } from "./errors-BpWbnbb_.js";
|
|
4
4
|
import { t as Rng } from "./rng-DP-SR7eg.js";
|
|
5
5
|
import { n as jsonEquals, r as jsonKind, t as jsonClone } from "./json-CwwhxQgb.js";
|
|
6
6
|
import { a as getNodeSignals, c as mergeStaticSignals, i as getNodeSchema, l as registerNode, n as clearRegistry, o as getNodeType, r as createNode, u as registeredTypes } from "./registry-CF70EArN.js";
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
7
|
+
import { i as joystickVector, n as attachTouchControls, t as TouchControls } from "./touch-DEAmqGdf.js";
|
|
8
|
+
import { n as startRecording, r as auditScene, t as replay } from "./replay-BkpDV51O.js";
|
|
9
|
+
import { i as parseDrive, n as logReport, r as logText, t as resolveRendering } from "./rendering-options-ByAdi8PF.js";
|
|
9
10
|
import { t as createNoise2D } from "./noise-CGUMx44x.js";
|
|
10
11
|
import { a as PARTICLE_PRESETS, i as ParticleSim, n as resolveFrames, o as PARTICLE_PRESET_NAMES, s as applyParticlePreset, t as resolveAnimation } from "./sprite-animation-CY-mrr1L.js";
|
|
11
|
-
import { a as preloadUrls, i as preloadSceneAssets, n as newUid, o as findPath, r as assetUrls, s as gridFromRows, t as VERSION } from "./src-
|
|
12
|
-
import { t as duplicateNode } from "./duplicate-
|
|
12
|
+
import { a as preloadUrls, i as preloadSceneAssets, n as newUid, o as findPath, r as assetUrls, s as gridFromRows, t as VERSION } from "./src-BLlsGJW9.js";
|
|
13
|
+
import { t as duplicateNode } from "./duplicate-B8QnX2-r.js";
|
|
13
14
|
export { AudioBuses, AudioPlayer, BASE_LOCALE, Behavior, CONST_REF_KEY, EffectLog, Engine, HudLayer, IncantoError, InputMap, Localization, LogManager, MusicManager, Node, ORDER_GROUP_BASE, PARTICLE_PRESETS, PARTICLE_PRESET_NAMES, ParticleSim, ROLLOFF_MODELS, Respawn, Rng, SCENE_FORMAT, SFX_PRESETS, SFX_PRESET_NAMES, SaveSlots, Scene, SceneTree, Settings, SfxEngine, Signal, T_PREFIX, Timer, TouchControls, UiBanner, UiBar, UiButton, UiDialogue, UiFrameCapSelect, UiImage, UiLanguageSelect, UiMuteToggle, UiPanel, UiQualitySelect, UiRenderScaleSelect, UiSelect, UiSlider, UiText, UiToggle, UiVolumeSlider, VERSION, WebAudioMusicBackend, applyParticlePreset, assetUrls, attachTouchControls, auditScene, behaviorSchema, behaviorSignals, behaviorsWithoutSave, captureBehaviors, clearBehaviors, clearRegistry, computeViewport, createNode, createNoise2D, createSaveStore, crossfadeGains, describeRefProblem, duplicateNode, effectiveOrder, fadeGain, findPath, getBehavior, getNodeSchema, getNodeSignals, getNodeType, gridFromRows, isAudioContextAvailable, isConstRef, joystickVector, jsonClone, jsonEquals, jsonKind, loadScene, logReport, logText, mergeStaticSignals, newUid, nodeRefWarnings, parseDrive, parseNodePath, preloadSceneAssets, preloadUrls, qualityEnvironment, readDeviceHints, registerBehavior, registerCoreNodes, registerNode, registeredBehaviors, registeredTypes, replay, resolveAnimation, resolveConstants, resolveFrames, resolveOrderGroups, resolveRefInJson, resolveRendering, resolveViewport, restoreBehaviors, savesWithoutUid, serializeNode, sfxDuration, spatialGain, spatialPan, startRecording, suggestLocale, suggestQuality, synthSfx, translationKey };
|
|
@@ -20,6 +20,17 @@ var Signal = class {
|
|
|
20
20
|
disconnectAll() {
|
|
21
21
|
this.connections.length = 0;
|
|
22
22
|
}
|
|
23
|
+
/**
|
|
24
|
+
* How many listeners are attached.
|
|
25
|
+
*
|
|
26
|
+
* A leak is a SLOPE, and a game had no way to see one: every check in this
|
|
27
|
+
* engine is a snapshot. A handler connected per frame and never disconnected,
|
|
28
|
+
* or a `once` that armed and never fired, accumulates invisibly and is
|
|
29
|
+
* perfectly healthy for the first thirty seconds of every playthrough.
|
|
30
|
+
*/
|
|
31
|
+
get count() {
|
|
32
|
+
return this.connections.length;
|
|
33
|
+
}
|
|
23
34
|
emit(...args) {
|
|
24
35
|
const snapshot = [...this.connections];
|
|
25
36
|
for (const conn of snapshot) {
|
|
@@ -652,6 +663,16 @@ var Node = class {
|
|
|
652
663
|
off(signal, fn) {
|
|
653
664
|
this._signals.get(signal)?.disconnect(fn);
|
|
654
665
|
}
|
|
666
|
+
/**
|
|
667
|
+
* How many listeners this node has on `signal` — 0 for one nobody watches.
|
|
668
|
+
*
|
|
669
|
+
* The engine's own leak test reads it, and so can a game: a handler connected
|
|
670
|
+
* every frame and never disconnected is invisible to every other check here,
|
|
671
|
+
* because every other check is a snapshot and a leak is a slope.
|
|
672
|
+
*/
|
|
673
|
+
listenerCount(signal) {
|
|
674
|
+
return this._signals.get(signal)?.count ?? 0;
|
|
675
|
+
}
|
|
655
676
|
emit(signal, ...args) {
|
|
656
677
|
this.assertDeclared(signal);
|
|
657
678
|
this._signals.get(signal)?.emit(...args);
|
|
@@ -1674,6 +1695,7 @@ const FREED_KEY = "#freed";
|
|
|
1674
1695
|
function captureBehaviors(root, source) {
|
|
1675
1696
|
const state = {};
|
|
1676
1697
|
const unaddressable = [];
|
|
1698
|
+
const unrecordable = [];
|
|
1677
1699
|
let saveable = 0;
|
|
1678
1700
|
const walk = (node) => {
|
|
1679
1701
|
const behavior = node.behavior;
|
|
@@ -1698,12 +1720,45 @@ function captureBehaviors(root, source) {
|
|
|
1698
1720
|
mark(root);
|
|
1699
1721
|
const freed = authoredUids(source).filter((uid) => !alive.has(uid));
|
|
1700
1722
|
if (freed.length > 0) state[FREED_KEY] = freed;
|
|
1723
|
+
unrecordable.push(...goneWithoutUid(source, root));
|
|
1701
1724
|
}
|
|
1702
1725
|
return {
|
|
1703
1726
|
state,
|
|
1704
1727
|
unaddressable,
|
|
1705
|
-
saveable
|
|
1728
|
+
saveable,
|
|
1729
|
+
unrecordable
|
|
1730
|
+
};
|
|
1731
|
+
}
|
|
1732
|
+
/**
|
|
1733
|
+
* Authored nodes this run CONSUMED that the ledger cannot record.
|
|
1734
|
+
*
|
|
1735
|
+
* `#freed` is authored uids minus alive uids, so a node with no uid can never
|
|
1736
|
+
* enter it — it is silently omitted, and on load it comes back. Every collected
|
|
1737
|
+
* coin in a scene without uids returns, while the score that counted it does
|
|
1738
|
+
* not, and nothing says a word.
|
|
1739
|
+
*
|
|
1740
|
+
* A uid is the only stable handle (it survives a rename and a reparent), so the
|
|
1741
|
+
* engine must not guess a replacement — a saved PATH would point at whatever
|
|
1742
|
+
* node moved into that slot after the next edit. What it can do is notice, by
|
|
1743
|
+
* walking the authored tree and asking the live one whether each node is still
|
|
1744
|
+
* there. Reported, not repaired.
|
|
1745
|
+
*/
|
|
1746
|
+
function goneWithoutUid(source, root) {
|
|
1747
|
+
const out = [];
|
|
1748
|
+
const walk = (node, path) => {
|
|
1749
|
+
if (typeof node !== "object" || node === null) return;
|
|
1750
|
+
const n = node;
|
|
1751
|
+
const name = typeof n.name === "string" ? n.name : "";
|
|
1752
|
+
const here = path === "" ? name : `${path}/${name}`;
|
|
1753
|
+
if (!(typeof n.uid === "string" && n.uid !== "") && here !== "" && path !== "") {
|
|
1754
|
+
const live = root.getNodeOrNull(here.slice(here.indexOf("/") + 1));
|
|
1755
|
+
const leaving = live ? live.tree?._isQueuedFree(live) ?? false : false;
|
|
1756
|
+
if (!live || leaving) out.push(here);
|
|
1757
|
+
}
|
|
1758
|
+
if (Array.isArray(n.children)) for (const child of n.children) walk(child, here);
|
|
1706
1759
|
};
|
|
1760
|
+
walk(source.root, "");
|
|
1761
|
+
return out;
|
|
1707
1762
|
}
|
|
1708
1763
|
/** Every uid the scene FILE declares, in document order. */
|
|
1709
1764
|
function authoredUids(source) {
|
|
@@ -3004,6 +3059,7 @@ function buildNodeJson(json, opts) {
|
|
|
3004
3059
|
return buildNode(json, opts, [], "", void 0);
|
|
3005
3060
|
}
|
|
3006
3061
|
function validateHeader(json) {
|
|
3062
|
+
rejectUnknownKeys(json, SCENE_KEYS, "the scene", "");
|
|
3007
3063
|
if (json.format !== 1) throw new IncantoError("BAD_FORMAT", `Unsupported scene format ${JSON.stringify(json.format)}; this engine reads format 1.`);
|
|
3008
3064
|
if (json.type !== "scene") throw new IncantoError("BAD_FORMAT", `Expected "type": "scene", got ${JSON.stringify(json.type)}.`);
|
|
3009
3065
|
if (typeof json.name !== "string" || json.name === "") throw new IncantoError("BAD_FORMAT", "Scene \"name\" must be a non-empty string.");
|
|
@@ -3042,9 +3098,100 @@ function withNodeContext(e, path, nj) {
|
|
|
3042
3098
|
});
|
|
3043
3099
|
return e;
|
|
3044
3100
|
}
|
|
3101
|
+
/**
|
|
3102
|
+
* Every key a node object may carry.
|
|
3103
|
+
*
|
|
3104
|
+
* The node object was an OPEN dictionary sitting between a dozen closed ones —
|
|
3105
|
+
* `props`, `environment`, `material`, `network` and the environment's own
|
|
3106
|
+
* sub-blocks all reject an unknown key with a did-you-mean. A node accepted
|
|
3107
|
+
* anything, and the one that costs an author a day is `connections`:
|
|
3108
|
+
*
|
|
3109
|
+
* ```jsonc
|
|
3110
|
+
* { "name": "Room", "type": "Node3D",
|
|
3111
|
+
* "connections": [ … ], // <- silently nothing
|
|
3112
|
+
* "children": [ … ] }
|
|
3113
|
+
* ```
|
|
3114
|
+
*
|
|
3115
|
+
* `wireConnections` is reached from the scene header and from a sub-scene's own
|
|
3116
|
+
* header, and NOTHING reads `nodeJson.connections`. Measured on two scenes
|
|
3117
|
+
* differing only in which brace the same wire sits inside:
|
|
3118
|
+
*
|
|
3119
|
+
* ```
|
|
3120
|
+
* inside Dst.n=0 validateScene.ok=true auditWarnings=0
|
|
3121
|
+
* beside Dst.n=1 validateScene.ok=true auditWarnings=0
|
|
3122
|
+
* none Dst.n=0 validateScene.ok=true auditWarnings=0
|
|
3123
|
+
* ```
|
|
3124
|
+
*
|
|
3125
|
+
* The misplaced wire is bit-for-bit indistinguishable from deleting it. A
|
|
3126
|
+
* builder moved 28 of them into `root`, got `1/1 scene(s) valid` with zero
|
|
3127
|
+
* warnings, and found out sixty seconds later from `incanto-playtest`.
|
|
3128
|
+
*/
|
|
3129
|
+
const NODE_KEYS = [
|
|
3130
|
+
"name",
|
|
3131
|
+
"uid",
|
|
3132
|
+
"type",
|
|
3133
|
+
"instance",
|
|
3134
|
+
"overrides",
|
|
3135
|
+
"groups",
|
|
3136
|
+
"tags",
|
|
3137
|
+
"props",
|
|
3138
|
+
"script",
|
|
3139
|
+
"network",
|
|
3140
|
+
"children"
|
|
3141
|
+
];
|
|
3142
|
+
/** Every key the scene HEADER may carry — closed for the same reason. */
|
|
3143
|
+
const SCENE_KEYS = [
|
|
3144
|
+
"format",
|
|
3145
|
+
"type",
|
|
3146
|
+
"name",
|
|
3147
|
+
"dimension",
|
|
3148
|
+
"viewport",
|
|
3149
|
+
"assets",
|
|
3150
|
+
"constants",
|
|
3151
|
+
"orderGroups",
|
|
3152
|
+
"input",
|
|
3153
|
+
"multiplayer",
|
|
3154
|
+
"environment",
|
|
3155
|
+
"strings",
|
|
3156
|
+
"physics",
|
|
3157
|
+
"root",
|
|
3158
|
+
"connections"
|
|
3159
|
+
];
|
|
3160
|
+
/** Closest known key by edit distance — only a genuinely близкая one. */
|
|
3161
|
+
function nearestKey(key, known) {
|
|
3162
|
+
const lower = key.toLowerCase();
|
|
3163
|
+
let best = null;
|
|
3164
|
+
let bestScore = 3;
|
|
3165
|
+
for (const candidate of known) {
|
|
3166
|
+
let d = 0;
|
|
3167
|
+
const a = lower;
|
|
3168
|
+
const b = candidate.toLowerCase();
|
|
3169
|
+
const rows = Array.from({ length: a.length + 1 }, (_, i) => [i, ...Array(b.length).fill(0)]);
|
|
3170
|
+
for (let j = 0; j <= b.length; j++) rows[0][j] = j;
|
|
3171
|
+
for (let i = 1; i <= a.length; i++) for (let j = 1; j <= b.length; j++) {
|
|
3172
|
+
const cost = a[i - 1] === b[j - 1] ? 0 : 1;
|
|
3173
|
+
rows[i][j] = Math.min(rows[i - 1][j] + 1, rows[i][j - 1] + 1, rows[i - 1][j - 1] + cost);
|
|
3174
|
+
}
|
|
3175
|
+
d = rows[a.length][b.length];
|
|
3176
|
+
if (d < bestScore) {
|
|
3177
|
+
bestScore = d;
|
|
3178
|
+
best = candidate;
|
|
3179
|
+
}
|
|
3180
|
+
}
|
|
3181
|
+
return best;
|
|
3182
|
+
}
|
|
3183
|
+
/** Reject a key the shape does not have, the way `props` already does. */
|
|
3184
|
+
function rejectUnknownKeys(obj, known, what, where) {
|
|
3185
|
+
for (const key of Object.keys(obj)) {
|
|
3186
|
+
if (known.includes(key)) continue;
|
|
3187
|
+
const guess = nearestKey(key, known);
|
|
3188
|
+
throw new IncantoError("BAD_FORMAT", `Unknown key "${key}" on ${what}${where ? ` '${where}'` : ""}.` + (guess ? ` Did you mean "${guess}"?` : "") + ` Valid keys: [${known.join(", ")}].` + (key === "connections" ? " Connections live on the SCENE, beside \"root\" — a node cannot carry them, and one placed here does exactly nothing." : ""), { validOptions: [...known] });
|
|
3189
|
+
}
|
|
3190
|
+
}
|
|
3045
3191
|
function buildNode(nj, opts, stack, parentPath, constants, bands = []) {
|
|
3046
3192
|
const path = `${parentPath}/${nj.name}`;
|
|
3047
3193
|
try {
|
|
3194
|
+
rejectUnknownKeys(nj, NODE_KEYS, "node", nj.name ?? "");
|
|
3048
3195
|
if (nj.instance !== void 0 && nj.type !== void 0) throw new IncantoError("BAD_FORMAT", `Node '${nj.name}' declares both "type" and "instance" — they are mutually exclusive.`);
|
|
3049
3196
|
if (nj.instance !== void 0) return buildInstance(nj, opts, stack, path, constants, bands);
|
|
3050
3197
|
if (nj.type === void 0) throw new IncantoError("BAD_FORMAT", `Node '${nj.name}' must declare either "type" or "instance".`);
|
package/dist/net.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { d as PropSchema, jt as Node } from "./behavior-
|
|
2
|
-
import { a as NetworkManagerOptions, c as LocalGameServer, d as ServerClass, f as createLocalGameServer, g as Unsubscribe, h as NetworkTransport, i as NetworkManager, l as LocalGameServerOptions, m as LoopbackTransport, n as SplitScreenPlayer, o as applySyncPatch, p as LoopbackHub, r as createSplitScreen, s as CollectionOptions, t as SplitScreenOptions, u as LocalGameServerTransport } from "./split-screen-
|
|
1
|
+
import { d as PropSchema, jt as Node } from "./behavior-ZnfzKDo3.js";
|
|
2
|
+
import { a as NetworkManagerOptions, c as LocalGameServer, d as ServerClass, f as createLocalGameServer, g as Unsubscribe, h as NetworkTransport, i as NetworkManager, l as LocalGameServerOptions, m as LoopbackTransport, n as SplitScreenPlayer, o as applySyncPatch, p as LoopbackHub, r as createSplitScreen, s as CollectionOptions, t as SplitScreenOptions, u as LocalGameServerTransport } from "./split-screen-DD5eYIgW.js";
|
|
3
3
|
|
|
4
4
|
//#region src/net/agent8.d.ts
|
|
5
5
|
/**
|
package/dist/net.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { n as createAgent8Server } from "./agent8-CvsfVskX.js";
|
|
2
|
-
import { a as NetworkManager, d as createLocalGameServer, f as LoopbackHub, l as LocalGameServer, n as registerNodesNet, o as applySyncPatch, p as LoopbackTransport, r as NetworkSpawner, t as createSplitScreen, u as LocalGameServerTransport } from "./split-screen-
|
|
2
|
+
import { a as NetworkManager, d as createLocalGameServer, f as LoopbackHub, l as LocalGameServer, n as registerNodesNet, o as applySyncPatch, p as LoopbackTransport, r as NetworkSpawner, t as createSplitScreen, u as LocalGameServerTransport } from "./split-screen-DS8RaUV_.js";
|
|
3
3
|
export { LocalGameServer, LocalGameServerTransport, LoopbackHub, LoopbackTransport, NetworkManager, NetworkSpawner, applySyncPatch, createAgent8Server, createLocalGameServer, createSplitScreen, registerNodesNet };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
|
|
2
|
-
import { k as diagnose } from "./loader-
|
|
2
|
+
import { k as diagnose } from "./loader-KZESOZmE.js";
|
|
3
3
|
import { t as IncantoError } from "./errors-BpWbnbb_.js";
|
|
4
|
-
import { _ as RigidBody2D, b as validateCollider2D, g as PhysicsBody2D, h as CharacterBody2D, m as Area2D, p as Joint2D, y as Node2D } from "./register-
|
|
4
|
+
import { _ as RigidBody2D, b as validateCollider2D, g as PhysicsBody2D, h as CharacterBody2D, m as Area2D, p as Joint2D, y as Node2D } from "./register-vIxU3Xbv.js";
|
|
5
5
|
import { n as registerDebugSource } from "./debug-draw-BM3DsvtT.js";
|
|
6
6
|
import { n as jointContacts, t as withoutRapierInitNoise } from "./quiet-rapier-C6fW4zcW.js";
|
|
7
7
|
//#region src/2d/physics/physics-2d.ts
|
|
@@ -66,6 +66,7 @@ var Physics2D = class {
|
|
|
66
66
|
this.unregisterDebug = registerDebugSource(this);
|
|
67
67
|
this.disconnect = engine.fixedUpdated.connect((dt) => this.step(dt));
|
|
68
68
|
this.disconnectScene = engine.sceneChanged.connect(() => {
|
|
69
|
+
this.pruneOverlaps();
|
|
69
70
|
if (engine.scene) this.syncBodies();
|
|
70
71
|
});
|
|
71
72
|
engine.physics = this;
|
|
@@ -306,6 +307,31 @@ var Physics2D = class {
|
|
|
306
307
|
if (set.size === 0) this.overlaps.delete(self);
|
|
307
308
|
}
|
|
308
309
|
}
|
|
310
|
+
/**
|
|
311
|
+
* Forget every overlap whose node has left the tree.
|
|
312
|
+
*
|
|
313
|
+
* The lazy drop inside `overlapping()` only cleans the SETS of a key someone
|
|
314
|
+
* asks about, and only when they ask. This clears the KEYS, which is where the
|
|
315
|
+
* dead nodes were pinned.
|
|
316
|
+
*/
|
|
317
|
+
/** Drop one node from the overlap map, both as a key and as a member. */
|
|
318
|
+
forgetOverlaps(node) {
|
|
319
|
+
this.overlaps.delete(node);
|
|
320
|
+
for (const [self, others] of this.overlaps) {
|
|
321
|
+
others.delete(node);
|
|
322
|
+
if (others.size === 0) this.overlaps.delete(self);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
pruneOverlaps() {
|
|
326
|
+
for (const [self, others] of this.overlaps) {
|
|
327
|
+
if (self.tree === null) {
|
|
328
|
+
this.overlaps.delete(self);
|
|
329
|
+
continue;
|
|
330
|
+
}
|
|
331
|
+
for (const other of others) if (other.tree === null) others.delete(other);
|
|
332
|
+
if (others.size === 0) this.overlaps.delete(self);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
309
335
|
/** The bodies currently overlapping `node`. Freed nodes are dropped on read. */
|
|
310
336
|
overlapping(node) {
|
|
311
337
|
const set = this.overlaps.get(node);
|
|
@@ -426,6 +452,7 @@ var Physics2D = class {
|
|
|
426
452
|
this.byColliderHandle.delete(e.collider.handle);
|
|
427
453
|
this.world.removeRigidBody(e.body);
|
|
428
454
|
this.entries.delete(node);
|
|
455
|
+
this.forgetOverlaps(node);
|
|
429
456
|
node._physics = null;
|
|
430
457
|
}
|
|
431
458
|
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
|
|
2
|
-
import { k as diagnose } from "./loader-
|
|
2
|
+
import { k as diagnose } from "./loader-KZESOZmE.js";
|
|
3
3
|
import { t as IncantoError } from "./errors-BpWbnbb_.js";
|
|
4
|
-
import { H as CharacterBody3D, K as Node3D, U as PhysicsBody3D, V as Area3D, W as RigidBody3D, q as validateCollider3D } from "./gameplay-
|
|
4
|
+
import { H as CharacterBody3D, K as Node3D, U as PhysicsBody3D, V as Area3D, W as RigidBody3D, q as validateCollider3D } from "./gameplay-CGSv-9XR.js";
|
|
5
5
|
import { n as registerDebugSource } from "./debug-draw-BM3DsvtT.js";
|
|
6
6
|
import { n as jointContacts, t as withoutRapierInitNoise } from "./quiet-rapier-C6fW4zcW.js";
|
|
7
|
-
import { A as Terrain3D, F as InstancedMesh3D, L as buildMeshGeometry, P as Joint3D } from "./environment-presets-
|
|
7
|
+
import { A as Terrain3D, F as InstancedMesh3D, L as buildMeshGeometry, P as Joint3D } from "./environment-presets-C-5g2pMh.js";
|
|
8
8
|
import { Euler, Matrix4, Quaternion, Vector3 } from "three";
|
|
9
9
|
//#region src/3d/physics/collider-lines.ts
|
|
10
10
|
/**
|
|
@@ -262,6 +262,7 @@ var Physics3D = class {
|
|
|
262
262
|
this.unregisterDebug = registerDebugSource(this);
|
|
263
263
|
this.disconnect = engine.fixedUpdated.connect((dt) => this.step(dt));
|
|
264
264
|
this.disconnectScene = engine.sceneChanged.connect(() => {
|
|
265
|
+
this.pruneOverlaps();
|
|
265
266
|
if (engine.scene) this.syncBodies();
|
|
266
267
|
});
|
|
267
268
|
engine.physics = this;
|
|
@@ -609,6 +610,7 @@ var Physics3D = class {
|
|
|
609
610
|
this.byColliderHandle.delete(e.collider.handle);
|
|
610
611
|
this.world.removeRigidBody(e.body);
|
|
611
612
|
this.entries.delete(node);
|
|
613
|
+
this.forgetOverlaps(node);
|
|
612
614
|
node._physics = null;
|
|
613
615
|
node._interpPrev = node._interpCurr = null;
|
|
614
616
|
}
|
|
@@ -824,6 +826,31 @@ var Physics3D = class {
|
|
|
824
826
|
}
|
|
825
827
|
}
|
|
826
828
|
/**
|
|
829
|
+
* Forget every overlap whose node has left the tree.
|
|
830
|
+
*
|
|
831
|
+
* The lazy drop inside `overlapping()` only cleans the SETS of a key someone
|
|
832
|
+
* asks about, and only when they ask. This clears the KEYS, which is where the
|
|
833
|
+
* dead nodes were pinned.
|
|
834
|
+
*/
|
|
835
|
+
/** Drop one node from the overlap map, both as a key and as a member. */
|
|
836
|
+
forgetOverlaps(node) {
|
|
837
|
+
this.overlaps.delete(node);
|
|
838
|
+
for (const [self, others] of this.overlaps) {
|
|
839
|
+
others.delete(node);
|
|
840
|
+
if (others.size === 0) this.overlaps.delete(self);
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
pruneOverlaps() {
|
|
844
|
+
for (const [self, others] of this.overlaps) {
|
|
845
|
+
if (self.tree === null) {
|
|
846
|
+
this.overlaps.delete(self);
|
|
847
|
+
continue;
|
|
848
|
+
}
|
|
849
|
+
for (const other of others) if (other.tree === null) others.delete(other);
|
|
850
|
+
if (others.size === 0) this.overlaps.delete(self);
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
/**
|
|
827
854
|
* The bodies currently overlapping `node` — the standing answer behind
|
|
828
855
|
* `triggerEnter`/`triggerExit`.
|
|
829
856
|
*
|
package/dist/react.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { P as Scene, b as Engine, n as BehaviorCtor } from "./behavior-
|
|
1
|
+
import { P as Scene, b as Engine, n as BehaviorCtor } from "./behavior-ZnfzKDo3.js";
|
|
2
2
|
import { c as JsonValue } from "./schema-CFeioQRE.js";
|
|
3
3
|
import { CSSProperties, ReactNode } from "react";
|
|
4
4
|
|
package/dist/react.js
CHANGED
|
@@ -156,7 +156,7 @@ function IncantoCanvas(props) {
|
|
|
156
156
|
pointer: latest.pointer,
|
|
157
157
|
...keyboard !== void 0 ? { keyboard } : {}
|
|
158
158
|
};
|
|
159
|
-
const next = await (_gameFactory ?? (mode === "3d" ? async (o) => (await import("./create-game-
|
|
159
|
+
const next = await (_gameFactory ?? (mode === "3d" ? async (o) => (await import("./create-game-FAXdHta3.js").then((n) => n.n)).createGame3D(o) : async (o) => (await import("./create-game-DMetd3vR.js").then((n) => n.n)).createGame2D(o)))(opts);
|
|
160
160
|
if (disposed) {
|
|
161
161
|
next.dispose();
|
|
162
162
|
return;
|