bacommon.assetspec package¶
Asset specs: authoring-level references to asset-package assets.
A spec is a minimal claim about an asset – an apverid plus a
logical name – carrying no asset data and no guarantee the package is
locally present (or still exists). Per the D28 semantic split (see
strings-asset-migration.md in ballistica-internal), assets ladder
through three tiers: TextureSpec (this claim form; wire/model
currency) -> client bauiv1.TextureHandle (a verified-local subclass
adding .get(); its wrapper pin resolved before use) ->
bauiv1.Texture (the loaded engine asset). Servers hold only specs;
consuming clients verify/resolve before display. Each kind gets a
distinct type (TextureSpec, MeshSpec) so a consumer
schema can enforce where each kind may go.
Type-safe, ergonomic access to a package’s references comes from a generated
wrapper module (emitted server-side; the codegen lives in
baserver.assetwrappergen), whose per-kind roots (textures, meshes)
are driven at runtime by AssetGroup – mirroring the client-side
asset-package wrappers.
- class bacommon.assetspec.AssetBucketKind(*values)[source]¶
Bases:
EnumWhich bucket kind a spec’s asset lives in.
Values match the asset-package bucket names. Each kind is its own flat index domain, so an index is only meaningful alongside the kind of the slot holding it – which the schema always fixes (a texture slot holds a texture).
- AUDIO = 'audio'¶
- CONSTANT = 'constant'¶
- MESHES = 'meshes'¶
- TEXTURES = 'textures'¶
- class bacommon.assetspec.AssetGroup(apverid: str, node: AssetGroupTree, prefix: str)[source]¶
Bases:
objectDynamic accessor for one subdirectory of an asset-package’s refs.
Attribute access resolves against the wrapper’s nested kind-code tree: a subdirectory yields another
AssetGroup; a leaf yields the reference for its kind. All real type information lives in the wrapper’sif TYPE_CHECKING:shadow, so callers never type-check through this class.
- type bacommon.assetspec.AssetGroupTree = dict[str, str | AssetGroupTree]¶
- class bacommon.assetspec.AssetIndexContext(packages: list[str], listings: ListingSource)[source]¶
Bases:
objectConverts asset specs to and from flat indices for one manifest.
Built from the manifest’s package list (in index order) and a way to obtain each package’s full logical-path listing. The offset table is built on first use and cached, since obtaining a listing can be the expensive part.
- describe_domain() str[source]¶
Per-package slice widths, for diagnosing a digest mismatch.
Names each package and how wide a slice it got here, which is what pins a mismatch to one package rather than to the payload as a whole.
- domain_digest() str[source]¶
Short digest of the exact domain this context addresses.
The two ends derive their listings from different sources (the server from vendored package data, the client from its resolved registry), and nothing about a wrong-but-in-range index makes itself known: it simply names a different asset. So a payload carries the producer’s digest and the consumer refuses to de-index when its own does not match – turning a silent wrong-art render into a loud, locatable failure.
Taken over the effective listings, i.e. the slices actually laid out, with an unknown package contributing an empty one exactly as it does when preparing the offset table. That is the right thing to compare: a package one end has no listing for still occupies zero width on both, and it is the widths and contents that decide what an index means.
- from_index(index: int, kind: AssetBucketKind) AnySpec[source]¶
Return the spec a flat index names.
kindcomes from the slot holding the index and decides which spec type is produced. It is not a domain selector – there is one domain per manifest – so it cannot shift which asset an index resolves to; it only decides how that asset is typed.Raises
AssetIndexErrorfor an index outside the domain.
- to_index(spec: AnySpec) int[source]¶
Return the flat index for a spec.
Raises
AssetIndexErrorif the spec’s package is not in the manifest or its asset is not in that package.
- exception bacommon.assetspec.AssetIndexError[source]¶
Bases:
ExceptionAn asset reference could not be indexed or de-indexed.
Always an authoring or wiring fault rather than a runtime condition: a package missing from the manifest, an asset absent from its package, or an index outside its domain. Callers should fail visibly rather than substitute a placeholder – a silently wrong texture is worse than a loud error.
- class bacommon.assetspec.CollisionMeshSpec(_apverid: str, _name: str)[source]¶
Bases:
objectA language-independent reference to a collision-mesh in a package.
Identity is a package version plus the collision-mesh’s logical path within it (e.g.
meshes/courtyard_level_collide); the engine resolves the qualified<apverid>:<name>form.Both parts are private; see
TextureSpecfor why.Collision meshes are a scene-only kind (physics; they ride the flavor-invariant
constantbucket – asset-packages decision #26), so nothing server-side emits one. The type exists so the scene wrapper’s handle leaves stay kind-distinct like every other kind.
- class bacommon.assetspec.CubeMapTextureSpec(_apverid: str, _name: str)[source]¶
Bases:
objectA language-independent reference to a cube-map texture.
Identity is a package version plus the cube map’s logical path within it (e.g.
textures/reflection_sharp); the engine resolves the qualified<apverid>:<name>form.Both parts are private; see
TextureSpecfor why.A distinct type from
TextureSpecdeliberately: cube maps share the 2D textures’ logical-path namespace and delivery bucket (asset-packages decision #24) but load through a different engine call producing a different texture type, and the engine’s texture registry does not type-check cache hits – so mixing the two up must be a static error at the handle tier, not a silent wrong-type asset at draw time.
- class bacommon.assetspec.MeshSpec(_apverid: str, _name: str)[source]¶
Bases:
objectA language-independent reference to a mesh in an asset-package.
Identity is a package version plus the mesh’s logical path within it (e.g.
meshes/box); the engine resolves the qualified<apverid>:<name>form.Both parts are private: a spec is produced by a generated wrapper module and consumed as a whole, and code that reaches in to rebuild a path string by hand is exactly what asset renames used to rot. Nothing accepts such a string any more (see the ap*get bindings), so reaching in has no destination.
- class bacommon.assetspec.SoundSpec(_apverid: str, _name: str)[source]¶
Bases:
objectA language-independent reference to a sound in an asset-package.
Identity is a package version plus the sound’s logical path within it (e.g.
audio/swish); the engine resolves the qualified<apverid>:<name>form.Both parts are private: a spec is produced by a generated wrapper module and consumed as a whole, and code that reaches in to rebuild a path string by hand is exactly what asset renames used to rot. Nothing accepts such a string any more (see the ap*get bindings), so reaching in has no destination.
- class bacommon.assetspec.TextureSpec(_apverid: str, _name: str)[source]¶
Bases:
objectA language-independent reference to a texture in an asset-package.
Identity is a package version plus the texture’s logical path within it (e.g.
textures/zoe_icon); the engine resolves the qualified<apverid>:<name>form.Both parts are private: a spec is produced by a generated wrapper module and consumed as a whole, and code that reaches in to rebuild a path string by hand is exactly what asset renames used to rot. Nothing accepts such a string any more (see the ap*get bindings), so reaching in has no destination.
- bacommon.assetspec.spec_kind(spec: AnySpec) AssetBucketKind[source]¶
Return the bucket kind a spec addresses.