97 lines
3.0 KiB
Markdown
97 lines
3.0 KiB
Markdown
# Save & Locale
|
|
|
|
---
|
|
|
|
## Save system (`src/dusk/save/`)
|
|
|
|
Slot-based persistent storage. Currently disabled in engine init (commented out in `engine.c`) — the system is fully implemented but not yet wired up.
|
|
|
|
### Slots
|
|
|
|
Up to `SAVE_FILE_COUNT_MAX` (3) save slots. The global `SAVE` holds all slots:
|
|
|
|
```c
|
|
saveInit();
|
|
saveExists(slot); // bool_t — check before load
|
|
saveLoad(slot); // read from platform storage → SAVE.files[slot]
|
|
saveWrite(slot); // write SAVE.files[slot] → platform storage
|
|
saveDelete(slot);
|
|
savefile_t *f = saveGet(slot);
|
|
saveDispose();
|
|
```
|
|
|
|
### Save file format
|
|
|
|
`savefile_t` is the serialized struct stored per slot. Currently minimal:
|
|
|
|
```c
|
|
typedef struct {
|
|
char_t header[3]; // "DSK"
|
|
uint32_t version; // SAVE_FILE_VERSION = 1
|
|
bool_t exists;
|
|
} savefile_t;
|
|
```
|
|
|
|
Extend this struct to add game-specific save data (player position, story flags, etc.).
|
|
|
|
### Stream serialization (`save/savestream.h`)
|
|
|
|
`savestream_t` is a cursor used to read/write a save slot's bytes. It CRC32-checksums all data written through it and verifies the checksum on read.
|
|
|
|
Write a save:
|
|
```c
|
|
savestream_t stream;
|
|
// (platform opens stream for slot)
|
|
saveFileWriteHeader(&stream, SAVE_FILE_HEADER);
|
|
saveFileWriteVersion(&stream, SAVE_FILE_VERSION);
|
|
saveFileWriteBool(&stream, myFlag);
|
|
saveFileWriteInt32(&stream, myInt);
|
|
saveFileWriteString(&stream, myString, sizeof(myString));
|
|
saveStreamFinalizeWriteImpl(&stream); // writes CRC
|
|
```
|
|
|
|
Read a save:
|
|
```c
|
|
saveFileReadHeader(&stream, headerBuf);
|
|
saveFileReadVersion(&stream, &version);
|
|
saveFileReadBool(&stream, &myFlag);
|
|
saveFileReadInt32(&stream, &myInt);
|
|
saveFileReadString(&stream, myString, sizeof(myString));
|
|
saveStreamVerifyChecksumImpl(&stream, slot); // returns error if CRC mismatch
|
|
```
|
|
|
|
All multi-byte values are stored in little-endian byte order. The `saveFile*` macros are thin wrappers over the `*Impl` functions that integrate `errorChain` — always use the macros.
|
|
|
|
### Platform backends
|
|
|
|
Each `src/dusk{platform}/save/` provides `saveplatform_t` (e.g. a file path on Linux, a memory-card handle on GameCube). The stream implementations (`savestream{platform}.c`) do the actual I/O.
|
|
|
|
---
|
|
|
|
## Locale / i18n (`src/dusk/locale/`)
|
|
|
|
Translations are stored as GNU `.po` files in `assets/locale/`. Only `en_US.po` currently exists.
|
|
|
|
### Loading
|
|
|
|
`localemanager_t LOCALE` tracks the active locale and its in-progress asset entry:
|
|
|
|
```c
|
|
localeManagerInit(); // loads en_US by default
|
|
localeManagerSetLocale(&LOCALE_EN_US); // switch locale (async load)
|
|
localeManagerDispose();
|
|
```
|
|
|
|
`LOCALE_EN_US` is a predefined `localeinfo_t` constant (`name = "en-US"`, `file = "locale/en_US.po"`).
|
|
|
|
### Looking up strings
|
|
|
|
```c
|
|
char_t buf[128];
|
|
localeManagerGetText("my.key", buf, sizeof(buf), 1, /* format args */ );
|
|
```
|
|
|
|
The macro handles plural forms and `printf`-style format arguments. Pass plural `1` for singular, any other value for plural.
|
|
|
|
`assetlocaleloader.c` parses the `.po` format (msgid / msgstr pairs) into a key→string table during the async asset load phase.
|