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
+2
View File
@@ -62,6 +62,8 @@ func apply_snapshot(snapshot: Dictionary) -> void:
if not has_explicit_positions:
visible_positions.clear()
for vtile in snapshot.visible_tiles:
if not vtile is Dictionary or not vtile.has("x") or not vtile.has("y"):
continue
var pos := Vector2i(vtile.x, vtile.y)
if vtile.has("visibility"):
visibility_sectors[pos] = vtile.visibility
+2 -1
View File
@@ -7,7 +7,8 @@ const TILE_SIZE: int = 32
# D-033: Entity relationship color palette
# Color represents the player's RELATIONSHIP to the entity, not an objective property.
# Phase 1: default colors by entity kind. Phase 2 (#361): driven by RelationshipState.
# Phase 1: default colors mapped by entity kind (Player/Npc/Object/Terrain).
# Phase 2 (#361): colors derived from RelationshipState via the knowledge graph.
const ENTITY_COLOR_UNKNOWN: Color = Color("#4a9ebb") # Unknown/Neutral — cool teal
const ENTITY_COLOR_FRIENDLY: Color = Color("#6bc9a6") # Known/Friendly — soft green
const ENTITY_COLOR_POI: Color = Color("#e8c547") # Person of Interest — warm amber
+4 -4
View File
@@ -79,11 +79,11 @@ func _update_entity_node(entity_id: int, entity_data: Dictionary) -> void:
)
# v2: Peripheral vision dimming (D-015)
# null visibility (v1 backward compat) defaults to full alpha
var visibility: Variant = entity_data.get("visibility")
if visibility == "Peripheral":
entity_node.modulate.a = Constants.PERIPHERAL_ALPHA
else:
entity_node.modulate.a = 1.0
var target_alpha := Constants.PERIPHERAL_ALPHA if visibility == "Peripheral" else 1.0
if not is_equal_approx(entity_node.modulate.a, target_alpha):
entity_node.modulate.a = target_alpha
# v2: Update facing indicator rotation (player entity only)
if entity_id == GameState.player_entity_id: