neon-sprawl/docs/decomposition/modules/E3_M1_ResourceNodeAndGather...

106 lines
8.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# E3.M1 — ResourceNodeAndGatherLoop
## Summary
| Field | Value |
|--------|--------|
| **Module ID** | E3.M1 |
| **Epic** | [Epic 3 — Crafting Economy](../epics/epic_03_crafting_economy.md) |
| **Stage target** | Prototype |
| **Status** | In Progress — Slice 2 backlog [NEO-57](https://linear.app/neon-sprawl/issue/NEO-57)[NEO-64](https://linear.app/neon-sprawl/issue/NEO-64) ([E3M1-prototype-backlog](../../plans/E3M1-prototype-backlog.md); NEO-41 anchor below; see [dependency register](module_dependency_register.md)) |
| **Linear** | Label **`E3.M1`** per [decomposition README — Linear alignment](../README.md#linear-alignment) |
## Purpose
**Authority:** [Client vs server authority](client_server_authority.md) — the server resolves **whether** a gather succeeds, **what** items are granted, **remaining node capacity**, and **skill XP** from gather; the client sends **interact intent** via [E1.M3 — InteractionAndTargetingLayer](E1_M3_InteractionAndTargetingLayer.md) (`POST …/interact`) and displays outcomes.
World resource nodes, gather interactions, and yield outputs feeding inventory ([E3.M3](E3_M3_ItemizationAndInventorySchema.md)) and skill XP ([E2.M2](E2_M2_XpAwardAndLevelEngine.md)). Ecology / respawn pacing per zone defers to [E4.M2 — SpawnEcologyController](E4_M2_SpawnEcologyController.md).
## Boundary: E1.M3 vs E3.M1
| Topic | E1.M3 (today) | E3.M1 (this module) |
|--------|----------------|---------------------|
| **Primary job** | Interactable eligibility (range, known id, kind) | **Gather resolution**: yields, depletion, inventory + XP side effects |
| **Wire / HTTP** | `POST …/interact` + `InteractionResponse` | No separate gather route in prototype — E3.M1 hooks **after** E1.M3 allows interact |
| **Registry** | `PrototypeInteractableRegistry` / `GET …/interactables` | **`ResourceNodeDef`** + **`ResourceYieldTable`** content; instance capacity store |
| **Denials** | `out_of_range`, `unknown_interactable` | Adds **`node_depleted`**, `inventory_full`, etc. via gather engine |
**Shared policy:** horizontal reach on **X/Z** matches [NEO-9](../../plans/NEO-9-implementation-plan.md) / E1.M3 — gather does not redefine range math.
## Responsibilities
- Author **`ResourceNodeDef`** and **`ResourceYieldTable`** content; load and expose defs to server subsystems.
- Track per-instance **remaining gathers** (prototype capacity/depletion); deny when exhausted.
- Resolve **`GatherResult`**: item grants into [E3.M3](E3_M3_ItemizationAndInventorySchema.md) inventory, **`salvage`** skill XP via [E2.M2](E2_M2_XpAwardAndLevelEngine.md) grant operations.
- Integrate with **`resource_node`** interactables in `PrototypeInteractableRegistry` (world anchors until [E4.M1](E4_M1_ZoneGraphAndTravelRules.md)).
**Deferred:** zone spawn profiles, regen timers, probabilistic yields, cross-skill unlock nodes — [gathering.md](../../game-design/gathering.md) open questions.
## Key contracts
| Contract | Kind | Role |
|----------|------|------|
| `ResourceNodeDef` | Content | Node type, max gathers, gather lens, link to yield table. |
| `ResourceYieldTable` | Content | Fixed item outputs per gather (`itemId`, quantity). |
| `GatherResult` | Server-internal (prototype) | Success/deny, granted items, depletion snapshot, reason codes. |
### Contract notes ([contracts.md](contracts.md))
- **Content** defs live under `content/resource-nodes/` with JSON Schema in CI ([E3M1-01](../../plans/E3M1-prototype-backlog.md#e3m1-01--prototype-resourcenodedef--yield-tables--schemas--ci)).
- **`GatherResult`** may promote to **wire** JSON or Protobuf when the client needs explicit gather payloads; until then, prototype uses **`InteractionResponse`** + inventory GET for verification.
- **Denials:** stable **`reasonCode`** strings on interact deny (`node_depleted`, `inventory_full`, …) consistent with [E1.M3](E1_M3_InteractionAndTargetingLayer.md) patterns.
**Logical fields (illustrative):**
| Contract | Illustrative fields |
|----------|---------------------|
| `ResourceNodeDef` | `nodeDefId`; `displayName`; `gatherLens` (`consumer_salvage`, `subsurface`, `bio`, `urban_bulk`); `maxGathers` — see `content/resource-nodes/*_resource_nodes.json` |
| `ResourceYieldTable` | `nodeDefId`; `itemId`; `quantity` — prototype: one row per node in `*_resource_yields.json` |
| `GatherResult` | `success`; `reasonCode`; `grantsApplied[]`; `remainingGathers`; optional `xpGrantSummary` |
## Module dependencies
- **E1.M3** — InteractionAndTargetingLayer (`POST …/interact`, interactable descriptors).
- **E2.M2** — XpAwardAndLevelEngine (skill XP grant operations).
- **E3.M3** — ItemizationAndInventorySchema (inventory grants) — logical dependency for Slice 2 yields; register lists E1.M3 + E2.M2 only so gather XP anchor ([NEO-41](../../plans/NEO-41-implementation-plan.md)) could land before inventory.
## Dependents (by design)
- **E3.M2** — RefinementAndRecipeExecution (crafted inputs from gathered materials).
- **E4.M2** — SpawnEcologyController (respawn / ecology).
## Designer note: gather lenses and yields
Prototype Slice 2 uses **four** nodes — one per [gather lens](../../game-design/gathering.md#node-lenses-design-facing). All prototype yields grant **`scrap_metal_bulk`** (different quantities per node are allowed) so the gather→refine loop can start without expanding the item catalog. **Skill XP** stays **`salvage`** + **`activity`** (10 XP) on every node until per-lens skill mapping is a deliberate content pass.
**Depletion:** each interactable instance has **`maxGathers`** successful collects; at zero, interact returns **`node_depleted`**. Regen on timer is **out of scope** for Slice 2 ([E4.M2](E4_M2_SpawnEcologyController.md)).
## Prototype Slice 2 freeze (E3M1-01)
The **first shipped four-node spine** is **frozen** for downstream references (recipes, ecology, quests). **`nodeDefId`** must match **`interactableId`** in `PrototypeInteractableRegistry` for prototype wiring.
| `nodeDefId` / `interactableId` | `gatherLens` | Notes |
|-------------------------------|--------------|--------|
| **`prototype_resource_node_alpha`** | `consumer_salvage` | Existing NEO-9/NEO-41 anchor (12, 6) |
| **`prototype_subsurface_vein_beta`** | `subsurface` | New anchor — plan PR sets X/Z |
| **`prototype_bio_mat_gamma`** | `bio` | New anchor — plan PR sets X/Z |
| **`prototype_urban_bulk_delta`** | `urban_bulk` | New anchor — plan PR sets X/Z |
**Rules:** Do **not** rename these ids after ship. CI enforces **exactly four** node defs and valid yield item references. Relaxing the gate belongs in a new Linear issue when the roster grows.
## Related implementation slices
Epic 3 **Slice 2** — [gather nodes and outputs](../epics/epic_03_crafting_economy.md#epic-3-slice-2): 46 node types, yield tables, `resource_gathered`, `gather_node_depleted`.
**Prototype implementation anchor (NEO-41):** until **`GatherResult`** lands, a **successful** **`POST …/interact`** on **`kind: resource_node`** grants **`salvage`** skill XP only (`activity`, 10 XP) via `SkillProgressionGrantOperations`**no** inventory or depletion. **E3M1-07** migrates XP into the gather engine and adds item + capacity behavior ([E3M1-prototype-backlog](../../plans/E3M1-prototype-backlog.md)).
**Resource node definitions HTTP (NEO-60):** **`GET /game/world/resource-node-definitions`** — versioned read-only projection (`schemaVersion` **1**, **`nodes`**) backed by **`IResourceNodeDefinitionRegistry`**; each row includes nested **`yield`** summary. Bruno `bruno/neon-sprawl-server/resource-node-definitions/`. Plan: [NEO-60 implementation plan](../../plans/NEO-60-implementation-plan.md).
**Linear backlog (decomposed):** [E3M1-prototype-backlog.md](../../plans/E3M1-prototype-backlog.md) — **E3M1-01** [NEO-57](https://linear.app/neon-sprawl/issue/NEO-57) through **E3M1-08** [NEO-64](https://linear.app/neon-sprawl/issue/NEO-64).
## Source anchors
- Master plan: [`neon_sprawl_vision.plan.md`](../../../neon_sprawl_vision.plan.md) — Epic 3.
- [gathering.md](../../game-design/gathering.md)
- [Module dependency register](module_dependency_register.md)