Bounded cooked registry shards¶
RuneSchema 0.8.0.0 supports a flat, explicit shard index. A conventional root
inside each enabled mod's PAK lists its child data assets by exact object path.
RuneSchema loads those assets directly on Steam, Game Pass and dedicated-server
builds using the same code path. It does not require a whole-project
AssetRegistry.bin, wildcard package scans or Asset Registry enumeration of
each shard. Live validation on all three environments remains necessary.
This extends the cooked PAK declaration. The per-document ceiling is 512 KiB in the October 16 correction; lane, reference, shard-count and aggregate budgets remain independently enforced.
Cook the root¶
For an enabled mod folder named Dye, cook exactly this root data asset:
The asset must expose these reflected String/FString properties:
RegistryOwner:Dye(exact enabled mod folder name).RuneSchemaRegistryJson: the JSON below, serialized as a string.RegistryJsonremains a supported alias.
A mod-owned Blueprint class derived from PrimaryDataAsset with those string
properties is supported. The reader does not require RuneSchema's shared
Blueprint base or a new framework PAK. If the class lives in a Core module,
other modules still require that Core class to be cooked and available.
{
"SchemaVersion": 1,
"Entries": [],
"RegistryShards": [
"/Game/Mods/Dye/Registry/Shards/RSREG_Dye_0001.RSREG_Dye_0001",
"/Game/Mods/Dye/Registry/Shards/RSREG_Dye_0002.RSREG_Dye_0002"
]
}
The root may additionally contain its own normal NativeRegistries,
LoaderDefinitions and up to 256 ordinary presentation Entries. Omit native
fields entirely for an index-only root; do not add empty native declarations.
Root presentation entries must all validate before the group is published.
Cook each child¶
Each child must be directly inside /Game/Mods/<Owner>/Registry/Shards/.
Its package and object names must be identical and follow
RSREG_<Owner>_<Id>, using ASCII letters, digits and underscores only.
The complete asset name is limited to 128 characters. No subfolders,
traversal, cross-owner paths, alternative mounts, subobjects or nested indexes
are accepted. Duplicate paths are rejected case-insensitively.
For the first example child, set RegistryOwner to Dye and
RuneSchemaRegistryJson to:
{
"SchemaVersion": 1,
"Entries": [],
"RegistryShard": true,
"LoaderDefinitions": {
"Recipes": {
"/Example/Recipes/RECIPE_BlackArmor.RECIPE_BlackArmor": {
"Unlock": false,
"Discovery": {
"AllItems": [
"/Example/Items/ITEM_BlackDye.ITEM_BlackDye",
"/Example/Items/ITEM_Armor.ITEM_Armor"
]
},
"AddTo": [{
"DataTable": "/Example/Stations/DT_Stations.DT_Stations",
"Row": "DyeStation",
"Category": "Dyes"
}]
}
}
}
}
Replace the example recipe, item, table, row and category with actual native
paths and values. Each child must have RegistryShard: true, Entries: []
and a nonempty NativeRegistries and/or LoaderDefinitions payload. It cannot
have RegistryShards. All supported native lanes can be split across children,
including journals and lore. No duplicate loose /assets, /recipes,
/journal or /lore pointer file is needed for these announced assets.
LoaderDefinitions.Recipes requires existing cooked RecipeData object
paths, not local runtime recipe keys. Converting a previously runtime-authored
recipe to a cooked asset is separate authoring work: retain its exact shipped
PersistenceID and compatible internal identity. Sharding does not clone assets,
generate new saved identities, change quantities or synthesize missing recipes.
Limits and failure behavior¶
| Scope | Limit |
|---|---|
| Each UTF-8 JSON string | 512 KiB |
| Each native lane array / loader map in one document | 4,096 entries |
| All native paths plus loader definitions in one document | 16,384 references |
| Children listed by one root | 256 |
| Root plus children combined | 64 MiB of UTF-8 JSON; 262,144 references |
| JSON nesting | 64 parser levels |
Budget against the actual serialized UTF-8 strings, not only item counts. Duplicate JSON keys are rejected. The conventional root can therefore discover up to 256 explicitly named pages without any shard metadata enumeration. The root and each child must independently fit their document limit. Grouping is flat: no recursion, include cycles or directory scans.
The complete index is path-validated before any child callback runs.
Every listed child must load, match RegistryOwner, have a valid envelope and
parse its native declarations. Conflicting recipe/journal/lore bodies across
pages reject the group. Native declarations publish as one batch, with no
earlier-page prefix left behind if preparation or conflict checks fail.
Independent metadata discovery cannot enroll a child on its own after its
root fails. Disabled owners do not contribute their shard group.
Declaration publication is not gameplay-object registration. The normal loaders still class-check assets, reconcile native identities, place recipes and apply supported discovery rules. A later registration failure also vetoes automatic character cleanup; there is no promise to roll back every native subsystem or third-party gameplay side effect. Missing/invalid enabled shards are not evidence that their saved IDs are orphaned.
Unindexed child metadata for an enabled owner is ignored and reported once per owner, deferring automatic character cleanup. A legacy mod with no conventional root remains supported; without either a root or usable metadata the loader cannot infer that a completely absent declaration was intended. Always include the root and verify the final cooked package. Correct a failed group and fully restart before expecting cleanup authority or new enrollment.
Cook and validate¶
- Use one root per enabled module (
Dye,Dye_BronzeTrim, etc.), with matching owner-specific paths. Modules may reference shared Core station assets in recipe bodies; shard references themselves cannot cross owners. - Serialize valid JSON into the string property. JSONC comments are for loose authoring files, not the cooked JSON string.
- Explicitly include the root, every child, its Blueprint class/dependencies and all referenced gameplay assets in cooking. Paths inside JSON strings are not Unreal hard references and do not automatically force cooking.
- Check the finished PAK/IoStore asset list, not only the source project.
- Expect
[PAK-REGISTRY][SHARDS][READY] owner='Dye' documents=... references=.... A healthy group includes the root indocuments; an index with two pages reports three documents. Inspect every subsequent loader/registry rejection. - Ship matching packages to participating clients and the server. Never ship
a whole-project
AssetRegistry.binjust to make shard discovery work. - Test fresh and existing-character discovery, save/reload, multiplayer and disabled-content orphan cleanup on disposable copies before release.
The authoring schema is cooked-registry.schema.json.
Examples live in docs/examples/CookedRegistryShards. Runtime remains
authoritative for owner-dependent paths, case-insensitive duplicates, aggregate
budgets and actual reflected/gameplay type checks.