refactor(M03): extract M2 unique placement registry

This commit is contained in:
2026-07-16 10:01:09 +04:00
parent c13c993645
commit acb3a809bb
10 changed files with 518 additions and 70 deletions
+10 -14
View File
@@ -1,12 +1,14 @@
extends SceneTree
const STREAMING_WORLD_LOADER := preload("res://src/scenes/streaming/streaming_world_loader.gd")
const M2_UNIQUE_PLACEMENT_REGISTRY := preload(
"res://src/render/m2/m2_unique_placement_registry.gd"
)
var _failures := 0
func _initialize() -> void:
var loader = STREAMING_WORLD_LOADER.new()
var registry: RefCounted = M2_UNIQUE_PLACEMENT_REGISTRY.new()
var placement := {
"name_id": 0,
"unique_id": 11785,
@@ -15,30 +17,24 @@ func _initialize() -> void:
"scale": 1.0,
}
var first: Dictionary = loader.call("_reserve_tile_m2_placements", "30_49", [placement])
var first: Dictionary = registry.call("reserve", "30_49", [placement])
_expect((first.get("placements", []) as Array).size() == 1, "first tile should reserve unique M2 placement")
_expect((first.get("unique_keys", []) as Array).has("uid:11785"), "first tile should own uid:11785")
_expect((first.get("skipped_unique_keys", []) as Array).is_empty(), "first tile should not skip uid:11785")
var duplicate: Dictionary = loader.call("_reserve_tile_m2_placements", "31_49", [placement])
var duplicate: Dictionary = registry.call("reserve", "31_49", [placement])
_expect((duplicate.get("placements", []) as Array).is_empty(), "second tile should skip duplicate uid:11785")
_expect((duplicate.get("skipped_unique_keys", []) as Array).has("uid:11785"), "second tile should remember skipped uid:11785")
loader.call("_release_tile_m2_unique_keys", {
"key": "30_49",
"m2_unique_keys": ["uid:11785"],
"m2_skipped_unique_keys": [],
}, false)
var after_release: Dictionary = loader.call("_reserve_tile_m2_placements", "31_49", [placement])
registry.call("release", "30_49", ["uid:11785"])
var after_release: Dictionary = registry.call("reserve", "31_49", [placement])
_expect((after_release.get("placements", []) as Array).size() == 1, "second tile should reserve uid:11785 after owner release")
_expect((after_release.get("unique_keys", []) as Array).has("uid:11785"), "second tile should own uid:11785 after release")
var same_tile_loader = STREAMING_WORLD_LOADER.new()
var same_tile_duplicate: Dictionary = same_tile_loader.call("_reserve_tile_m2_placements", "31_49", [placement, placement])
var same_tile_registry: RefCounted = M2_UNIQUE_PLACEMENT_REGISTRY.new()
var same_tile_duplicate: Dictionary = same_tile_registry.call("reserve", "31_49", [placement, placement])
_expect((same_tile_duplicate.get("placements", []) as Array).size() == 1, "same tile should keep only one copy of duplicate uid:11785")
loader.free()
same_tile_loader.free()
if _failures > 0:
push_error("M2 unique dedupe verification failed: %d issue(s)" % _failures)
quit(1)
@@ -0,0 +1,156 @@
extends SceneTree
## Asset-free ownership, lifecycle, dependency and timing regression for M2 IDs.
const REGISTRY_SCRIPT := preload("res://src/render/m2/m2_unique_placement_registry.gd")
const LOADER_PATH := "res://src/scenes/streaming/streaming_world_loader.gd"
func _initialize() -> void:
var failures: Array[String] = []
_verify_unkeyed_and_invalid_placements(failures)
_verify_same_tile_and_cross_tile_deduplication(failures)
_verify_owner_checked_release_and_retry(failures)
_verify_clear_and_detached_diagnostics(failures)
_verify_loader_boundary(failures)
var elapsed_milliseconds := _verify_bounded_timing(failures)
if not failures.is_empty():
for failure in failures:
push_error("M2_UNIQUE_PLACEMENT_REGISTRY: %s" % failure)
quit(1)
return
print(
"M2_UNIQUE_PLACEMENT_REGISTRY PASS cases=10 iterations=100 elapsed_ms=%.3f"
% elapsed_milliseconds
)
quit(0)
func _verify_unkeyed_and_invalid_placements(failures: Array[String]) -> void:
var registry: RefCounted = REGISTRY_SCRIPT.new()
var result: Dictionary = registry.call("reserve", "tile-a", [
{"unique_id": -1},
{"unique_id": 0},
{"name_id": 7},
"invalid",
])
_expect_equal((result["placements"] as Array).size(), 3, "unkeyed placements pass", failures)
_expect_true((result["unique_keys"] as Array).is_empty(), "unkeyed placements not owned", failures)
_expect_equal(int(registry.call("active_count")), 0, "unkeyed active count", failures)
func _verify_same_tile_and_cross_tile_deduplication(failures: Array[String]) -> void:
var registry: RefCounted = REGISTRY_SCRIPT.new()
var placement := {"unique_id": 11785, "name_id": 0}
var first: Dictionary = registry.call("reserve", "30_49", [placement, placement])
_expect_equal((first["placements"] as Array).size(), 1, "same call duplicate filtered", failures)
_expect_string_array((first["unique_keys"] as Array), ["uid:11785"], "first owner key", failures)
var same_owner_retry: Dictionary = registry.call("reserve", "30_49", [placement])
_expect_equal((same_owner_retry["placements"] as Array).size(), 1, "same owner later call passes", failures)
var competing: Dictionary = registry.call("reserve", "31_49", [placement, placement])
_expect_true((competing["placements"] as Array).is_empty(), "competing tile filtered", failures)
_expect_string_array(
competing["skipped_unique_keys"] as Array,
["uid:11785"],
"competing skip recorded once",
failures
)
func _verify_owner_checked_release_and_retry(failures: Array[String]) -> void:
var registry: RefCounted = REGISTRY_SCRIPT.new()
var placement := {"unique_id": 44}
registry.call("reserve", "owner", [placement])
_expect_true(
(registry.call("release", "other", ["uid:44"]) as Array).is_empty(),
"non-owner release ignored",
failures
)
_expect_equal(int(registry.call("active_count")), 1, "non-owner keeps reservation", failures)
var released: Array = registry.call("release", "owner", ["", "uid:44", "uid:44"])
_expect_string_array(released, ["uid:44"], "owner release order and dedupe", failures)
var retried: Dictionary = registry.call("reserve", "other", [placement])
_expect_equal((retried["placements"] as Array).size(), 1, "waiting tile reserves after release", failures)
func _verify_clear_and_detached_diagnostics(failures: Array[String]) -> void:
var registry: RefCounted = REGISTRY_SCRIPT.new()
registry.call("reserve", "tile-b", [{"unique_id": 20}])
registry.call("reserve", "tile-a", [{"unique_id": 10}])
var snapshot: Dictionary = registry.call("diagnostic_snapshot")
var owners: Array = snapshot["owners"]
_expect_equal(int(snapshot["active_count"]), 2, "diagnostic count", failures)
_expect_string_equal(String(owners[0]["unique_key"]), "uid:10", "diagnostic sorted", failures)
owners[0]["tile_key"] = "mutated"
var fresh_snapshot: Dictionary = registry.call("diagnostic_snapshot")
_expect_string_equal(
String((fresh_snapshot["owners"] as Array)[0]["tile_key"]),
"tile-a",
"diagnostics detached",
failures
)
registry.call("clear")
registry.call("clear")
_expect_equal(int(registry.call("active_count")), 0, "clear idempotent", failures)
func _verify_loader_boundary(failures: Array[String]) -> void:
var source := _read_text(LOADER_PATH, failures)
_expect_true(source.contains("M2_UNIQUE_PLACEMENT_REGISTRY_SCRIPT.new()"), "loader composes registry", failures)
_expect_true(source.contains("_m2_unique_placement_registry.reserve("), "loader delegates reserve", failures)
_expect_true(source.contains("_m2_unique_placement_registry.release("), "loader delegates release", failures)
_expect_true(source.contains("_m2_unique_placement_registry.clear()"), "loader delegates clear", failures)
_expect_true(not source.contains("var _m2_unique_registry"), "loader omits registry dictionary", failures)
_expect_true(not source.contains("func _m2_unique_key("), "loader omits key formula", failures)
func _verify_bounded_timing(failures: Array[String]) -> float:
var placements: Array = []
for placement_index in range(256):
placements.append({"unique_id": placement_index + 1})
var registry: RefCounted = REGISTRY_SCRIPT.new()
var started_microseconds := Time.get_ticks_usec()
for _iteration in range(100):
var reservation: Dictionary = registry.call("reserve", "owner", placements)
registry.call("release", "owner", reservation["unique_keys"])
var elapsed_milliseconds := float(Time.get_ticks_usec() - started_microseconds) / 1000.0
_expect_true(elapsed_milliseconds < 1000.0, "100 reserve/release cycles remain bounded", failures)
return elapsed_milliseconds
func _read_text(path: String, failures: Array[String]) -> String:
var file := FileAccess.open(path, FileAccess.READ)
if file == null:
failures.append("cannot open %s" % path)
return ""
return file.get_as_text()
func _expect_equal(actual_value: int, expected_value: int, label: String, failures: Array[String]) -> void:
if actual_value != expected_value:
failures.append("%s expected %d, got %d" % [label, expected_value, actual_value])
func _expect_string_equal(
actual_value: String,
expected_value: String,
label: String,
failures: Array[String]
) -> void:
if actual_value != expected_value:
failures.append("%s expected %s, got %s" % [label, expected_value, actual_value])
func _expect_string_array(
actual_values: Array,
expected_values: Array,
label: String,
failures: Array[String]
) -> void:
if actual_values != expected_values:
failures.append("%s expected %s, got %s" % [label, expected_values, actual_values])
func _expect_true(actual_value: bool, label: String, failures: Array[String]) -> void:
if not actual_value:
failures.append("%s expected true" % label)
@@ -0,0 +1 @@
uid://inw4fft20be0