Files
dusk/.claude/assets.md
T
2026-06-16 10:15:59 -05:00

126 lines
4.1 KiB
Markdown

# Asset System
Source: `src/dusk/asset/`
## Overview
All game assets are packed into a single ZIP archive named `dusk.dsk`
(`ASSET_FILE_NAME`). The asset system loads entries from this archive
asynchronously on a background thread, caches them, and provides
synchronous blocking access when an asset is required immediately.
## Key limits
| Constant | Value | Meaning |
|----------|-------|---------|
| `ASSET_LOADING_COUNT_MAX` | 4 | Concurrent in-flight loads |
| `ASSET_ENTRY_COUNT_MAX` | 128 | Cached entries |
## Top-level API (`asset.h`)
```c
errorret_t assetInit(); // Open dusk.dsk, start background thread
void assetUpdate(); // Dispatch completed-load callbacks (main thread)
errorret_t assetDispose(); // Wait for loads, close archive
assetentry_t *assetGetEntry(
const char_t *path,
assetloadertype_t type,
assetloaderinput_t *input
); // Get (or create) a cache entry; does NOT start loading
errorret_t assetRequireLoaded(assetentry_t *entry);
// Block the calling thread until this entry is fully loaded.
// Only safe to call from the main thread.
void assetLock(assetentry_t *entry);
void assetUnlock(assetentry_t *entry);
// Reference counting. Lock before using loaded data; unlock when done.
// The entry will not be evicted while locked.
```
## Asset entry states
Each cache entry goes through a state machine:
```
IDLE -> QUEUED -> READING (async) -> PROCESSING (sync, main thread) -> LOADED
-> ERROR
```
- **READING** runs on the background loader thread (file I/O).
- **PROCESSING** runs on the main thread (GPU uploads, parsing finalization).
- Once LOADED, data is available in `entry->data`.
## Loader types
Loader types are registered in the `ASSET_LOADER_CALLBACKS[]` table.
Each type implements three callbacks: `loadSync`, `loadAsync`, `dispose`.
| `assetloadertype_t` | Data read | Description |
|---------------------|-----------|-------------|
| `ASSET_LOADER_TYPE_TEXTURE` | STB image | Loads image bytes async, creates GPU texture sync |
| `ASSET_LOADER_TYPE_TILESET` | `.dtf` binary | Custom tile format (magic, version, grid, UVs) |
| `ASSET_LOADER_TYPE_MESH` | `.stl` | STL mesh with configurable axis orientation |
| `ASSET_LOADER_TYPE_JSON` | yyjson | Up to 256 KB; parsed async |
| `ASSET_LOADER_TYPE_LOCALE` | Gettext `.po` | PO parser with plural-form expression evaluation |
| `ASSET_LOADER_TYPE_SCRIPT` | JS source | JerryScript module |
## Adding a new loader type
1. Add an enum value before `_COUNT` in `assetloadertype_t`
(`src/dusk/asset/loader/assetloader.h`).
2. Add fields to the input/loading/output unions in `assetloader.h`.
3. Implement `assetXxxLoaderSync`, `assetXxxLoaderAsync`, and
`assetXxxDispose` in `src/dusk/asset/loader/xxx/`.
4. Register the three callbacks in `ASSET_LOADER_CALLBACKS[]` in
`src/dusk/asset/loader/assetloader.c`.
5. If user-facing, create a JS module and a `.d.ts` file (see `CLAUDE.md`).
## Asset batch (`assetbatch.h`)
`assetbatch_t` groups multiple asset requests into a single logical
load. All entries in the batch start loading concurrently. The batch
fires a completion callback once every entry has reached LOADED (or
ERROR).
```c
assetbatch_t batch;
assetBatchInit(&batch, entries, count, onComplete, user);
assetBatchStart(&batch);
// ... later, after assetUpdate() fires the callback ...
assetBatchDispose(&batch);
```
## Usage pattern
```c
// 1. Get or create the cache entry (no I/O yet).
assetentry_t *tex = assetGetEntry(
"textures/hero.png",
ASSET_LOADER_TYPE_TEXTURE,
NULL
);
assetLock(tex);
// 2. Option A -- non-blocking: check tex->state each frame.
// Option B -- blocking (main thread only):
errorChain(assetRequireLoaded(tex));
// 3. Use the loaded data.
texture_t *t = &tex->data.texture;
// 4. Release when done.
assetUnlock(tex);
```
## Error macros (inside loader implementations)
```c
assetLoaderErrorThrow("msg %d", val); // errorThrow equivalent
assetLoaderErrorChain(someCall()); // errorChain equivalent
```
Use these instead of the bare error macros inside loader callbacks so
that failures include the loader context in the stack trace.