Log inGet started
World

Builtin Library

Branchmain
Branchesmainpublish
Commit65083fe8f2

README.md

asset_observe

What the engine is holding for content, and why one asset cannot be used. Backs asset.observe, asset.diagnose, asset.cpuResident, asset.gpuResident and asset.unusableReasons, composing the readings only the engine can take (__assetObserve) with the resolution, import and VFS surfaces already in Luau.

The reading

M.observe() returns the residency document the engine published, with each device row joined to the asset its guid names:

local r = asset.observe()
for _, t in r.textures do print(t.identity or t.key, t.bytes) end
print(r.totals.textureBytes, r.totals.meshBytes, r.totals.cpuCount)

Four pools, named because they are different pools: textures and meshes are the device's, cpu is the set a live script-component context holds, and offDevice is every mesh nothing displays: its GPU buffers were given back, and its row says what the engine keeps to bring it back (held is "definition" for the mesh's whole CPU definition, "source" for only the stored file source it reads the mesh from again) and the CPU bytes that costs. An asset can be in one and not the others. totals carries the aggregates the rows sum to, so a listing reconciles against renderer.textureMemory() and the meshes category of renderer.gpuMemory(). devicePublished and cpuPublished say whether the engine can answer at all, which reads differently from an engine answering with nothing resident.

A row carrying an identity reached the device through that asset; a row without one is held under a guid no asset claims — a camera's own render target, a glyph atlas a script built.

The diagnosis

M.diagnose(ref) answers for one asset, from the engine's own reading rather than from what the caller asked for:

local d = asset.diagnose("myTexture")
if not d.usable then print(d.reason, d.detail) end
print(d.primary)  -- the file the type's declared `primary` resolved to

reason is one of M.reasons(), and each is a state the engine distinguishes:

ReasonWhat the engine read
noSuchAssetnothing resolves under that name
noPrimaryFilethe type's declared primary list matched no file in the asset's folder
payloadEmptythe primary resolved to a file holding no bytes
decodeFailedthe bytes are not the payload the file claims to be — the format's identifying bytes disagree, or the engine's decoder read them and refused
importFailedan import ran over this asset's source and failed; the importer's own error text travels alongside
importInFlightan import over it is queued or running, so its payload is not settled yet

Each is the reading at the moment of the call, so a payload being removed is reported at whichever stage the call catches it: payloadEmpty while the file is there with nothing in it, noPrimaryFile once it is gone. The verdict is whether a load would succeed now — a resource already on the device stays resident under a payload that has since gone, which M.gpuResident reports.

primary is worth reading even when an asset loads: a type declares its payload as a list tried in order, so an asset that lost its encoded payload keeps loading from whatever image is left beside it, including a thumbnail. Naming the file is what makes that visible.

Reading the payload costs a decode wherever the engine has a decoder for the container — a ZTEX header parse, or the image decode the texture loader itself performs, taken at a single texel.