OverviewFilesCommitsIssuesDocsReleasesPeers

hyper-tps commits / c3d24f7

#120 L4: AssetFold.payloads — one builder for the fold's synthetic records and Make Real
Refactor, no behaviour change: a placement's records as journal payloads (M applied, references resolved by dot_of) are built once; the fold maps them to synthetic dots and parses them, Make Real (step 4) will journal them under fresh dots. gate_asset_fold 21/21 (F1 digest unchanged), gate_asset_doc 24/24, gate_asset_library 20/20. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
c3d24f7d7fce6e6fe4ecca0c4e508b078da02803
by plankatron <fleeky@gmail.com> · 2026-10-19T21:36:12.000Z

Changed files (1) +66 -39

scenes/maps/asset_fold.gd +66 -39
……@@ -117,27 +117,61 @@ static func _expand_one(p: Dictionary, doc: Dictionary, parse: Callable, out: Ar
117117 var pa := String(p["author"])
118118 var ps := int(p["seq"])
119119 var pdot := String(p["dot"])
120 var m := placement_xform(p["frame"], doc["pivot"])
120 var names := local_names(doc)
121 var dot_of := func(local: String) -> String:
122 return "%s/A%04d:%d" % [pa, int(names[local]), ps] if names.has(local) else ""
121123 var moved: bool = int(p["ver"]) > ps
122 var names := {} # "L:<n>" -> synthetic author
124 for e: Dictionary in payloads(p, doc, dot_of):
125 var local := String(e["local"])
126 var au := "%s/A%04d%s" % [pa, int(names[local]), String(e["suffix"])]
127 var pl: Dictionary = e["payload"]
128 var rec: Dictionary = parse.call(au, ps, pl)
129 if rec.is_empty():
130 continue
131 rec["inst"] = pdot
132 out.append(rec)
133 match String(pl["kind"]):
134 "shape.create":
135 inst[dot_of.call(local)] = pdot
136 if moved:
137 # Same frame, later seq: ShapeFold's <ver> rule renames the pieces.
138 var xr: Dictionary = parse.call(au, int(p["ver"]), {"kind": "shape.xform",
139 "target": dot_of.call(local), "frame": pl["frame"]})
140 if not xr.is_empty():
141 xr["inst"] = pdot
142 out.append(xr)
143 "brush.create":
144 inst[String(pl["group"])] = pdot
145 "object.create":
146 inst[dot_of.call(local)] = pdot
147
148
149## Local name -> its number: every record's dot, and every brush object's local GROUP (a
150## name its brush.create records share, not a record of its own — it needs a name too: ""
151## would merge it with every ungrouped brush in the level).
152static func local_names(doc: Dictionary) -> Dictionary:
153 var names := {}
123154 for r: Dictionary in (doc["records"] as Array):
124 var n := int(String(r["dot"]).substr(2))
125 names[String(r["dot"])] = "%s/A%04d" % [pa, n]
126 # A brush object's GROUP is a local name its brush.create records share, not a
127 # record of its own: it needs a name too ("" would merge it with every ungrouped
128 # brush in the level).
155 names[String(r["dot"])] = int(String(r["dot"]).substr(2))
129156 var lg := String(r.get("group", "")) if String(r["kind"]) == "brush.create" else ""
130157 if lg.begins_with("L:") and not names.has(lg):
131 names[lg] = "%s/A%04d" % [pa, int(lg.substr(2))]
132 var dot_of := func(local: String) -> String:
133 return "%s:%d" % [names[local], ps] if names.has(local) else ""
134 var emit := func(author: String, seq: int, payload: Dictionary) -> void:
135 var rec: Dictionary = parse.call(author, seq, payload)
136 if not rec.is_empty():
137 rec["inst"] = pdot
138 out.append(rec)
158 names[lg] = int(lg.substr(2))
159 return names
160
161
162## A placement's records as journal PAYLOADS, M applied and every local reference resolved
163## by `dot_of` (local name -> the dot it becomes): [{local, suffix, payload}], in the blob's
164## order. `suffix` "" = the local's own record; "r" / "t" a brush object's turn / move,
165## "s" a modifier's or cut's off switch, "p" / "q" an object's parent / props — follow-ups
166## that must sort after it. SHARED by the fold (synthetic dots) and Make Real (fresh dots),
167## so the two cannot drift.
168static func payloads(p: Dictionary, doc: Dictionary, dot_of: Callable) -> Array:
169 var out: Array = []
170 var m := placement_xform(p["frame"], doc["pivot"])
171 var add := func(local: String, suffix: String, payload: Dictionary) -> void:
172 out.append({"local": local, "suffix": suffix, "payload": payload})
139173 for r: Dictionary in (doc["records"] as Array):
140 var au: String = names[String(r["dot"])]
174 var local := String(r["dot"])
141175 var kind := String(r["kind"])
142176 var pl: Dictionary = r.duplicate(true)
143177 pl.erase("dot")
……@@ -152,10 +186,9 @@ static func _expand_one(p: Dictionary, doc: Dictionary, parse: Callable, out: Ar
152186 q2[hk] = _arr(m.basis * _v3(q[hk]))
153187 pts.append(q2)
154188 pl["points"] = pts
155 emit.call(au, ps, pl)
189 add.call(local, "", pl)
156190 "shape.create":
157 var f := m * SceneObjects.xform_from(pl["frame"])
158 pl["frame"] = SceneObjects.xform_to(f)
191 pl["frame"] = SceneObjects.xform_to(m * SceneObjects.xform_from(pl["frame"]))
159192 var sp: Dictionary = pl["params"]
160193 for ck: String in ["curve", "profile_curve"]:
161194 if sp.has(ck):
……@@ -164,12 +197,7 @@ static func _expand_one(p: Dictionary, doc: Dictionary, parse: Callable, out: Ar
164197 pl["link"] = dot_of.call(String(pl["link"]))
165198 else:
166199 pl.erase("link")
167 emit.call(au, ps, pl)
168 inst[dot_of.call(String(r["dot"]))] = pdot
169 if moved:
170 # Same frame, later seq: ShapeFold's <ver> rule renames the pieces.
171 emit.call(au, int(p["ver"]), {"kind": "shape.xform", "target": dot_of.call(String(r["dot"])),
172 "frame": pl["frame"]})
200 add.call(local, "", pl)
173201 "mod.create":
174202 var mp: Dictionary = pl["params"]
175203 if mp.has("curve"):
……@@ -179,9 +207,9 @@ static func _expand_one(p: Dictionary, doc: Dictionary, parse: Callable, out: Ar
179207 pl["target"] = dot_of.call(String(pl["target"]))
180208 var on := bool(pl.get("on", true))
181209 pl.erase("on")
182 emit.call(au, ps, pl)
210 add.call(local, "", pl)
183211 if not on:
184 emit.call(au + "s", ps, {"kind": "mod.set", "target": dot_of.call(String(r["dot"])), "on": false})
212 add.call(local, "s", {"kind": "mod.set", "target": dot_of.call(local), "on": false})
185213 "op.create":
186214 pl["cutter"] = dot_of.call(String(pl["cutter"]))
187215 var tg: Array = []
……@@ -190,39 +218,38 @@ static func _expand_one(p: Dictionary, doc: Dictionary, parse: Callable, out: Ar
190218 pl["targets"] = tg
191219 var on2 := bool(pl.get("on", true))
192220 pl.erase("on")
193 emit.call(au, ps, pl)
221 add.call(local, "", pl)
194222 if not on2:
195 emit.call(au + "s", ps, {"kind": "op.set", "target": dot_of.call(String(r["dot"])), "on": false})
223 add.call(local, "s", {"kind": "op.set", "target": dot_of.call(local), "on": false})
196224 "brush.create":
197225 pl["group"] = dot_of.call(String(pl["group"]))
198 inst[String(pl["group"])] = pdot
199 emit.call(au, ps, pl)
200 var key: String = dot_of.call(String(r["dot"]))
226 add.call(local, "", pl)
227 var key: String = dot_of.call(local)
201228 # Turned about the world origin by M's basis, then moved by M's origin: the
202 # same map as M, through the store's texture lock. Identity emits nothing.
229 # same map as M, through the store's texture lock. Identity adds nothing.
203230 var q3 := m.basis.get_rotation_quaternion()
204231 var ang := rad_to_deg(q3.get_angle())
205232 if absf(ang) > 1.0e-9:
206 emit.call(au + "r", ps, {"kind": "brush.rotate", "brush_key": key, "axis": _arr(q3.get_axis()),
233 add.call(local, "r", {"kind": "brush.rotate", "brush_key": key, "axis": _arr(q3.get_axis()),
207234 "angle": ang, "pivot": [0, 0, 0], "tex_lock": true})
208235 if m.origin != Vector3.ZERO:
209 emit.call(au + "t", ps, {"kind": "brush.translate", "brush_key": key, "delta": _arr(m.origin),
236 add.call(local, "t", {"kind": "brush.translate", "brush_key": key, "delta": _arr(m.origin),
210237 "tex_lock": true})
211238 "object.create":
212239 var par := String(pl.get("parent", ""))
213240 var x := SceneObjects.xform_from(pl["xform"])
214241 var props: Dictionary = pl.get("props", {})
215 emit.call(au, ps, {"kind": "object.create", "type": pl["type"],
242 add.call(local, "", {"kind": "object.create", "type": pl["type"],
216243 "xform": SceneObjects.xform_to(x if par != "" else m * x)})
217 inst[dot_of.call(String(r["dot"]))] = pdot
218244 if par != "":
219 emit.call(au + "p", ps, {"kind": "object.parent", "target": dot_of.call(String(r["dot"])),
245 add.call(local, "p", {"kind": "object.parent", "target": dot_of.call(local),
220246 "parent": dot_of.call(par), "xform": SceneObjects.xform_to(x)})
221247 if not props.is_empty():
222 emit.call(au + "q", ps, {"kind": "object.set_prop", "target": dot_of.call(String(r["dot"])),
248 add.call(local, "q", {"kind": "object.set_prop", "target": dot_of.call(local),
223249 "props": props.duplicate(true)})
224250 _:
225251 pass # col.create: organisation, not geometry
252 return out
226253
227254
228255## The wire box of a placement whose blob is not here: bounds unknown too, so a 1 m cube at