diff --git a/client/tests/test_step_canvas_cache.gd b/client/tests/test_step_canvas_cache.gd index 7eebe7579..9bed56f4b 100644 --- a/client/tests/test_step_canvas_cache.gd +++ b/client/tests/test_step_canvas_cache.gd @@ -21,12 +21,30 @@ func test_make_key_distinguishes_body_rung_center_and_extent() -> void: assert_str(k1).is_not_equal(k5) -## Global collapses center/extent to a fixed sentinel regardless of what's -## passed — every Global request for the same body_id must land on ONE slot. -func test_make_key_global_ignores_center_and_extent() -> void: - var k1 := StepCanvasCache.make_key("GJ1c", "Global", Vector2i(10, 20), Vector2i(64, 64)) - var k2 := StepCanvasCache.make_key("GJ1c", "Global", Vector2i(999, -999), Vector2i(1, 1)) - assert_str(k1).is_equal(k2) +## Global collapses the CENTRE to a sentinel (its canvas is whole-body and +## origin-anchored, so the server genuinely ignores `center`) but NOT the +## extent. Zeroing the extent was correct while Global had exactly one +## possible size per body; since the D-255 extent inversion made it +## viewport-sized, collapsing it meant the first canvas cached for a body +## answered every later request — so a window resize could never take effect, +## because the differently-sized request was a HIT on the stale one. +func test_make_key_global_ignores_center_but_honours_extent() -> void: + var same_size_a := StepCanvasCache.make_key( + "GJ1c", "Global", Vector2i(10, 20), Vector2i(64, 64) + ) + var same_size_b := StepCanvasCache.make_key( + "GJ1c", "Global", Vector2i(999, -999), Vector2i(64, 64) + ) + assert_str(same_size_a).override_failure_message( + "Global must ignore centre — its canvas is origin-anchored" + ).is_equal(same_size_b) + + var other_size := StepCanvasCache.make_key( + "GJ1c", "Global", Vector2i(10, 20), Vector2i(960, 480) + ) + assert_str(same_size_a).override_failure_message( + "Global must NOT ignore extent — a resize has to be able to miss" + ).is_not_equal(other_size) func test_miss_returns_null_and_has_reports_false() -> void: diff --git a/client/tests/test_step_canvas_disk_cache.gd b/client/tests/test_step_canvas_disk_cache.gd index 10e350b43..0765591e2 100644 --- a/client/tests/test_step_canvas_disk_cache.gd +++ b/client/tests/test_step_canvas_disk_cache.gd @@ -586,10 +586,30 @@ func test_size_bytes_matches_actual_payload_file_length_on_disk() -> void: # ============================================================================= -func test_make_key_global_ignores_center_and_extent() -> void: - var k1 := StepCanvasDiskCache.make_key("GJ1c", "Global", Vector2i(10, 20), Vector2i(64, 64)) - var k2 := StepCanvasDiskCache.make_key("GJ1c", "Global", Vector2i(999, -999), Vector2i(1, 1)) - assert_str(k1).is_equal(k2) +## Global collapses the CENTRE to a sentinel (its canvas is whole-body and +## origin-anchored, so the server genuinely ignores `center`) but NOT the +## extent. Zeroing the extent was correct while Global had exactly one +## possible size per body; since the D-255 extent inversion made it +## viewport-sized, collapsing it meant the first canvas cached for a body +## answered every later request — so a window resize could never take effect, +## because the differently-sized request was a HIT on the stale one. +func test_make_key_global_ignores_center_but_honours_extent() -> void: + var same_size_a := StepCanvasDiskCache.make_key( + "GJ1c", "Global", Vector2i(10, 20), Vector2i(64, 64) + ) + var same_size_b := StepCanvasDiskCache.make_key( + "GJ1c", "Global", Vector2i(999, -999), Vector2i(64, 64) + ) + assert_str(same_size_a).override_failure_message( + "Global must ignore centre — its canvas is origin-anchored" + ).is_equal(same_size_b) + + var other_size := StepCanvasDiskCache.make_key( + "GJ1c", "Global", Vector2i(10, 20), Vector2i(960, 480) + ) + assert_str(same_size_a).override_failure_message( + "Global must NOT ignore extent — a resize has to be able to miss" + ).is_not_equal(other_size) func test_clear_all_removes_every_body_and_the_root_directory() -> void: diff --git a/client/tests/test_step_canvas_viewer.gd b/client/tests/test_step_canvas_viewer.gd index a70115301..da0d3cc5d 100644 --- a/client/tests/test_step_canvas_viewer.gd +++ b/client/tests/test_step_canvas_viewer.gd @@ -491,11 +491,18 @@ func test_disk_sweep_timeout_handler_runs_background_sweep_for_the_current_body( ## and _global_body_extent actually populate through the real signal wiring. static func _land_global_canvas(v: StepCanvasViewer, width: int, height: int) -> void: var req: Variant = v.get_request() + # Cache under the extent the viewer will actually REQUEST. This used to pass + # Vector2i.ZERO because Global's cache key collapsed the extent to a + # sentinel — correct while Global had exactly one possible size per body, + # wrong since the D-255 extent inversion made it viewport-sized (a stale + # sentinel entry answered every request forever, so a resize could never + # take effect). The centre stays ZERO: Global's canvas really is whole-body + # and origin-anchored, so the server genuinely ignores it. req.get_cache().put( v.get_body_id(), "Global", Vector2i.ZERO, - Vector2i.ZERO, + v._request_extent(), TestStepCanvasViewer._synthetic_canvas(width, height) ) v._fire_request() # Global's own request — served from the cache hit just landed diff --git a/client/tests/visual_capture.gd b/client/tests/visual_capture.gd index 9a190b3eb..7e7361373 100644 --- a/client/tests/visual_capture.gd +++ b/client/tests/visual_capture.gd @@ -334,7 +334,8 @@ func _log_atlas_view_transform(tree_root: Node, scenario_name: String) -> void: print( ( "visual_capture: view-transform[%s] rung=%s world_center=%s held_extent=%s " - + "canvas_position=%s canvas_scale=%s footprint_px=%s canvas_cells=%dx%d" + + "canvas_position=%s canvas_scale=%s footprint_px=%s canvas_cells=%dx%d " + + "courses=%d settlements=%d" ) % [ scenario_name, @@ -346,6 +347,8 @@ func _log_atlas_view_transform(tree_root: Node, scenario_name: String) -> void: str(on_screen_footprint_px), int(summary.get("canvas_width", 0)), int(summary.get("canvas_height", 0)), + int(summary.get("course_count", 0)), + int(summary.get("settlement_count", 0)), ] ) diff --git a/client/tests/visual_scenarios.gd b/client/tests/visual_scenarios.gd index 820fd0da0..1e5062b04 100644 --- a/client/tests/visual_scenarios.gd +++ b/client/tests/visual_scenarios.gd @@ -128,6 +128,7 @@ func apply_setup(scenario_name: String, tree_root: Node) -> bool: return true var body := { "body_id": "GJ71c", + "body_radius_km": 5503.5, "proper_name": "Threshold", "terrain_reference": "wiki/star-systems/GJ-71/bodies/GJ71c/heightmap.png", } @@ -155,6 +156,7 @@ func apply_setup(scenario_name: String, tree_root: Node) -> bool: tree_root, { "body_id": "GJ380c", + "body_radius_km": 6238.4, "proper_name": "Lendel", "terrain_reference": "wiki/star-systems/GJ-380/bodies/GJ380c/heightmap.png", }, @@ -168,6 +170,7 @@ func apply_setup(scenario_name: String, tree_root: Node) -> bool: tree_root, { "body_id": "GJ380c", + "body_radius_km": 6238.4, "proper_name": "Lendel", "terrain_reference": "wiki/star-systems/GJ-380/bodies/GJ380c/heightmap.png", }, @@ -181,6 +184,7 @@ func apply_setup(scenario_name: String, tree_root: Node) -> bool: tree_root, { "body_id": "GJ380c", + "body_radius_km": 6238.4, "proper_name": "Lendel", "terrain_reference": "wiki/star-systems/GJ-380/bodies/GJ380c/heightmap.png", }, @@ -194,6 +198,7 @@ func apply_setup(scenario_name: String, tree_root: Node) -> bool: tree_root, { "body_id": "GJ144e", + "body_radius_km": 6959.3, "proper_name": "Vethis", "terrain_reference": "wiki/star-systems/GJ-144/bodies/GJ144e/heightmap.png", }, @@ -207,6 +212,7 @@ func apply_setup(scenario_name: String, tree_root: Node) -> bool: tree_root, { "body_id": "GJ144e", + "body_radius_km": 6959.3, "proper_name": "Vethis", "terrain_reference": "wiki/star-systems/GJ-144/bodies/GJ144e/heightmap.png", }, @@ -220,6 +226,7 @@ func apply_setup(scenario_name: String, tree_root: Node) -> bool: tree_root, { "body_id": "GJ338Bd", + "body_radius_km": 6711.0, "proper_name": "Arbour", "terrain_reference": "wiki/star-systems/GJ-338B/bodies/GJ338Bd/heightmap.png", }, @@ -233,6 +240,7 @@ func apply_setup(scenario_name: String, tree_root: Node) -> bool: tree_root, { "body_id": "GJ338Bd", + "body_radius_km": 6711.0, "proper_name": "Arbour", "terrain_reference": "wiki/star-systems/GJ-338B/bodies/GJ338Bd/heightmap.png", }, @@ -246,6 +254,7 @@ func apply_setup(scenario_name: String, tree_root: Node) -> bool: tree_root, { "body_id": "GJ820Bc", + "body_radius_km": 6062.0, "proper_name": "Ferrath", "terrain_reference": "wiki/star-systems/GJ-820B/bodies/GJ820Bc/heightmap.png", }, @@ -259,6 +268,7 @@ func apply_setup(scenario_name: String, tree_root: Node) -> bool: tree_root, { "body_id": "GJ820Bc", + "body_radius_km": 6062.0, "proper_name": "Ferrath", "terrain_reference": "wiki/star-systems/GJ-820B/bodies/GJ820Bc/heightmap.png", },