id (acme.turrets:turret_7) and owns metadata. Do not
set either.
localId, required
Unique within your adapter, within one capture. Must match [A-Za-z0-9_-]+.
This is the identity. Read Identity before choosing how you generate it: it
is the field that decides whether a restore matches the right object or destroys the wrong
one.
type, required
A non-empty string in your own vocabulary: acme_turret, darkrp_job_spawn,
example_marker.
Blueprints never interprets it. It is shown to humans and compared between captures, so a
type that changes for the same object reads as a replacement.
identity, required
scope may be stronger than your descriptor’s declared scope, never weaker. See
Identity.
transform, optional
Vector or Angle.
Omit it entirely for configuration that has no position. If you supply it, both pos and
ang are required: an object with a position but no meaningful facing supplies
ang = { 0, 0, 0 } and declares orientation = "none" from PrepareMaterialize.
bounds, optional
properties, optional
Flat scalars only: string, number (finite), boolean. No tables, no nested
structures, no nil.
Keys are strings and are yours to choose. Blueprints compares them between captures to decide
what changed, and (if you declare the properties capability) writes them back during a
restore.
Numbers compare with a small epsilon, so a float that loses precision through JSON is not
reported as a change forever after.
label, optional
A human-readable name, for reports and the interface. Never used to match, never diffed
for classification. Rename freely.
What is prohibited, always
What you get BACK is a different shape
This is the single easiest thing to get wrong, so it is stated plainly. What you return fromCollect is the table above. What Blueprints hands back to you
(the source argument of PrepareMaterialize, Materialize, PrepareProperties and
ApplyProperties) is the normalized record, and two of your fields have moved:
Reaching for
source.localId or source.label gets you nil, silently, on a path that only
runs during a real migration or restore.
Immutability
Determinism
Two consecutiveCollect calls on an unchanged world must name the same objects and describe
them identically.
That is stronger than it sounds. It rules out:
- iteration order that depends on Lua’s hash order, where it decides ids;
- timestamps, tick counts, uptimes or random values in
properties; - a value read from a source that is still initialising.