1.9 KiB
1.9 KiB
0005. Namespaced content IDs
- Status: Accepted
- Date: 2026-06-27
Context
All registered content — blocks, items, recipes, biomes, entities, and so on — needs a stable identifier that is unambiguous across the engine, data packs, Lua mods, recipe references, and save files. First-party and third-party content must coexist without collision, and identifiers must survive being written to disk and read back.
Decision
Content is identified by a namespaced string of the form "namespace:id".
- The namespace
core:is reserved for first-party content ("core:stone","core:iron_sword"). Mods choose their own short namespace ("mymod:weird_dirt"). - The strict form is mandatory. A bare id with no
:is an error at registration / parse time, never silently coerced tocore:. The rule is identical everywhere: engine scripts, data packs, Lua mods, recipe references, save files. - Charset: namespace and id are each
[a-z0-9_-]+with exactly one:between them. Lowercase ASCII only — no uppercase, Unicode, spaces, dots, or slashes. - At registration time each id string is interned into a small integer handle (e.g.
BlockId(u32)). Hot paths compare handles; the original string is kept for display, save/load, and the Lua API.
The reserved namespace is deliberately core: rather than the project name, so it remains stable independent of branding.
Consequences
- Identifiers are greppable, filesystem-safe, and unambiguous in logs and save files.
- First-party and mod content cannot collide, and the absence of a silent default means mistakes surface immediately rather than corrupting data.
- A small runtime cost is paid at registration to intern strings, in exchange for handle comparison on hot paths.
- The strict form is a permanent contract: relaxing it later (e.g. defaulting bare ids) would change the meaning of existing save files and is therefore effectively irreversible.