| … | … | @@ -0,0 +1,102 @@ |
| 1 | extends Node |
| 2 | ## PROBE (not a gate) — WHAT PLACED ASSETS COST THE FOLD (#120 L4 §15.8 step 7). One room |
| 3 | ## per process, PROBE_N placements (default 10) of a 50-shape asset ("Kit": 50 boxes in a |
| 4 | ## 10 x 5 grid, every 5th with a mirror), then, each the median of PROBE_REPS (3): |
| 5 | ## refold() the whole fold, forced (no skip, no tail) |
| 6 | ## AssetFold.expand the placements' expansion alone |
| 7 | ## move one placement asset.xform + its refold (what a G on one costs) |
| 8 | ## and the SAME geometry as ordinary shapes — N copies of the 50 boxes recorded directly — for |
| 9 | ## the reference: what instancing adds over owning the records. |
| 10 | ## DIGESTS: the placements' brushes vs the copies' (offset), so the two rooms are the same. |
| 11 | ## |
| 12 | ## RUN: PROBE_N=10 CI=true HYPERTPS_DAEMON_TCP=127.0.0.1:1 "$HYPER_TPS_GODOT" --headless --path . res://scenes/test/_probe_asset_fold.tscn |
| 13 | |
| 14 | var map: Node3D |
| 15 | var persist: Node |
| 16 | var level: Node |
| 17 | |
| 18 | |
| 19 | func _ready() -> void: |
| 20 | var gs: Node = get_tree().root.get_node_or_null("/root/GameState") |
| 21 | gs.route("world:level:*", 1, "peer") |
| 22 | var keet: Node = get_tree().root.get_node_or_null("/root/KeetService") |
| 23 | if keet != null: |
| 24 | keet.current_member_id = "probe" |
| 25 | get_tree().root.get_node("/root/GameMode").set_mode("build") |
| 26 | map = (load("res://scenes/maps/map_dev_test.tscn") as PackedScene).instantiate() |
| 27 | add_child(map) |
| 28 | for i in 6: |
| 29 | await get_tree().process_frame |
| 30 | persist = map.get("_persist") |
| 31 | level = map.get("level") |
| 32 | var n := int(OS.get_environment("PROBE_N")) if OS.get_environment("PROBE_N") != "" else 10 |
| 33 | var reps := int(OS.get_environment("PROBE_REPS")) if OS.get_environment("PROBE_REPS") != "" else 3 |
| 34 | var mode := OS.get_environment("PROBE_MODE") if OS.get_environment("PROBE_MODE") != "" else "assets" |
| 35 | var O0 := Vector3(1000, 0, 1000) |
| 36 | # The asset: 50 boxes, every 5th mirrored. |
| 37 | persist.begin_gesture("kit") |
| 38 | var members: Array = [] |
| 39 | for i in 50: |
| 40 | var at := O0 + Vector3((i % 10) * 3.0, 0, (i / 10) * 3.0) |
| 41 | var d: String = persist.record("shape.create", {"type": "box", "gv": 1, "params": {}, |
| 42 | "frame": SceneObjects.xform_to(Transform3D(Basis.IDENTITY, at)), "size": [2, 2, 2], "material_id": 2, "level_id": 0}) |
| 43 | if i % 5 == 0: |
| 44 | persist.record("mod.create", {"target": d, "mod": "mirror", "params": {"axis": "x", "offset": 0.0}}) |
| 45 | members.append("g:" + d) |
| 46 | var kit: String = persist.record("col.create", {"name": "Kit", "parent": ""}) |
| 47 | persist.record("col.link", {"target": kit, "members": members}) |
| 48 | persist.end_gesture() |
| 49 | persist.refold() |
| 50 | var lib: Node = map.asset_library() |
| 51 | lib.save_collection(kit, "Kit", true, false) |
| 52 | var base_brushes := (level.get_live_brush_ids() as PackedInt32Array).size() |
| 53 | var dots: Array = [] |
| 54 | persist.begin_gesture("place") |
| 55 | for k in n: |
| 56 | var f := Transform3D(Basis.IDENTITY, O0 + Vector3(0, 0, 40 + k * 20)) |
| 57 | if mode == "assets": |
| 58 | dots.append(persist.record("asset.place", {"asset": lib.rows()[0]["oid"], "name": "Kit", "frame": SceneObjects.xform_to(f)})) |
| 59 | else: |
| 60 | # The reference: the same 50 boxes (+ mirrors) recorded as the user's own shapes. |
| 61 | for i2 in 50: |
| 62 | var at2 := f.origin + Vector3((i2 % 10) * 3.0, 0, (i2 / 10) * 3.0) - Vector3(0, 0, 0) |
| 63 | var d2: String = persist.record("shape.create", {"type": "box", "gv": 1, "params": {}, |
| 64 | "frame": SceneObjects.xform_to(Transform3D(Basis.IDENTITY, at2)), "size": [2, 2, 2], "material_id": 2, "level_id": 0}) |
| 65 | if i2 % 5 == 0: |
| 66 | persist.record("mod.create", {"target": d2, "mod": "mirror", "params": {"axis": "x", "offset": 0.0}}) |
| 67 | persist.end_gesture() |
| 68 | persist.refold() |
| 69 | var brushes := (level.get_live_brush_ids() as PackedInt32Array).size() - base_brushes |
| 70 | var tf := [] |
| 71 | for r in reps: |
| 72 | persist.set("_brush_ver_folded", -1) |
| 73 | persist.set("_ix_tail_ok", false) |
| 74 | var t0 := Time.get_ticks_usec() |
| 75 | persist.refold() |
| 76 | tf.append(float(Time.get_ticks_usec() - t0) / 1000.0) |
| 77 | var te := [] |
| 78 | if mode == "assets": |
| 79 | var arecs: Array = (persist.records(false) as Array).filter(func(x: Dictionary) -> bool: return String(x["kind"]).begins_with("asset.")) |
| 80 | for r2 in reps: |
| 81 | var t1 := Time.get_ticks_usec() |
| 82 | LevelPersistence.AssetFold.expand(arecs, persist.get("_asset_docs"), persist._parse_as) |
| 83 | te.append(float(Time.get_ticks_usec() - t1) / 1000.0) |
| 84 | var tm := [] |
| 85 | for r3 in reps: |
| 86 | var t2 := Time.get_ticks_usec() |
| 87 | persist.begin_gesture("move") |
| 88 | if mode == "assets": |
| 89 | persist.record("asset.xform", {"target": dots[0], "frame": SceneObjects.xform_to(Transform3D(Basis.IDENTITY, O0 + Vector3(r3 + 1, 0, 40)))}) |
| 90 | else: |
| 91 | persist.record("shape.xform", {"target": String(members[0]).substr(2), "frame": SceneObjects.xform_to(Transform3D(Basis.IDENTITY, O0 + Vector3(r3 + 1, 0, 0)))}) |
| 92 | persist.end_gesture() |
| 93 | persist.refold() |
| 94 | tm.append(float(Time.get_ticks_usec() - t2) / 1000.0) |
| 95 | print("PROBE %s N=%d: %d brushes from them | refold() %.1f ms | AssetFold.expand %s | move one %.1f ms" |
| 96 | % [mode, n, brushes, _med(tf), ("%.1f ms" % _med(te)) if not te.is_empty() else "—", _med(tm)]) |
| 97 | get_tree().quit(0) |
| 98 | |
| 99 | |
| 100 | func _med(ts: Array) -> float: |
| 101 | ts.sort() |
| 102 | return ts[ts.size() / 2] |