fix(client): address PR #4 review feedback

Hoshe critical fixes:
- _action_enum_to_wire uses InputMapper.Action constants instead of
  fragile integer literals; OPEN_MENU explicitly handled as client-only
- Remove int() coercion on tick/entity_id — use direct assignment since
  GDScript int is signed 64-bit (safe for realistic tick values)
- Check encode result before buffering in send_input() — reject empty
  bytes instead of corrupting the outbound stream
- Test snapshot now uses Protocol format {tick, entities} instead of
  legacy schema; GameState updated to derive player position from
  entity data; main.gd and world_renderer.gd updated accordingly

Hoshe warnings:
- 5 negative tests added (truncated bytes, wrong type, missing fields,
  empty bytes, encode validation) — 20/20 tests pass
- receive_bytes signal is emitted at consume time in poll_snapshot by
  design (documented in code)

Tyre suggestions:
- Remove duplicated root-level fixtures — single source of truth in
  client/tests/fixtures/msgpack/
- gen_fixtures.rs writes directly to client/ directory
- Add `make fixtures` target for regeneration

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-11 19:32:49 +01:00
co-authored by Claude Opus 4.6
parent 9af9b3f3aa
commit bc9a691bc1
15 changed files with 109 additions and 89 deletions
+14 -19
View File
@@ -1,31 +1,26 @@
extends Node
# Updated each frame from ObserverSnapshot data
# Updated each frame from ObserverSnapshot data (Protocol format: {tick, entities}).
# Entities use Protocol decoded format: {entity_id, x, y, z, kind: {variant, data}}.
var current_snapshot: Dictionary = {}
var current_tick: int = 0
var player_position: Vector2 = Vector2.ZERO
var visible_entities: Array = []
var fog_state: Dictionary = {}
var hud_data: Dictionary = {}
# Player entity ID — the first entity is assumed to be the player (will be
# refined when the server assigns explicit player entity IDs).
var player_entity_id: int = 1
func apply_snapshot(snapshot: Dictionary) -> void:
current_snapshot = snapshot
# Parse player data
if snapshot.has("player") and snapshot.player.has("position"):
var pos = snapshot.player.position
if pos is Array and pos.size() >= 2:
player_position = Vector2(pos[0], pos[1])
else:
push_warning("GameState: malformed player position in snapshot")
if snapshot.has("tick"):
current_tick = snapshot.tick
# Parse entities
if snapshot.has("entities"):
visible_entities = snapshot.entities
# Parse fog state
if snapshot.has("fog"):
fog_state = snapshot.fog
# Parse HUD data
if snapshot.has("hud"):
hud_data = snapshot.hud
# Derive player position from the player entity
for entity in visible_entities:
if entity.has("entity_id") and entity.entity_id == player_entity_id:
player_position = Vector2(entity.x, entity.y)
break