Skip to main content

Module asset_resolver

Module asset_resolver 

Source
Expand description

Authored-reference → resolved-handle pump.

A PreExtract data system that turns each entity’s authored asset references into the runtime handles the GPU projection consumes. It covers two reference kinds with one collect-then-mutate pass each:

Materials — [MaterialRef] → [MaterialHandle] (HandleComponent<Box<dyn Material>>):

  • [MaterialRef::Inline] embeds the material value — it is wrapped into a handle keyed by a content-derived UUID, so two entities holding the same inline material share one resolved handle (and one GpuMaterial).
  • [MaterialRef::Asset] references a .kmat in the VFS — it is loaded via the AssetService and the resulting handle is keyed by the asset’s stable UUID.

Meshes — [MeshRef] → HandleComponent<Mesh>:

  • [MeshRef::Procedural] carries primitive params — the geometry is rebuilt via [reconstruct_procedural_mesh] and keyed by a content-derived UUID, so identical procedural meshes dedup to one resolved handle (and one GpuMesh).
  • [MeshRef::Asset] references an imported mesh (glTF, OBJ) in the VFS — it is loaded via the AssetService and keyed by the asset’s stable UUID.

Each resolved CPU value is also inserted into the matching shared [AssetStore] sub-store (store::<Box<dyn Material>>() / store::<Mesh>()) so the GPU projection and future sharing see it. This system runs before both gpu_material_sync and gpu_mesh_sync, so a freshly-spawned entity resolves and projects in the same tick.

The resolver is the sole authority that keeps resolved handles consistent with their authored references. Each authored ref carries an identity UUID (content-derived for Inline/Procedural, the stable asset UUID for Asset); every tick the resolver compares it against the resolved handle’s UUID. In steady state this is a single cheap compare — nothing is loaded, cloned, or hashed. When the comparison fails (the developer/editor changed the ref, or no handle exists yet) the resolver (re)resolves, replaces the stale CPU handle, and drops the stale HandleComponent<GpuMaterial> / HandleComponent<GpuMesh> so the GPU projection re-projects under the new identity. This single read-phase compare covers editor inspector edits, .kmat assignment, save-as, and runtime gameplay mutation alike — there is no per-mutation-site invalidation.

khora-data never depends on khora-io; this resolver lives here because it calls the khora-io-owned AssetService while mutating the khora-data World + AssetStore.