Builtin Library
README.md
defaults
The Preset Manager: the world's ordered [[presets]] rows in
/zero/source/.world_settings. A row names one declarer (target), one
preset for that declarer (preset) and a path glob (filter). When something
a declarer governs is created — an asset of an assetType, an import an
importer runs, a component added to an entity — the first row naming that
declarer whose filter matches the new thing's path gives a layer of its
settings. Rows are read only at creation.
A component row's filter reads the entity's hierarchy path (names from the root
down, joined with /). What a scene build's capture scope
adds takes the rows in any mode, whoever runs the build; outside a build, a
component takes a row when it is added in edit mode. A component put back from
existing content takes none: one added inside materializing (a saved scene, a
peer's record, a template clone, a bundle's hierarchy, a build's records), and
one a component's own code adds outside a build, on any coroutine that code
runs. A scene build records which fields the rows gave each component, and a
rebuild restates a component only when the code states it differently, so a
row edit alone changes nothing a build already placed.
Rows are written as guid envelopes and checked as a whole. A row is refused
when its target does not resolve, is consulted at no creation, or declares no
settings; when its preset does not resolve, is not a preset, or targets
another declarer; or when its filter is not a string. A write replaces the
[[presets]] block and keeps the rest of the file byte for byte.
The row format
[[presets]]
target = { __ref = "8cc28fc8-ed63-48ee-83a6-15f4192e27e1", type = "importer", name = "texture" }
preset = { __ref = "0b6c1f0e-5d0c-4d5e-9d64-3c1b7f2a9e11", type = "preset", name = "pixel_art" }
filter = "sprites/**"
target and preset are guid envelopes: __ref is the guid, and type
and name tell a person reading the file what it names. A row written by
hand may name either by identity or guid; the next write rewrites it as
envelopes. .world_settings's .refs pins each row's target and preset by
guid.
Matching
For a new thing a declarer governs, the rows are read in order and the
first naming that declarer whose filter matches the thing's path applies;
the rest are not consulted. A filter is a glob (preset.glob) over the
path relative to /source with forward slashes, or an entity's hierarchy
path for a component row; the empty filter matches everything, and a
filter that is not a string matches nothing. A matching row whose preset
does not resolve, or targets another declarer, is the match and contributes
nothing, with one warning. A preset value the declarer's schema rejects is
left out and the rest apply.
Sync
The rows are part of .world_settings, so they sync with the world like
any other file and every peer reads the same rows. A row applies where the
creation happens, when it happens: a peer's edit reaches only what is
created after it arrives, and what was created before keeps the settings it
was stamped with. A runtime asset lives for the engine process; a peer that
started before a row edit keeps its old settings on a re-created runtime
identity until it restarts.
Exports
Defaults.PATH,Defaults.BLOCK— the file and the array-of-tables name.Defaults.SCHEMA— the block's Field schema,{ presets = Field.list(row) }.Defaults.rows() -> { Row }— every row, resolved, with its problems.Defaults.write(rows)— normalise, check, and replace the rows.Defaults.normalize(input) -> StoredRowDefaults.rowProblems(row) -> (problems, targetRef, presetRef)Defaults.consultedAt(declarer) -> "asset.create" | "import" | "component.add" | nilDefaults.relativePathOf(path) -> string?— the path a filter reads.Defaults.match(declarerGuid, relPath) -> (Row?, index?)Defaults.layerFor(declarerGuid, relPath) -> (values?, Match?)Defaults.check(value, constraint) -> (ok, reason)— thepresetDefaultRowconstraint.Defaults.removeAt(index)— remove one row, writing every other row back as the file holds it.Defaults.importerSettings(importerRef, sourcePath) -> (settings, Match?)Defaults.materializing(fn, ...) -> ...— runfnwith no row reaching a component add.Defaults.entityPath(id) -> string— the hierarchy path a component row's filter reads.Defaults.forComponent(entityId, typeName, data?) -> data?— the data a component add takes.Defaults.batchLayers(targets, typeName, data?) -> { { targets, data } }— a batch add split into runs.Defaults.resolveValue(v) -> AssetRef?— a row value as the asset it names.Defaults.recordingStamps(fn, ...) -> (stamps, ...)— runfnand return what the rows gave the components a capture scope added meanwhile, perstampKey.Defaults.stampKey(entityId, componentGuid, instanceName?) -> string
The preset global exposes the rows as preset.defaults,
preset.setDefaults, preset.addDefault, preset.removeDefault and
preset.defaultFor.