Log inGet started
World

Builtin Library

Branchmain
Branchesmainpublish
Commit3bb1da2647

README.md

value_type

Converts a handle-backed value type — ColorSequence, NumberSequence — between the live object a session holds and the durable payload its serialize() produces.

A sequence has two forms:

FormShapeMeaning
live{ kind = "ColorSequence", __h = 13 }__h names a curve in this process's curve registry
durable{ kind = "ColorSequence", keypoints = { … } }the curve itself, which any session rebuilds

__h is minted when the curve is created and is meaningful for exactly as long as that registry lives, so a record carrying it names nothing in the session that reads it back. The keypoints are the authored data, and they cross every boundary intact — which is why a record carries the durable form and a live component field carries the live one.

Both forms carry kind, so a value read out of a component field says which converter owns it whether it came from memory or from a record. The two are told apart by which of __h / keypoints the table itself holds.

Field.table copies the table it is handed and drops its metatable, so a live value read back off a component field answers no methods at all. The field gives that same stored table back on every read, so bind puts the methods on it once and the field answers them from then on.

API

local ValueType = require("modules.value_type")

local color = ColorSequence.new({ 1, 0.3, 0.1 }, { 0.1, 0.1, 1 })

ValueType.kindOf(color)                  -- "ColorSequence"
ValueType.isLive(color)                  -- true
ValueType.isPayload(color:serialize())   -- true

-- The keypoints out of either form. The second argument is the kind to read a
-- bare `{ __h = n }` as, for a caller that knows its field's type.
ValueType.keypoints(component.color, "ColorSequence")

-- The durable payload for a live value; nil for anything else.
ValueType.serialize(color)   -- { kind = "ColorSequence", keypoints = { … } }

-- The live value a payload names, rebuilt in this session; nil for anything else.
ValueType.revive(record.color)

-- A whole component field map, with every payload rebuilt.
local applyData, rebuilt = ValueType.withRevived(record.data)

-- Put the methods back on a value read out of a component field.
ValueType.bind(component.color, "ColorSequence"):evaluate(0)

withRevived returns the same table when the map carries no payload, so the common case allocates nothing; the second return says how many fields were rebuilt.

Consumers

scene_saver asks per field as it serialises an entity, and writes the payload in place of the handle. scene_loader rebuilds the payloads in a component's record before applying it, so the component takes the field holding the same curve it held when the record was written. dirty_hot_reload does the same as it applies a body, and reduces the live side of its record comparison to the durable form so both sides are compared in one shape.