Bump PROTOCOL_VERSION from 7 to 8 to match server. Three changes:
1. Add dialogue_response field decoding (DialogueResponseEvent with
line_id, text, speaker_entity_id) from server #305/D-028.
2. Fix Interact encoding: server changed PlayerAction::Interact from
unit variant to struct variant with {target_entity_id, verb}.
Extract _encode_action() helper to handle this consistently.
3. Update all test assertions that checked version=7 or expected
Interact as a bare string.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fog entity cognitive delay rendering (D-059/D-060): sonar-style sound
pings (3 concentric rings, 1.5s fade), unrecognized grey blobs with
breathing pulse, D-033 color transition at 50% recognition progress,
±0.5 tile position drift. FogEntities node at z:950 between fog
shader and InsertOverlay.
Protocol v7 bump to match server PR #23 (pending_recognitions field).
Wires dialogue box and fog entities into game loop with mock test data.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Upgrade client protocol bridge from v5 to v6 to match server.
Adds player_stance (4 variants) and player_inventory decode to
ObserverSnapshot. Adds TOGGLE_STANCE_UP/DOWN to InputMapper.
Includes 25 gdUnit4 tests for v6 decode + server serialization
test gap fix.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Three fixes to make the gameplay loop functional end-to-end:
- Add Interactable component to NPC spawn so E-prompt detection works
- Build monologue trigger system (enter_location + time_idle) with
MonologueBuffer/MonologueState components, wire through ObserverSnapshot
as current_monologue field, decode on client and display via HUD
- Change PlayerAction::Interact from unit to struct variant carrying
optional target_entity_id and verb fields
Bumps protocol version from 4 to 5. Regenerates MessagePack fixtures.
All 200 tests pass (170 unit + 30 integration).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Protocol decoder now reads tile_kind from VisibleTile and maps it to
the client's tile type string (floor/wall/door/object). GameState
falls back to visible_tiles when the test-mode tiles array is absent,
enabling live server tile rendering.
Fix entity-to-tile alignment: server sends tile-center render coords
(tile 16 -> 16.5) but entity renderer was using raw floats, placing
entities half a tile off. Now floors the coords to get the tile index.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Server-driven interaction prompt that displays "E - Talk" when near
an interactable NPC. Decodes v4 nearby_interactions from snapshot,
stores in GameState, renders via InteractionPrompt UI with fade
animation. Extensible interface (get_interaction_target/get_selected_verb)
for future radial verb menu (v0.2).
- Protocol: decode nearby_interactions array with nested VerbOption structs,
entity relationship/observation fields, tick_rate in GameTime
- GameState: store/clear nearby_interactions per snapshot
- SimBridge: test mode generates v4 format with structured verbs
- InteractionPrompt: PanelContainer with fade in/out, polls GameState
- Tests: 19 new test cases covering protocol, state, sim bridge, UI, encoding
- Fixture assertions updated for v4 protocol version
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Client now rejects snapshots where version != PROTOCOL_VERSION (4).
Returns null with error log on mismatch. Test snapshot updated to
use Protocol.PROTOCOL_VERSION and v4 game_time format (tick_rate
replaces paused field).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Server shipped ObserverSnapshot v2 with game_time, player_facing,
visible_tiles (with visibility sectors), and per-entity visibility.
Protocol decoder was silently ignoring these fields. Now extracts
all v2 data with null defaults for backward compatibility.
GameState gains game_time, player_facing, visibility_sectors vars.
Derives visible_positions from visible_tiles when present (for real
server mode). Test snapshot updated with v2 fields.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Server expects a MessagePack array of PlayerInput objects in one framed
message per tick, not individual inputs per frame. Added
Protocol.encode_player_inputs() for batch encoding. Changed SimBridge to
buffer raw input dicts and batch-encode in _process(). Also fixed server
port default (9876) and positional arg format to match server CLI.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Critical fixes from Hoshe review:
1. Race condition: defer TCP connect to _process() with retry logic
(MAX_CONNECT_RETRIES=20, 100ms interval) so server has time to bind.
2. Buffer corruption: disconnect on oversized message instead of
clearing valid buffered data (_corrupt flag, fail-safe).
3. Silent input drop: send_input() returns Error so callers can detect
encode/validation failures.
Warnings addressed:
- ServerProcess validates server_path exists before spawning
- SIGKILL and health check TODOs documented for future work
- Diagonal keybindings documented as intentional deferral
- send_message uses single put_data() call (no partial write risk)
- Static frame helpers documented as D-030 Layer 2 test-only
New tests (36 total, up from 33):
- Partial read scenario (chunked TCP delivery)
- Multi-message sequential decode (exercises buffer corruption fix)
- send_input error return on invalid action
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
LocalBridge wraps StreamPeerTCP with 4-byte big-endian length-prefix
framing matching server/src/bridge/framing.rs. ServerProcess manages
the Rust server as a subprocess via OS.create_process(). Together
they form the D-020 IPC transport layer for ticket #79.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- decode_snapshot() reports dropped entities via push_error and returns
decode_errors count so callers can detect partial data (D-010
information boundary compliance)
- receive_bytes() warns when overwriting unconsumed snapshot, documents
latest-wins semantics
- Rename misleading test to test_encode_produces_nonempty_bytes
- Fix tick rate comment: 10 ticks/game-minute per D-031
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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>
Protocol.gd decodes ObserverSnapshot and PlayerInput from Rust's
rmp_serde wire format, and encodes PlayerInput for sending to server.
Handles rmp_serde enum encoding: unit variants as bare strings,
data variants as single-element maps.
8 fixture-based tests verify decode of Rust-generated fixtures,
GDScript encode/decode roundtrips, and cross-language compatibility.
All 15 tests pass (3 suites).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>