@vgai/engine 0.5.4 → 0.5.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapter/adapter-surface.d.ts +30 -0
- package/dist/adapter/adapter-surface.d.ts.map +1 -0
- package/dist/adapter/adapter-surface.js +18 -0
- package/dist/adapter/authoring.d.ts +597 -0
- package/dist/adapter/authoring.d.ts.map +1 -0
- package/dist/adapter/authoring.js +22 -0
- package/dist/adapter/colyseus-networking-adapter.d.ts +77 -0
- package/dist/adapter/colyseus-networking-adapter.d.ts.map +1 -0
- package/dist/adapter/colyseus-networking-adapter.js +76 -0
- package/dist/adapter/first-party-systems.d.ts +23 -0
- package/dist/adapter/first-party-systems.d.ts.map +1 -0
- package/dist/adapter/first-party-systems.js +196 -0
- package/dist/adapter/host-context.d.ts +194 -0
- package/dist/adapter/host-context.d.ts.map +1 -0
- package/dist/adapter/host-context.js +80 -0
- package/dist/adapter/index.d.ts +33 -0
- package/dist/adapter/index.d.ts.map +1 -0
- package/dist/adapter/index.js +25 -0
- package/dist/adapter/ingest/game-contract.d.ts +53 -0
- package/dist/adapter/ingest/game-contract.d.ts.map +1 -0
- package/dist/adapter/ingest/game-contract.js +30 -0
- package/dist/adapter/ingest/scene-capture.d.ts +121 -0
- package/dist/adapter/ingest/scene-capture.d.ts.map +1 -0
- package/dist/adapter/ingest/scene-capture.js +270 -0
- package/dist/adapter/ingest/structural-ids.d.ts +64 -0
- package/dist/adapter/ingest/structural-ids.d.ts.map +1 -0
- package/dist/adapter/ingest/structural-ids.js +110 -0
- package/dist/adapter/ingest/upstream-pin.d.ts +44 -0
- package/dist/adapter/ingest/upstream-pin.d.ts.map +1 -0
- package/dist/adapter/ingest/upstream-pin.js +47 -0
- package/dist/adapter/loop-gate-report.d.ts +34 -0
- package/dist/adapter/loop-gate-report.d.ts.map +1 -0
- package/dist/adapter/loop-gate-report.js +37 -0
- package/dist/adapter/rapier-physics-adapter.d.ts +69 -0
- package/dist/adapter/rapier-physics-adapter.d.ts.map +1 -0
- package/dist/adapter/rapier-physics-adapter.js +135 -0
- package/dist/adapter/root-adapter.d.ts +195 -0
- package/dist/adapter/root-adapter.d.ts.map +1 -0
- package/dist/adapter/root-adapter.js +25 -0
- package/dist/adapter/setup-three-root-adapter.d.ts +87 -0
- package/dist/adapter/setup-three-root-adapter.d.ts.map +1 -0
- package/dist/adapter/setup-three-root-adapter.js +791 -0
- package/dist/adapter/system-adapter.d.ts +453 -0
- package/dist/adapter/system-adapter.d.ts.map +1 -0
- package/dist/adapter/system-adapter.js +13 -0
- package/dist/adapter/transform.d.ts +18 -0
- package/dist/adapter/transform.d.ts.map +1 -0
- package/dist/adapter/transform.js +1 -0
- package/dist/ai/navigation.d.ts +78 -0
- package/dist/ai/navigation.d.ts.map +1 -0
- package/dist/ai/navigation.js +152 -0
- package/dist/animation/anim-graph-types.d.ts +25 -0
- package/dist/animation/anim-graph-types.d.ts.map +1 -0
- package/dist/animation/anim-graph-types.js +1 -0
- package/dist/animation/animation-clock.d.ts +213 -0
- package/dist/animation/animation-clock.d.ts.map +1 -0
- package/dist/animation/animation-clock.js +301 -0
- package/dist/animation/blend-node.d.ts +22 -0
- package/dist/animation/blend-node.d.ts.map +1 -0
- package/dist/animation/blend-node.js +97 -0
- package/dist/animation/camera-ownership.d.ts +249 -0
- package/dist/animation/camera-ownership.d.ts.map +1 -0
- package/dist/animation/camera-ownership.js +169 -0
- package/dist/animation/cinematic-cues.d.ts +200 -0
- package/dist/animation/cinematic-cues.d.ts.map +1 -0
- package/dist/animation/cinematic-cues.js +213 -0
- package/dist/animation/clip-map.d.ts +12 -0
- package/dist/animation/clip-map.d.ts.map +1 -0
- package/dist/animation/clip-map.js +31 -0
- package/dist/animation/cubic-spline-interpolant.d.ts +54 -0
- package/dist/animation/cubic-spline-interpolant.d.ts.map +1 -0
- package/dist/animation/cubic-spline-interpolant.js +111 -0
- package/dist/animation/theatre-clock-binding.d.ts +89 -0
- package/dist/animation/theatre-clock-binding.d.ts.map +1 -0
- package/dist/animation/theatre-clock-binding.js +29 -0
- package/dist/animation/theatre-director.d.ts +277 -0
- package/dist/animation/theatre-director.d.ts.map +1 -0
- package/dist/animation/theatre-director.js +248 -0
- package/dist/animation/theatre-object-binding.d.ts +305 -0
- package/dist/animation/theatre-object-binding.d.ts.map +1 -0
- package/dist/animation/theatre-object-binding.js +351 -0
- package/dist/animation/xstate-animation-binding.d.ts +119 -0
- package/dist/animation/xstate-animation-binding.d.ts.map +1 -0
- package/dist/animation/xstate-animation-binding.js +349 -0
- package/dist/animation/xstate-animation-meta.d.ts +266 -0
- package/dist/animation/xstate-animation-meta.d.ts.map +1 -0
- package/dist/animation/xstate-animation-meta.js +252 -0
- package/dist/asset-formats/camera.d.ts +15 -0
- package/dist/asset-formats/camera.d.ts.map +1 -0
- package/dist/asset-formats/camera.js +15 -0
- package/dist/asset-formats/collider.d.ts +21 -0
- package/dist/asset-formats/collider.d.ts.map +1 -0
- package/dist/asset-formats/collider.js +53 -0
- package/dist/asset-formats/index.d.ts +46 -0
- package/dist/asset-formats/index.d.ts.map +1 -0
- package/dist/asset-formats/index.js +36 -0
- package/dist/asset-formats/instances.d.ts +17 -0
- package/dist/asset-formats/instances.d.ts.map +1 -0
- package/dist/asset-formats/instances.js +31 -0
- package/dist/asset-formats/light.d.ts +21 -0
- package/dist/asset-formats/light.d.ts.map +1 -0
- package/dist/asset-formats/light.js +35 -0
- package/dist/asset-formats/material.d.ts +129 -0
- package/dist/asset-formats/material.d.ts.map +1 -0
- package/dist/asset-formats/material.js +88 -0
- package/dist/asset-formats/mesh.d.ts +22 -0
- package/dist/asset-formats/mesh.d.ts.map +1 -0
- package/dist/asset-formats/mesh.js +64 -0
- package/dist/asset-formats/parse.d.ts +20 -0
- package/dist/asset-formats/parse.d.ts.map +1 -0
- package/dist/asset-formats/parse.js +34 -0
- package/dist/asset-formats/particles.d.ts +1390 -0
- package/dist/asset-formats/particles.d.ts.map +1 -0
- package/dist/asset-formats/particles.js +319 -0
- package/dist/asset-formats/render-env.d.ts +387 -0
- package/dist/asset-formats/render-env.d.ts.map +1 -0
- package/dist/asset-formats/render-env.js +300 -0
- package/dist/asset-formats/tuples.d.ts +12 -0
- package/dist/asset-formats/tuples.d.ts.map +1 -0
- package/dist/asset-formats/tuples.js +14 -0
- package/dist/asset-loaders.d.ts +97 -0
- package/dist/asset-loaders.d.ts.map +1 -0
- package/dist/asset-loaders.js +209 -0
- package/dist/asset-parse-error.d.ts +24 -0
- package/dist/asset-parse-error.d.ts.map +1 -0
- package/dist/asset-parse-error.js +29 -0
- package/dist/asset-registry.d.ts +38 -0
- package/dist/asset-registry.d.ts.map +1 -0
- package/dist/asset-registry.js +66 -0
- package/dist/assets.d.ts +26 -0
- package/dist/assets.d.ts.map +1 -0
- package/dist/assets.js +55 -0
- package/dist/audio/wav-encode.d.ts +38 -0
- package/dist/audio/wav-encode.d.ts.map +1 -0
- package/dist/audio/wav-encode.js +97 -0
- package/dist/canvas-react/engine-bridge.d.ts +45 -0
- package/dist/canvas-react/engine-bridge.d.ts.map +1 -0
- package/dist/canvas-react/engine-bridge.js +45 -0
- package/dist/canvas-react/index.d.ts +42 -0
- package/dist/canvas-react/index.d.ts.map +1 -0
- package/dist/canvas-react/index.js +41 -0
- package/dist/canvas-react/pixi-primitive.d.ts +85 -0
- package/dist/canvas-react/pixi-primitive.d.ts.map +1 -0
- package/dist/canvas-react/pixi-primitive.js +181 -0
- package/dist/canvas-react/pixi-react-adapter.d.ts +71 -0
- package/dist/canvas-react/pixi-react-adapter.d.ts.map +1 -0
- package/dist/canvas-react/pixi-react-adapter.js +229 -0
- package/dist/canvas-react/pixi-react-root-factory.d.ts +56 -0
- package/dist/canvas-react/pixi-react-root-factory.d.ts.map +1 -0
- package/dist/canvas-react/pixi-react-root-factory.js +73 -0
- package/dist/canvas-react/world-context.d.ts +88 -0
- package/dist/canvas-react/world-context.d.ts.map +1 -0
- package/dist/canvas-react/world-context.js +212 -0
- package/dist/config.d.ts +9 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +8 -0
- package/dist/core/frame-pacing.d.ts +90 -0
- package/dist/core/frame-pacing.d.ts.map +1 -0
- package/dist/core/frame-pacing.js +89 -0
- package/dist/core/game-loop.d.ts +62 -0
- package/dist/core/game-loop.d.ts.map +1 -0
- package/dist/core/game-loop.js +189 -0
- package/dist/core/seeded-random.d.ts +69 -0
- package/dist/core/seeded-random.d.ts.map +1 -0
- package/dist/core/seeded-random.js +121 -0
- package/dist/core/sim-clock.d.ts +199 -0
- package/dist/core/sim-clock.d.ts.map +1 -0
- package/dist/core/sim-clock.js +291 -0
- package/dist/core/system-runner.d.ts +96 -0
- package/dist/core/system-runner.d.ts.map +1 -0
- package/dist/core/system-runner.js +253 -0
- package/dist/core/types.d.ts +111 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +25 -0
- package/dist/data/data-asset.d.ts +101 -0
- package/dist/data/data-asset.d.ts.map +1 -0
- package/dist/data/data-asset.js +122 -0
- package/dist/data/data-check-core.d.ts +109 -0
- package/dist/data/data-check-core.d.ts.map +1 -0
- package/dist/data/data-check-core.js +177 -0
- package/dist/data/data-ref.d.ts +79 -0
- package/dist/data/data-ref.d.ts.map +1 -0
- package/dist/data/data-ref.js +130 -0
- package/dist/data/vite-plugin-data.d.ts +79 -0
- package/dist/data/vite-plugin-data.d.ts.map +1 -0
- package/dist/data/vite-plugin-data.js +217 -0
- package/dist/defaults.d.ts +233 -0
- package/dist/defaults.d.ts.map +1 -0
- package/dist/defaults.js +137 -0
- package/dist/dev/chrome-trace.d.ts +45 -0
- package/dist/dev/chrome-trace.d.ts.map +1 -0
- package/dist/dev/chrome-trace.js +114 -0
- package/dist/dev/console-bridge.d.ts +22 -0
- package/dist/dev/console-bridge.d.ts.map +1 -0
- package/dist/dev/console-bridge.js +71 -0
- package/dist/dev/debug-draw.d.ts +24 -0
- package/dist/dev/debug-draw.d.ts.map +1 -0
- package/dist/dev/debug-draw.js +73 -0
- package/dist/dev/instruments.d.ts +133 -0
- package/dist/dev/instruments.d.ts.map +1 -0
- package/dist/dev/instruments.js +231 -0
- package/dist/dev/logger.d.ts +30 -0
- package/dist/dev/logger.d.ts.map +1 -0
- package/dist/dev/logger.js +90 -0
- package/dist/dev/performance-profiler.d.ts +111 -0
- package/dist/dev/performance-profiler.d.ts.map +1 -0
- package/dist/dev/performance-profiler.js +215 -0
- package/dist/dev/render-debug-adapter.d.ts +57 -0
- package/dist/dev/render-debug-adapter.d.ts.map +1 -0
- package/dist/dev/render-debug-adapter.js +141 -0
- package/dist/dev/render-memory.d.ts +53 -0
- package/dist/dev/render-memory.d.ts.map +1 -0
- package/dist/dev/render-memory.js +190 -0
- package/dist/dev/webgl-frame-capture.d.ts +134 -0
- package/dist/dev/webgl-frame-capture.d.ts.map +1 -0
- package/dist/dev/webgl-frame-capture.js +270 -0
- package/dist/dev/webgl-gpu-timer.d.ts +8 -0
- package/dist/dev/webgl-gpu-timer.d.ts.map +1 -0
- package/dist/dev/webgl-gpu-timer.js +52 -0
- package/dist/ecs/scene-index.d.ts +179 -0
- package/dist/ecs/scene-index.d.ts.map +1 -0
- package/dist/ecs/scene-index.js +331 -0
- package/dist/ecs/scene-query.d.ts +6 -0
- package/dist/ecs/scene-query.d.ts.map +1 -0
- package/dist/ecs/scene-query.js +40 -0
- package/dist/ecs/user-data.d.ts +193 -0
- package/dist/ecs/user-data.d.ts.map +1 -0
- package/dist/ecs/user-data.js +145 -0
- package/dist/index.d.ts +35 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +29 -0
- package/dist/input/input-manager.d.ts +944 -0
- package/dist/input/input-manager.d.ts.map +1 -0
- package/dist/input/input-manager.js +2209 -0
- package/dist/input/input-types.d.ts +174 -0
- package/dist/input/input-types.d.ts.map +1 -0
- package/dist/input/input-types.js +1 -0
- package/dist/input/prompt-labels.d.ts +21 -0
- package/dist/input/prompt-labels.d.ts.map +1 -0
- package/dist/input/prompt-labels.js +121 -0
- package/dist/input/rebind-controller.d.ts +59 -0
- package/dist/input/rebind-controller.d.ts.map +1 -0
- package/dist/input/rebind-controller.js +85 -0
- package/dist/input/schema.d.ts +16 -0
- package/dist/input/schema.d.ts.map +1 -0
- package/dist/input/schema.js +228 -0
- package/dist/loader.d.ts +76 -0
- package/dist/loader.d.ts.map +1 -0
- package/dist/loader.js +114 -0
- package/dist/manifest/editor-port.d.ts +53 -0
- package/dist/manifest/editor-port.d.ts.map +1 -0
- package/dist/manifest/editor-port.js +67 -0
- package/dist/manifest/filename.d.ts +14 -0
- package/dist/manifest/filename.d.ts.map +1 -0
- package/dist/manifest/filename.js +43 -0
- package/dist/manifest/index.d.ts +6 -0
- package/dist/manifest/index.d.ts.map +1 -0
- package/dist/manifest/index.js +9 -0
- package/dist/manifest/load-file.d.ts +7 -0
- package/dist/manifest/load-file.d.ts.map +1 -0
- package/dist/manifest/load-file.js +23 -0
- package/dist/manifest/load.d.ts +161 -0
- package/dist/manifest/load.d.ts.map +1 -0
- package/dist/manifest/load.js +269 -0
- package/dist/manifest/locate.d.ts +24 -0
- package/dist/manifest/locate.d.ts.map +1 -0
- package/dist/manifest/locate.js +48 -0
- package/dist/manifest/schema.d.ts +293 -0
- package/dist/manifest/schema.d.ts.map +1 -0
- package/dist/manifest/schema.js +633 -0
- package/dist/physics/collider-dimensions.d.ts +63 -0
- package/dist/physics/collider-dimensions.d.ts.map +1 -0
- package/dist/physics/collider-dimensions.js +98 -0
- package/dist/physics/collision-system.d.ts +41 -0
- package/dist/physics/collision-system.d.ts.map +1 -0
- package/dist/physics/collision-system.js +64 -0
- package/dist/physics/physics-registry.d.ts +45 -0
- package/dist/physics/physics-registry.d.ts.map +1 -0
- package/dist/physics/physics-registry.js +65 -0
- package/dist/physics/transform-writer.d.ts +16 -0
- package/dist/physics/transform-writer.d.ts.map +1 -0
- package/dist/physics/transform-writer.js +38 -0
- package/dist/pixi/authoring.d.ts +93 -0
- package/dist/pixi/authoring.d.ts.map +1 -0
- package/dist/pixi/authoring.js +207 -0
- package/dist/pixi/index.d.ts +16 -0
- package/dist/pixi/index.d.ts.map +1 -0
- package/dist/pixi/index.js +15 -0
- package/dist/pixi/ingest-iframe.d.ts +82 -0
- package/dist/pixi/ingest-iframe.d.ts.map +1 -0
- package/dist/pixi/ingest-iframe.js +166 -0
- package/dist/pixi/ingest.d.ts +97 -0
- package/dist/pixi/ingest.d.ts.map +1 -0
- package/dist/pixi/ingest.js +40 -0
- package/dist/pixi/physics-registry.d.ts +24 -0
- package/dist/pixi/physics-registry.d.ts.map +1 -0
- package/dist/pixi/physics-registry.js +38 -0
- package/dist/pixi/scene-capture.d.ts +43 -0
- package/dist/pixi/scene-capture.d.ts.map +1 -0
- package/dist/pixi/scene-capture.js +92 -0
- package/dist/pixi/system-adapters.d.ts +16 -0
- package/dist/pixi/system-adapters.d.ts.map +1 -0
- package/dist/pixi/system-adapters.js +37 -0
- package/dist/react/unmanaged-root-detector.d.ts +18 -0
- package/dist/react/unmanaged-root-detector.d.ts.map +1 -0
- package/dist/react/unmanaged-root-detector.js +70 -0
- package/dist/react/use-data.d.ts +60 -0
- package/dist/react/use-data.d.ts.map +1 -0
- package/dist/react/use-data.js +101 -0
- package/dist/react/use-selection.d.ts +54 -0
- package/dist/react/use-selection.d.ts.map +1 -0
- package/dist/react/use-selection.js +71 -0
- package/dist/react/world-state.d.ts +154 -0
- package/dist/react/world-state.d.ts.map +1 -0
- package/dist/react/world-state.js +220 -0
- package/dist/render/auto-batcher.d.ts +34 -0
- package/dist/render/auto-batcher.d.ts.map +1 -0
- package/dist/render/auto-batcher.js +140 -0
- package/dist/render/instance-mesh.d.ts +5 -0
- package/dist/render/instance-mesh.d.ts.map +1 -0
- package/dist/render/instance-mesh.js +19 -0
- package/dist/render/light-camera-factory.d.ts +24 -0
- package/dist/render/light-camera-factory.d.ts.map +1 -0
- package/dist/render/light-camera-factory.js +71 -0
- package/dist/render/lod.d.ts +13 -0
- package/dist/render/lod.d.ts.map +1 -0
- package/dist/render/lod.js +16 -0
- package/dist/render/material-factory.d.ts +15 -0
- package/dist/render/material-factory.d.ts.map +1 -0
- package/dist/render/material-factory.js +186 -0
- package/dist/render/mesh-shadow.d.ts +11 -0
- package/dist/render/mesh-shadow.d.ts.map +1 -0
- package/dist/render/mesh-shadow.js +19 -0
- package/dist/render/particles-factory.d.ts +99 -0
- package/dist/render/particles-factory.d.ts.map +1 -0
- package/dist/render/particles-factory.js +361 -0
- package/dist/render/render-batch-system.d.ts +33 -0
- package/dist/render/render-batch-system.d.ts.map +1 -0
- package/dist/render/render-batch-system.js +223 -0
- package/dist/render/render-features.d.ts +47 -0
- package/dist/render/render-features.d.ts.map +1 -0
- package/dist/render/render-features.js +105 -0
- package/dist/render/render-settings.d.ts +35 -0
- package/dist/render/render-settings.d.ts.map +1 -0
- package/dist/render/render-settings.js +51 -0
- package/dist/render/spark-renderer-lifecycle.d.ts +18 -0
- package/dist/render/spark-renderer-lifecycle.d.ts.map +1 -0
- package/dist/render/spark-renderer-lifecycle.js +57 -0
- package/dist/render/viewport-shading.d.ts +17 -0
- package/dist/render/viewport-shading.d.ts.map +1 -0
- package/dist/render/viewport-shading.js +87 -0
- package/dist/runtime/create-runtime.d.ts +259 -0
- package/dist/runtime/create-runtime.d.ts.map +1 -0
- package/dist/runtime/create-runtime.js +666 -0
- package/dist/runtime/debug-bridge.d.ts +288 -0
- package/dist/runtime/debug-bridge.d.ts.map +1 -0
- package/dist/runtime/debug-bridge.js +277 -0
- package/dist/runtime/debug-registry.d.ts +287 -0
- package/dist/runtime/debug-registry.d.ts.map +1 -0
- package/dist/runtime/debug-registry.js +528 -0
- package/dist/runtime/dev-layers.d.ts +34 -0
- package/dist/runtime/dev-layers.d.ts.map +1 -0
- package/dist/runtime/dev-layers.js +40 -0
- package/dist/runtime/frame-selector-cache.d.ts +41 -0
- package/dist/runtime/frame-selector-cache.d.ts.map +1 -0
- package/dist/runtime/frame-selector-cache.js +65 -0
- package/dist/runtime/game.d.ts +576 -0
- package/dist/runtime/game.d.ts.map +1 -0
- package/dist/runtime/game.js +1003 -0
- package/dist/runtime/gameplay-rng-trap.d.ts +47 -0
- package/dist/runtime/gameplay-rng-trap.d.ts.map +1 -0
- package/dist/runtime/gameplay-rng-trap.js +95 -0
- package/dist/runtime/input-router.d.ts +78 -0
- package/dist/runtime/input-router.d.ts.map +1 -0
- package/dist/runtime/input-router.js +171 -0
- package/dist/runtime/mount-game.d.ts +126 -0
- package/dist/runtime/mount-game.d.ts.map +1 -0
- package/dist/runtime/mount-game.js +159 -0
- package/dist/runtime/mount-manifest.d.ts +174 -0
- package/dist/runtime/mount-manifest.d.ts.map +1 -0
- package/dist/runtime/mount-manifest.js +304 -0
- package/dist/runtime/presentation.d.ts +85 -0
- package/dist/runtime/presentation.d.ts.map +1 -0
- package/dist/runtime/presentation.js +92 -0
- package/dist/runtime/render-audio-control.d.ts +126 -0
- package/dist/runtime/render-audio-control.d.ts.map +1 -0
- package/dist/runtime/render-audio-control.js +116 -0
- package/dist/runtime/render-control.d.ts +347 -0
- package/dist/runtime/render-control.d.ts.map +1 -0
- package/dist/runtime/render-control.js +317 -0
- package/dist/runtime/render-seed.d.ts +56 -0
- package/dist/runtime/render-seed.d.ts.map +1 -0
- package/dist/runtime/render-seed.js +73 -0
- package/dist/runtime/state-bridge.d.ts +60 -0
- package/dist/runtime/state-bridge.d.ts.map +1 -0
- package/dist/runtime/state-bridge.js +62 -0
- package/dist/runtime/types.d.ts +285 -0
- package/dist/runtime/types.d.ts.map +1 -0
- package/dist/runtime/types.js +1 -0
- package/dist/runtime/unexported-game-trap.d.ts +36 -0
- package/dist/runtime/unexported-game-trap.d.ts.map +1 -0
- package/dist/runtime/unexported-game-trap.js +80 -0
- package/dist/setup/setup-audio.d.ts +20 -0
- package/dist/setup/setup-audio.d.ts.map +1 -0
- package/dist/setup/setup-audio.js +41 -0
- package/dist/setup/setup-particles.d.ts +17 -0
- package/dist/setup/setup-particles.d.ts.map +1 -0
- package/dist/setup/setup-particles.js +16 -0
- package/dist/setup/setup-physics.d.ts +25 -0
- package/dist/setup/setup-physics.d.ts.map +1 -0
- package/dist/setup/setup-physics.js +51 -0
- package/dist/setup/setup-renderer.d.ts +82 -0
- package/dist/setup/setup-renderer.d.ts.map +1 -0
- package/dist/setup/setup-renderer.js +381 -0
- package/dist/world3d-react/engine-bridge.d.ts +47 -0
- package/dist/world3d-react/engine-bridge.d.ts.map +1 -0
- package/dist/world3d-react/engine-bridge.js +48 -0
- package/dist/world3d-react/index.d.ts +47 -0
- package/dist/world3d-react/index.d.ts.map +1 -0
- package/dist/world3d-react/index.js +46 -0
- package/dist/world3d-react/r3f-adapter.d.ts +51 -0
- package/dist/world3d-react/r3f-adapter.d.ts.map +1 -0
- package/dist/world3d-react/r3f-adapter.js +368 -0
- package/dist/world3d-react/r3f-root-factory.d.ts +62 -0
- package/dist/world3d-react/r3f-root-factory.d.ts.map +1 -0
- package/dist/world3d-react/r3f-root-factory.js +79 -0
- package/dist/world3d-react/rapier-physics-bridge.d.ts +76 -0
- package/dist/world3d-react/rapier-physics-bridge.d.ts.map +1 -0
- package/dist/world3d-react/rapier-physics-bridge.js +120 -0
- package/dist/world3d-react/renderer-config.d.ts +58 -0
- package/dist/world3d-react/renderer-config.d.ts.map +1 -0
- package/dist/world3d-react/renderer-config.js +96 -0
- package/dist/world3d-react/world-context.d.ts +123 -0
- package/dist/world3d-react/world-context.d.ts.map +1 -0
- package/dist/world3d-react/world-context.js +204 -0
- package/dist-config/config.js +303 -0
- package/dist-config/config.js.map +7 -0
- package/package.json +14 -3
- package/src/adapter/rapier-physics-adapter.ts +77 -34
- package/src/config.ts +8 -0
- package/src/core/frame-pacing.ts +26 -0
- package/src/core/game-loop.ts +4 -3
- package/src/dev/instruments.ts +302 -0
- package/src/runtime/mount-game.ts +6 -0
- package/src/runtime/unexported-game-trap.ts +82 -0
- package/src/setup/setup-renderer.ts +2 -0
- package/src/world3d-react/index.ts +9 -0
- package/src/world3d-react/rapier-physics-bridge.tsx +137 -0
|
@@ -0,0 +1,528 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The game-scoped debug/synthetic-player registry. ONE registry per `Game` root —
|
|
3
|
+
* every world's `ctx.debug` (see `DebugCtxSurface`, `runtime/types.ts`) feeds the
|
|
4
|
+
* SAME registry via {@link DebugRegistry.forRoot}, so a name a game registers is
|
|
5
|
+
* visible (and name-collision-checked) across every world, not just the one that
|
|
6
|
+
* registered it. `createGame` (`runtime/game.ts`) constructs the registry
|
|
7
|
+
* alongside the state bridge and files it in the `Game -> DebugRegistry` WeakMap
|
|
8
|
+
* this module owns; later consumers (the react `useDebugProvider`/
|
|
9
|
+
* `useDebugCommand` hooks, editor panels) reach it via {@link getDebugRegistry}
|
|
10
|
+
* rather than threading it through every call site.
|
|
11
|
+
*
|
|
12
|
+
* Provenance note: a registration's "world" is the MOUNT's adapter id (the
|
|
13
|
+
* `fromSetup(id, ...)` / `SetupThreeRootConfig.id` a project already names each
|
|
14
|
+
* world's entry with) rather than the `RootInstance.id` `registerThreeRoot`
|
|
15
|
+
* assigns — that id isn't known until AFTER `mount()` resolves (`create-
|
|
16
|
+
* runtime.ts` calls `registerThreeRoot` with it only once `mount()` returns),
|
|
17
|
+
* which is after every `setup()`-time registration has already run. For the
|
|
18
|
+
* single-world case (nearly every project today) this is simply `'setup-three'`;
|
|
19
|
+
* a multi-world manifest names each world's adapter to match its declared id
|
|
20
|
+
* by convention, so collision messages stay meaningful in practice.
|
|
21
|
+
*/
|
|
22
|
+
import { z } from 'zod';
|
|
23
|
+
/** Engine-local error for the debug seam — mirrors the `code` + `data` shape
|
|
24
|
+
* `packages/vgai-sdk/src/errors.ts` uses (no import: the engine does not
|
|
25
|
+
* depend on `@vgai/sdk`). `code` is always machine-readable; nothing reading
|
|
26
|
+
* this error may key off `message` prose. */
|
|
27
|
+
export class DebugError extends Error {
|
|
28
|
+
code;
|
|
29
|
+
data;
|
|
30
|
+
constructor(code, message, data) {
|
|
31
|
+
super(message);
|
|
32
|
+
this.name = 'DebugError';
|
|
33
|
+
this.code = code;
|
|
34
|
+
this.data = data;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
const REGISTRATION_HINT = 'ctx.debug.registerStateProvider(name, fn) — see the template example component';
|
|
38
|
+
/** A thrown value flattened to JSON-SAFE fields. Every caller of a debug
|
|
39
|
+
* command is on the far side of a JSON boundary — the editor session relay
|
|
40
|
+
* (`POST /__editor/command`) and `page.evaluate` both serialize the error's
|
|
41
|
+
* `data` bag — and an `Error` stringifies to `{}` there, so a command's own
|
|
42
|
+
* refusal text ("no such waypoint") vanished and the developer at
|
|
43
|
+
* `vgai eval` saw only `debug: command "x" threw`. The text has to travel as
|
|
44
|
+
* plain strings, and in the `message` above all: that is the one field every
|
|
45
|
+
* client (`SessionError`, the CLI's own error print) actually surfaces. */
|
|
46
|
+
function describeCause(cause) {
|
|
47
|
+
if (cause instanceof Error) {
|
|
48
|
+
const described = { causeName: cause.name, causeMessage: cause.message };
|
|
49
|
+
return cause.stack === undefined ? described : { ...described, causeStack: cause.stack };
|
|
50
|
+
}
|
|
51
|
+
return { causeName: typeof cause, causeMessage: String(cause) };
|
|
52
|
+
}
|
|
53
|
+
/** Task 2.2 — how long `invoke()` waits for a `locus: 'server'` command's
|
|
54
|
+
* `__vgai:debugCommandResult` reply before failing loudly. */
|
|
55
|
+
const SERVER_COMMAND_TIMEOUT_MS = 10_000;
|
|
56
|
+
/** Provenance `worldId` for every registration made through the react door
|
|
57
|
+
* (`useDebugProvider`/`useDebugCommand`, `packages/engine/src/react/game-
|
|
58
|
+
* state.tsx`) — react roots have no `setup()`/`ctx.debug` of their own
|
|
59
|
+
* (spec §3.1's "react-world registration door" paragraph), so all of them
|
|
60
|
+
* share this one provenance string; a name collision between two DIFFERENT
|
|
61
|
+
* react components is therefore the same-world "replace + warn once" case,
|
|
62
|
+
* never the cross-world throw (which is reserved for a first-party world
|
|
63
|
+
* vs. the react door genuinely disagreeing about a name).
|
|
64
|
+
*
|
|
65
|
+
* Defect 7 fix: this used to be the bare string `'react'`, which collided in
|
|
66
|
+
* provenance with a manifest world literally named `'react'` (e.g. a
|
|
67
|
+
* `kind: 'dom'` world whose `id` is `"react"`) — `forRoot('react')` and
|
|
68
|
+
* the react door would then be treated as the SAME world for collision
|
|
69
|
+
* purposes, which is wrong (they are genuinely different registrants that
|
|
70
|
+
* happen to share a display name). Namespaced like `'__engine__'` so no
|
|
71
|
+
* real project world id can ever collide with it. */
|
|
72
|
+
const REACT_WORLD_ID = '__react__';
|
|
73
|
+
function warnOnce(warned, name, kind, worldId) {
|
|
74
|
+
if (warned.has(name))
|
|
75
|
+
return;
|
|
76
|
+
warned.add(name);
|
|
77
|
+
// biome-ignore lint/suspicious/noConsole: structured, greppable — the debug seam's own duplicate-registration signal (spec §3.1)
|
|
78
|
+
console.warn(`[debug] ${kind} "${name}" re-registered (world "${worldId}")`);
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Construct a fresh game-scoped debug registry. `getTick`/`getSimT` are
|
|
82
|
+
* suppliers (not values) so the built-in `time` provider always reads the
|
|
83
|
+
* CURRENT counters — `createGame` passes closures over its own mutable
|
|
84
|
+
* `tick`/`simT`, incremented in `runFrame`'s tail (T1.2). `getDefaultRootId`
|
|
85
|
+
* (D15/T-D15.5, optional) resolves the manifest's first/default world id —
|
|
86
|
+
* `createGame` passes `() => (roots.length ? requireDefaultRoot().id :
|
|
87
|
+
* null)`; a bare `createDebugRegistry()` test stand-in with no `Game` behind
|
|
88
|
+
* it omits it (per-world resolution then falls back to "the single
|
|
89
|
+
* registered world" or "whichever registered first" — see
|
|
90
|
+
* `resolveInputRootId`). `getLoopLiveness` (issue #175, optional) supplies
|
|
91
|
+
* the REAL `GameLoop.liveness` — `createGame` passes `() => opts.loop.
|
|
92
|
+
* liveness`; a bare `createDebugRegistry()` test stand-in with no loop
|
|
93
|
+
* behind it omits it, and the built-in `time` provider reports `null`
|
|
94
|
+
* rather than fabricating `'running'` (this module must never claim health
|
|
95
|
+
* it cannot observe, same rule the loop's own liveness getter documents).
|
|
96
|
+
*/
|
|
97
|
+
export function createDebugRegistry(opts) {
|
|
98
|
+
const providers = new Map();
|
|
99
|
+
const commands = new Map();
|
|
100
|
+
const warnedProviders = new Set();
|
|
101
|
+
const warnedCommands = new Set();
|
|
102
|
+
const ring = [];
|
|
103
|
+
const RING_CAP = 500;
|
|
104
|
+
// Run-4 friction #5 — monotonic, registry-lifetime counter backing
|
|
105
|
+
// `TickStampedEvent.seq`. Never reset, never shared by two events (unlike
|
|
106
|
+
// `tick`, which a debug-command emission and a fenced consumer's snapshot
|
|
107
|
+
// can legitimately collide on — see that field's doc comment in
|
|
108
|
+
// `adapter/system-adapter.ts`).
|
|
109
|
+
let seqCounter = 0;
|
|
110
|
+
let roomDeclared = false;
|
|
111
|
+
// D15/T-D15.5 — per-world maps (Map preserves insertion order, which
|
|
112
|
+
// `resolveInputRootId`'s "whichever registered first" fallback relies on
|
|
113
|
+
// when no `getDefaultRootId` is available to disambiguate).
|
|
114
|
+
const inputActionsSources = new Map();
|
|
115
|
+
const inputTraceSources = new Map();
|
|
116
|
+
const virtualInputTargets = new Map();
|
|
117
|
+
let runTicksTarget = null;
|
|
118
|
+
let attachedRoom = null;
|
|
119
|
+
const pendingServerCommands = new Map();
|
|
120
|
+
let requestCounter = 0;
|
|
121
|
+
/**
|
|
122
|
+
* The ONE resolution function every per-world input seam shares (D15
|
|
123
|
+
* review objection: the debug bridge and the editor relay must never be
|
|
124
|
+
* able to disagree about which world an unqualified actuation targets).
|
|
125
|
+
*
|
|
126
|
+
* - `explicit` given: must be a registered world id, else throws
|
|
127
|
+
* `DEBUG_INPUT_WORLD_NOT_FOUND` (a caller mistake — distinct from
|
|
128
|
+
* "nothing mounted yet", which returns `null` below instead of throwing).
|
|
129
|
+
* - `explicit` omitted: the manifest's first/default world id
|
|
130
|
+
* (`opts.getDefaultRootId()`) iff that world has actually registered —
|
|
131
|
+
* else (no `Game`/no default resolvable, or the default world never
|
|
132
|
+
* wired one — e.g. a foreign/opaque mount) the single registered world,
|
|
133
|
+
* or, with more than one and no resolvable default, whichever registered
|
|
134
|
+
* FIRST (`Map` insertion order) — the closest analogue to this seam's
|
|
135
|
+
* pre-D15.5 single-slot behavior, but now a stable, principled choice
|
|
136
|
+
* instead of "whichever mounted last".
|
|
137
|
+
* - Nothing registered at all: `null`.
|
|
138
|
+
*/
|
|
139
|
+
function resolveInputRootId(explicit) {
|
|
140
|
+
if (explicit !== undefined) {
|
|
141
|
+
if (!virtualInputTargets.has(explicit)) {
|
|
142
|
+
throw new DebugError('DEBUG_INPUT_WORLD_NOT_FOUND', `debug: no InputManager wired for world "${explicit}" — registered: ` +
|
|
143
|
+
(virtualInputTargets.size ? [...virtualInputTargets.keys()].join(', ') : '(none)'), { worldId: explicit, registered: [...virtualInputTargets.keys()] });
|
|
144
|
+
}
|
|
145
|
+
return explicit;
|
|
146
|
+
}
|
|
147
|
+
return resolveRootForSource(virtualInputTargets.keys());
|
|
148
|
+
}
|
|
149
|
+
/** The same "default world, else the one registered, else whichever
|
|
150
|
+
* registered first" fallback {@link resolveInputRootId} uses for the
|
|
151
|
+
* ACTUATION target, generalized over any per-world registration set
|
|
152
|
+
* (`inputActionsSources`/`inputTraceSources` included) — every one of
|
|
153
|
+
* these maps is keyed by the same world ids, populated at the same
|
|
154
|
+
* per-world mount seed spot, so "the default world" means the same thing
|
|
155
|
+
* for all of them. Never throws (no explicit-id case here — the two
|
|
156
|
+
* builtin providers that call this have no way to accept a caller-chosen
|
|
157
|
+
* worldId today; see their own doc comments). */
|
|
158
|
+
function resolveRootForSource(registered) {
|
|
159
|
+
const ids = [...registered];
|
|
160
|
+
if (ids.length === 0)
|
|
161
|
+
return null;
|
|
162
|
+
const defaultId = opts.getDefaultRootId?.() ?? null;
|
|
163
|
+
if (defaultId !== null && ids.includes(defaultId))
|
|
164
|
+
return defaultId;
|
|
165
|
+
return ids[0];
|
|
166
|
+
}
|
|
167
|
+
providers.set('time', {
|
|
168
|
+
// `loopLiveness` (issue #175): `null` when no loop is wired behind this
|
|
169
|
+
// registry (a bare `createDebugRegistry()` test stand-in) — never a
|
|
170
|
+
// fabricated `'running'`. Every real `Game` (`createGame`) wires this,
|
|
171
|
+
// so every live play session reports a real value.
|
|
172
|
+
fn: () => ({
|
|
173
|
+
simSeconds: opts.getSimT(),
|
|
174
|
+
tick: opts.getTick(),
|
|
175
|
+
loopLiveness: opts.getLoopLiveness?.() ?? null,
|
|
176
|
+
}),
|
|
177
|
+
tier: 'observable',
|
|
178
|
+
worldId: '__engine__',
|
|
179
|
+
builtin: true,
|
|
180
|
+
});
|
|
181
|
+
providers.set('input.actions', {
|
|
182
|
+
// Resolves to the DEFAULT world's action list (see `resolveInputRootId`)
|
|
183
|
+
// — deterministic across every world that registers, rather than the
|
|
184
|
+
// pre-D15.5 "whichever mounted last" behavior.
|
|
185
|
+
fn: () => {
|
|
186
|
+
const worldId = resolveRootForSource(inputActionsSources.keys());
|
|
187
|
+
return (worldId ? inputActionsSources.get(worldId) : undefined)?.() ?? [];
|
|
188
|
+
},
|
|
189
|
+
tier: 'observable',
|
|
190
|
+
worldId: '__engine__',
|
|
191
|
+
builtin: true,
|
|
192
|
+
});
|
|
193
|
+
// D15/T-D15.5 — the post-gate action-delta trace, readable via a provider.
|
|
194
|
+
// Absent a wired source (no world mounted yet) reads an empty, correctly-
|
|
195
|
+
// versioned trace rather than throwing. Same default-world resolution as
|
|
196
|
+
// `input.actions` immediately above.
|
|
197
|
+
providers.set('input.trace', {
|
|
198
|
+
fn: () => {
|
|
199
|
+
const worldId = resolveRootForSource(inputTraceSources.keys());
|
|
200
|
+
return ((worldId ? inputTraceSources.get(worldId) : undefined)?.() ?? {
|
|
201
|
+
version: 1,
|
|
202
|
+
seed: null,
|
|
203
|
+
fixedDt: null,
|
|
204
|
+
ticks: [],
|
|
205
|
+
});
|
|
206
|
+
},
|
|
207
|
+
tier: 'observable',
|
|
208
|
+
worldId: '__engine__',
|
|
209
|
+
builtin: true,
|
|
210
|
+
});
|
|
211
|
+
function registerStateProvider(worldId, name, fn, tier, token) {
|
|
212
|
+
const existing = providers.get(name);
|
|
213
|
+
if (existing?.builtin) {
|
|
214
|
+
// Defect 1 fix: a builtin name (`time`, `input.actions`) must never be
|
|
215
|
+
// silently shadowed — the old `!existing.builtin` guard skipped BOTH
|
|
216
|
+
// the collision throw and the warn for this case, so
|
|
217
|
+
// `registerStateProvider('time', ...)` quietly replaced engine truth,
|
|
218
|
+
// and a later `strip()` deleted it outright (leaving NO `time`
|
|
219
|
+
// provider at all post-hot-reload). Throw loudly instead; there is no
|
|
220
|
+
// silent-replace path for a builtin.
|
|
221
|
+
throw new DebugError('DEBUG_BUILTIN_RESERVED', `debug: "${name}" is a built-in state provider (registered by "${existing.worldId}") — ` +
|
|
222
|
+
'built-in names cannot be registered over, from a world or the react door', { name, registered: existing.worldId });
|
|
223
|
+
}
|
|
224
|
+
if (existing) {
|
|
225
|
+
if (existing.worldId !== worldId) {
|
|
226
|
+
throw new DebugError('DEBUG_NAME_COLLISION', `debug: state provider "${name}" is registered by both world "${existing.worldId}" ` +
|
|
227
|
+
`and world "${worldId}" — each provider name must be unique across live roots`, { name, roots: [existing.worldId, worldId] });
|
|
228
|
+
}
|
|
229
|
+
warnOnce(warnedProviders, name, 'provider', worldId);
|
|
230
|
+
}
|
|
231
|
+
providers.set(name, { fn, tier, worldId, builtin: false, token });
|
|
232
|
+
}
|
|
233
|
+
function registerCommand(worldId, name, spec, fn, token) {
|
|
234
|
+
if (spec.locus === undefined && roomDeclared) {
|
|
235
|
+
throw new DebugError('DEBUG_COMMAND_LOCUS_REQUIRED', "this project declares a Colyseus room — declare locus: 'client' | 'server' so " +
|
|
236
|
+
'fixtures mutate authoritative state, not client prediction', { name, worldId });
|
|
237
|
+
}
|
|
238
|
+
const existing = commands.get(name);
|
|
239
|
+
if (existing) {
|
|
240
|
+
if (existing.worldId !== worldId) {
|
|
241
|
+
throw new DebugError('DEBUG_NAME_COLLISION', `debug: command "${name}" is registered by both world "${existing.worldId}" and ` +
|
|
242
|
+
`world "${worldId}" — each command name must be unique across live roots`, { name, roots: [existing.worldId, worldId] });
|
|
243
|
+
}
|
|
244
|
+
warnOnce(warnedCommands, name, 'command', worldId);
|
|
245
|
+
}
|
|
246
|
+
commands.set(name, {
|
|
247
|
+
description: spec.description,
|
|
248
|
+
argsSchema: spec.args,
|
|
249
|
+
locus: spec.locus,
|
|
250
|
+
fn,
|
|
251
|
+
worldId,
|
|
252
|
+
token,
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
function emit(event, detail) {
|
|
256
|
+
seqCounter += 1;
|
|
257
|
+
ring.push({ tick: opts.getTick(), simT: opts.getSimT(), event, detail, seq: seqCounter });
|
|
258
|
+
if (ring.length > RING_CAP)
|
|
259
|
+
ring.shift();
|
|
260
|
+
}
|
|
261
|
+
/** See `DebugAdapter.events`'s doc comment (`adapter/system-adapter.ts`)
|
|
262
|
+
* for the full contract — `seq` is the ONLY fence (the defective
|
|
263
|
+
* `sinceTick` filter was removed). */
|
|
264
|
+
function events(sinceSeq) {
|
|
265
|
+
if (sinceSeq === undefined)
|
|
266
|
+
return ring.slice();
|
|
267
|
+
return ring.filter((e) => e.seq > sinceSeq);
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Task 2.2 — server-locus command routing (client leg). A `locus: 'server'`
|
|
271
|
+
* command never calls its own registered `fn` locally: `invoke()` instead
|
|
272
|
+
* sends the reserved room message `__vgai:debugCommand` and resolves on the
|
|
273
|
+
* matching `__vgai:debugCommandResult` reply, so a fixture mutates the
|
|
274
|
+
* AUTHORITATIVE (server) copy of state, not client prediction. Request ids
|
|
275
|
+
* are a monotonic per-registry counter (`dbg-<n>`), not `Math.random`/
|
|
276
|
+
* `Date.now`, so two in-flight commands never collide and correlation is
|
|
277
|
+
* trivially inspectable in logs.
|
|
278
|
+
*/
|
|
279
|
+
function invokeServerCommand(name, args) {
|
|
280
|
+
if (!attachedRoom) {
|
|
281
|
+
throw new DebugError('DEBUG_COMMAND_FAILED', `debug: command "${name}" is locus:'server' but no Colyseus room is attached ` +
|
|
282
|
+
'(call ctx.debug.attachRoom(room) once your game joins its room)', { reason: 'no room connection' });
|
|
283
|
+
}
|
|
284
|
+
const requestId = `dbg-${++requestCounter}`;
|
|
285
|
+
const room = attachedRoom;
|
|
286
|
+
return new Promise((resolve, reject) => {
|
|
287
|
+
const timer = setTimeout(() => {
|
|
288
|
+
pendingServerCommands.delete(requestId);
|
|
289
|
+
reject(new DebugError('DEBUG_COMMAND_FAILED', `debug: command "${name}" (requestId "${requestId}") timed out waiting for the server`, { reason: 'server timeout' }));
|
|
290
|
+
}, SERVER_COMMAND_TIMEOUT_MS);
|
|
291
|
+
pendingServerCommands.set(requestId, { resolve, reject, timer });
|
|
292
|
+
room.send('__vgai:debugCommand', { name, args, requestId });
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
// Defect 8 fix — the live detach() for whatever room is CURRENTLY attached
|
|
296
|
+
// (or null if none). `attachRoom` calls this itself before attaching a new
|
|
297
|
+
// room: without it, a second `attachRoom` call (no explicit `detach()` in
|
|
298
|
+
// between) left the first room's `__vgai:debugCommandResult` subscription
|
|
299
|
+
// live forever (a leak — the old room keeps getting messages dispatched to
|
|
300
|
+
// a handler nothing reads anymore) and stranded any of ITS in-flight
|
|
301
|
+
// commands riding the full 10s timeout with no way to ever be answered.
|
|
302
|
+
let detachCurrentRoom = null;
|
|
303
|
+
/** {@link DebugCtxSurface.attachRoom} — shared across every world's ctx
|
|
304
|
+
* surface (game-scoped, last-attached room wins — and, since Defect 8,
|
|
305
|
+
* actually CLEANS UP the previous attachment rather than merely
|
|
306
|
+
* overwriting the pointer). Subscribes to the reserved
|
|
307
|
+
* `__vgai:debugCommandResult` reply and resolves/rejects the matching
|
|
308
|
+
* in-flight {@link invokeServerCommand} promise by `requestId`. */
|
|
309
|
+
function attachRoom(room) {
|
|
310
|
+
// Last-wins, but with cleanup: detach whatever room was attached before
|
|
311
|
+
// (unsubscribes its listener, rejects ITS in-flight pendings — see
|
|
312
|
+
// `detach` below) rather than leaking it.
|
|
313
|
+
detachCurrentRoom?.();
|
|
314
|
+
attachedRoom = room;
|
|
315
|
+
const unsubscribe = room.onMessage('__vgai:debugCommandResult', (message) => {
|
|
316
|
+
const reply = message;
|
|
317
|
+
const requestId = reply?.requestId;
|
|
318
|
+
if (requestId === undefined)
|
|
319
|
+
return;
|
|
320
|
+
const pending = pendingServerCommands.get(requestId);
|
|
321
|
+
if (!pending)
|
|
322
|
+
return;
|
|
323
|
+
pendingServerCommands.delete(requestId);
|
|
324
|
+
clearTimeout(pending.timer);
|
|
325
|
+
if (reply?.ok) {
|
|
326
|
+
pending.resolve(reply.result);
|
|
327
|
+
}
|
|
328
|
+
else {
|
|
329
|
+
pending.reject(new DebugError('DEBUG_COMMAND_FAILED', `debug: server command failed: ${String(reply?.error)}`, { cause: reply?.error }));
|
|
330
|
+
}
|
|
331
|
+
});
|
|
332
|
+
const detach = () => {
|
|
333
|
+
// Idempotent, and a no-op if a LATER attachRoom already superseded
|
|
334
|
+
// this attachment (its own detach ran first via detachCurrentRoom?.()
|
|
335
|
+
// above) — calling this stale detach again must not clobber the new
|
|
336
|
+
// attachment's state.
|
|
337
|
+
if (detachCurrentRoom !== detach)
|
|
338
|
+
return;
|
|
339
|
+
detachCurrentRoom = null;
|
|
340
|
+
if (attachedRoom === room)
|
|
341
|
+
attachedRoom = null;
|
|
342
|
+
if (typeof unsubscribe === 'function')
|
|
343
|
+
unsubscribe();
|
|
344
|
+
// Defect 8 fix: reject every command still awaiting THIS room's reply
|
|
345
|
+
// right now, rather than let it silently ride out the full 10s
|
|
346
|
+
// `SERVER_COMMAND_TIMEOUT_MS` with no room left to ever answer it.
|
|
347
|
+
for (const [requestId, pending] of pendingServerCommands) {
|
|
348
|
+
clearTimeout(pending.timer);
|
|
349
|
+
pending.reject(new DebugError('DEBUG_COMMAND_FAILED', `debug: command (requestId "${requestId}") failed — its room was detached before a reply arrived`, { reason: 'no room connection' }));
|
|
350
|
+
}
|
|
351
|
+
pendingServerCommands.clear();
|
|
352
|
+
};
|
|
353
|
+
detachCurrentRoom = detach;
|
|
354
|
+
return detach;
|
|
355
|
+
}
|
|
356
|
+
const adapter = {
|
|
357
|
+
providers() {
|
|
358
|
+
return [...providers.entries()].map(([name, entry]) => ({ name, tier: entry.tier }));
|
|
359
|
+
},
|
|
360
|
+
state(name) {
|
|
361
|
+
const entry = providers.get(name);
|
|
362
|
+
if (!entry) {
|
|
363
|
+
throw new DebugError('STATE_PROVIDER_NOT_FOUND', `debug: no state provider registered under "${name}"`, {
|
|
364
|
+
registered: [...providers.keys()],
|
|
365
|
+
registrationHint: REGISTRATION_HINT,
|
|
366
|
+
});
|
|
367
|
+
}
|
|
368
|
+
return entry.fn();
|
|
369
|
+
},
|
|
370
|
+
stateAll() {
|
|
371
|
+
const result = {};
|
|
372
|
+
for (const [name, entry] of providers) {
|
|
373
|
+
try {
|
|
374
|
+
result[name] = entry.fn();
|
|
375
|
+
}
|
|
376
|
+
catch (err) {
|
|
377
|
+
result[name] = { __error: String(err) };
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
return result;
|
|
381
|
+
},
|
|
382
|
+
commands() {
|
|
383
|
+
return [...commands.entries()].map(([name, entry]) => ({
|
|
384
|
+
name,
|
|
385
|
+
description: entry.description,
|
|
386
|
+
argsJsonSchema: entry.argsSchema
|
|
387
|
+
? z.toJSONSchema(entry.argsSchema, { unrepresentable: 'any' })
|
|
388
|
+
: undefined,
|
|
389
|
+
locus: entry.locus ?? 'client',
|
|
390
|
+
}));
|
|
391
|
+
},
|
|
392
|
+
async invoke(name, args) {
|
|
393
|
+
const entry = commands.get(name);
|
|
394
|
+
if (!entry) {
|
|
395
|
+
throw new DebugError('DEBUG_COMMAND_NOT_REGISTERED', `debug: no command registered under "${name}"`, { registered: [...commands.keys()], registrationHint: REGISTRATION_HINT });
|
|
396
|
+
}
|
|
397
|
+
let parsedArgs = args;
|
|
398
|
+
if (entry.argsSchema) {
|
|
399
|
+
const result = entry.argsSchema.safeParse(args);
|
|
400
|
+
if (!result.success) {
|
|
401
|
+
throw new DebugError('DEBUG_COMMAND_ARGS_INVALID', `debug: command "${name}" received invalid args`, { issues: result.error.issues });
|
|
402
|
+
}
|
|
403
|
+
parsedArgs = result.data;
|
|
404
|
+
}
|
|
405
|
+
if ((entry.locus ?? 'client') === 'server') {
|
|
406
|
+
return invokeServerCommand(name, parsedArgs);
|
|
407
|
+
}
|
|
408
|
+
try {
|
|
409
|
+
return await entry.fn(...parsedArgs);
|
|
410
|
+
}
|
|
411
|
+
catch (cause) {
|
|
412
|
+
// `cause` stays for in-process readers; the flattened fields are what
|
|
413
|
+
// survive the wire (see `describeCause`).
|
|
414
|
+
const described = describeCause(cause);
|
|
415
|
+
throw new DebugError('DEBUG_COMMAND_FAILED', `debug: command "${name}" threw: ${described.causeMessage}`, { cause, ...described });
|
|
416
|
+
}
|
|
417
|
+
},
|
|
418
|
+
events(sinceSeq) {
|
|
419
|
+
return events(sinceSeq);
|
|
420
|
+
},
|
|
421
|
+
};
|
|
422
|
+
return {
|
|
423
|
+
adapter,
|
|
424
|
+
forRoot(worldId) {
|
|
425
|
+
return {
|
|
426
|
+
registerStateProvider(name, fn, providerOpts) {
|
|
427
|
+
registerStateProvider(worldId, name, fn, providerOpts?.tier ?? 'observable');
|
|
428
|
+
},
|
|
429
|
+
registerCommand(name, spec, fn) {
|
|
430
|
+
// Cast: the public generic (`DebugCtxSurface.registerCommand`,
|
|
431
|
+
// `DebugCommandArgs<T>`) exists purely for the CALLER's inference —
|
|
432
|
+
// internally, every entry is stored/invoked through the same
|
|
433
|
+
// untyped `(...args: unknown[])` shape (`invoke()` parses `args`
|
|
434
|
+
// against `argsSchema` at the seam, not at the type level).
|
|
435
|
+
registerCommand(worldId, name, spec, fn);
|
|
436
|
+
},
|
|
437
|
+
emit(event, detail) {
|
|
438
|
+
emit(event, detail);
|
|
439
|
+
},
|
|
440
|
+
attachRoom(room) {
|
|
441
|
+
return attachRoom(room);
|
|
442
|
+
},
|
|
443
|
+
};
|
|
444
|
+
},
|
|
445
|
+
emitReact(event, detail) {
|
|
446
|
+
emit(event, detail);
|
|
447
|
+
},
|
|
448
|
+
strip(worldId) {
|
|
449
|
+
// Defect 2 fix — scoped when `worldId` is given (a single mount's
|
|
450
|
+
// hot-reload re-seed), global otherwise (the whole game going away, or
|
|
451
|
+
// a test's blanket teardown). See this method's interface doc comment.
|
|
452
|
+
for (const [name, entry] of providers) {
|
|
453
|
+
if (entry.builtin)
|
|
454
|
+
continue;
|
|
455
|
+
if (worldId !== undefined && entry.worldId !== worldId)
|
|
456
|
+
continue;
|
|
457
|
+
providers.delete(name);
|
|
458
|
+
warnedProviders.delete(name);
|
|
459
|
+
}
|
|
460
|
+
for (const [name, entry] of commands) {
|
|
461
|
+
if (worldId !== undefined && entry.worldId !== worldId)
|
|
462
|
+
continue;
|
|
463
|
+
commands.delete(name);
|
|
464
|
+
warnedCommands.delete(name);
|
|
465
|
+
}
|
|
466
|
+
},
|
|
467
|
+
setRoomDeclared(declared) {
|
|
468
|
+
roomDeclared = declared;
|
|
469
|
+
},
|
|
470
|
+
setInputActionsSource(worldId, fn) {
|
|
471
|
+
inputActionsSources.set(worldId, fn);
|
|
472
|
+
},
|
|
473
|
+
setInputTraceSource(worldId, fn) {
|
|
474
|
+
inputTraceSources.set(worldId, fn);
|
|
475
|
+
},
|
|
476
|
+
setVirtualInputTarget(worldId, target) {
|
|
477
|
+
virtualInputTargets.set(worldId, target);
|
|
478
|
+
},
|
|
479
|
+
getVirtualInputTarget(worldId) {
|
|
480
|
+
const resolved = resolveInputRootId(worldId);
|
|
481
|
+
return resolved !== null ? (virtualInputTargets.get(resolved) ?? null) : null;
|
|
482
|
+
},
|
|
483
|
+
setRunTicksTarget(target) {
|
|
484
|
+
runTicksTarget = target;
|
|
485
|
+
},
|
|
486
|
+
getRunTicksTarget() {
|
|
487
|
+
return runTicksTarget;
|
|
488
|
+
},
|
|
489
|
+
getGameTick() {
|
|
490
|
+
return opts.getTick();
|
|
491
|
+
},
|
|
492
|
+
registerReactProvider(name, fn, providerOpts) {
|
|
493
|
+
const token = Symbol(name);
|
|
494
|
+
registerStateProvider(REACT_WORLD_ID, name, fn, providerOpts?.tier ?? 'observable', token);
|
|
495
|
+
return () => {
|
|
496
|
+
const entry = providers.get(name);
|
|
497
|
+
if (entry?.token === token) {
|
|
498
|
+
providers.delete(name);
|
|
499
|
+
warnedProviders.delete(name);
|
|
500
|
+
}
|
|
501
|
+
};
|
|
502
|
+
},
|
|
503
|
+
registerReactCommand(name, spec, fn) {
|
|
504
|
+
const token = Symbol(name);
|
|
505
|
+
// See the `forRoot().registerCommand` cast above — same reason.
|
|
506
|
+
registerCommand(REACT_WORLD_ID, name, spec, fn, token);
|
|
507
|
+
return () => {
|
|
508
|
+
const entry = commands.get(name);
|
|
509
|
+
if (entry?.token === token) {
|
|
510
|
+
commands.delete(name);
|
|
511
|
+
warnedCommands.delete(name);
|
|
512
|
+
}
|
|
513
|
+
};
|
|
514
|
+
},
|
|
515
|
+
};
|
|
516
|
+
}
|
|
517
|
+
const registryByGame = new WeakMap();
|
|
518
|
+
/** Called once by `createGame`, right after both the registry and the Game
|
|
519
|
+
* shell object exist, to file the association {@link getDebugRegistry} reads. */
|
|
520
|
+
export function registerDebugRegistry(game, registry) {
|
|
521
|
+
registryByGame.set(game, registry);
|
|
522
|
+
}
|
|
523
|
+
/** The game-scoped registry backing `game.systemAdapters.debug`, or `null` for
|
|
524
|
+
* a `Game` built without one (there is always one for every `createGame`
|
|
525
|
+
* call — `null` only for a `Game`-shaped stand-in a test builds by hand). */
|
|
526
|
+
export function getDebugRegistry(game) {
|
|
527
|
+
return registryByGame.get(game) ?? null;
|
|
528
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* THE one owner of "are dev layers enabled" (`vgai.project.json`'s `dev: true`
|
|
3
|
+
* root flag). Every reader that has to answer that question calls
|
|
4
|
+
* {@link devLayersEnabled}; there is deliberately NO second source of truth —
|
|
5
|
+
* not a module-level cached boolean, not a `globalThis` flag, not a per-host
|
|
6
|
+
* copy of the `import.meta.env` read below. A dev GUI that ships to players
|
|
7
|
+
* because two places disagreed about what "dev" means is exactly the failure
|
|
8
|
+
* this single owner exists to make impossible.
|
|
9
|
+
*
|
|
10
|
+
* Ownership, stated in one place (the build rule):
|
|
11
|
+
* - OWNER: this function. It resolves the answer; nothing else derives it.
|
|
12
|
+
* - SHARERS: `mountManifestRoots` (the ship gate — a dev root only mounts
|
|
13
|
+
* when this returns true). Any future host that mounts manifest roots
|
|
14
|
+
* itself calls this too, with its own `override`.
|
|
15
|
+
* - TEARDOWN: none. This is a pure predicate over build config and one
|
|
16
|
+
* caller-supplied argument — it owns no resource, allocates nothing, and
|
|
17
|
+
* has no lifecycle to end.
|
|
18
|
+
*
|
|
19
|
+
* The three inputs, highest precedence first:
|
|
20
|
+
* 1. `override` — the explicit per-mount answer. A headless test, a capture
|
|
21
|
+
* harness, or a host that knows better passes `true`/`false` and gets
|
|
22
|
+
* exactly that. Passing `undefined` (or omitting it) means "decide for
|
|
23
|
+
* me" and falls through.
|
|
24
|
+
* 2. A dev build — `import.meta.env.DEV`. The ordinary local/editor case:
|
|
25
|
+
* dev layers are on.
|
|
26
|
+
* 3. A production build's EXPLICIT opt-in — `VITE_VGAI_DEV_LAYERS=true`.
|
|
27
|
+
* Shipping the dev GUI in a production bundle is a real, legitimate
|
|
28
|
+
* choice (an internal playtest build, a QA build), and it must be an
|
|
29
|
+
* opt-in someone had to type, never something a default drifts into.
|
|
30
|
+
*
|
|
31
|
+
* Anything else — a production build with no opt-in — is `false`.
|
|
32
|
+
*/
|
|
33
|
+
export declare function devLayersEnabled(override?: boolean | undefined): boolean;
|
|
34
|
+
//# sourceMappingURL=dev-layers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dev-layers.d.ts","sourceRoot":"","sources":["../../src/runtime/dev-layers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,CAAC,EAAE,OAAO,GAAG,SAAS,GAAG,OAAO,CAOxE"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* THE one owner of "are dev layers enabled" (`vgai.project.json`'s `dev: true`
|
|
3
|
+
* root flag). Every reader that has to answer that question calls
|
|
4
|
+
* {@link devLayersEnabled}; there is deliberately NO second source of truth —
|
|
5
|
+
* not a module-level cached boolean, not a `globalThis` flag, not a per-host
|
|
6
|
+
* copy of the `import.meta.env` read below. A dev GUI that ships to players
|
|
7
|
+
* because two places disagreed about what "dev" means is exactly the failure
|
|
8
|
+
* this single owner exists to make impossible.
|
|
9
|
+
*
|
|
10
|
+
* Ownership, stated in one place (the build rule):
|
|
11
|
+
* - OWNER: this function. It resolves the answer; nothing else derives it.
|
|
12
|
+
* - SHARERS: `mountManifestRoots` (the ship gate — a dev root only mounts
|
|
13
|
+
* when this returns true). Any future host that mounts manifest roots
|
|
14
|
+
* itself calls this too, with its own `override`.
|
|
15
|
+
* - TEARDOWN: none. This is a pure predicate over build config and one
|
|
16
|
+
* caller-supplied argument — it owns no resource, allocates nothing, and
|
|
17
|
+
* has no lifecycle to end.
|
|
18
|
+
*
|
|
19
|
+
* The three inputs, highest precedence first:
|
|
20
|
+
* 1. `override` — the explicit per-mount answer. A headless test, a capture
|
|
21
|
+
* harness, or a host that knows better passes `true`/`false` and gets
|
|
22
|
+
* exactly that. Passing `undefined` (or omitting it) means "decide for
|
|
23
|
+
* me" and falls through.
|
|
24
|
+
* 2. A dev build — `import.meta.env.DEV`. The ordinary local/editor case:
|
|
25
|
+
* dev layers are on.
|
|
26
|
+
* 3. A production build's EXPLICIT opt-in — `VITE_VGAI_DEV_LAYERS=true`.
|
|
27
|
+
* Shipping the dev GUI in a production bundle is a real, legitimate
|
|
28
|
+
* choice (an internal playtest build, a QA build), and it must be an
|
|
29
|
+
* opt-in someone had to type, never something a default drifts into.
|
|
30
|
+
*
|
|
31
|
+
* Anything else — a production build with no opt-in — is `false`.
|
|
32
|
+
*/
|
|
33
|
+
export function devLayersEnabled(override) {
|
|
34
|
+
if (override !== undefined)
|
|
35
|
+
return override;
|
|
36
|
+
const env = import.meta.env;
|
|
37
|
+
if (env?.DEV === true)
|
|
38
|
+
return true;
|
|
39
|
+
return env?.VITE_VGAI_DEV_LAYERS === 'true';
|
|
40
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure, react-free frame-version cache (T7.4 slice 1).
|
|
3
|
+
* `useWorldState` (`packages/editor/template/src/
|
|
4
|
+
* ui/game-state.tsx`) is a thin `useSyncExternalStore` wrapper
|
|
5
|
+
* around this: `getSnapshot` re-runs the selector once per `frameVersion`
|
|
6
|
+
* bump (`GameStateBridge`, `runtime/state-bridge.ts`), caches by version,
|
|
7
|
+
* and returns the PREVIOUS reference when `equals` holds against the fresh
|
|
8
|
+
* result — that reference stability is what lets `useSyncExternalStore`
|
|
9
|
+
* (and thus React) bail out of a re-render.
|
|
10
|
+
*
|
|
11
|
+
* Extracted to its own react-free module (no react import here, or anywhere
|
|
12
|
+
* under `runtime/`) so this cache/equality logic — the part of the hook
|
|
13
|
+
* that has real branching to get wrong — is unit-testable headlessly under
|
|
14
|
+
* `packages/engine/test/`, without needing a react test harness (none
|
|
15
|
+
* exists in this repo today; see `test/frame-selector-cache.test.ts`).
|
|
16
|
+
*/
|
|
17
|
+
/** Equality comparator for `FrameSelectorCache`/`useWorldState`. Defaults to
|
|
18
|
+
* `Object.is` (T7.4 §3); pass {@link shallow} for tuples/plain objects. */
|
|
19
|
+
export type Equals<T> = (a: T, b: T) => boolean;
|
|
20
|
+
/**
|
|
21
|
+
* One-level shallow-equality helper (own enumerable keys, `Object.is` per
|
|
22
|
+
* value) — the opt-in equality for selectors that return a fresh
|
|
23
|
+
* object/array/tuple every call. Two non-object values fall back to
|
|
24
|
+
* `Object.is`; a non-object compared against an object is never equal.
|
|
25
|
+
*/
|
|
26
|
+
export declare function shallow<T>(a: T, b: T): boolean;
|
|
27
|
+
export interface FrameSelectorCache<T> {
|
|
28
|
+
/**
|
|
29
|
+
* Return the cached value for `frameVersion` if it's the SAME version as
|
|
30
|
+
* the last call (selector not re-run at all). Otherwise call `compute()`
|
|
31
|
+
* once: if the fresh result is `equals` to the previously cached value,
|
|
32
|
+
* the PREVIOUS reference is returned (and re-tagged with this
|
|
33
|
+
* `frameVersion`, so the next same-version call also short-circuits);
|
|
34
|
+
* otherwise the fresh value is cached and returned.
|
|
35
|
+
*/
|
|
36
|
+
get(frameVersion: number, compute: () => T): T;
|
|
37
|
+
}
|
|
38
|
+
/** Construct a fresh per-subscriber cache. One per `useWorldState` call site
|
|
39
|
+
* (a fresh cache each mount — see the hook). */
|
|
40
|
+
export declare function createFrameSelectorCache<T>(equals?: Equals<T>): FrameSelectorCache<T>;
|
|
41
|
+
//# sourceMappingURL=frame-selector-cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frame-selector-cache.d.ts","sourceRoot":"","sources":["../../src/runtime/frame-selector-cache.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH;4EAC4E;AAC5E,MAAM,MAAM,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,OAAO,CAAC;AAEhD;;;;;GAKG;AACH,wBAAgB,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,OAAO,CAa9C;AAED,MAAM,WAAW,kBAAkB,CAAC,CAAC;IACnC;;;;;;;OAOG;IACH,GAAG,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC;CAChD;AAED;iDACiD;AACjD,wBAAgB,wBAAwB,CAAC,CAAC,EAAE,MAAM,GAAE,MAAM,CAAC,CAAC,CAAa,GAAG,kBAAkB,CAAC,CAAC,CAAC,CAwBhG"}
|