diff --git a/client/README.md b/client/README.md index 94353dc..a4b9705 100644 --- a/client/README.md +++ b/client/README.md @@ -82,7 +82,7 @@ If the server is **down**, boot **`GET`** fails silently (check Output for warni On boot, **`InteractablesCatalogClient`** **`GET`s** **`/game/world/interactables`**; **`interactable_world_builder.gd`** spawns **walkable** prototype props plus **two** small glow markers per row under **`World/InteractionMarkers`**. **`interaction_radius_indicators.gd`** compares the snapped **`CharacterBody3D`** **`global_position`** to each descriptor’s **`anchor`** on **X/Z** with the same **`interactionRadius`** and inclusive **`<=`** rule as the server — **preview only**; **`POST /game/players/{id}/interact`** remains authoritative. -- **`InteractionRequestClient`**: **`interact`** (**E**) → **`prototype_terminal`**; **`interact_secondary`** (**R**) → **`prototype_resource_node_alpha`** (stable ids; must match `PrototypeInteractableRegistry.cs`). **Output** prints `allowed` / `reasonCode` per response (lines prefixed with `Interaction []: …`). Only one HTTP POST runs at a time; if you press **E** then **R** while the first request is still in flight, the **latest** id is remembered and sent **immediately after** the first completes (last-wins coalescing — not a silent drop). +- **`InteractionRequestClient`**: **`interact`** (**E**) → **`prototype_terminal`**; **`interact_secondary`** (**R**) → **nearest in-range** **`resource_node`** from the interactables catalog (falls back to **`prototype_resource_node_alpha`** when none in range). **Output** prints `allowed` / `reasonCode` per response (lines prefixed with `Interaction []: …`). Only one HTTP POST runs at a time; if you press **E** then **R** while the first request is still in flight, the **latest** id is remembered and sent **immediately after** the first completes (last-wins coalescing — not a silent drop). - **Inspector:** match **`base_url`** on **`InteractablesCatalogClient`**, **`InteractionRequestClient`**, and **`PositionAuthorityClient`** to the running server. - **No server:** catalog **GET** fails → **Output** errors; props and glow markers do not spawn (expected prototype degradation). @@ -144,6 +144,16 @@ Full checklist: [`docs/manual-qa/NEO-31.md`](../docs/manual-qa/NEO-31.md) · cas Full checklist: [`docs/manual-qa/NEO-72.md`](../docs/manual-qa/NEO-72.md). +## Gather feedback on interact (NEO-73) + +- **`POST /game/players/{id}/interact`** on **`resource_node`** kinds — server gather engine (NEO-63); no separate gather HTTP on client. +- **`GET /game/players/{id}/skill-progression`** — **`salvage`** row on **`SkillProgressionLabel`**; boot hydrate + refresh after successful gather. +- **Scripts:** `scripts/skill_progression_client.gd`, `scripts/prototype_interactable_picker.gd`; **`interaction_request_client.gd`** emits **`interaction_result_received`**; wired from `main.gd`. +- **HUD:** `UICanvas/GatherFeedbackLabel` — success delta **`+N {displayName}`** or deny **`Gather: denied — {reasonCode}`** (including **`node_depleted`**). **`InventoryLabel`** refreshes automatically on successful gather (no **I**). +- **R binding:** nearest in-range **`resource_node`** by horizontal distance to catalog anchors (same radius rule as glow preview). + +Full checklist: [`docs/manual-qa/NEO-73.md`](../docs/manual-qa/NEO-73.md). + ### Manual check (NEO-24) 1. Run the server and client as in NEO-7 / NEO-9; confirm spawn snap at `(-5, 0.9, -5)`. diff --git a/docs/manual-qa/NEO-73.md b/docs/manual-qa/NEO-73.md new file mode 100644 index 0000000..2bd057e --- /dev/null +++ b/docs/manual-qa/NEO-73.md @@ -0,0 +1,29 @@ +# NEO-73 — Manual QA checklist + +| Field | Value | +|-------|-------| +| Key | NEO-73 | +| Title | E3.M1: Client gather feedback on interact (E3S5-02) | +| Linear | https://linear.app/neon-sprawl/issue/NEO-73/e3m1-client-gather-feedback-on-interact-e3s5-02 | +| Plan | `docs/plans/NEO-73-implementation-plan.md` | +| Branch | `NEO-73-e3m1-client-gather-feedback-on-interact` | + +## Preconditions + +- Server running with default dev player (`dev-local-1`); gather via interact landed (NEO-63); inventory HUD landed (NEO-72). + +## Checklist + +1. Start server: `cd server/NeonSprawl.Server && dotnet run`. +2. Run Godot main scene (**F5**). Confirm **`SkillProgressionLabel`** shows **`salvage: level …, xp …`** after boot (often **`level 1, xp 0`** on fresh player). +3. **WASD** to **`prototype_resource_node_alpha`** anchor **(12, −6)** until the resource glow pair brightens. Press **R** (do **not** press **I** first). +4. **`GatherFeedbackLabel`** shows **`Gather: +1 Scrap Metal (Bulk)`** (or agreed display name). **`InventoryLabel`** updates scrap quantity without manual refresh. **`SkillProgressionLabel`** **`salvage`** xp increases by **10**. +5. Walk to **`prototype_subsurface_vein_beta`** **(18, −6)**; press **R**. Feedback shows **`+2`** scrap delta; inventory and salvage xp update again. +6. Repeat at **`prototype_bio_mat_gamma`** **(12, 0)** (**+3**) and **`prototype_urban_bulk_delta`** **(18, 0)** (**+5**) if nodes still have capacity. +7. Deplete **`prototype_urban_bulk_delta`**: press **R** ten times while in range, then once more. **`GatherFeedbackLabel`** shows **`Gather: denied — node_depleted`** (inventory unchanged on last press — verify with **I** if needed). +8. Press **E** at terminal: **`GatherFeedbackLabel`** stays on last gather message (terminal does not overwrite gather line). + +## Notes + +- **R** posts the **nearest in-range** `resource_node` from the interactables catalog; walk to each anchor before pressing **R**. +- Output still prints **`Interaction []: …`** lines for dev debugging. diff --git a/docs/plans/E3S5-client-prototype-backlog.md b/docs/plans/E3S5-client-prototype-backlog.md index 5741357..62d9717 100644 --- a/docs/plans/E3S5-client-prototype-backlog.md +++ b/docs/plans/E3S5-client-prototype-backlog.md @@ -101,9 +101,9 @@ Working backlog for **Epic 3 — Slice 5** ([client economy integration](../deco **Acceptance criteria** -- [ ] In-range interact on fresh node updates inventory HUD without manual refresh. -- [ ] Depleted node shows **`node_depleted`** (or agreed copy) on HUD. -- [ ] **Salvage** skill level or XP visible and changes after successful gather (Epic 2 Slice 3 visibility). +- [x] In-range interact on fresh node updates inventory HUD without manual refresh. +- [x] Depleted node shows **`node_depleted`** (or agreed copy) on HUD. +- [x] **Salvage** skill level or XP visible and changes after successful gather (Epic 2 Slice 3 visibility). --- diff --git a/docs/plans/NEO-73-implementation-plan.md b/docs/plans/NEO-73-implementation-plan.md index b78dd03..74662f7 100644 --- a/docs/plans/NEO-73-implementation-plan.md +++ b/docs/plans/NEO-73-implementation-plan.md @@ -51,9 +51,17 @@ No other blocking decisions — **`node_depleted`** deny copy follows **`CastFee ## Acceptance criteria checklist -- [ ] In-range interact on fresh node updates **inventory HUD** without manual **I** refresh. -- [ ] Depleted node shows **`node_depleted`** (or agreed copy) on **`GatherFeedbackLabel`**. -- [ ] **Salvage** skill level/XP visible on **`SkillProgressionLabel`** and changes after successful gather. +- [x] In-range interact on fresh node updates **inventory HUD** without manual **I** refresh. +- [x] Depleted node shows **`node_depleted`** (or agreed copy) on **`GatherFeedbackLabel`**. +- [x] **Salvage** skill level/XP visible on **`SkillProgressionLabel`** and changes after successful gather. + +## Implementation reconciliation (shipped) + +- **Clients:** `skill_progression_client.gd`; `interaction_request_client.gd` emits **`interaction_result_received`** + **`post_interact_id`**. +- **Picker:** `prototype_interactable_picker.gd` — nearest in-range **`resource_node`** on **R** (alpha fallback). +- **HUD:** `GatherFeedbackLabel` (delta / deny); `SkillProgressionLabel` (salvage row); inventory auto-refresh on gather success. +- **Tests:** `skill_progression_client_test.gd`, `prototype_interactable_picker_test.gd`, `gather_feedback_refresh_test.gd`; extended `interaction_request_client_test.gd`. +- **Docs:** `client/README.md` gather section; [`NEO-73` manual QA](../manual-qa/NEO-73.md). ## Technical approach