Add claude docs
This commit is contained in:
@@ -0,0 +1,125 @@
|
||||
# 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.
|
||||
Reference in New Issue
Block a user