@forgeax/engine-assets-runtime 0.1.4 → 0.1.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/README.md +442 -175
- package/dist/.tsbuildinfo +1 -1
- package/dist/__tests__/aabb.unit.test.d.ts +2 -0
- package/dist/__tests__/aabb.unit.test.d.ts.map +1 -0
- package/dist/__tests__/artifact-integrity.unit.test.d.ts +2 -0
- package/dist/__tests__/artifact-integrity.unit.test.d.ts.map +1 -0
- package/dist/__tests__/artifact-io.unit.test.d.ts +2 -0
- package/dist/__tests__/artifact-io.unit.test.d.ts.map +1 -0
- package/dist/__tests__/asset-evidence-sdk.integration.test.d.ts +2 -0
- package/dist/__tests__/asset-evidence-sdk.integration.test.d.ts.map +1 -0
- package/dist/__tests__/asset-evidence.unit.test.d.ts +2 -0
- package/dist/__tests__/asset-evidence.unit.test.d.ts.map +1 -0
- package/dist/__tests__/asset-kind.unit.test.d.ts +2 -0
- package/dist/__tests__/asset-kind.unit.test.d.ts.map +1 -0
- package/dist/__tests__/asset-registry-catalog-reconcile.integration.test.d.ts +2 -0
- package/dist/__tests__/asset-registry-catalog-reconcile.integration.test.d.ts.map +1 -0
- package/dist/__tests__/asset-registry-catalog-reconcile.unit.test.d.ts +2 -0
- package/dist/__tests__/asset-registry-catalog-reconcile.unit.test.d.ts.map +1 -0
- package/dist/__tests__/asset-registry-catalog.unit.test.d.ts +2 -0
- package/dist/__tests__/asset-registry-catalog.unit.test.d.ts.map +1 -0
- package/dist/__tests__/asset-registry.pack-cache.test.d.ts +2 -0
- package/dist/__tests__/asset-registry.pack-cache.test.d.ts.map +1 -0
- package/dist/__tests__/asset-registry.unit.test.d.ts +2 -0
- package/dist/__tests__/asset-registry.unit.test.d.ts.map +1 -0
- package/dist/__tests__/asset-runtime-error-code-owner.test-d.d.ts +2 -0
- package/dist/__tests__/asset-runtime-error-code-owner.test-d.d.ts.map +1 -0
- package/dist/__tests__/catalog-replica.unit.test.d.ts +2 -0
- package/dist/__tests__/catalog-replica.unit.test.d.ts.map +1 -0
- package/dist/__tests__/catalog-source-v2.unit.test.d.ts +2 -0
- package/dist/__tests__/catalog-source-v2.unit.test.d.ts.map +1 -0
- package/dist/__tests__/catalog-source.unit.test.d.ts +2 -0
- package/dist/__tests__/catalog-source.unit.test.d.ts.map +1 -0
- package/dist/__tests__/catalog-subscription-order.unit.test.d.ts +2 -0
- package/dist/__tests__/catalog-subscription-order.unit.test.d.ts.map +1 -0
- package/dist/__tests__/catalog-subscription.unit.test.d.ts +2 -0
- package/dist/__tests__/catalog-subscription.unit.test.d.ts.map +1 -0
- package/dist/__tests__/decode-image-bytes-pass-through.test.d.ts +2 -0
- package/dist/__tests__/decode-image-bytes-pass-through.test.d.ts.map +1 -0
- package/dist/__tests__/decode-image-bytes.browser.test.d.ts +2 -0
- package/dist/__tests__/decode-image-bytes.browser.test.d.ts.map +1 -0
- package/dist/__tests__/decode-image-bytes.test-d.d.ts +2 -0
- package/dist/__tests__/decode-image-bytes.test-d.d.ts.map +1 -0
- package/dist/__tests__/decode-image-bytes.test.d.ts +2 -0
- package/dist/__tests__/decode-image-bytes.test.d.ts.map +1 -0
- package/dist/__tests__/dynamic-texture-store.unit.test.d.ts +2 -0
- package/dist/__tests__/dynamic-texture-store.unit.test.d.ts.map +1 -0
- package/dist/__tests__/errors-asset.unit.test.d.ts +2 -0
- package/dist/__tests__/errors-asset.unit.test.d.ts.map +1 -0
- package/dist/__tests__/inline-pack-loaders.unit.test.d.ts +2 -0
- package/dist/__tests__/inline-pack-loaders.unit.test.d.ts.map +1 -0
- package/dist/__tests__/instantiate-context.unit.test.d.ts +2 -0
- package/dist/__tests__/instantiate-context.unit.test.d.ts.map +1 -0
- package/dist/__tests__/instantiate-publication-fence.unit.test.d.ts +2 -0
- package/dist/__tests__/instantiate-publication-fence.unit.test.d.ts.map +1 -0
- package/dist/__tests__/instantiate.unit.test.d.ts +2 -0
- package/dist/__tests__/instantiate.unit.test.d.ts.map +1 -0
- package/dist/__tests__/loader-input-contract.unit.test.d.ts +2 -0
- package/dist/__tests__/loader-input-contract.unit.test.d.ts.map +1 -0
- package/dist/__tests__/loader-registry.unit.test.d.ts +2 -0
- package/dist/__tests__/loader-registry.unit.test.d.ts.map +1 -0
- package/dist/__tests__/material-dependency-invalidation.unit.test.d.ts +2 -0
- package/dist/__tests__/material-dependency-invalidation.unit.test.d.ts.map +1 -0
- package/dist/__tests__/material-generation-cache.unit.test.d.ts +2 -0
- package/dist/__tests__/material-generation-cache.unit.test.d.ts.map +1 -0
- package/dist/__tests__/material-load-consumer.test-d.d.ts +2 -0
- package/dist/__tests__/material-load-consumer.test-d.d.ts.map +1 -0
- package/dist/__tests__/material-ready.integration.test.d.ts +2 -0
- package/dist/__tests__/material-ready.integration.test.d.ts.map +1 -0
- package/dist/__tests__/material-stale-generation.unit.test.d.ts +2 -0
- package/dist/__tests__/material-stale-generation.unit.test.d.ts.map +1 -0
- package/dist/__tests__/mesh-bin-morph-v3.test.d.ts +2 -0
- package/dist/__tests__/mesh-bin-morph-v3.test.d.ts.map +1 -0
- package/dist/__tests__/mesh-bin.unit.test.d.ts +2 -0
- package/dist/__tests__/mesh-bin.unit.test.d.ts.map +1 -0
- package/dist/__tests__/mipmap-generator.unit.test.d.ts +2 -0
- package/dist/__tests__/mipmap-generator.unit.test.d.ts.map +1 -0
- package/dist/__tests__/pack-artifact-transcode-model-owner.test.d.ts +2 -0
- package/dist/__tests__/pack-artifact-transcode-model-owner.test.d.ts.map +1 -0
- package/dist/__tests__/pack-basis-load.integration.test.d.ts +2 -0
- package/dist/__tests__/pack-basis-load.integration.test.d.ts.map +1 -0
- package/dist/__tests__/payload-validate.unit.test.d.ts +2 -0
- package/dist/__tests__/payload-validate.unit.test.d.ts.map +1 -0
- package/dist/__tests__/plugin.test.d.ts +2 -0
- package/dist/__tests__/plugin.test.d.ts.map +1 -0
- package/dist/__tests__/registry-concurrency.bench.test.d.ts +2 -0
- package/dist/__tests__/registry-concurrency.bench.test.d.ts.map +1 -0
- package/dist/__tests__/registry-failure-retry.integration.test.d.ts +2 -0
- package/dist/__tests__/registry-failure-retry.integration.test.d.ts.map +1 -0
- package/dist/__tests__/registry-load-graph.integration.test.d.ts +2 -0
- package/dist/__tests__/registry-load-graph.integration.test.d.ts.map +1 -0
- package/dist/__tests__/registry-load-state.unit.test.d.ts +2 -0
- package/dist/__tests__/registry-load-state.unit.test.d.ts.map +1 -0
- package/dist/__tests__/registry-package-cache.unit.test.d.ts +2 -0
- package/dist/__tests__/registry-package-cache.unit.test.d.ts.map +1 -0
- package/dist/__tests__/registry-public-ready.unit.test.d.ts +2 -0
- package/dist/__tests__/registry-public-ready.unit.test.d.ts.map +1 -0
- package/dist/__tests__/resolve-asset-handle.unit.test.d.ts +2 -0
- package/dist/__tests__/resolve-asset-handle.unit.test.d.ts.map +1 -0
- package/dist/__tests__/scene-handle-fields.unit.test.d.ts +2 -0
- package/dist/__tests__/scene-handle-fields.unit.test.d.ts.map +1 -0
- package/dist/__tests__/scene-payload.unit.test.d.ts +2 -0
- package/dist/__tests__/scene-payload.unit.test.d.ts.map +1 -0
- package/dist/__tests__/scene-publication-fence.test.d.ts +2 -0
- package/dist/__tests__/scene-publication-fence.test.d.ts.map +1 -0
- package/dist/__tests__/scriptable-pack-public-surface.test-d.d.ts +2 -0
- package/dist/__tests__/scriptable-pack-public-surface.test-d.d.ts.map +1 -0
- package/dist/__tests__/static-rig.integration.test.d.ts +2 -0
- package/dist/__tests__/static-rig.integration.test.d.ts.map +1 -0
- package/dist/__tests__/validate-material.unit.test.d.ts +2 -0
- package/dist/__tests__/validate-material.unit.test.d.ts.map +1 -0
- package/dist/__tests__/video-pack-loader.integration.test.d.ts +2 -0
- package/dist/__tests__/video-pack-loader.integration.test.d.ts.map +1 -0
- package/dist/aabb.d.ts +3 -0
- package/dist/aabb.d.ts.map +1 -0
- package/dist/asset-registry.d.ts +552 -0
- package/dist/asset-registry.d.ts.map +1 -0
- package/dist/builtin-asset-registry.d.ts +22 -0
- package/dist/builtin-asset-registry.d.ts.map +1 -0
- package/dist/catalog-source.d.ts +2 -1
- package/dist/catalog-source.d.ts.map +1 -1
- package/dist/decode-image-bytes.d.ts +57 -0
- package/dist/decode-image-bytes.d.ts.map +1 -0
- package/dist/dynamic-texture-store.d.ts +89 -0
- package/dist/dynamic-texture-store.d.ts.map +1 -0
- package/dist/errors/asset.d.ts +201 -0
- package/dist/errors/asset.d.ts.map +1 -0
- package/dist/handles.d.ts +141 -0
- package/dist/handles.d.ts.map +1 -0
- package/dist/image-error.d.ts +6 -0
- package/dist/image-error.d.ts.map +1 -0
- package/dist/index.d.ts +32 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +7218 -114
- package/dist/index.mjs.map +1 -1
- package/dist/internal.d.ts +1 -1
- package/dist/internal.d.ts.map +1 -1
- package/dist/loader-registry.d.ts +63 -0
- package/dist/loader-registry.d.ts.map +1 -0
- package/dist/loaders/inline-pack.d.ts +72 -0
- package/dist/loaders/inline-pack.d.ts.map +1 -0
- package/dist/loaders/mesh-bin.d.ts +21 -0
- package/dist/loaders/mesh-bin.d.ts.map +1 -0
- package/dist/loaders/pack-artifact.d.ts +20 -0
- package/dist/loaders/pack-artifact.d.ts.map +1 -0
- package/dist/material/dependency-graph.d.ts +9 -0
- package/dist/material/dependency-graph.d.ts.map +1 -0
- package/dist/material/generation-cache.d.ts +24 -0
- package/dist/material/generation-cache.d.ts.map +1 -0
- package/dist/material/inspection.d.ts +24 -0
- package/dist/material/inspection.d.ts.map +1 -0
- package/dist/material/loader.d.ts +59 -0
- package/dist/material/loader.d.ts.map +1 -0
- package/dist/material/runtime-shader.d.ts +14 -0
- package/dist/material/runtime-shader.d.ts.map +1 -0
- package/dist/mesh-bin.d.ts +3 -0
- package/dist/mesh-bin.d.ts.map +1 -0
- package/dist/mipmap-generator.d.ts +132 -0
- package/dist/mipmap-generator.d.ts.map +1 -0
- package/dist/payload-validate.d.ts +60 -0
- package/dist/payload-validate.d.ts.map +1 -0
- package/dist/plugin.d.ts +16 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/registry/artifact-io.d.ts +16 -0
- package/dist/registry/artifact-io.d.ts.map +1 -0
- package/dist/registry/asset-evidence.d.ts +13 -0
- package/dist/registry/asset-evidence.d.ts.map +1 -0
- package/dist/registry/catalog-state.d.ts +47 -0
- package/dist/registry/catalog-state.d.ts.map +1 -0
- package/dist/registry/catalog.d.ts +48 -0
- package/dist/registry/catalog.d.ts.map +1 -0
- package/dist/registry/instantiate.d.ts +153 -0
- package/dist/registry/instantiate.d.ts.map +1 -0
- package/dist/registry/load-by-guid.d.ts +247 -0
- package/dist/registry/load-by-guid.d.ts.map +1 -0
- package/dist/registry/load-state.d.ts +26 -0
- package/dist/registry/load-state.d.ts.map +1 -0
- package/dist/registry/runtime-projection.d.ts +16 -0
- package/dist/registry/runtime-projection.d.ts.map +1 -0
- package/dist/registry/scene-publication-fence.d.ts +38 -0
- package/dist/registry/scene-publication-fence.d.ts.map +1 -0
- package/dist/registry/validate-material.d.ts +77 -0
- package/dist/registry/validate-material.d.ts.map +1 -0
- package/dist/resolve-asset-handle.d.ts +43 -0
- package/dist/resolve-asset-handle.d.ts.map +1 -0
- package/dist/resolve-tileset-runtime.d.ts +23 -0
- package/dist/resolve-tileset-runtime.d.ts.map +1 -0
- package/dist/scene-handle-fields.d.ts +88 -0
- package/dist/scene-handle-fields.d.ts.map +1 -0
- package/dist/scene-payload.d.ts +15 -0
- package/dist/scene-payload.d.ts.map +1 -0
- package/dist/wire-default-loaders.d.ts +29 -0
- package/dist/wire-default-loaders.d.ts.map +1 -0
- package/package.json +22 -9
- package/src/__tests__/aabb.unit.test.ts +97 -0
- package/src/__tests__/artifact-integrity.unit.test.ts +99 -0
- package/src/__tests__/artifact-io.unit.test.ts +127 -0
- package/src/__tests__/asset-evidence-sdk.integration.test.ts +32 -0
- package/src/__tests__/asset-evidence.unit.test.ts +32 -0
- package/src/__tests__/{asset-kind.test.ts → asset-kind.unit.test.ts} +1 -1
- package/src/__tests__/asset-registry-catalog-reconcile.integration.test.ts +74 -0
- package/src/__tests__/asset-registry-catalog-reconcile.unit.test.ts +89 -0
- package/src/__tests__/asset-registry-catalog.unit.test.ts +170 -0
- package/src/__tests__/asset-registry.pack-cache.test.ts +96 -0
- package/src/__tests__/asset-registry.unit.test.ts +511 -0
- package/src/__tests__/asset-runtime-error-code-owner.test-d.ts +63 -0
- package/src/__tests__/catalog-replica.unit.test.ts +196 -0
- package/src/__tests__/catalog-source-v2.unit.test.ts +158 -0
- package/src/__tests__/catalog-source.unit.test.ts +126 -0
- package/src/__tests__/catalog-subscription-order.unit.test.ts +65 -0
- package/src/__tests__/catalog-subscription.unit.test.ts +28 -0
- package/src/__tests__/decode-image-bytes-pass-through.test.ts +34 -0
- package/src/__tests__/decode-image-bytes.browser.test.ts +102 -0
- package/src/__tests__/decode-image-bytes.test-d.ts +108 -0
- package/src/__tests__/decode-image-bytes.test.ts +90 -0
- package/src/__tests__/decode-image-mime-owner.test.ts +2 -5
- package/src/__tests__/dynamic-texture-store.unit.test.ts +115 -0
- package/src/__tests__/errors-asset.unit.test.ts +92 -0
- package/src/__tests__/inline-pack-loaders.unit.test.ts +548 -0
- package/src/__tests__/instantiate-context.unit.test.ts +65 -0
- package/src/__tests__/instantiate-publication-fence.unit.test.ts +158 -0
- package/src/__tests__/instantiate.unit.test.ts +684 -0
- package/src/__tests__/loader-input-contract.unit.test.ts +89 -0
- package/src/__tests__/loader-registry.unit.test.ts +101 -0
- package/src/__tests__/material-dependency-invalidation.unit.test.ts +14 -0
- package/src/__tests__/material-generation-cache.unit.test.ts +46 -0
- package/src/__tests__/material-load-consumer.test-d.ts +42 -0
- package/src/__tests__/material-ready.integration.test.ts +492 -0
- package/src/__tests__/material-stale-generation.unit.test.ts +152 -0
- package/src/__tests__/mesh-bin-morph-v3.test.ts +22 -0
- package/src/__tests__/mesh-bin.unit.test.ts +152 -0
- package/src/__tests__/mipmap-generator.unit.test.ts +202 -0
- package/src/__tests__/pack-artifact-transcode-model-owner.test.ts +32 -0
- package/src/__tests__/pack-basis-load.integration.test.ts +168 -0
- package/src/__tests__/payload-validate.unit.test.ts +285 -0
- package/src/__tests__/plugin.test.ts +55 -0
- package/src/__tests__/registry-concurrency.bench.test.ts +40 -0
- package/src/__tests__/registry-failure-retry.integration.test.ts +69 -0
- package/src/__tests__/registry-load-graph.integration.test.ts +246 -0
- package/src/__tests__/registry-load-state.unit.test.ts +35 -0
- package/src/__tests__/registry-package-cache.unit.test.ts +53 -0
- package/src/__tests__/registry-public-ready.unit.test.ts +38 -0
- package/src/__tests__/resolve-asset-handle.unit.test.ts +238 -0
- package/src/__tests__/scene-handle-fields.unit.test.ts +129 -0
- package/src/__tests__/scene-payload.unit.test.ts +151 -0
- package/src/__tests__/scene-publication-fence.test.ts +129 -0
- package/src/__tests__/scriptable-pack-public-surface.test-d.ts +16 -0
- package/src/__tests__/static-rig.integration.test.ts +8 -0
- package/src/__tests__/validate-material.unit.test.ts +359 -0
- package/src/__tests__/video-pack-loader.integration.test.ts +83 -0
- package/src/aabb.ts +107 -0
- package/src/asset-registry.ts +2040 -0
- package/src/builtin-asset-registry.ts +164 -0
- package/src/catalog-source.ts +14 -70
- package/src/decode-image-bytes.ts +126 -0
- package/src/dynamic-texture-store.ts +234 -0
- package/src/errors/asset.ts +347 -0
- package/src/handles.ts +180 -0
- package/src/image-error.ts +45 -0
- package/src/index.ts +177 -19
- package/src/internal.ts +1 -0
- package/src/loader-registry.ts +157 -0
- package/src/loaders/inline-pack.ts +837 -0
- package/src/loaders/mesh-bin.ts +304 -0
- package/src/loaders/pack-artifact.ts +665 -0
- package/src/material/dependency-graph.ts +46 -0
- package/src/material/generation-cache.ts +177 -0
- package/src/material/inspection.ts +46 -0
- package/src/material/loader.ts +326 -0
- package/src/material/runtime-shader.ts +133 -0
- package/src/mesh-bin.ts +5 -0
- package/src/mipmap-generator.ts +450 -0
- package/src/payload-validate.ts +573 -0
- package/src/plugin.ts +48 -0
- package/src/registry/artifact-io.ts +259 -0
- package/src/registry/asset-evidence.ts +51 -0
- package/src/registry/catalog-state.ts +409 -0
- package/src/registry/catalog.ts +369 -0
- package/src/registry/instantiate.ts +1056 -0
- package/src/registry/load-by-guid.ts +1657 -0
- package/src/registry/load-state.ts +115 -0
- package/src/registry/runtime-projection.ts +63 -0
- package/src/registry/scene-publication-fence.ts +256 -0
- package/src/registry/validate-material.ts +386 -0
- package/src/resolve-asset-handle.ts +147 -0
- package/src/resolve-tileset-runtime.ts +72 -0
- package/src/scene-handle-fields.ts +221 -0
- package/src/scene-payload.ts +207 -0
- package/src/wire-default-loaders.ts +79 -0
- package/dist/__tests__/asset-graph-red.integration.test.d.ts +0 -2
- package/dist/__tests__/asset-graph-red.integration.test.d.ts.map +0 -1
- package/dist/__tests__/asset-kind.test.d.ts +0 -2
- package/dist/__tests__/asset-kind.test.d.ts.map +0 -1
- package/dist/__tests__/asset-registry-core.integration.test.d.ts +0 -2
- package/dist/__tests__/asset-registry-core.integration.test.d.ts.map +0 -1
- package/dist/__tests__/asset-registry-public-api.test-d.d.ts +0 -2
- package/dist/__tests__/asset-registry-public-api.test-d.d.ts.map +0 -1
- package/dist/__tests__/asset-runtime-core-lifecycle.integration.test.d.ts +0 -2
- package/dist/__tests__/asset-runtime-core-lifecycle.integration.test.d.ts.map +0 -1
- package/dist/__tests__/asset-runtime-snapshot.unit.test.d.ts +0 -2
- package/dist/__tests__/asset-runtime-snapshot.unit.test.d.ts.map +0 -1
- package/dist/__tests__/catalog-session-red.unit.test.d.ts +0 -2
- package/dist/__tests__/catalog-session-red.unit.test.d.ts.map +0 -1
- package/dist/__tests__/registry-lifecycle-red.integration.test.d.ts +0 -2
- package/dist/__tests__/registry-lifecycle-red.integration.test.d.ts.map +0 -1
- package/src/__tests__/asset-graph-red.integration.test.ts +0 -113
- package/src/__tests__/asset-registry-core.integration.test.ts +0 -161
- package/src/__tests__/asset-registry-public-api.test-d.ts +0 -31
- package/src/__tests__/asset-runtime-core-lifecycle.integration.test.ts +0 -79
- package/src/__tests__/asset-runtime-snapshot.unit.test.ts +0 -23
- package/src/__tests__/catalog-session-red.unit.test.ts +0 -276
- package/src/__tests__/registry-lifecycle-red.integration.test.ts +0 -80
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
// @forgeax/engine-assets-runtime — scene-handle-fields: shared reflection helper for
|
|
2
|
+
// SceneAsset handle-field extraction (plan-strategy D-4 / requirements B-5).
|
|
3
|
+
//
|
|
4
|
+
// `_resolveSceneGuids` (instantiate) and `buildSceneChildContext` (breadcrumb)
|
|
5
|
+
// consume this helper so the "identify shared<...> / array<shared<...>> schema
|
|
6
|
+
// fields + read GUID string" logic has exactly one authoritative location
|
|
7
|
+
// (Derive, Don't Duplicate).
|
|
8
|
+
//
|
|
9
|
+
// This helper returns raw GUID strings WITHOUT mutating the registry; resolution
|
|
10
|
+
// to Handle numbers is the caller's responsibility.
|
|
11
|
+
//
|
|
12
|
+
// Both consumers prefer the structured `envelope.refs` edges (D-3) when an
|
|
13
|
+
// envelope is catalogued for the scene, and fall back to this entity-component
|
|
14
|
+
// walk only when no envelope (or no per-entity edge detail) is available:
|
|
15
|
+
// - `_resolveSceneGuids`: envelope-less scenes (e.g. unit tests that build a
|
|
16
|
+
// SceneAsset directly without cataloguing it; no `sceneGuidKey`).
|
|
17
|
+
// - `buildSceneChildContext`: prod GUID-only refs[] edges whose `sourceField`
|
|
18
|
+
// was stripped at the serialization boundary (w7 D-10), plus direct
|
|
19
|
+
// `catalog()` scene registration with no refs. The walk recovers the
|
|
20
|
+
// (entityLocalId, componentName, fieldName, arrayIndex) triple the bare
|
|
21
|
+
// edge no longer carries.
|
|
22
|
+
|
|
23
|
+
import type { Component } from '@forgeax/engine-ecs';
|
|
24
|
+
import { componentSchema } from '@forgeax/engine-ecs/internal';
|
|
25
|
+
import type { MountOverride } from '@forgeax/engine-types';
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* A single handle-field reference extracted from a SceneAsset entity.
|
|
29
|
+
*
|
|
30
|
+
* `entityLocalId` is the `node.localId`; `componentName` and `fieldName`
|
|
31
|
+
* identify the schema field whose `fieldType` starts with `shared\<` or
|
|
32
|
+
* `array\<shared\<`. `guidString` is the raw GUID string value from the
|
|
33
|
+
* entity's component data (NOT a parsed `AssetGuid` — callers parse or
|
|
34
|
+
* resolve as needed).
|
|
35
|
+
*
|
|
36
|
+
* `arrayIndex` is `undefined` for plain `handle<T>` fields; for
|
|
37
|
+
* `array<handle<T>>` fields it is the 0-based index into the array.
|
|
38
|
+
*/
|
|
39
|
+
export interface SceneHandleFieldEntry {
|
|
40
|
+
readonly entityLocalId: number;
|
|
41
|
+
readonly componentName: string;
|
|
42
|
+
readonly fieldName: string;
|
|
43
|
+
readonly guidString: string;
|
|
44
|
+
/** 0-based index for `array<handle<T>>` elements; `undefined` for plain `handle<T>` fields. */
|
|
45
|
+
readonly arrayIndex?: number;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Shape of a single entity passed to {@link extractSceneEntityHandleGuids}.
|
|
50
|
+
*
|
|
51
|
+
* Compatible with both `SceneEntity` (from `@forgeax/engine-types`, where
|
|
52
|
+
* `components` is `Partial<ComponentValuesMap>`) and test-side plain objects.
|
|
53
|
+
*/
|
|
54
|
+
interface SceneEntityLike {
|
|
55
|
+
readonly localId: number;
|
|
56
|
+
readonly components: Record<string, Record<string, unknown>>;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Walk every `SceneEntityLike` in `entities` and extract all GUID strings
|
|
61
|
+
* bound to schema fields with `handle<...>` or `array<handle<...>>` fieldType.
|
|
62
|
+
*
|
|
63
|
+
* Unknown component names (absent from the supplied World-local catalog) are
|
|
64
|
+
* silently skipped — the ecs layer's `additionalProperties` check will catch
|
|
65
|
+
* unknowns at spawn time if appropriate.
|
|
66
|
+
*
|
|
67
|
+
* Values that are already numbers (resolved Handles) or non-strings are
|
|
68
|
+
* skipped (they are not GUID refs).
|
|
69
|
+
*
|
|
70
|
+
* @internal Shared by {@link AssetRegistry._resolveSceneGuids} and
|
|
71
|
+
* `buildSceneChildContext` as the entity-walk fallback used when the structured
|
|
72
|
+
* `envelope.refs` edges are unavailable or carry no per-entity detail.
|
|
73
|
+
*/
|
|
74
|
+
export function extractSceneEntityHandleGuids(
|
|
75
|
+
components: ReadonlyMap<string, Component>,
|
|
76
|
+
entities: ReadonlyArray<SceneEntityLike>,
|
|
77
|
+
): SceneHandleFieldEntry[] {
|
|
78
|
+
const entries: SceneHandleFieldEntry[] = [];
|
|
79
|
+
|
|
80
|
+
for (const node of entities) {
|
|
81
|
+
const rawComponents: Record<string, Record<string, unknown>> = node.components as Record<
|
|
82
|
+
string,
|
|
83
|
+
Record<string, unknown>
|
|
84
|
+
>;
|
|
85
|
+
|
|
86
|
+
for (const compName of Object.keys(rawComponents)) {
|
|
87
|
+
const rawFields = rawComponents[compName];
|
|
88
|
+
if (!rawFields) continue;
|
|
89
|
+
|
|
90
|
+
const comp = components.get(compName);
|
|
91
|
+
if (!comp) continue;
|
|
92
|
+
|
|
93
|
+
for (const fieldName of Object.keys(rawFields)) {
|
|
94
|
+
forEachHandleGuid(
|
|
95
|
+
componentSchema(comp)[fieldName],
|
|
96
|
+
rawFields[fieldName],
|
|
97
|
+
(guidString, arrayIndex) => {
|
|
98
|
+
entries.push({
|
|
99
|
+
entityLocalId: node.localId,
|
|
100
|
+
componentName: compName,
|
|
101
|
+
fieldName,
|
|
102
|
+
guidString,
|
|
103
|
+
...(arrayIndex !== undefined ? { arrayIndex } : {}),
|
|
104
|
+
});
|
|
105
|
+
},
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return entries;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* One handle-field GUID reference extracted from a {@link MountOverride}'s value
|
|
116
|
+
* (feat-20260713 M3 / w12). Mirrors {@link SceneHandleFieldEntry} but keys on the
|
|
117
|
+
* override's array index (there is no entity `localId` — an override targets a
|
|
118
|
+
* mount member by its own `localId`, resolved by the ecs apply loop, not here).
|
|
119
|
+
*
|
|
120
|
+
* `fieldName` is the schema field the GUID binds to: the override's own `field`
|
|
121
|
+
* for the patch form, or a key of the component-add value map for the add form.
|
|
122
|
+
*/
|
|
123
|
+
export interface MountOverrideHandleFieldEntry {
|
|
124
|
+
/** 0-based index into the `overrides[]` array passed to the extractor. */
|
|
125
|
+
readonly overrideIndex: number;
|
|
126
|
+
readonly componentName: string;
|
|
127
|
+
readonly fieldName: string;
|
|
128
|
+
readonly guidString: string;
|
|
129
|
+
/** 0-based index for `array<shared<T>>` elements; `undefined` for scalar `shared<T>`. */
|
|
130
|
+
readonly arrayIndex?: number;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Walk `overrides` and extract every GUID string bound to a `shared<...>` /
|
|
135
|
+
* `array<shared<...>>` schema field inside each override's value (feat-20260713
|
|
136
|
+
* M3 / w12, plan-strategy D-2). This is the apply-side counterpart to
|
|
137
|
+
* {@link extractSceneEntityHandleGuids}: it feeds `resolveMountsRec`'s
|
|
138
|
+
* GUID→handle down-drill so a `mounts[].overrides[].value` carrying a raw GUID
|
|
139
|
+
* (e.g. an `AnimationPlayer.clips` clip GUID) resolves to a live handle before
|
|
140
|
+
* the ecs apply loop, which only ever sees numeric handles (D-2: the GUID domain
|
|
141
|
+
* stays sealed in assets-runtime).
|
|
142
|
+
*
|
|
143
|
+
* The `{comp, field?, value}` discriminant is normalized to `(fieldName, value)`
|
|
144
|
+
* pairs: the patch form (`field` present) yields one pair; the component-add form
|
|
145
|
+
* (`field` absent, `value` is a per-field map) yields one pair per value key.
|
|
146
|
+
* Field type is judged from the supplied catalog token schema, the same
|
|
147
|
+
* schema SSOT the entity walk uses. Unknown components / non-shared fields /
|
|
148
|
+
* non-string (already-resolved number) values are skipped (D-8 number pass-through).
|
|
149
|
+
*
|
|
150
|
+
* @internal Shared identification core; resolution lives in `resolveMountsRec`.
|
|
151
|
+
*/
|
|
152
|
+
export function extractMountOverrideHandleGuids(
|
|
153
|
+
components: ReadonlyMap<string, Component>,
|
|
154
|
+
overrides: ReadonlyArray<MountOverride>,
|
|
155
|
+
): MountOverrideHandleFieldEntry[] {
|
|
156
|
+
const entries: MountOverrideHandleFieldEntry[] = [];
|
|
157
|
+
|
|
158
|
+
for (let overrideIndex = 0; overrideIndex < overrides.length; overrideIndex++) {
|
|
159
|
+
const ov = overrides[overrideIndex];
|
|
160
|
+
if (ov === undefined) continue;
|
|
161
|
+
|
|
162
|
+
const comp = components.get(ov.comp);
|
|
163
|
+
if (!comp) continue;
|
|
164
|
+
|
|
165
|
+
for (const [fieldName, value] of normalizeOverrideFields(ov)) {
|
|
166
|
+
forEachHandleGuid(componentSchema(comp)[fieldName], value, (guidString, arrayIndex) => {
|
|
167
|
+
entries.push({
|
|
168
|
+
overrideIndex,
|
|
169
|
+
componentName: ov.comp,
|
|
170
|
+
fieldName,
|
|
171
|
+
guidString,
|
|
172
|
+
...(arrayIndex !== undefined ? { arrayIndex } : {}),
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
return entries;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Normalize a {@link MountOverride}'s `{comp, field?, value}` shape into
|
|
183
|
+
* `(fieldName, value)` pairs (feat-20260713 M3 / w12). Patch form (`field`
|
|
184
|
+
* present) → one pair; component-add form (`field` absent, `value` a per-field
|
|
185
|
+
* map) → one pair per value key. A non-object add value yields no pairs.
|
|
186
|
+
*/
|
|
187
|
+
function normalizeOverrideFields(ov: MountOverride): ReadonlyArray<readonly [string, unknown]> {
|
|
188
|
+
if (ov.field !== undefined) return [[ov.field, ov.value]];
|
|
189
|
+
const value = ov.value;
|
|
190
|
+
if (typeof value !== 'object' || value === null || Array.isArray(value)) return [];
|
|
191
|
+
const map = value as Record<string, unknown>;
|
|
192
|
+
return Object.keys(map).map((key) => [key, map[key]] as const);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Shared handle-GUID identification core (feat-20260713 M3 / w12 SSOT): given a
|
|
197
|
+
* schema `fieldType` and a `value`, invoke `sink(guidString, arrayIndex?)` for
|
|
198
|
+
* every GUID string the field binds — once for a `shared<T>` scalar string, once
|
|
199
|
+
* per string element of an `array<shared<T>>`. Non-shared fields, non-string
|
|
200
|
+
* scalars, and non-string array elements (already-resolved handle numbers, D-8)
|
|
201
|
+
* are skipped. Both the entity walk and the override walk route through here so
|
|
202
|
+
* the "is this a shared handle field + read its GUID" logic has one home
|
|
203
|
+
* (architecture-principles §1 SSOT).
|
|
204
|
+
*/
|
|
205
|
+
function forEachHandleGuid(
|
|
206
|
+
fieldType: string | undefined,
|
|
207
|
+
value: unknown,
|
|
208
|
+
sink: (guidString: string, arrayIndex?: number) => void,
|
|
209
|
+
): void {
|
|
210
|
+
if (fieldType === undefined || typeof fieldType !== 'string') return;
|
|
211
|
+
if (fieldType.startsWith('shared<')) {
|
|
212
|
+
if (typeof value === 'string') sink(value);
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
if (fieldType.startsWith('array<shared<') && Array.isArray(value)) {
|
|
216
|
+
for (let elemIdx = 0; elemIdx < value.length; elemIdx++) {
|
|
217
|
+
const elem = value[elemIdx];
|
|
218
|
+
if (typeof elem === 'string') sink(elem, elemIdx);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
// @forgeax/engine-assets-runtime -- scene payload parse + ref resolution
|
|
2
|
+
// (feat-20260705-runtime-tier2-decomposition M1 / w4, D-4 F1 straight-cut).
|
|
3
|
+
// Pure move from asset-registry.ts; zero identifier changes.
|
|
4
|
+
|
|
5
|
+
import type {
|
|
6
|
+
LocalEntityId,
|
|
7
|
+
SceneAsset,
|
|
8
|
+
SceneEntity,
|
|
9
|
+
SceneInstanceMount,
|
|
10
|
+
} from '@forgeax/engine-types';
|
|
11
|
+
import { HANDLE_ARRAY_FIELD_NAMES, HANDLE_FIELD_NAMES } from './handles';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Structured error returned by parseScenePayload when a refs index is
|
|
15
|
+
* out of bounds (F-2 / AC-02).
|
|
16
|
+
*/
|
|
17
|
+
interface ParseSceneError {
|
|
18
|
+
readonly localId: number;
|
|
19
|
+
readonly component: string;
|
|
20
|
+
readonly field: string;
|
|
21
|
+
readonly index: number;
|
|
22
|
+
readonly refsLength: number;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Reconstruct a SceneAsset POD from a serialised pack payload (feat-20260514
|
|
26
|
+
// w3 / parseAssetPayload 'scene' dispatch). The payload arrives as the
|
|
27
|
+
// outer pack file's `assets[i].payload` object after ajv structural
|
|
28
|
+
// validation; this helper re-stamps the LocalEntityId brand on each
|
|
29
|
+
// SceneEntity.localId field and freezes the resulting POD shape so consumer
|
|
30
|
+
// code sees the same readonly surface as a hand-authored SceneAsset (AC-01
|
|
31
|
+
// + plan-strategy §3.1 rt_pkg sub-graph).
|
|
32
|
+
//
|
|
33
|
+
// feat-20260528-scene-asset-guid-refs-and-post-instantiate M1-fixup F-1:
|
|
34
|
+
// refs parameter — when provided, integer values in handle-type component
|
|
35
|
+
// fields (identified via HANDLE_FIELD_NAMES allowlist, plan-strategy D-4)
|
|
36
|
+
// are replaced with refs[N] (GUID string). Non-handle integer fields
|
|
37
|
+
// (Transform pos/quat/scale lanes, ChildOf.parent Entity, etc.)
|
|
38
|
+
// are kept as-is.
|
|
39
|
+
//
|
|
40
|
+
// feat-20260528-scene-asset-guid-refs-and-post-instantiate M1-fixup F-2:
|
|
41
|
+
// out-of-bounds (N < 0 or N >= refs.length) returns a structured
|
|
42
|
+
// ParseSceneError with localId + component + field + index + refs.length
|
|
43
|
+
// so the caller can construct a precise AssetError (AC-02).
|
|
44
|
+
// The M1 stop-on-first-error (AC-08) behaviour is preserved.
|
|
45
|
+
export function parseScenePayload(
|
|
46
|
+
payload: Record<string, unknown>,
|
|
47
|
+
refs?: string[],
|
|
48
|
+
): SceneAsset | ParseSceneError | undefined {
|
|
49
|
+
const rawEntities = payload.entities;
|
|
50
|
+
if (!Array.isArray(rawEntities)) return undefined;
|
|
51
|
+
const nodes: SceneEntity[] = [];
|
|
52
|
+
for (const rn of rawEntities as Array<{ localId?: unknown; components?: unknown }>) {
|
|
53
|
+
if (typeof rn.localId !== 'number') return undefined;
|
|
54
|
+
const rawComponents = (rn.components ?? {}) as Record<string, Record<string, unknown>>;
|
|
55
|
+
|
|
56
|
+
// Resolve refs indices to GUID strings only for handle-type fields
|
|
57
|
+
// (plan-strategy D-4 / F-1 fix: non-handle integers preserved as-is).
|
|
58
|
+
if (refs) {
|
|
59
|
+
const resolvedComponents: Record<string, Record<string, unknown>> = {};
|
|
60
|
+
for (const compName of Object.keys(rawComponents)) {
|
|
61
|
+
const rawFields = rawComponents[compName];
|
|
62
|
+
if (!rawFields) continue;
|
|
63
|
+
const resolvedFields: Record<string, unknown> = {};
|
|
64
|
+
for (const fieldName of Object.keys(rawFields)) {
|
|
65
|
+
const value = rawFields[fieldName];
|
|
66
|
+
if (
|
|
67
|
+
HANDLE_FIELD_NAMES.has(fieldName) &&
|
|
68
|
+
typeof value === 'number' &&
|
|
69
|
+
Number.isInteger(value)
|
|
70
|
+
) {
|
|
71
|
+
const idx = value;
|
|
72
|
+
if (idx < 0 || idx >= refs.length) {
|
|
73
|
+
return {
|
|
74
|
+
localId: rn.localId as number,
|
|
75
|
+
component: compName,
|
|
76
|
+
field: fieldName,
|
|
77
|
+
index: idx,
|
|
78
|
+
refsLength: refs.length,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
resolvedFields[fieldName] = refs[idx];
|
|
82
|
+
} else if (HANDLE_ARRAY_FIELD_NAMES.has(fieldName) && Array.isArray(value)) {
|
|
83
|
+
// feat-20260608 M2 / w7: array<handle<X>> field — each element is a
|
|
84
|
+
// refs index resolved to a GUID string. Out-of-bounds in any element
|
|
85
|
+
// surfaces the same ParseSceneError as the scalar handle path.
|
|
86
|
+
const resolvedArr: string[] = [];
|
|
87
|
+
for (let elemIdx = 0; elemIdx < value.length; elemIdx++) {
|
|
88
|
+
const elem = value[elemIdx];
|
|
89
|
+
if (typeof elem !== 'number' || !Number.isInteger(elem)) {
|
|
90
|
+
resolvedFields[fieldName] = value;
|
|
91
|
+
resolvedArr.length = 0;
|
|
92
|
+
break;
|
|
93
|
+
}
|
|
94
|
+
if (elem < 0 || elem >= refs.length) {
|
|
95
|
+
return {
|
|
96
|
+
localId: rn.localId as number,
|
|
97
|
+
component: compName,
|
|
98
|
+
field: `${fieldName}[${elemIdx}]`,
|
|
99
|
+
index: elem,
|
|
100
|
+
refsLength: refs.length,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
const ref = refs[elem];
|
|
104
|
+
if (ref !== undefined) resolvedArr.push(ref);
|
|
105
|
+
}
|
|
106
|
+
if (resolvedArr.length === value.length) {
|
|
107
|
+
resolvedFields[fieldName] = resolvedArr;
|
|
108
|
+
} else if (resolvedFields[fieldName] === undefined) {
|
|
109
|
+
resolvedFields[fieldName] = value;
|
|
110
|
+
}
|
|
111
|
+
} else {
|
|
112
|
+
resolvedFields[fieldName] = value;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
resolvedComponents[compName] = resolvedFields as Record<string, unknown>;
|
|
116
|
+
}
|
|
117
|
+
nodes.push({
|
|
118
|
+
localId: rn.localId as LocalEntityId,
|
|
119
|
+
components: resolvedComponents,
|
|
120
|
+
});
|
|
121
|
+
} else {
|
|
122
|
+
nodes.push({
|
|
123
|
+
localId: rn.localId as LocalEntityId,
|
|
124
|
+
components: rawComponents,
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
const resolvedMounts = resolveMounts(payload, refs);
|
|
129
|
+
if (resolvedMounts === undefined && Array.isArray(payload.mounts)) {
|
|
130
|
+
// mounts resolution failed (e.g. out-of-bounds source index)
|
|
131
|
+
return undefined;
|
|
132
|
+
}
|
|
133
|
+
// feat-20260612 M2 fixup: resolve `skinGuids` field (refs[] indices on disk
|
|
134
|
+
// -> GUID strings post-parse). The SkinAsset chain has no entity-component
|
|
135
|
+
// hook so the scene must carry an explicit cross-edge list; without it,
|
|
136
|
+
// browser-async-pack-fetch never loads SkinAssets and postSpawnResolveJoints
|
|
137
|
+
// silently skips, leaving Skin.joints.length=0 for every frame.
|
|
138
|
+
const resolvedSkinGuids = resolveSkinGuids(payload, refs);
|
|
139
|
+
if (resolvedSkinGuids === undefined && Array.isArray(payload.skinGuids)) {
|
|
140
|
+
return undefined;
|
|
141
|
+
}
|
|
142
|
+
return {
|
|
143
|
+
kind: 'scene',
|
|
144
|
+
entities: nodes,
|
|
145
|
+
mounts: resolvedMounts as unknown as readonly SceneInstanceMount[],
|
|
146
|
+
...(resolvedSkinGuids !== undefined ? { skinGuids: resolvedSkinGuids } : {}),
|
|
147
|
+
} as SceneAsset;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* feat-20260612 M2 fixup: resolve `SceneAsset.skinGuids` -- on-disk refs[]
|
|
152
|
+
* indices into post-parse GUID strings. Mirror of {@link resolveMounts}.
|
|
153
|
+
* Returns undefined when no `skinGuids` field is present (back-compat:
|
|
154
|
+
* pre-M2 SceneAssets carry no skin cross-edges).
|
|
155
|
+
*/
|
|
156
|
+
function resolveSkinGuids(
|
|
157
|
+
payload: Record<string, unknown>,
|
|
158
|
+
refs: readonly string[] | undefined,
|
|
159
|
+
): readonly string[] | undefined {
|
|
160
|
+
const raw = payload.skinGuids;
|
|
161
|
+
if (!Array.isArray(raw)) return undefined;
|
|
162
|
+
const out: string[] = [];
|
|
163
|
+
for (const item of raw as ReadonlyArray<unknown>) {
|
|
164
|
+
if (typeof item === 'string') {
|
|
165
|
+
// Pre-resolved GUID string (in-memory dawn smoke / direct register path).
|
|
166
|
+
out.push(item);
|
|
167
|
+
} else if (typeof item === 'number' && Number.isInteger(item)) {
|
|
168
|
+
// refs[] index path (browser pack-fetch JSON-roundtrip shape).
|
|
169
|
+
if (refs === undefined) return undefined;
|
|
170
|
+
if (item < 0 || item >= refs.length) return undefined;
|
|
171
|
+
const guid = refs[item];
|
|
172
|
+
if (typeof guid !== 'string') return undefined;
|
|
173
|
+
out.push(guid);
|
|
174
|
+
} else {
|
|
175
|
+
return undefined;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
return out;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Resolve mounts[].source integer indices through refs[] to GUID strings.
|
|
183
|
+
* Mount.source is resolved positionally (not through HANDLE_FIELD_NAMES),
|
|
184
|
+
* per AC-11. Returns undefined when no mounts field is present (back-compat).
|
|
185
|
+
*/
|
|
186
|
+
function resolveMounts(
|
|
187
|
+
payload: Record<string, unknown>,
|
|
188
|
+
refs: readonly string[] | undefined,
|
|
189
|
+
): ReadonlyArray<Record<string, unknown>> | undefined {
|
|
190
|
+
const rawMounts = payload.mounts;
|
|
191
|
+
if (!Array.isArray(rawMounts)) return undefined;
|
|
192
|
+
if (refs === undefined) return rawMounts as ReadonlyArray<Record<string, unknown>>;
|
|
193
|
+
const resolved: Record<string, unknown>[] = [];
|
|
194
|
+
for (const rm of rawMounts as ReadonlyArray<Record<string, unknown>>) {
|
|
195
|
+
const mount = { ...rm };
|
|
196
|
+
const source = rm.source;
|
|
197
|
+
if (typeof source === 'number' && Number.isInteger(source)) {
|
|
198
|
+
const idx = source;
|
|
199
|
+
if (idx < 0 || idx >= refs.length) {
|
|
200
|
+
return undefined;
|
|
201
|
+
}
|
|
202
|
+
mount.source = refs[idx];
|
|
203
|
+
}
|
|
204
|
+
resolved.push(mount);
|
|
205
|
+
}
|
|
206
|
+
return resolved;
|
|
207
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
// @forgeax/engine-assets-runtime - wireDefaultLoaders + seed-table SSOT
|
|
2
|
+
// (feat-20260603-asset-import-loader-injection M1 / w5 + w8; restructured by
|
|
3
|
+
// feat-20260705-runtime-tier2-decomposition M1 / w8, D-2).
|
|
4
|
+
//
|
|
5
|
+
// wireDefaultLoaders is a one-line host helper that wires the engine's default
|
|
6
|
+
// loader set onto a `LoaderRegistry`, mirroring the Console
|
|
7
|
+
// `wireDefaultInspectors` shape (packages/console/src/wire-default-inspectors.ts;
|
|
8
|
+
// research Finding 8). An AI user that has wired inspectors once recognises the
|
|
9
|
+
// same form here at near-zero cost (requirements §AI User Affordances).
|
|
10
|
+
//
|
|
11
|
+
// The two seed tables INLINE_PACK_LOADERS + PACK_ARTIFACT_LOADERS are the
|
|
12
|
+
// default set. videoLoader lives in graphics-extras and is wired here. The
|
|
13
|
+
// complete ordinary Asset vocabulary is registered once at this boundary;
|
|
14
|
+
// host-specific loaders may extend the table through `extraLoaders`.
|
|
15
|
+
//
|
|
16
|
+
// Default set wired internally: the 16 ordinary Asset kinds plus the existing
|
|
17
|
+
// UI consumer loader. Host-only execution remains separate from descriptor load.
|
|
18
|
+
//
|
|
19
|
+
import { videoLoader } from '@forgeax/engine-graphics-extras';
|
|
20
|
+
import type { Loader } from '@forgeax/engine-types';
|
|
21
|
+
import { createUiLoader, type UiAsset } from '@forgeax/engine-ui';
|
|
22
|
+
import { LoaderRegistry } from './loader-registry';
|
|
23
|
+
import { INLINE_PACK_LOADERS } from './loaders/inline-pack';
|
|
24
|
+
import { PACK_ARTIFACT_LOADERS } from './loaders/pack-artifact';
|
|
25
|
+
|
|
26
|
+
const uiPayloadLoader = createUiLoader();
|
|
27
|
+
const uiLoader: Loader<UiAsset> = {
|
|
28
|
+
kind: 'ui',
|
|
29
|
+
load: (payload) => {
|
|
30
|
+
const result = uiPayloadLoader.load(payload);
|
|
31
|
+
return result.ok ? result.value : undefined;
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Wire the engine's default loader set (16 ordinary kinds plus UI) plus any
|
|
37
|
+
* `extraLoaders` onto `registry` in
|
|
38
|
+
* one call. Returns the same `registry` for chaining (so `wireDefaultLoaders(new
|
|
39
|
+
* LoaderRegistry())` is a one-expression wired registry). The `extraLoaders` are
|
|
40
|
+
* appended after the defaults and must use kinds outside the ordinary set.
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* ```ts
|
|
44
|
+
* import { LoaderRegistry, wireDefaultLoaders } from '@forgeax/engine-assets-runtime';
|
|
45
|
+
* const loaders = wireDefaultLoaders(new LoaderRegistry());
|
|
46
|
+
* // loaders.get('mesh') / .get('texture') / .get('font') / .get('video') are
|
|
47
|
+
* // non-undefined; all ordinary Asset kinds share this same owner table.
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
export function wireDefaultLoaders(
|
|
51
|
+
registry: LoaderRegistry,
|
|
52
|
+
extraLoaders: readonly Loader[] = [],
|
|
53
|
+
): LoaderRegistry {
|
|
54
|
+
const extraKinds = new Set(extraLoaders.map((loader) => loader.kind));
|
|
55
|
+
const seeded = new Set<string>();
|
|
56
|
+
for (const loader of [...INLINE_PACK_LOADERS, ...PACK_ARTIFACT_LOADERS]) {
|
|
57
|
+
if (extraKinds.has(loader.kind)) continue;
|
|
58
|
+
if (seeded.has(loader.kind)) continue;
|
|
59
|
+
seeded.add(loader.kind);
|
|
60
|
+
registry.register(loader);
|
|
61
|
+
}
|
|
62
|
+
registry.register(videoLoader);
|
|
63
|
+
registry.register(uiLoader);
|
|
64
|
+
for (const loader of extraLoaders) registry.register(loader);
|
|
65
|
+
return registry;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Convenience factory: a fresh `LoaderRegistry` pre-wired with the default
|
|
70
|
+
* loader set (plus any `extraLoaders`). The production assembly point
|
|
71
|
+
* (`createRenderer`) and tests pass the result into `new LoaderRegistry()` (D-7
|
|
72
|
+
* constructor-injection; loaders always wired at construction -- used by
|
|
73
|
+
* `AssetRegistry` internally via `createDefaultLoaderRegistry(extraLoaders)` and
|
|
74
|
+
* by host code / tests independently) -- no setter / no illegal intermediate
|
|
75
|
+
* state).
|
|
76
|
+
*/
|
|
77
|
+
export function createDefaultLoaderRegistry(extraLoaders: readonly Loader[] = []): LoaderRegistry {
|
|
78
|
+
return wireDefaultLoaders(new LoaderRegistry(), extraLoaders);
|
|
79
|
+
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"asset-graph-red.integration.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/asset-graph-red.integration.test.ts"],"names":[],"mappings":""}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"asset-kind.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/asset-kind.test.ts"],"names":[],"mappings":""}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"asset-registry-core.integration.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/asset-registry-core.integration.test.ts"],"names":[],"mappings":""}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"asset-registry-public-api.test-d.d.ts","sourceRoot":"","sources":["../../src/__tests__/asset-registry-public-api.test-d.ts"],"names":[],"mappings":""}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"asset-runtime-core-lifecycle.integration.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/asset-runtime-core-lifecycle.integration.test.ts"],"names":[],"mappings":""}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"asset-runtime-snapshot.unit.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/asset-runtime-snapshot.unit.test.ts"],"names":[],"mappings":""}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"catalog-session-red.unit.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/catalog-session-red.unit.test.ts"],"names":[],"mappings":""}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"registry-lifecycle-red.integration.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/registry-lifecycle-red.integration.test.ts"],"names":[],"mappings":""}
|