synvael/docs/packs.md

58 lines
3.6 KiB
Markdown

# Data packs & resource packs
Two distinct, orthogonal systems. They are kept separate and are not collapsed into one "pack" concept. The decision that data packs register through the modding API rather than a parallel path is recorded in [ADR-0007](adr/0007-declarative-content-via-modding-api.md).
## Resource packs
Client-side asset overlays: textures, sounds, models, fonts, language files. No logic.
A pack is a directory tree mirroring `/assets/` that overrides files by path. The renderer/asset loader resolves logical asset IDs against a stack of pack roots (base game → installed packs by priority) and the topmost hit wins. Ownership sits with the asset pipeline (in `client`, or a sibling `assets` crate if it grows). Pack authors never touch Lua.
A client's own resource packs are a purely local choice; the server has no say over them and they are never part of gameplay modlist matching. The **one** exception is a **server resource pack**: a server may push a single cosmetic overlay of its own (a themed / total-conversion server) to connecting clients. It is a one-way server → client push, applied on top of the client's local stack, and enforced per the server's choice — *optional* packs the client may decline and keep playing, a *required* pack the client declines or fails to fetch rejects the connection. It is still `assets/`-only (no `data/`, no `scripts/`), so it can never affect authoritative state. Fetch and enforcement semantics live in the vault's `Architecture/Load order.md` § Streaming.
## Data packs
Declarative content definitions in JSON (or TOML/RON, TBD): blocks, items, recipes, loot tables, biomes, tags.
No parallel registration system is built. The loader reads the declarative files and calls the same Lua API the engine and Lua mods use. One source of truth:
```
data/blocks/stone.json → loader → blocks.register{ id = "stone", ... }
```
The loader belongs in `scripting` (or a sibling crate if it grows). Every data-pack schema is a stable contract, the same as the Lua API, version it deliberately.
**Declarative-first (ADR-0007):** JSON and Lua are not free alternatives. Anything expressible as data — the static fields of a block, item, recipe, loot table, biome, or tag — is authored as data in `data/`; Lua is reserved for behavior (logic that runs on an event or tick). A pure-data block therefore needs no Lua, and a data pack can register such a primitive on its own; only its behavior half (if any) comes from a Lua mod. Engine first-party content follows the same rule, keeping pure-data `core` content in `data/` and only behavioral systems in `scripts/`. To avoid hand-authoring large volumes of near-identical files, modders may use **datagen**: code that emits `data/` files at build time, before the pack ships — its output, not its code, is the shipped artifact, and it never runs at load time.
## Canonical load order
Later layers override earlier ones:
```
base game (assets/scripts + assets/data)
→ data packs (declarative content add/override)
→ Lua mods (full API access)
→ resource packs (client-only, asset overlay, always last so visuals win)
```
## Repo layout
```
/assets/
data/ # base-game declarative content
blocks/ items/ recipes/ ...
scripts/ # base-game Lua (behavior)
textures/ models/ sounds/ icons/ shaders/ # base-game assets
```
## User-data layout
Runtime, resolved via the `directories` / `dirs` crate:
```
<user-data>/
mods/ # Lua mods
datapacks/ # JSON content packs
resourcepacks/ # asset overlays (client only)
```