Option datasets
Why you’d want this
Section titled “Why you’d want this”A param picker normally gets its choices inline: a JSON Schema enum or an
x-mobrule-options list
right in the param’s schema. That’s fine for a six-item status dropdown. It is
the wrong tool for a 500-entry item picker: inlining hundreds of choices
bloats your pack.toml, the manifest’s canonical form, and its manifest_hash.
An option dataset is a named choice list a param references by name
(x-mobrule-source) instead of inlining. It has two backends:
- a file (
path = "data/items.json") for a list too long to hand-write into the schema (a 500-entry item picker). The platform fetches the file to populate a searchable picker. - inline (
options = [...]) for a small list you reuse across several params (atarget_sidetoggle, a status-condition set). Authored once inpack.toml; the loader copies it onto every referencing param, so you never paste the same option block twice.
Reach for the file backend when a list is long; reach for the inline backend when the same short list appears on more than one param.
It is presentation only: the dataset decides which choices the UI shows,
never which values are valid. The param’s own JSON Schema (type, minimum,
maximum, enum) still does all validation, on every write. A stale, missing,
or wrong dataset can never let through a value the schema would reject.
File backend: the three pieces
Section titled “File backend: the three pieces”1. Declare the dataset ([data.<name>])
Section titled “1. Declare the dataset ([data.<name>])”A [data.<name>] table maps a dataset name to a static file your pack ships,
relative to the pack root:
[data.items]path = "data/items.json"The path must stay inside the pack directory. The loader reads the file and content-hashes it into the manifest (see Pinning below), so the file must exist when the pack loads.
2. Ship the file
Section titled “2. Ship the file”The file is a JSON array of choice entries, the same shape as
x-mobrule-options:
[ { "value": 0, "label": "Random (within category)" }, { "value": 1, "label": "Health potion" }, { "value": 2, "label": "Shield" }, { "value": 4, "label": "Ammo box" }]Each entry needs a value and a label; color is optional, and extra fields
(e.g. a category for future client-side filtering) are ignored. Generate it from
whatever source of truth you already have: a game data table, a spreadsheet
export.
3. Point a param at it (x-mobrule-source)
Section titled “3. Point a param at it (x-mobrule-source)”Add x-mobrule-source = "<name>" to the param. It joins the x-mobrule-*
presentation family; the validator ignores it.
[events.adjust_item.params_schema.properties.item_id]type = "integer"minimum = 0maximum = 500"x-mobrule-source" = "items"description = "Specific item id (0 = random within category)."A sourced param defaults to the searchable
combobox widget (the dataset is assumed
large). The broadcaster sees a type-to-filter picker fed live from your file.
Inline x-mobrule-options on the same param takes precedence over
x-mobrule-source. Declare one or the other, not both.
Inline backend: author once, reuse anywhere
Section titled “Inline backend: author once, reuse anywhere”When the same short option list appears on several params, declare it once with
options = [...] instead of path, and reference it the same way. The list is
the same choice-entry shape (value, label, optional color):
[data.target_side]options = [ { value = 0, label = "Player", color = "#86efac" }, { value = 1, label = "Opponent", color = "#ff7a7a" },][events.apply_stat.params_schema.properties.target_side]type = "integer"enum = [0, 1]"x-mobrule-widget" = "chips""x-mobrule-source" = "target_side"A [data.<name>] declares exactly one backend: path (file) or options
(inline). Declaring both is an error.
Unlike the file backend, the loader expands an inline dataset into
x-mobrule-options on every referencing param when the pack loads. That means:
- The choices ride the manifest directly: they are not asset-served, and there is no separate file to ship.
- Your param’s
x-mobrule-widgetis honoured as written. Usechipsorsegmentedfor a small set (the file backend’s searchablecomboboxdefault does not apply). Colours render exactly as inline options would. - Keep the param’s
enum(or other validation) as you would for an inline list: the dataset is presentation only and validates nothing.
Pinning
Section titled “Pinning”A dataset’s name and a content hash ride in the manifest, so it is part of
manifest_hash. For a file dataset the hash is over the file’s bytes; for an
inline dataset it is over the canonical option JSON. Either way, editing the
choices changes manifest_hash. That makes schema↔data skew and tampering
detectable, and means you must re-pin any compiled-in MANIFEST_HASH (e.g. an
Adapter’s) afterward. A file dataset’s local path is not hashed: relocating
the file within the pack keeps the hash; changing its bytes re-pins it.
How delivery works
Section titled “How delivery works”This section is about the file backend; an inline dataset is expanded into the params at load (above) and is never delivered separately.
The dataset is served over the existing /pack-assets/* surface, the same
place your overlay files come from, so there is no new protocol surface and
nothing for your Adapter to implement. The platform UI resolves the source name
to the file’s asset URL and fetches it to populate the picker. Only files you
declare in a [data.<name>] table are reachable this way; the rest of your pack
stays private.
Because it is asset-served and static, the picker populates offline: the broadcaster can configure rewards before launch, when the Adapter isn’t even connected.
See also
Section titled “See also”- UI hint vocabulary: inline
x-mobrule-optionsand the widget set, includingcombobox. - Manifest reference: where
[data.<name>]sits in the manifest. - Defining Events: params that carry the source hint.