hafen.asset: The Handles
What a loaded file answers: the verbs every asset shares, and each type adds its own. Unprotected, and none of it reads the disk again: a handle is the file as it was loaded.
local icon = hafen.asset():get("icon.png")
hafen.log():write(icon:type() .. " " .. icon:path() .. " " .. icon:size().w .. " wide")
Every asset
| Method |
Returns |
Permission |
Description |
asset:type() |
string |
Unprotected |
"image", "font", "mesh" or "data": what the extension dispatched to. |
asset:path() |
string |
Unprotected |
The addon-relative path it was loaded from. |
| Rule |
Detail |
| Freeing is the collection’s verb |
hafen.asset():remove(asset). Every asset is bridge-owned and freed on reload, disable and relogin, so nothing leaks a GPU texture. Remove early only to release a large asset. |
| An object, not a table |
Verbs are called with :. Nothing can be written to it. A name it does not answer raises where you wrote it: icon:sizes() names :type, :path and :size. icon.size = nil raises. tostring(icon) is Asset(image, icon.png). |
| Nothing but a handle resolves to a file |
A look-alike table is refused by the verbs that take a picture, naming this loader. The draw verbs, which never throw, draw nothing for it. |
| An image you did not load |
One from another addon’s rule, read back through widget:style(), answers :type(), :path() and :size() as your own does. hafen.asset():remove(it) is refused naming the addon that loaded it. |
Image
| Method |
Returns |
Permission |
Description |
image:size() |
{w=, h=} |
Unprotected |
The file’s own dimensions, in design pixels. |
image:info() |
{width, height} |
Unprotected |
The same two, as a flat snapshot. |
| Rule |
Detail |
| Pixels are design pixels |
A 32×32 PNG answers 32, 32 and covers 32×32 wherever drawn, beside the client’s own art at every interface scale. |
| Where it goes |
resource:layers():add takes an image asset as an image or tex picture. A stylesheet may name the file by path, {asset = "img/panel.png"}, loading through this door and interning to this object: the one path exception in the API. |
| Freed |
Draws nothing thereafter. The draw verbs never throw. |
Font
A font asset is a FontHandle with the two asset verbs on top: hafen.font has :derive(), :family(), :size() and the surfaces to install it on. Removing one frees nothing (a font holds no releasable resource). It drops the cache entry, so the next load re-reads and re-registers the file. A stylesheet may name it by path, {asset = "fonts/Inter.ttf", size = 12}, under the same path exception.
Mesh
| Method |
Returns |
Permission |
Description |
mesh:bounds() |
{min={x=,y=,z=}, max={x=,y=,z=}, extent={x=,y=,z=}} |
Unprotected |
Axis-aligned bounds in world units. The span is extent, since a size is two numbers. |
mesh:info() |
{prims, textured, lit, textures, verts, tris} |
Unprotected |
What the parser produced. |
The supported subset is on hafen.virtual. A malformed file or an unsupported feature raises naming the feature.
Disposing a mesh an object is standing does not break that object. It keeps drawing, textured and unchanged, having captured its samplers when built. What you forfeit is the freeing. The memory stays until that object is destroyed. The handle is dead, so the mesh cannot be stood again. A later :get(path) re-reads into a new one. Remove a mesh only when nothing stands it. The automatic teardown gets the order right.
Data
| Method |
Returns |
Permission |
Description |
data:bytes() |
string |
Unprotected |
The file’s contents as a string of bytes, exactly as on disk: string.byte reads them, #data:bytes() is the file’s size. |
data:text() |
string |
Unprotected |
The contents decoded as UTF-8. A leading BOM is stripped. |
data:info() |
{bytes} |
Unprotected |
The file’s size, without reading either string. |
local theme = hafen.json():parse(hafen.asset():get("theme.json"):text())
hafen.ui():sheet():load(theme.rules):install() -- a stylesheet that is data
| Rule |
Detail |
| What is data |
Every file that is not a picture, a font or a model. A .json or .txt is read as text. A .mid or any binary is read as bytes. An .ogg data asset is what resource:layers():add takes as an audio2 clip, a .res one what resource:layers(file) takes. |
| Bytes or text, not a parsed table |
Reading a file is hafen.asset, parsing JSON is hafen.json, parsing a binary format is the addon that knows it. A parsed table would be mutable shared state handed to every re-load of the path. A string cannot be edited behind your back, which keeps interning honest. |
Binary goes through :bytes() |
One Lua character per byte, read with string.byte and string.sub. :text() replaces a byte that is not UTF-8, and its length is the decoded string’s, not the file’s. |
| Cached on first call |
Each string is made once and held by the handle. An edit to the file takes effect on :reload, which drops the cache with the addon’s environment. Removing a data asset drops that cache entry only. |
See Also
hafen.asset — the door: the types, the sandbox, interning.
- Collection — loading, listing, freeing, and the files a folder of yours holds.
hafen.font — what a font asset does once you have it.
hafen.virtual — standing a mesh, and the glTF subset it accepts.
hafen.json — turning a data asset’s :text() into a table.