Commit Graph
66 Commits
Author SHA1 Message Date
jpmschweitzerandClaude Opus 4.6 ee3ac75578 fix(client): add pause toggle, hold-to-move, snapshot event carry-forward
Three client input/bridge fixes:

1. Pause toggle: add UNPAUSE action and toggle logic based on
   GameState.game_time.tick_rate. Wire UNPAUSE in sim_bridge.gd.

2. Hold-to-move: replace press-event movement with polled _process()
   direction sampling. Composite diagonals via simultaneous keys
   (W+D → northeast). Client-side throttle per stance (D-053):
   Sprint=200ms, Walk=400ms, Careful=600ms, Crouch=800ms.

3. Snapshot carry-forward: when a newer snapshot overwrites an
   unconsumed one, carry forward current_monologue and current_dialogue
   so one-shot events aren't silently dropped.

Fixes bugs #5 (monologue lost on overwrite) and #6 (overwrite spam).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 23:26:07 +01:00
jpmschweitzerandClaude Opus 4.6 2dd1e9545d fix(client): anchor camera to player before first frame renders
Camera2D's internal smoothed_camera_pos starts at (0,0) and lerps
toward global_position, causing a visible white-screen drift on startup.
Disable position_smoothing in _ready(), snap camera to player position
from the first snapshot, then re-enable smoothing with reset_smoothing()
after the first anchored frame. Add tick guards to monologue/dialogue
consumption to prevent re-triggering when client FPS > sim tick rate.

Fixes bug #2 (camera doesn't center on player at startup).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 23:25:58 +01:00
jpmschweitzerandClaude Opus 4.6 be168d59ef refactor(client): rename test_protocol_v6.gd to test_protocol_bridge.gd
Version numbers in test filenames go stale every sprint. The file tests
bridge protocol features (stance, inventory, fixtures) not a specific
protocol version.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 01:33:53 +01:00
jpmschweitzerandClaude Opus 4.6 6d6b59c17b fix(client): address PR #24 review — 5 critical bugs, 3 warnings, 8 suggestions
Critical:
- Protocol test assertions updated v6→v7 (test_protocol_v6.gd)
- Dialogue signal connections wired (option_selected→DialogueResponse,
  dialogue_dismissed→DialogueEnd sent to server via SimBridge)
- Consume-once race fixed: _consume_dialogue() checks is_dialogue_active()
  before re-showing; dialogue_id tracking prevents re-trigger during fade
- Dialogue box responsive: _update_layout() clamps width to MAX_WIDTH_PX
  (832px) or 65% viewport, height to 20% viewport (MAX_HEIGHT_RATIO)
- Auto-pause added: SimBridge.send_input(PAUSE) on dialogue open/close

Warnings:
- Test coverage: 16 new tests in test_protocol_v7.gd (pending_recognitions
  decode, current_dialogue, GameState, SimBridge mock data, insert colors)
- queue_redraw() optimization: early return when no entities and no pings
- Fixed 200px height → responsive 20% viewport via _update_layout()

Suggestions:
- WASD detection refactored to _WALK_AWAY_ACTIONS array loop
- Button colors reference Constants.INSERT_COLOR_TEXT/HOVER/ACTIVE
- Named constants: COLOR_TRANSITION_START, SILHOUETTE_APPEAR_THRESHOLD,
  SILHOUETTE_SIZE with explanatory comments
- Bounds check: MAX_PENDING_RECOGNITIONS=64 with truncation warning
- Mock dialogue sustained across ticks (not 1-tick flash)
- COLOR_PING coupling with cursor documented as intentional
- Consume helpers extracted: _consume_monologue(), _consume_dialogue()

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 01:30:15 +01:00
jpmschweitzer 90a80e73df Merge remote-tracking branch 'origin/main' into client 2026-02-16 01:26:36 +01:00
jpmschweitzer 7edc513632 Merge remote-tracking branch 'origin/audio'
# Conflicts:
#	CHANGELOG.md
2026-02-16 01:25:40 +01:00
jpmschweitzerandClaude Opus 4.6 6035d2049a feat(audio): add 6 interaction UI audio assets for #440
Generated via Stable Audio Open with sonic family prompt prefixes:
- cursor_hover.ogg (insert-tech, digital click)
- weapon_aim.ogg (insert-tech, mechanical latch sketch)
- implant_open.ogg (insert-tech, neural lattice rising tone)
- fog_recognition.ogg (organic, cognitive realization chime)
- sfx_monologue_chime.ogg (insert-tech, placeholder per D-071)
- sfx_monologue_chime_urgent.ogg (insert-tech, placeholder per D-071)

All assets need duration trimming in next audio sprint (#453).
Updated docs/assets/audio/ui.md status to draft.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 01:22:56 +01:00
jpmschweitzerandClaude Opus 4.6 2659de0c28 feat(client): add fog entity visualization and wire Sprint 7 UI (#431, #434)
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>
2026-02-16 01:19:24 +01:00
jpmschweitzerandClaude Opus 4.6 2d56131221 feat(ui): add dialogue box — bottom screen, max 20% height, walk-away (#434)
D-061 compliant UI skeleton: NPC speech top, max 3 response options
below, left-aligned. Insert-styled colors (white-blue, amber hover,
green pressed). WASD walk-away fades over 300ms, no close button.
InsertOverlay (CanvasLayer 10, z-layer 6). Mock data in next commit.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 01:19:15 +01:00
jpmschweitzerandClaude Opus 4.6 4d8fe996fc feat(perception): add cognitive delay system for fog recognition (#423)
New CognitiveDelay component buffers perception events before emitting
KnowledgeEvents. Normal delay: 6 ticks (0.6s), urgent: 3 ticks (0.3s).
Drain system runs after emit_observation_events, before process_knowledge_events.

Adds pending_recognitions to ObserverSnapshot (protocol v7) for client
fog entity visualization. Includes cancellation when entity leaves LOS.

Monologue fires during delay (not after) per D-060 — cross-system
wiring deferred to follow-up ticket #451.

Ref: D-060 (cognitive delay), D-031 (10 tps), D-059 (fog layers)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 00:41:08 +01:00
jpmschweitzerandClaude Opus 4.6 9e8ccb13bf fix(client): address PR #22 review — 3 critical bugs, 2 warnings, 8 suggestions
Critical fixes:
- fog_state: guard _compute_bounds() against all-invalid tiles (negative Rect2i crash)
- fog_shader: read Camera2D zoom dynamically instead of hardcoded Vector2(2,2)
- world_radial: set custom_minimum_size in _ready() from spoke geometry

Warnings:
- fog.gdshader: tighten PERIPHERAL_LOW 0.15→0.55 to match D-059 peripheral band
- Extract color_for_entity_kind() to Constants.gd, decouple CursorRenderer from EntityRenderer

Documentation: shallow copy assumption, gradual decay TODO, tween guard rationale,
fade timing rationale, ToggleInsert TODO, monologue consume-once, hover offset safety,
v6 fixture gap TODO.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 23:23:11 +01:00
jpmschweitzerandClaude Opus 4.6 1fcf08d21f feat(client): Sprint 6 Touch — z-layer pipeline, cursor, fog, interactions, inventory, stance, radial
Three-scope z-layer rendering pipeline (D-049): world z:0-900 inside
CanvasGroup, insert overlay CanvasLayer 10, UI CanvasLayer 20, modal
CanvasLayer 30. Y-sort contract enforced (entities z_index=0). Reserved
ranges for VFX, airborne, lower floors documented in constants.gd.

Sprint 6 client tickets:
- #429: Cursor state machine — 4 states, 150ms transitions (D-056)
- #430: Fog shader rebuild — 5-layer fragment shader, animated noise (D-059)
- #432: Entity interaction list — vertical multi-verb, insert-styled (D-057)
- #433: World radial menu — 2 spokes, drag-release + click-click (D-058)
- #438: Inventory UI — 3x3 grid, 40x40px, 1-9 hotkeys (D-065)
- #439: Stance indicator — color-coded HUD, C/X keybinds (D-053)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 23:06:03 +01:00
jpmschweitzerandClaude Opus 4.6 24cce41379 feat(client): protocol v6 bridge — stance, inventory, input mapping
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>
2026-02-15 23:05:47 +01:00
jpmschweitzerandClaude Opus 4.6 98f4cedc03 feat(simulation): Sprint 6 Touch — stance, tile presence, verbs, protocol v6
Implements the core Sprint 6: Touch systems across 5 tickets:

- #449 ObserverSnapshot v6: add player_stance (MovementStance) and
  player_inventory (Vec<InventoryItem>) wire fields with serde defaults
  for backward compatibility. Bump PROTOCOL_VERSION 5→6.

- #417 Stance system: Sprint/Walk/Careful/Crouch movement stance with
  tick-based speed (1/2/3/4 ticks per move), monologue rate multipliers,
  and PlayerMoveCooldown component. ToggleStanceUp/Down player actions.

- #420 TilePresence: posture-layer collision system allowing same-tile
  occupancy for different layers (Standing/Prone/Seated/Fixture).
  Layer-based collision in validate_movement.

- #421 ObjectType component: Readable/Container/Terminal/Door/Pickup/
  Furniture types with Phase 1 verb sets computed from type + proximity.

- #422 Phase 2 verb filter: KG-gated observer-side verb processing —
  POI priority flips, Confront injection at KnowsDetails+, contradiction
  marking, archetype-specific label relabeling (Smuggler/Detective).

217 unit tests + 17 integration tests passing. All MessagePack fixtures
regenerated for v6 wire format.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 15:38:59 +01:00
jpmschweitzerandClaude Opus 4.6 c41bec0d15 chore(client): track Godot .uid resource identifier files
These are auto-generated by Godot 4 to provide stable resource
references across renames. Tracking them prevents UID divergence.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 09:49:41 +01:00
jpmschweitzerandClaude Opus 4.6 3c106aa2d0 feat(simulation): complete interaction and monologue pipelines (#413, #414, #415)
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>
2026-02-13 19:23:47 +01:00
jpmschweitzerandClaude Opus 4.6 470ec59b63 fix(ui): adapt client to new ui-strings.yaml structure
The copy team rewrote ui-strings.yaml with multi-level nesting,
renamed sections, and inline comments. Update the YAML parser to
use a stack-based approach for arbitrary nesting depth, update HUD
and interaction prompt to reference the new key names, and align
tests with the new structure.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 18:07:15 +01:00
jpmschweitzer 15ea6f1375 Merge remote-tracking branch 'origin/copy'
# Conflicts:
#	CHANGELOG.md
#	client/data/ui-strings.yaml
2026-02-13 17:57:10 +01:00
jpmschweitzerandClaude Opus 4.6 fe3232377d refactor(content): move ui-strings.yaml to client/data/
UI microcopy strings belong in the client data directory where
the Godot client can load them directly, not in campaign content.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 17:54:55 +01:00
jpmschweitzerandClaude Opus 4.6 5a04656781 feat(ui): add YAML-based UI string loading system (#409)
Adds UIStrings autoload that loads display text from a YAML file,
replacing hardcoded strings in HUD and interaction prompt. Copy team
can now author UI microcopy in client/data/ui-strings.yaml without
touching GDScript. Includes 38 strings across 5 categories and 16
gdUnit4 tests for the parser and lookup API.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 17:18:01 +01:00
jpmschweitzerandClaude Opus 4.6 e6d6802c8d fix(client): align tests with kind-based player detection
Tests used entity_id matching to find the player, but game_state now
finds the player by kind.variant == "Player". Update test fixture to
include a Player entity and remove stale player_entity_id assignments.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 02:07:43 +01:00
jpmschweitzerandClaude Opus 4.6 e810abdcaf fix(client): use server tick for movement input processing
Client was sending Time.get_ticks_msec() (e.g. 12345) as the input
tick, but the server's drain_for_tick only processes inputs where
tick <= current_tick (a small frame counter). Inputs accumulated in
the queue and were never processed, making movement keys unresponsive
in live mode. Use GameState.current_tick from the latest snapshot.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 02:07:38 +01:00
jpmschweitzerandClaude Opus 4.6 ea9cf554c6 fix(client): decode tile_kind and fix entity alignment (#412)
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>
2026-02-13 02:07:29 +01:00
jpmschweitzerandClaude Opus 4.6 29c5003403 fix(simulation): add TileKind to VisibleTile wire protocol (#412)
Server was sending visible_tiles without tile type data, so the client
could not distinguish floor from wall in live mode. Add TileKind enum
(Floor/Wall/Door/Object) to VisibleTile, populated from WalkabilityMap
in the NaturalVision perception query. Update test fixtures to include
the new field. Uses #[serde(default)] for backward compatibility.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 02:07:19 +01:00
jpmschweitzerandClaude Opus 4.6 33f4f6078c feat(client): add input roundtrip integration test (#411)
Three tests validating the full client-server input path through a
live server: movement roundtrip (MoveNorth/MoveEast with position
verification), interact roundtrip (unit variant accepted as no-op),
and mixed sequence (movement then interact preserves position).

Catches integration seams that unit tests miss — each test spawns a
real server binary on a random port, connects via LocalBridge, and
exercises the TCP→deserialize→simulation→snapshot→decode pipeline.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 01:48:35 +01:00
jpmschweitzerandClaude Opus 4.6 473eda03cd feat(client): add live server mode with make game target
Add SR_LIVE=1 environment variable to switch SimBridge from test mode
to TCP connection. Default behavior unchanged (test mode).

- sim_bridge.gd: read SR_LIVE env var instead of hardcoded test_mode
- game_state.gd: find player entity by kind.variant == "Player" instead
  of hardcoded entity_id 1 (real server assigns different IDs)
- Makefile: add 'make game' (builds server, starts it, launches client
  with SR_LIVE=1, kills server on exit) and 'make stop' helper

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 01:46:09 +01:00
jpmschweitzerandClaude Opus 4.6 67978d0819 feat(client): wire interaction prompt target+verb to server (#405)
Enable the interaction data attachment in main.gd game loop. When E
is pressed and the prompt is active, target_entity_id and verb are
attached to the Interact action before sending to the server. Without
a target, bare Interact is still sent as safe fallback.

Completes the v0.1 interaction prompt data flow:
server sends nearby_interactions → client shows prompt → E press
attaches target+verb → SimBridge encodes and sends to server.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 01:46:02 +01:00
jpmschweitzerandClaude Opus 4.6 a1c5db9490 fix(client): make E2E tests resilient to entity ordering
Server proof room now has 3 NPCs instead of 1. Find player entity
by kind instead of assuming entities[0]. Wall-hides test checks
specific NPC position (16.5, 13.5) rather than asserting zero NPC
count. Corner-reveal test searches for NPC1 by position.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 00:05:07 +01:00
jpmschweitzerandClaude Opus 4.6 52972e6f21 fix(client): align tests and data with server v4 protocol changes
Server team shipped strict PROTOCOL_VERSION enforcement (c05ff7b),
1-indexed verb priorities, and "Observe" label for ExamineNpc.
Updates all test snapshots to include version: 4, fixes sim_bridge
test mode priorities (0-indexed → 1-indexed) and labels, replaces
v1 backward-compat tests with strict version rejection tests.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 00:04:58 +01:00
jpmschweitzer 7af8de0117 Merge remote-tracking branch 'origin/main' into client
# Conflicts:
#	CHANGELOG.md
#	client/scripts/autoloads/sim_bridge.gd
2026-02-12 23:45:48 +01:00
jpmschweitzerandClaude Opus 4.6 6bebbd9933 feat(client): add interaction prompt system (#405)
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>
2026-02-12 23:43:37 +01:00
jpmschweitzerandClaude Opus 4.6 c05ff7b063 feat(client): enforce PROTOCOL_VERSION check in snapshot decode
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>
2026-02-12 23:32:49 +01:00
jpmschweitzerandClaude Opus 4.6 9943684f2c refactor(server): address PR #16 review feedback
Hoshe + Tyre review items:
- Use StableId consistently for wire entity_id (H4) across observer,
  observation, interpretation, and interaction systems
- Make NearbyInteractionBuffer.interactions private with take() (H1/H20)
- Add system ordering constraint for compute_nearby_interactions (H5)
- Panic on missing PlayerCharacter in input processing (H2)
- Remove redundant paused field from GameTime (Tyre8)
- Remove #[serde(default)] from nearby_interactions (H3)
- Change NearbyInteraction.distance from f32 to u32 (H8)
- Add sort stability for equal verb priorities (H6)
- Scope constants to pub(crate) (H7)
- Add debug_assert for last_observed_tick ordering (H10)
- Strengthen unregistered entity handling to debug_assert + error (H11)
- Document fractional tick accumulation (Tyre9)
- Extract collect_remembered_entities helper (Tyre2/H17)
- Add half_rate_no_drift_over_10000_frames test (H14)
- Add mid-range and deterministic sort tests (H15)
- Add fixture version assertion (H16)
- Regenerate msgpack fixtures for wire format changes

146 unit + 19 integration tests pass, zero clippy warnings.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 20:14:35 +01:00
jpmschweitzer 9d0774cae8 Merge remote-tracking branch 'origin/client' 2026-02-12 02:09:01 +01:00
jpmschweitzerandClaude Opus 4.6 68a554f1f0 fix(client): address PR #13 review — LOS tests, reset consistency, docs
- Use reset_test_state() consistently in test_snapshot_parsing.gd (Tyre critical)
- Fix misleading wall comment: (12,9) → (12,10) (Hoshe warning)
- Add coordinate space documentation to _test_snapshot() (Tyre warning)
- Add 4 Bresenham LOS unit tests: clear, blocked, diagonal, self (Hoshe warning)
- Check OS.is_process_running() in connection loop (Hoshe warning)
- Verify NPC position in corner reveal test (Hoshe suggestion)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 02:01:54 +01:00
jpmschweitzerandClaude Opus 4.6 22de6c714f fix(simulation): address PR #12 review — z-level filter, visible tile dedup, version bump
- Filter remembered entities by z-level (Hoshe + Tyre warning)
- Skip remembered ghosts on currently visible tiles (Hoshe warning)
- Bump ObserverSnapshot version to 3 (Tyre suggestion)
- Add edge case tests: visible tile collision, different z-level,
  knowledge without position (Hoshe suggestion)
- Regenerate msgpack fixtures for v3

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 01:47:35 +01:00
jpmschweitzerandClaude Opus 4.6 0db120ed58 feat(client): Sprint 2 proof E2E tests + dynamic test snapshot (#357)
Three E2E proof tests verify all acceptance criteria through the real
server pipeline: player movement, v2 snapshot with visible_tiles,
wall hiding (NPC behind wall invisible), corner reveal (move around
wall to see NPC). Dynamic test snapshot tracks player position from
queued inputs with simple LOS and Manhattan-distance visibility for
standalone demo mode. 88 client + 112 server tests passing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 01:45:54 +01:00
jpmschweitzerandClaude Opus 4.6 9c0190c7c2 feat(simulation): integrate knowledge graph into observer snapshot (#366)
VisibleEntity now carries relationship state (D-033 entity color) and
observation type (Visible vs Remembered). compute_observer_snapshot
queries the player's KnowledgeGraph to overlay relationship data on
visible entities and include remembered (not-in-LOS) entities as fog
ghosts at their last known position. Regenerated msgpack fixtures.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 01:28:53 +01:00
jpmschweitzerandClaude Opus 4.6 64897a40b3 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>
2026-02-12 01:07:02 +01:00
jpmschweitzerandClaude Opus 4.6 f3793bf16e feat(client): D-033 entity colors, peripheral dimming, facing indicator (#130)
Replace hardcoded entity colors with D-033 relationship palette:
Player=#e0e8ff, Npc=unknown teal #4a9ebb, Object=grey #8b8ba0.
Phase 1 defaults by entity kind; Phase 2 (#361) will derive color
from RelationshipState via knowledge graph.

Entities in peripheral vision dimmed to 50% alpha (D-015).
Player entity gets a Polygon2D triangle indicator showing facing
direction, rotated from GameState.player_facing.

82 tests total, 0 failures.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 00:53:28 +01:00
jpmschweitzerandClaude Opus 4.6 57da75c509 feat(client): upgrade protocol decoder and GameState for v2 snapshot
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>
2026-02-12 00:53:18 +01:00
jpmschweitzer a9f1cbd865 Merge remote-tracking branch 'origin/client'
# Conflicts:
#	CHANGELOG.md
2026-02-12 00:32:30 +01:00
jpmschweitzerandClaude Opus 4.6 6ff6be9a78 fix(client): use tick-based invalidation for world renderer
Count-based dirty tracking missed content changes when tile/visibility
count stayed the same (e.g., door opening, player moving through
corridor). Now re-renders all layers when GameState.current_tick
advances, which correctly handles every snapshot change.

Adds 3 tests for tick advancement and same-count-different-content
scenarios. 68 total tests, 0 failures.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 00:24:30 +01:00
jpmschweitzerandClaude Opus 4.6 bb6bc287e9 feat(simulation): add ObserverSnapshot v2 schema with visibility types (#358, #25)
Expand wire protocol with version field, GameTime (day/phase/paused),
FacingDirection (8-directional), VisibleTile, VisibilitySector
(Forward/Peripheral), and visibility tag on VisibleEntity.
Regenerate all msgpack fixtures for client compatibility.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 00:20:46 +01:00
jpmschweitzerandClaude Opus 4.6 aa3a3fea7d fix(client): address PR review — invalidation, constants, tests
Review feedback from Hoshe + Tyre on PR #8:

- Extract shared TILE_SIZE to Constants class_name (Tyre #5, Hoshe #7)
- Fix tile invalidation: detect tile/visibility count changes instead
  of one-shot dirty flag, supports chunk loading (Tyre #3, #4)
- Fog dirty tracking: only re-render when visible_positions changes
- Add bounds warning for unknown tile types (Hoshe #1)
- Add player-not-found warning in GameState (Hoshe #5)
- Use Image.fill_rect() instead of pixel loops (Tyre #10)
- Document _player_pos as reserved for fog decay #113 (Tyre #6)
- Add TODO(#130) for D-033 relationship colors (Hoshe #3, Tyre #8)
- Add class_name to EntityRenderer, FogRenderer, TileRenderer
- 20 new rendering tests (D-030 Layer 1): entity lifecycle, fog
  registration, tile type mapping, snapshot completeness, constants
- 65 total tests passing, 0 failures

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 00:15:42 +01:00
jpmschweitzerandClaude Opus 4.6 dcf887cb49 feat(client): add tile rendering, fog overlay, and camera smoothing
Sprint 2 rendering pipeline: tiles (#129), fog (#131), camera (#116).

- tile_renderer.gd: programmatic TileSet with floor/wall/door/object
  placeholder tiles, renders from snapshot tile data
- fog_renderer.gd: TileMapLayer overlay with three visibility states
  (visible/fog-edge/hidden), computed from visible_positions data
- Camera2D: smoothing enabled (speed 6.0), 2x zoom, locked to player
- game_state.gd: stores visible_tiles and visible_positions from snapshots
- sim_bridge.gd: test data with 8x8 room, corridor, and Manhattan
  distance visibility for development without server
- Scene render order: Tiles -> FogOverlay -> Entities
- Background clear color set to near-black for unexplored areas

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 23:48:02 +01:00
jpmschweitzerandClaude Opus 4.6 55b775ee73 fix(client): fix entity renderer to match protocol format
entity_renderer.gd used wrong field names ("id" instead of
"entity_id", "type" instead of "kind.variant", "position" instead
of x/y). Now matches Protocol.decode_entity() output exactly.
Also centers entities (24x24) within 32px tiles.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 23:47:49 +01:00
jpmschweitzerandClaude Opus 4.6 beee44b3c8 feat(client): add batch fixture, fixture smoke test, decode_errors test
Tyre #1: Added Rust-generated input_batch_two.msgpack fixture for
bidirectional D-030 Layer 1 symmetry (Vec<PlayerInput>).
Tyre #2: Added all_fixtures_deserialize Rust test that reads every
.msgpack fixture and verifies it deserializes (corruption guard).
Hoshe #3: Added test_decode_snapshot_malformed_entities_counted test
verifying the decode_errors counter on D-010 boundary violations.
45 client tests, 54 server tests pass.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 21:57:18 +01:00
jpmschweitzerandClaude Opus 4.6 8d12776b5d fix(client): address PR #7 review — ephemeral port, input drop docs
Hoshe #1: E2E test now uses random ephemeral port (49152-65535) with
port rotation on bind failure, avoiding conflicts in parallel CI.
Hoshe #2: Documented intentional input drop on encode failure in
SimBridge — re-queuing would retry bad data and server tick has
already advanced.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 21:57:11 +01:00
jpmschweitzerandClaude Opus 4.6 5e4b8dbcf3 feat(client): add E2E connection test and batch encoding tests
D-030 Layer 3: E2E test spawns the Rust server binary, connects via
LocalBridge, sends a batched MoveNorth input, and verifies the player
moved to (16.5, 15.5). Also adds batch encoding roundtrip tests,
framed batch test, and Player entity fixture decode test. 43/43 pass.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 21:44:27 +01:00