fix(client): use tick-based invalidation for world renderer

Count-based dirty tracking missed content changes when tile/visibility
count stayed the same (e.g., door opening, player moving through
corridor). Now re-renders all layers when GameState.current_tick
advances, which correctly handles every snapshot change.

Adds 3 tests for tick advancement and same-count-different-content
scenarios. 68 total tests, 0 failures.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-12 00:24:30 +01:00
co-authored by Claude Opus 4.6
parent aa3a3fea7d
commit 6ff6be9a78
2 changed files with 34 additions and 12 deletions
+23
View File
@@ -31,6 +31,12 @@ func test_tile_size_constant() -> void:
# -- GameState: tile and visibility data --
func test_game_state_tick_advances() -> void:
GameState.apply_snapshot({"tick": 1, "tiles": _test_tiles})
assert_that(GameState.current_tick).is_equal(1)
GameState.apply_snapshot({"tick": 2, "tiles": _test_tiles})
assert_that(GameState.current_tick).is_equal(2)
func test_game_state_stores_tiles() -> void:
GameState.apply_snapshot({"tick": 1, "tiles": _test_tiles})
assert_that(GameState.visible_tiles.size()).is_equal(5)
@@ -49,6 +55,23 @@ func test_game_state_clears_old_visible_positions() -> void:
assert_that(GameState.visible_positions.size()).is_equal(2)
assert_that(GameState.visible_positions.has(Vector2i(1, 1))).is_false()
func test_game_state_same_count_different_tiles_new_tick() -> void:
var tiles_a := [{"x": 0, "y": 0, "z": 0, "type": "floor"}]
var tiles_b := [{"x": 0, "y": 0, "z": 0, "type": "door"}]
GameState.apply_snapshot({"tick": 1, "tiles": tiles_a})
assert_that(GameState.visible_tiles[0].type).is_equal("floor")
GameState.apply_snapshot({"tick": 2, "tiles": tiles_b})
assert_that(GameState.current_tick).is_equal(2)
assert_that(GameState.visible_tiles[0].type).is_equal("door")
func test_game_state_same_count_different_visibility_new_tick() -> void:
GameState.apply_snapshot({"tick": 1, "visible_positions": [{"x": 1, "y": 1}]})
assert_that(GameState.visible_positions.has(Vector2i(1, 1))).is_true()
GameState.apply_snapshot({"tick": 2, "visible_positions": [{"x": 2, "y": 2}]})
assert_that(GameState.current_tick).is_equal(2)
assert_that(GameState.visible_positions.has(Vector2i(1, 1))).is_false()
assert_that(GameState.visible_positions.has(Vector2i(2, 2))).is_true()
func test_game_state_warns_on_missing_player() -> void:
GameState.player_entity_id = 999
GameState.player_position = Vector2(5, 5)