@volter/editor-game 0.5.65
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/LICENSE +661 -0
- package/NOTICE +23 -0
- package/contributions/asset-budget-asset.menu.ts +26 -0
- package/contributions/asset-budget.action.ts +18 -0
- package/contributions/asset-budget.document.tsx +21 -0
- package/contributions/asset-budget.menu.ts +22 -0
- package/contributions/audio-unlock.service.ts +17 -0
- package/contributions/audio.utility.tsx +15 -0
- package/contributions/autoplay.service.ts +48 -0
- package/contributions/bridge.command.ts +172 -0
- package/contributions/build-profiles.document.tsx +21 -0
- package/contributions/build-progress.status.tsx +45 -0
- package/contributions/build.action.ts +26 -0
- package/contributions/build.command.ts +27 -0
- package/contributions/build.header.tsx +37 -0
- package/contributions/build.menu.ts +31 -0
- package/contributions/build.service.ts +31 -0
- package/contributions/connection.status.tsx +43 -0
- package/contributions/coverage.service.ts +118 -0
- package/contributions/edit-mode-audio.service.ts +23 -0
- package/contributions/edit-mode-networking.service.ts +30 -0
- package/contributions/game-document.service.ts +25 -0
- package/contributions/game-eval.command.ts +210 -0
- package/contributions/game.layout.ts +19 -0
- package/contributions/gameplay.command.ts +255 -0
- package/contributions/generation.service.ts +96 -0
- package/contributions/generations.status.tsx +53 -0
- package/contributions/ingest.service.ts +80 -0
- package/contributions/instances.command.ts +75 -0
- package/contributions/navmesh.menu.ts +39 -0
- package/contributions/navmesh.service.ts +19 -0
- package/contributions/network.utility.tsx +17 -0
- package/contributions/play.command.ts +355 -0
- package/contributions/profiler.action.ts +16 -0
- package/contributions/profiler.menu.ts +22 -0
- package/contributions/profiler.utility.tsx +17 -0
- package/contributions/react/component-board.service.ts +21 -0
- package/contributions/react/design-time-mount.service.ts +60 -0
- package/contributions/react/pasteboard.action.ts +41 -0
- package/contributions/react/react-inspector.service.ts +85 -0
- package/contributions/react/story-documents.service.ts +44 -0
- package/contributions/scene-document.service.ts +32 -0
- package/contributions/state-watch.action.ts +17 -0
- package/contributions/state-watch.menu.ts +23 -0
- package/contributions/state-watch.utility.tsx +20 -0
- package/contributions/team-playtest.service.ts +124 -0
- package/contributions/three/camera-runtime.inspector.tsx +34 -0
- package/contributions/three/component-board.service.ts +24 -0
- package/contributions/three/component-verbs.command.ts +110 -0
- package/contributions/three/component-verbs.service.ts +92 -0
- package/contributions/three/constraints.inspector.tsx +34 -0
- package/contributions/three/model-asset-sections.service.ts +26 -0
- package/contributions/three/reflection-probe-capture.inspector.tsx +32 -0
- package/contributions/three/story-documents.service.ts +31 -0
- package/contributions/three/three-authoring.service.ts +66 -0
- package/contributions/transport.header.tsx +19 -0
- package/contributions/xstate-behavior.action.ts +42 -0
- package/contributions/xstate-behavior.document.tsx +73 -0
- package/contributions/xstate-behavior.inspector.tsx +28 -0
- package/contributions/xstate-behavior.menu.ts +23 -0
- package/package.json +144 -0
- package/src/asset-budget/AssetBudgetPanel.tsx +1172 -0
- package/src/asset-budget/asset-budget-model.ts +799 -0
- package/src/asset-budget/basis-encoder.ts +165 -0
- package/src/asset-budget/gltf-io.ts +154 -0
- package/src/asset-budget/gltf-optimize.ts +384 -0
- package/src/asset-budget/image-dims.ts +78 -0
- package/src/asset-budget/optimize-apply.ts +221 -0
- package/src/audio/AudioDebuggerPanel.tsx +457 -0
- package/src/audio/audio-debugger-model.ts +87 -0
- package/src/bridge/call.ts +60 -0
- package/src/bridge/dispatch.ts +459 -0
- package/src/bridge/live-frames.ts +25 -0
- package/src/bridge/screenshot.ts +316 -0
- package/src/build/BuildProfilesPanel.tsx +476 -0
- package/src/build/build-session.ts +247 -0
- package/src/build/format-bytes.ts +14 -0
- package/src/command-results.ts +36 -0
- package/src/coverage/live-authoring-surface.ts +30 -0
- package/src/coverage/live-project-verbs.ts +162 -0
- package/src/coverage/native-system-coverage.ts +143 -0
- package/src/coverage/root-coverage.ts +79 -0
- package/src/coverage/session-coverage.ts +193 -0
- package/src/design-system-stories/ApplicationChrome.stories.tsx +100 -0
- package/src/design-system-stories/InspectorNarrowBodies.stories.tsx +406 -0
- package/src/edit-mode/edit-mode-audio.ts +56 -0
- package/src/edit-mode/edit-mode-networking.ts +112 -0
- package/src/game-document/DevicePresetPicker.tsx +84 -0
- package/src/game-document/GameCaptureFrameButton.tsx +45 -0
- package/src/game-document/GameDocument.tsx +215 -0
- package/src/game-document/GamePanel.tsx +662 -0
- package/src/game-document/InstanceInspectorPicker.tsx +183 -0
- package/src/game-document/crowd-debug.ts +183 -0
- package/src/game-document/device-preview.ts +336 -0
- package/src/game-document/game-view-store.ts +107 -0
- package/src/game-document/physics-debug.ts +187 -0
- package/src/generation/GenerationActivity.tsx +421 -0
- package/src/generation/GenerationGallery.css +231 -0
- package/src/generation/generation-documents.tsx +338 -0
- package/src/generation/generation-jobs.ts +128 -0
- package/src/generation/generation-presentation.ts +257 -0
- package/src/host/adapter-reach.ts +445 -0
- package/src/host/adapter-runtime-bindings.ts +303 -0
- package/src/host/after-paint.ts +112 -0
- package/src/host/api/configurations.ts +66 -0
- package/src/host/authoring/babylon-authoring-adapter.ts +703 -0
- package/src/host/authoring/canvas-runtime-recognition.ts +50 -0
- package/src/host/authoring/contract-hierarchy-authoring.ts +144 -0
- package/src/host/authoring/contract-scenes-stories.ts +204 -0
- package/src/host/authoring/creation-site-related.ts +55 -0
- package/src/host/authoring/ephemeral-persistence.ts +29 -0
- package/src/host/authoring/gesture-persist.ts +84 -0
- package/src/host/authoring/ingest-data-writer.ts +232 -0
- package/src/host/authoring/ingest-source-persistence.ts +826 -0
- package/src/host/authoring/mount-isolated-pixi-screen.ts +250 -0
- package/src/host/authoring/mounted-authoring.ts +41 -0
- package/src/host/authoring/owned-pixi-ticker-listeners.ts +96 -0
- package/src/host/authoring/phaser-live-authoring-adapter.ts +265 -0
- package/src/host/authoring/pixi-authoring-adapter.ts +1554 -0
- package/src/host/authoring/pixi-creation-site-write-target.ts +60 -0
- package/src/host/authoring/pixi-isolation-assets.ts +25 -0
- package/src/host/authoring/pixi-live-write-target.ts +979 -0
- package/src/host/authoring/pixi-source-identity.ts +141 -0
- package/src/host/authoring/pixi-still-presentation.ts +71 -0
- package/src/host/authoring/pixi-structure-history.ts +237 -0
- package/src/host/authoring/pixi-transform-channels.ts +205 -0
- package/src/host/authoring/selection-remount-handoff.ts +23 -0
- package/src/host/authoring/source-persistence-backend.ts +373 -0
- package/src/host/authoring/source-refresh-revisions.ts +81 -0
- package/src/host/authoring/struct-write-pipe.ts +143 -0
- package/src/host/auto-frame-window.ts +89 -0
- package/src/host/binding-resolver.ts +393 -0
- package/src/host/browser-transpile.ts +631 -0
- package/src/host/canvas-entry-runtime.ts +95 -0
- package/src/host/components/CameraAuthoringOverlay.tsx +216 -0
- package/src/host/components/HeaderTelemetry.tsx +341 -0
- package/src/host/components/PixiIsolationSceneContent.tsx +280 -0
- package/src/host/components/ResolutionPicker.tsx +89 -0
- package/src/host/components/ThreeIsolationSceneContent.tsx +180 -0
- package/src/host/components/frame-debugger-model.ts +579 -0
- package/src/host/components/header-telemetry-model.ts +74 -0
- package/src/host/components/scene-document.tsx +447 -0
- package/src/host/components/utility-view-state.ts +87 -0
- package/src/host/components/world-root-stage-binding.tsx +133 -0
- package/src/host/components/world-root-stage.ts +1046 -0
- package/src/host/coverage/authoring-read-probe.ts +583 -0
- package/src/host/coverage/capability-coverage.ts +1587 -0
- package/src/host/coverage/coverage-accounting.ts +261 -0
- package/src/host/coverage/game-contract-seam-evidence.ts +82 -0
- package/src/host/coverage/project-verb-coverage.ts +148 -0
- package/src/host/coverage/system-adapter-coverage.ts +373 -0
- package/src/host/design-system-stories/StoryLayout.tsx +104 -0
- package/src/host/design-system-stories/fixtures/authoring.ts +247 -0
- package/src/host/design-system-stories/fixtures/editor-runtime.tsx +115 -0
- package/src/host/document-preview-three.ts +110 -0
- package/src/host/entry-adjudication.ts +89 -0
- package/src/host/game-location-guard.ts +150 -0
- package/src/host/game-module-access.ts +196 -0
- package/src/host/game-realm-page.ts +358 -0
- package/src/host/game-realm-reclaim.ts +55 -0
- package/src/host/game-realm-storage.ts +104 -0
- package/src/host/gameplay-export.ts +288 -0
- package/src/host/gameplay-recording.ts +717 -0
- package/src/host/gated-globals.ts +1511 -0
- package/src/host/history/json-history-resource.ts +254 -0
- package/src/host/ingest/registry.ts +261 -0
- package/src/host/instance-extract-actions.ts +120 -0
- package/src/host/instance-fork-actions.ts +120 -0
- package/src/host/play-control-hook.ts +26 -0
- package/src/host/playwright-shim.ts +479 -0
- package/src/host/projection/dom.ts +295 -0
- package/src/host/projection/pixi.ts +288 -0
- package/src/host/r3f-entry-runtime.ts +77 -0
- package/src/host/react-mount-runtime.ts +162 -0
- package/src/host/realm-services.ts +148 -0
- package/src/host/recording-preview.ts +106 -0
- package/src/host/roots/module-root.ts +203 -0
- package/src/host/roots/react-root.ts +181 -0
- package/src/host/same-realm-loop-gate.ts +544 -0
- package/src/host/scene-view-drawability.ts +69 -0
- package/src/host/sdk/tools.ts +31 -0
- package/src/host/served-bundle-runtime-modules.ts +331 -0
- package/src/host/server-log-bridge.ts +60 -0
- package/src/host/staged-projects.ts +24 -0
- package/src/host/stories/mounted-story-viewport-source.ts +64 -0
- package/src/host/stories/story-arg-descriptors.ts +50 -0
- package/src/host/stories/story-media-presence.ts +152 -0
- package/src/host/surface-content.ts +87 -0
- package/src/host/take-named-export.ts +23 -0
- package/src/host/three-ingest-runtime.ts +76 -0
- package/src/host/types-fastnoise-lite.d.ts +7 -0
- package/src/host/types-mikktspace.d.ts +20 -0
- package/src/host/types-troika-three-text.d.ts +7 -0
- package/src/host/use-active-performance-source.ts +53 -0
- package/src/host/viewport-pose-memory.ts +48 -0
- package/src/host/viewport-root-presentation.ts +40 -0
- package/src/ingest/active-ingest.ts +251 -0
- package/src/ingest/active-scene-navigation.ts +43 -0
- package/src/ingest/authoring/ingest-dom-surface-authoring.ts +191 -0
- package/src/ingest/authoring/ingest-root-adapter.ts +897 -0
- package/src/ingest/capture-wait-report.ts +122 -0
- package/src/ingest/deferred-ingest-play.ts +216 -0
- package/src/ingest/deferred-ingest-session.ts +23 -0
- package/src/ingest/discovery-public-ingest.ts +242 -0
- package/src/ingest/dom-stub-mark.ts +7 -0
- package/src/ingest/entry-load.ts +56 -0
- package/src/ingest/game-contract-realm.ts +34 -0
- package/src/ingest/game-pointer-lock.ts +89 -0
- package/src/ingest/held-scene-repaint.ts +73 -0
- package/src/ingest/host-surface-box.ts +174 -0
- package/src/ingest/ingest-boot-viewport.ts +54 -0
- package/src/ingest/ingest-canvas-scene-document.tsx +177 -0
- package/src/ingest/ingest-canvas-scene.ts +50 -0
- package/src/ingest/ingest-evidence-hook.ts +131 -0
- package/src/ingest/ingest-frame-snapshot.ts +183 -0
- package/src/ingest/ingest-play-commands.ts +134 -0
- package/src/ingest/ingest-play-control.ts +299 -0
- package/src/ingest/ingest-render-debug.ts +320 -0
- package/src/ingest/ingest-siblings.ts +487 -0
- package/src/ingest/ingest-status.ts +62 -0
- package/src/ingest/live-ingest-facet.ts +46 -0
- package/src/ingest/module-mode.ts +229 -0
- package/src/ingest/mount-canvas-ingest-root.ts +899 -0
- package/src/ingest/mount-coverage.ts +296 -0
- package/src/ingest/mount-dom-ingest-root.ts +282 -0
- package/src/ingest/mount-ingest-root.ts +744 -0
- package/src/ingest/mount-three-ingest-root.ts +366 -0
- package/src/ingest/resolve-canvas.ts +47 -0
- package/src/ingest/resolve-three.ts +123 -0
- package/src/ingest/served-bundle.ts +109 -0
- package/src/ingest/served-html-boot.ts +292 -0
- package/src/ingest/surface-canvas.ts +84 -0
- package/src/ingest/surface-dom.ts +84 -0
- package/src/ingest/surface-three.ts +128 -0
- package/src/ingest/types.ts +76 -0
- package/src/ingest/unmount-ingest-root.ts +224 -0
- package/src/navmesh/navmesh-actions.ts +27 -0
- package/src/navmesh/navmesh-handler.ts +237 -0
- package/src/navmesh/navmesh-workflow-store.ts +78 -0
- package/src/network/NetworkInspectorPanel.tsx +644 -0
- package/src/network/network-inspector-model.ts +225 -0
- package/src/play/play-boot-stall.ts +118 -0
- package/src/play/play-log-events.ts +26 -0
- package/src/play/play-mode.ts +2553 -0
- package/src/play/play-recording.ts +335 -0
- package/src/play/react-play-live-authoring.ts +165 -0
- package/src/play-bar/PlayBar.tsx +488 -0
- package/src/play-bar/PlayerCountPicker.tsx +100 -0
- package/src/profiler/FrameDebuggerPanel.tsx +458 -0
- package/src/profiler/PerformancePanel.tsx +1068 -0
- package/src/profiler/ProfilerPanel.tsx +53 -0
- package/src/profiler/frame-debugger-store.ts +97 -0
- package/src/profiler/main-thread-busy.ts +90 -0
- package/src/react/design-time-react-mount.ts +782 -0
- package/src/react/dom-authoring-adapter.ts +764 -0
- package/src/react/pasteboard-materialize.ts +154 -0
- package/src/react/react-inspector-section.tsx +2496 -0
- package/src/react/react-world-authoring-adapter.ts +3795 -0
- package/src/react/story-documents/story-args-section.ts +19 -0
- package/src/react/story-documents/story-documents.tsx +1380 -0
- package/src/react/story-paint-bounds.ts +94 -0
- package/src/react/ui-board-document.tsx +101 -0
- package/src/react/ui-board-title.ts +9 -0
- package/src/react/ui-component-board.ts +72 -0
- package/src/services/audio-pose-guard.ts +81 -0
- package/src/services/game-audio-unlock.ts +48 -0
- package/src/state-watch/StateWatchPanel.tsx +535 -0
- package/src/three/authoring/camera-runtime-inspector-section.tsx +135 -0
- package/src/three/authoring/constraint-inspector-section.tsx +189 -0
- package/src/three/authoring/design-time-renderer.ts +189 -0
- package/src/three/authoring/model-asset-inspector-section.css +41 -0
- package/src/three/authoring/model-asset-inspector-section.tsx +869 -0
- package/src/three/authoring/oid-source-persistence.ts +557 -0
- package/src/three/authoring/r3f-design-session.ts +1174 -0
- package/src/three/authoring/r3f-source-authoring-adapter.ts +5949 -0
- package/src/three/authoring/reflection-probe-inspector-section.tsx +76 -0
- package/src/three/authoring/spatial-audio-handles.ts +215 -0
- package/src/three/authoring/spatial-collider-handles.ts +229 -0
- package/src/three/authoring/spatial-joint-handles.ts +114 -0
- package/src/three/authoring/spatial-light-handles.ts +178 -0
- package/src/three/authoring/spatial-lod-handles.ts +93 -0
- package/src/three/authoring/spatial-particle-handles.ts +368 -0
- package/src/three/authoring/three-authoring-adapter.ts +1953 -0
- package/src/three/authoring/three-scene-identity.ts +19 -0
- package/src/three/authoring/three-spatial-handles.ts +161 -0
- package/src/three/authoring/typed-three-inspector.ts +528 -0
- package/src/three/component-verbs/extract-menu.ts +71 -0
- package/src/three/component-verbs/fork-menu.ts +78 -0
- package/src/three/component-verbs/internals-menu.ts +91 -0
- package/src/three/story-documents/three-story-documents.tsx +607 -0
- package/src/three/three-board/ThreeBoardDocument.tsx +888 -0
- package/src/three/three-board/board-framing.ts +412 -0
- package/src/three/three-board/board-layout.ts +401 -0
- package/src/three/three-board/board-scene.ts +901 -0
- package/src/three/three-board/three-component-board.ts +62 -0
- package/src/xstate/XStateBehaviorSection.tsx +130 -0
- package/src/xstate/XStateMachineInspector.tsx +566 -0
- package/src/xstate/character-animation-machine.fixture.ts +74 -0
- package/src/xstate/live-behaviors.ts +106 -0
- package/src/xstate/use-live-actor-state.ts +44 -0
- package/src/xstate/xstate-graph.ts +235 -0
- package/src/xstate/xstate-layout.ts +76 -0
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ONE manifest root → the surface-tagged adapter that mounts it, plus the
|
|
3
|
+
* DECLARATION the host completes into a `RootBinding` at registration.
|
|
4
|
+
*
|
|
5
|
+
* A game is a native program plus a declaration of itself; the editor is a
|
|
6
|
+
* universal client of that declaration. This module is where the declaration
|
|
7
|
+
* is READ: the manifest root, the project's parsed `vgai.adapter.ts`, and the
|
|
8
|
+
* entry module's own static surface, resolved against ONE realm
|
|
9
|
+
* (`realm-services.ts` — dev or packaged).
|
|
10
|
+
*
|
|
11
|
+
* ## What used to be here, and is not any more
|
|
12
|
+
*
|
|
13
|
+
* The realm question — where a root's entry module is loaded FROM — was
|
|
14
|
+
* answered independently inside the three,
|
|
15
|
+
* canvas and dom resolvers, three copies that had already drifted apart in
|
|
16
|
+
* their error messages and branch order. It is `RealmServices.loadEntryModule`
|
|
17
|
+
* now, asked once per root. Entry adjudication ("what does this three module
|
|
18
|
+
* MEAN?") likewise had two copies calling two DIFFERENT engine doors, one of
|
|
19
|
+
* which crashed the packaged runtime; it is `entry-adjudication.ts` now. The
|
|
20
|
+
* `{ module }` guards live in `roots/module-root.ts`, the two DOM identities in
|
|
21
|
+
* `roots/react-root.ts`, and the ingest descriptors — whose served-bundle
|
|
22
|
+
* choice is per-PROJECT, not per-realm — in `ingest/resolve-{three,canvas}.ts`.
|
|
23
|
+
*
|
|
24
|
+
* ## Why the return is a `{ surface, adapter }` PAIR
|
|
25
|
+
*
|
|
26
|
+
* Every identity produces an adapter for a DIFFERENT render surface, each with
|
|
27
|
+
* its own host-context parameter. A single `Promise<RootAdapter>` channel can
|
|
28
|
+
* only be ONE of them, so callers used to re-assert the real kind with
|
|
29
|
+
* `as unknown as` — kind ERASURE: information the manifest already carried,
|
|
30
|
+
* thrown away here and guessed back there. Widening to a bare union does NOT
|
|
31
|
+
* fix it — a union of function types intersects its parameters, so
|
|
32
|
+
* `.mount(host)` becomes uncallable at every call site. Carrying the surface
|
|
33
|
+
* alongside makes the result a discriminated union, so `switch (r.surface)`
|
|
34
|
+
* narrows `r.adapter` to a single signature.
|
|
35
|
+
*/
|
|
36
|
+
|
|
37
|
+
import {
|
|
38
|
+
beginProjectMountEpoch,
|
|
39
|
+
type EntrypointSelectionOverride,
|
|
40
|
+
} from '@volter/editor-sdk/session/project-module-url';
|
|
41
|
+
import {
|
|
42
|
+
nativeDebugBindingFromEntryModule,
|
|
43
|
+
nativeSystemsBindingFromEntryModule,
|
|
44
|
+
} from '@volter/game-runtime/adapter/native-debug-module';
|
|
45
|
+
import type { RootMountSpec } from '@volter/game-runtime/runtime/create-runtime';
|
|
46
|
+
import type { MountEntry } from '@volter/game-runtime/runtime/mount-manifest';
|
|
47
|
+
import type { SurfaceAdapter } from '@volter/editor-project/adapter';
|
|
48
|
+
import type { AdapterDefinition } from '@volter/editor-project/adapter/adapter-module';
|
|
49
|
+
import { assertNever } from '@volter/editor-project/adapter/adapter-surface';
|
|
50
|
+
import type { RootDeclaration } from '@volter/editor-project/adapter/binding';
|
|
51
|
+
import { declaredRoots } from '@volter/editor-project/adapter/manifest-interpreter';
|
|
52
|
+
import type { ResolvedAdapterRoot, ResolvedGameManifest } from '@volter/editor-project/manifest/load';
|
|
53
|
+
import { adjudicateThreeEntry } from './entry-adjudication';
|
|
54
|
+
import { projectAdapterDefinition } from '@volter/editor-core/project-adapter';
|
|
55
|
+
import { activeRealmServices, type RealmServices } from './realm-services';
|
|
56
|
+
import { resolveModuleAdapter } from './roots/module-root';
|
|
57
|
+
import { resolveDomAdapter, resolveIngestReactAdapter } from './roots/react-root';
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* What a root's binding is BEFORE anything mounts.
|
|
61
|
+
*
|
|
62
|
+
* `RootBinding` itself cannot exist yet: its `substrate.mounted` is the handle
|
|
63
|
+
* the adapter's `mount` returns, and mounting is the HOST's job, one layer
|
|
64
|
+
* further out. So resolution produces the adapter to mount and the declaration
|
|
65
|
+
* half; `create-runtime.ts`'s `register<Surface>Root` calls
|
|
66
|
+
* `createRootBinding` with both plus `mounted` at registration.
|
|
67
|
+
*/
|
|
68
|
+
export interface ResolvedRootBinding {
|
|
69
|
+
readonly adapter: SurfaceAdapter;
|
|
70
|
+
/** Absent only for a captured ingest, which never becomes a `RootAdapter`. */
|
|
71
|
+
readonly declaration: RootDeclaration;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** Optional per-root context for {@link resolveRootBinding}. */
|
|
75
|
+
export interface ResolveRootBindingOptions {
|
|
76
|
+
/**
|
|
77
|
+
* Serve this world's entry with its swap-slot const rewritten to `key`.
|
|
78
|
+
* Host-owned remount — the file on disk is untouched. Dev-only; the browser
|
|
79
|
+
* realms refuse it by name.
|
|
80
|
+
*/
|
|
81
|
+
readonly selectionOverride?: EntrypointSelectionOverride | undefined;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Resolve one manifest root against one realm.
|
|
86
|
+
*
|
|
87
|
+
* `adapterDef` is an INPUT, never something this function goes and fetches:
|
|
88
|
+
* `vgai.adapter.ts` loading stays in `project-adapter.ts`, and the binding is
|
|
89
|
+
* the hand-off's shape rather than a second loader.
|
|
90
|
+
*/
|
|
91
|
+
export async function resolveRootBinding(
|
|
92
|
+
root: ResolvedAdapterRoot,
|
|
93
|
+
realm: RealmServices,
|
|
94
|
+
adapterDef: AdapterDefinition | null,
|
|
95
|
+
opts?: ResolveRootBindingOptions,
|
|
96
|
+
): Promise<ResolvedRootBinding> {
|
|
97
|
+
const { adapter, module } = await resolveSurfaceAdapter(root, realm, opts);
|
|
98
|
+
return { adapter, declaration: declare(root, adapterDef, module) };
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/** The declaration half: the manifest root, the parsed definition, the entry
|
|
102
|
+
* namespace with its reach stated, and the entry's two static declared
|
|
103
|
+
* bindings harvested from that same namespace. */
|
|
104
|
+
function declare(
|
|
105
|
+
root: ResolvedAdapterRoot,
|
|
106
|
+
definition: AdapterDefinition | null,
|
|
107
|
+
module: Record<string, unknown>,
|
|
108
|
+
): RootDeclaration {
|
|
109
|
+
const debug = nativeDebugBindingFromEntryModule(root.id, module);
|
|
110
|
+
const systems = nativeSystemsBindingFromEntryModule(root.id, module, root.surface);
|
|
111
|
+
return {
|
|
112
|
+
root,
|
|
113
|
+
definition,
|
|
114
|
+
entry: { reach: 'full', module },
|
|
115
|
+
...(debug ? { entryDebug: debug } : {}),
|
|
116
|
+
...(systems ? { entrySystems: systems } : {}),
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* The per-identity dispatch. Each branch's tag is the identity's own surface,
|
|
122
|
+
* not a guess: `load.ts` derives a builtin identity FROM the declared surface
|
|
123
|
+
* and an ingest identity likewise, so identity and surface agree by
|
|
124
|
+
* construction. `{ module }` is the one identity that does not fix a surface,
|
|
125
|
+
* and it dispatches on `root.surface` itself.
|
|
126
|
+
*/
|
|
127
|
+
async function resolveSurfaceAdapter(
|
|
128
|
+
root: ResolvedAdapterRoot,
|
|
129
|
+
realm: RealmServices,
|
|
130
|
+
opts?: ResolveRootBindingOptions,
|
|
131
|
+
): Promise<{ adapter: SurfaceAdapter; module: Record<string, unknown> }> {
|
|
132
|
+
const { adapter } = root;
|
|
133
|
+
switch (adapter.identity) {
|
|
134
|
+
case 'three':
|
|
135
|
+
return resolveThreeRoot(root, realm, opts);
|
|
136
|
+
case 'canvas':
|
|
137
|
+
return resolveCanvasRoot(root, realm, opts);
|
|
138
|
+
case 'dom': {
|
|
139
|
+
let module: Record<string, unknown> = {};
|
|
140
|
+
const built = await resolveDomAdapter(root, realm, (m) => {
|
|
141
|
+
module = m;
|
|
142
|
+
});
|
|
143
|
+
return { adapter: { surface: 'dom', adapter: built }, module };
|
|
144
|
+
}
|
|
145
|
+
case 'module': {
|
|
146
|
+
const { resolved, module } = await resolveModuleAdapter(root, realm.projectRoot, realm.epoch);
|
|
147
|
+
return { adapter: resolved, module };
|
|
148
|
+
}
|
|
149
|
+
case 'ingest-react': {
|
|
150
|
+
const { adapter: built, module } = await resolveIngestReactAdapter(root, realm);
|
|
151
|
+
return { adapter: { surface: 'dom', adapter: built }, module };
|
|
152
|
+
}
|
|
153
|
+
case 'ingest-pixi':
|
|
154
|
+
case 'ingest-three':
|
|
155
|
+
return rejectCapturedIngestAsRootAdapter(root);
|
|
156
|
+
default: {
|
|
157
|
+
const exhaustive: never = adapter;
|
|
158
|
+
throw new Error(
|
|
159
|
+
`resolveRootBinding: unhandled adapter identity ${JSON.stringify(exhaustive)}`,
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/** A three root: `entry` is the only way one is authored, and what that module
|
|
166
|
+
* MEANS is `entry-adjudication.ts`'s single answer. */
|
|
167
|
+
async function resolveThreeRoot(
|
|
168
|
+
root: ResolvedAdapterRoot,
|
|
169
|
+
realm: RealmServices,
|
|
170
|
+
opts?: ResolveRootBindingOptions,
|
|
171
|
+
): Promise<{ adapter: SurfaceAdapter; module: Record<string, unknown> }> {
|
|
172
|
+
if (root.entry === undefined) {
|
|
173
|
+
// Unreachable in practice: `load.ts` requires `entry` for every three root
|
|
174
|
+
// at manifest-load time.
|
|
175
|
+
throw new Error(
|
|
176
|
+
`resolveRootBinding: world "${root.id}" is a three root with no \`entry\` — this should ` +
|
|
177
|
+
'have been rejected by manifest validation. A three root is authored as a TSX/R3F world ' +
|
|
178
|
+
'module.',
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
const module = await realm.loadEntryModule(root.entry, root.id, 'three', opts?.selectionOverride);
|
|
182
|
+
const built = await adjudicateThreeEntry(module, root.id, { entryPath: root.entry });
|
|
183
|
+
if (!built) {
|
|
184
|
+
throw new Error(
|
|
185
|
+
`Project script at ${root.entry} neither exports \`adapter\` nor default-exports a ` +
|
|
186
|
+
'React world component — every explicit first-party entry module satisfies one of the ' +
|
|
187
|
+
'two (`export default function World() { … }`, or an `adapter` export for full control).',
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
return { adapter: { surface: 'three', adapter: built }, module };
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* A canvas root is source-as-truth exactly like a three root: its `entry` is a
|
|
195
|
+
* TSX world file, and what that file EXPORTS is adjudicated in ONE place —
|
|
196
|
+
* `resolveCanvasEntryAdapter` (`@volter/game-runtime/canvas-react`, reached through the
|
|
197
|
+
* realm so the packaged runtime takes it from the PROJECT's graph), the same
|
|
198
|
+
* function the standalone mount path uses. Keeping the adjudication there
|
|
199
|
+
* rather than here is what stops the editor and the standalone build from
|
|
200
|
+
* disagreeing about what a world file means.
|
|
201
|
+
*/
|
|
202
|
+
async function resolveCanvasRoot(
|
|
203
|
+
root: ResolvedAdapterRoot,
|
|
204
|
+
realm: RealmServices,
|
|
205
|
+
opts?: ResolveRootBindingOptions,
|
|
206
|
+
): Promise<{ adapter: SurfaceAdapter; module: Record<string, unknown> }> {
|
|
207
|
+
if (root.entry === undefined) {
|
|
208
|
+
throw new Error(
|
|
209
|
+
`resolveRootBinding: world "${root.id}" is a canvas root with no \`entry\` — this should ` +
|
|
210
|
+
'have been rejected by manifest validation. A canvas root is authored as a TSX world ' +
|
|
211
|
+
'module; point `entry` at it.',
|
|
212
|
+
);
|
|
213
|
+
}
|
|
214
|
+
const module = await realm.loadEntryModule(
|
|
215
|
+
root.entry,
|
|
216
|
+
root.id,
|
|
217
|
+
'canvas',
|
|
218
|
+
opts?.selectionOverride,
|
|
219
|
+
);
|
|
220
|
+
const built = await realm.pixiRuntime(module, root.id);
|
|
221
|
+
if (!built) {
|
|
222
|
+
throw new Error(
|
|
223
|
+
`Project script at ${root.entry} (canvas root "${root.id}") must default-export a React ` +
|
|
224
|
+
'component (`export default function World() { … }`) — or export an `adapter` for full ' +
|
|
225
|
+
'control.',
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
return { adapter: { surface: 'canvas', adapter: built }, module };
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Captured Three/Canvas ingests are not `RootAdapter`s. The foreign game owns
|
|
233
|
+
* the renderer, canvas, loop and capture lifecycle, while a normal
|
|
234
|
+
* `RootAdapter.mount(host)` receives a host-owned renderer/surface. Returning
|
|
235
|
+
* an adapter whose `mount()` only throws would fabricate mountability.
|
|
236
|
+
*/
|
|
237
|
+
function rejectCapturedIngestAsRootAdapter(root: ResolvedAdapterRoot): never {
|
|
238
|
+
const resolver =
|
|
239
|
+
root.adapter.identity === 'ingest-pixi'
|
|
240
|
+
? 'resolveIngest2DDescriptor + mountCanvasIngestRootFromManifest'
|
|
241
|
+
: 'resolveIngestDescriptor + mountThreeIngestRootFromManifest';
|
|
242
|
+
throw new Error(
|
|
243
|
+
`resolveRootBinding: world "${root.id}" (${root.adapter.identity}) is a captured foreign ` +
|
|
244
|
+
`runtime, not a host-mounted RootAdapter; dispatch it through ${resolver}`,
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// ---------------------------------------------------------------------------
|
|
249
|
+
// Composition
|
|
250
|
+
// ---------------------------------------------------------------------------
|
|
251
|
+
|
|
252
|
+
/** Editor-only context for resolving a whole manifest composition. */
|
|
253
|
+
export interface ResolveAllRootEntriesOptions {
|
|
254
|
+
/**
|
|
255
|
+
* Remount the named region's entrypoint at this swap-slot key. Only that
|
|
256
|
+
* world's entry URL carries the override; siblings share `?vgai-mount=`
|
|
257
|
+
* alone so the module graph stays one instance.
|
|
258
|
+
*/
|
|
259
|
+
readonly selectionOverride?:
|
|
260
|
+
| (EntrypointSelectionOverride & { readonly regionId: string })
|
|
261
|
+
| undefined;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
interface ResolvedComposition {
|
|
265
|
+
readonly roots: { world: ResolvedAdapterRoot; resolved: ResolvedRootBinding }[];
|
|
266
|
+
readonly mountId: string;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Resolve every declared root in manifest order, against ONE realm and ONE
|
|
271
|
+
* mount epoch.
|
|
272
|
+
*
|
|
273
|
+
* The epoch opens HERE — once, before any root imports its entry — so every
|
|
274
|
+
* root of this composition resolves shared project modules to the same urls.
|
|
275
|
+
* It is the only place that call belongs: it is the single point every
|
|
276
|
+
* multi-root resolve funnels through, and moving it into the per-root
|
|
277
|
+
* resolvers would give each root its own generation, which is the defect.
|
|
278
|
+
*
|
|
279
|
+
* The COMPOSITION level is likewise where the project's two ambient inputs are
|
|
280
|
+
* fetched — the realm's services and the parsed `vgai.adapter.ts` — because
|
|
281
|
+
* both are properties of the open project rather than of any one root, and
|
|
282
|
+
* asking once per composition is what keeps every root of a game bound to the
|
|
283
|
+
* same declaration. `resolveRootBinding` itself still fetches neither: it is
|
|
284
|
+
* handed both, which is the rule that stops it becoming a second loader.
|
|
285
|
+
*/
|
|
286
|
+
async function resolveComposition(
|
|
287
|
+
manifest: ResolvedGameManifest,
|
|
288
|
+
projectRoot: string,
|
|
289
|
+
opts?: ResolveAllRootEntriesOptions,
|
|
290
|
+
): Promise<ResolvedComposition> {
|
|
291
|
+
const epoch = beginProjectMountEpoch();
|
|
292
|
+
const realm = await activeRealmServices(projectRoot, epoch);
|
|
293
|
+
const adapterDef = await projectAdapterDefinition();
|
|
294
|
+
|
|
295
|
+
const out: { world: ResolvedAdapterRoot; resolved: ResolvedRootBinding }[] = [];
|
|
296
|
+
for (const world of declaredRoots(manifest)) {
|
|
297
|
+
const override = opts?.selectionOverride;
|
|
298
|
+
const resolved = await resolveRootBinding(world, realm, adapterDef, {
|
|
299
|
+
...(override && world.id === override.regionId
|
|
300
|
+
? { selectionOverride: { selection: override.selection, key: override.key } }
|
|
301
|
+
: {}),
|
|
302
|
+
});
|
|
303
|
+
out.push({ world, resolved });
|
|
304
|
+
}
|
|
305
|
+
// Stringified because that is the form the id travels in everywhere else:
|
|
306
|
+
// the entry url's `?vgai-mount=` value, and therefore the key
|
|
307
|
+
// `gated-globals.ts` reads back off a module url.
|
|
308
|
+
return { roots: out, mountId: String(epoch) };
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/** Every host-mounted root as a `RootMountSpec[]` — the shape
|
|
312
|
+
* `createGameRuntime({ roots })` takes directly. */
|
|
313
|
+
export async function resolveAllRoots(
|
|
314
|
+
manifest: ResolvedGameManifest,
|
|
315
|
+
projectRoot: string,
|
|
316
|
+
): Promise<RootMountSpec[]> {
|
|
317
|
+
const { roots } = await resolveComposition(manifest, projectRoot);
|
|
318
|
+
|
|
319
|
+
const specs: RootMountSpec[] = [];
|
|
320
|
+
for (const { world, resolved } of roots) {
|
|
321
|
+
const base = {
|
|
322
|
+
id: world.id,
|
|
323
|
+
zOrder: world.zOrder,
|
|
324
|
+
pausable: world.pausable,
|
|
325
|
+
declaration: resolved.declaration,
|
|
326
|
+
};
|
|
327
|
+
const r = resolved.adapter;
|
|
328
|
+
switch (r.surface) {
|
|
329
|
+
case 'canvas':
|
|
330
|
+
specs.push({ ...base, kind: 'canvas', adapter: r.adapter });
|
|
331
|
+
break;
|
|
332
|
+
case 'dom':
|
|
333
|
+
specs.push({ ...base, kind: 'dom', adapter: r.adapter });
|
|
334
|
+
break;
|
|
335
|
+
case 'three':
|
|
336
|
+
specs.push({ ...base, kind: 'three', adapter: r.adapter });
|
|
337
|
+
break;
|
|
338
|
+
default:
|
|
339
|
+
assertNever(r, 'resolveAllRoots');
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
return specs;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* `resolveAllRoots`'s composer-path sibling: the same loop, returning
|
|
347
|
+
* `mountManifestRoots`'s own `entries` shape (`{ kind, adapter }` per world id)
|
|
348
|
+
* instead of a hand-built `RootMountSpec[]` — so `zOrder`/`pausable` and the
|
|
349
|
+
* per-kind spec ASSEMBLY come from `mount-manifest.ts`'s `buildRootMountSpec`,
|
|
350
|
+
* the one authoritative place that translation lives, rather than being
|
|
351
|
+
* duplicated here AND at the `mountManifestRoots` call site.
|
|
352
|
+
*
|
|
353
|
+
* It also returns this composition's `mountId` — the identity the whole
|
|
354
|
+
* isolation layer is keyed by. It is minted here (one epoch per composition),
|
|
355
|
+
* rides every project module url as `?vgai-mount=`, and is what
|
|
356
|
+
* `gated-globals.ts` resolves a realm and an input gate under.
|
|
357
|
+
*
|
|
358
|
+
* It does NOT return the entry modules' harvested `debug`/`systems` bindings.
|
|
359
|
+
* Those ride each root's own declaration into its binding, and
|
|
360
|
+
* `installAdapterRuntimeBindings` reads them off `game.roots` there — one
|
|
361
|
+
* carrier for one fact, instead of a second array the caller had to thread
|
|
362
|
+
* from here to the install site by hand.
|
|
363
|
+
*/
|
|
364
|
+
export async function resolveAllRootEntries(
|
|
365
|
+
manifest: ResolvedGameManifest,
|
|
366
|
+
projectRoot: string,
|
|
367
|
+
opts?: ResolveAllRootEntriesOptions,
|
|
368
|
+
): Promise<{
|
|
369
|
+
entries: Record<string, MountEntry>;
|
|
370
|
+
mountId: string;
|
|
371
|
+
}> {
|
|
372
|
+
const { roots, mountId } = await resolveComposition(manifest, projectRoot, opts);
|
|
373
|
+
|
|
374
|
+
const entries: Record<string, MountEntry> = {};
|
|
375
|
+
for (const { world, resolved } of roots) {
|
|
376
|
+
const { root: _root, ...declaration } = resolved.declaration;
|
|
377
|
+
const r = resolved.adapter;
|
|
378
|
+
switch (r.surface) {
|
|
379
|
+
case 'canvas':
|
|
380
|
+
entries[world.id] = { kind: 'canvas', adapter: r.adapter, declaration };
|
|
381
|
+
break;
|
|
382
|
+
case 'dom':
|
|
383
|
+
entries[world.id] = { kind: 'dom', adapter: r.adapter, declaration };
|
|
384
|
+
break;
|
|
385
|
+
case 'three':
|
|
386
|
+
entries[world.id] = { kind: 'three', adapter: r.adapter, declaration };
|
|
387
|
+
break;
|
|
388
|
+
default:
|
|
389
|
+
assertNever(r, 'resolveAllRootEntries');
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
return { entries, mountId };
|
|
393
|
+
}
|