fix(client): address PR #11 review — type safety, perf, tests

Add Dictionary validation in game_state visible_tiles loop to prevent
crash on malformed data (Hoshe critical). Skip redundant modulate.a
writes (Hoshe suggestion). Add 3 tests: malformed visible_tiles,
facing rotation accuracy, v1 backward compatibility. Clarify D-033
Phase 1/Phase 2 comments.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-12 01:07:02 +01:00
co-authored by Claude Opus 4.6
parent 30b028e85a
commit 64897a40b3
5 changed files with 68 additions and 5 deletions
+37
View File
@@ -98,6 +98,21 @@ func test_game_state_derives_visible_positions_from_visible_tiles() -> void:
assert_that(GameState.visibility_sectors[Vector2i(5, 5)]).is_equal("Forward")
assert_that(GameState.visibility_sectors[Vector2i(6, 5)]).is_equal("Peripheral")
func test_game_state_skips_malformed_visible_tiles() -> void:
var vtiles := [
{"x": 5, "y": 5, "z": 0, "visibility": "Forward"},
null,
"not_a_dict",
{"z": 0}, # missing x, y
{"x": 6, "y": 6, "z": 0, "visibility": "Peripheral"},
]
GameState.apply_snapshot({"tick": 1, "visible_tiles": vtiles})
# Only the 2 valid entries should be stored
assert_that(GameState.visible_positions.size()).is_equal(2)
assert_that(GameState.visible_positions.has(Vector2i(5, 5))).is_true()
assert_that(GameState.visible_positions.has(Vector2i(6, 6))).is_true()
assert_that(GameState.visibility_sectors.size()).is_equal(2)
func test_game_state_warns_on_missing_player() -> void:
GameState.player_entity_id = 999
GameState.player_position = Vector2(5, 5)
@@ -283,6 +298,28 @@ func test_entity_renderer_player_has_facing_indicator() -> void:
assert_that(indicator is Polygon2D).is_true()
renderer.queue_free()
func test_entity_renderer_facing_indicator_rotation_accuracy() -> void:
GameState.player_entity_id = 1
var renderer := _make_entity_renderer()
var directions := {
"North": 0.0,
"Northeast": PI / 4.0,
"East": PI / 2.0,
"Southeast": 3.0 * PI / 4.0,
"South": PI,
"Southwest": 5.0 * PI / 4.0,
"West": 3.0 * PI / 2.0,
"Northwest": 7.0 * PI / 4.0,
}
renderer.update_entities(_test_entities_v2)
var player_node = renderer.entity_nodes[1]
var indicator = player_node.get_node_or_null("FacingIndicator")
for dir_name in directions:
GameState.player_facing = dir_name
renderer.update_entities(_test_entities_v2)
assert_that(indicator.rotation).is_equal_approx(directions[dir_name], 0.001)
renderer.queue_free()
func test_entity_renderer_npc_has_no_facing_indicator() -> void:
GameState.player_entity_id = 1
var renderer := _make_entity_renderer()