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>
SimBridge now encodes player inputs via Protocol.encode_player_input()
and exposes receive_bytes()/drain_outbound() for the transport layer.
Test mode still works unchanged. Transport (ticket #79) will call
these methods to complete the IPC pipeline.
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>
- Camera2D now tracks player_position from GameState (D-015)
- Add SubViewport child to minimap SubViewportContainer (fixes editor warning)
- Wire MonologueDisplay into main loop for D-016 perception data path
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix input_mapper double-check bug (redundant InputEventKey + pressed filter)
- Add bounds checking for position arrays in entity_renderer and game_state
- Make test snapshot deterministic (incrementing counter, not wall clock)
- Fix tween overlap in monologue_display (cancel active tween before new one)
- Extract TILE_SIZE constant from magic number 32
- Add 5 D-030 Layer 1 fixture tests for snapshot parsing (7/7 total passing)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Set up the complete Godot 4.6 client foundation as a pure renderer (D-020):
- project.godot with 2D rendering, autoloads, input actions
- Main scene: Game > World (TileMapLayer, Entities, FogOverlay) + Camera2D + UILayer
- Autoloads: SimBridge (connection state machine + test mode), GameState, InputMapper
- Rendering stubs: WorldRenderer, EntityRenderer, FogRenderer
- UI stubs: HUD (health/perception/time), Minimap, MonologueDisplay
- Input mapping: WASD/arrows, E (interact), Tab (perception), Esc (menu), Space (pause)
- gdUnit4 smoke tests: scene loads, autoloads registered (2/2 passing)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>