docs: update plans with phase progress, bug log, and current architecture state
RESOURCE_NODE_MIGRATION.md: - Add progress overview table with per-phase completion status - Document key divergences from original plan (zone fallback removal, navigation_failed signal, stale-path prevention, duplicate detection) - Add bug log table (11 bugs found and fixed during implementation) - Mark completed phases 1-3 with checkmarks - Split phase 4 into 4a (wood, done) and 4b (player parity, not started) - Replace flat implementation order with checkable table - Update definition-of-done with per-criterion status PROJECT_CONTEXT.md: - Advance snapshot commit reference frome30d208tob8752f8- Note that gather_food/gather_wood now use ResourceNode instances - Explain zone marker status (player use only, NPCs use nodes) - Update runtime flow diagram with navigation_failed pathway - Add resource_nodes/ to repository map - Update technical debt entries to reflect current state
This commit is contained in:
+44
-24
@@ -2,7 +2,7 @@
|
||||
|
||||
> Agent-facing context for understanding the project quickly.
|
||||
>
|
||||
> Snapshot basis: repository state after commit `e30d208`, July 2026. Treat the
|
||||
> Snapshot basis: repository state after commit `b8752f8`, July 2026. Treat the
|
||||
> code as the source of truth when this document and the implementation differ.
|
||||
|
||||
## Quick orientation
|
||||
@@ -176,15 +176,17 @@ The intended loop is:
|
||||
|
||||
The current prototype implements a very early version of observe, autonomous
|
||||
task choice, physical travel, work completion, resource change, and direct
|
||||
player assistance. Its abstract task zones are explicitly transitional; the
|
||||
next world-object migration is documented in
|
||||
player assistance. NPC `gather_food` and `gather_wood` tasks now use finite
|
||||
world `ResourceNode` instances (berry bushes and trees) rather than abstract
|
||||
zone markers. The zone markers remain only for player interaction and
|
||||
non-resource tasks. The migration is documented in
|
||||
[the ResourceNode plan](RESOURCE_NODE_MIGRATION.md).
|
||||
|
||||
## Current technology
|
||||
|
||||
- **Engine:** Godot 4.7 project configuration
|
||||
- **Renderer feature:** Forward Plus
|
||||
- **Language:** GDScript
|
||||
- **Language:** GDScript (`odig` analysis with warnings treated as errors)
|
||||
- **Main scene:** `res://main.tscn`
|
||||
- **Terrain:** Terrain3D 1.0.2 is installed and enabled
|
||||
- **Terrain compatibility floor:** Godot 4.4 according to the bundled extension
|
||||
@@ -253,6 +255,8 @@ Task states are:
|
||||
|
||||
```text
|
||||
idle -> traveling -> working -> complete -> idle
|
||||
|
|
||||
+-> navigation_failed -> wander -> idle
|
||||
```
|
||||
|
||||
NPCs currently choose among:
|
||||
@@ -293,10 +297,15 @@ The main scene contains placeholder zones for:
|
||||
The farm, forest, guard, study, rest, and food locations are represented by
|
||||
primitive geometry and a few tree assets.
|
||||
|
||||
These markers are not the intended long-term work model. Food and wood should
|
||||
first migrate to finite world `ResourceNode` instances. Storage, rest, study,
|
||||
and guard behavior should later migrate to target types that match their actual
|
||||
semantics rather than treating every usable object as a resource source.
|
||||
**Migration status:** NPC `gather_food` and `gather_wood` no longer use the
|
||||
farm and forest zones. They target `ResourceNode` instances (berry bushes and
|
||||
trees) instead. The zone markers remain for:
|
||||
- Player interaction (pressing E near farm/forest zones adds resources)
|
||||
- Non-resource NPC tasks (patrol → guard_zone, study → study_zone, rest → rest_zone, eat → food_zone)
|
||||
|
||||
Storage, rest, study, and guard behavior should later migrate to target types
|
||||
that match their actual semantics rather than treating every usable object as a
|
||||
resource source.
|
||||
|
||||
### Current UI
|
||||
|
||||
@@ -381,25 +390,32 @@ SimNPC updates needs and chooses/advances a task
|
||||
npc_task_changed signal
|
||||
|
|
||||
v
|
||||
WorldViewManager selects a task-zone marker
|
||||
WorldViewManager resolves target:
|
||||
gather_food/wood -> nearest available ResourceNode (interaction point)
|
||||
wander -> random offset from current position
|
||||
other -> task-zone marker (guard, study, rest, eat)
|
||||
|
|
||||
v
|
||||
NpcVisual navigates through the active world
|
||||
|
|
||||
v
|
||||
arrived_at_target signal
|
||||
+-- arrived_at_target signal
|
||||
| |
|
||||
| v
|
||||
| SimulationManager marks NPC as working
|
||||
| |
|
||||
| v
|
||||
| Later ticks complete work
|
||||
| |
|
||||
| v
|
||||
| ResourceNode.extract() -> village.apply_resource_delta()
|
||||
| |
|
||||
| v
|
||||
| village_changed signal updates the UI
|
||||
|
|
||||
v
|
||||
SimulationManager marks the NPC as working
|
||||
|
|
||||
v
|
||||
Later ticks complete work
|
||||
|
|
||||
v
|
||||
SimVillage applies production/consumption
|
||||
|
|
||||
v
|
||||
village_changed signal updates the UI
|
||||
+-- navigation_failed signal
|
||||
|
|
||||
v
|
||||
SimulationManager releases reservation, sets last_task, sends NPC to wander
|
||||
```
|
||||
|
||||
## Repository map
|
||||
@@ -422,6 +438,10 @@ village_changed signal updates the UI
|
||||
│ ├── SimVillage.gd
|
||||
│ └── SimulationManager.gd
|
||||
├── world/
|
||||
│ ├── resource_nodes/
|
||||
│ │ ├── ResourceNode.gd
|
||||
│ │ ├── ResourceNode.gd.uid
|
||||
│ │ └── ResourceNode.tscn
|
||||
│ ├── world_view_manager.gd
|
||||
│ └── ui/ui.gd
|
||||
├── main.tscn
|
||||
@@ -433,7 +453,7 @@ village_changed signal updates the UI
|
||||
These are expected prototype constraints, not necessarily isolated bugs:
|
||||
|
||||
- Task names and task-to-zone mappings are duplicated strings.
|
||||
- Task zones are abstract destinations rather than real usable world objects.
|
||||
- Task zones remain for non-resource tasks and player interaction; gather food/wood NPCs use ResourceNode instances instead.
|
||||
- Mutable simulation state is not serializable through a defined save schema.
|
||||
- Randomness is not seeded for deterministic replay.
|
||||
- Simulation time depends on `_process` and a scene-tree node.
|
||||
@@ -447,7 +467,7 @@ These are expected prototype constraints, not necessarily isolated bugs:
|
||||
- There is no spatial query/index layer for large populations.
|
||||
- Simulation, orchestration, and player-facing mutation APIs are concentrated
|
||||
in `SimulationManager`.
|
||||
- Path failure and interruption behavior is minimal.
|
||||
- Path failure and interruption emit a `navigation_failed` signal and send the NPC to wander; this is functional but not yet polished.
|
||||
- Terrain3D is enabled but not yet used by the main game scene.
|
||||
- Combat, companions, factions, politics, trade, rumours, quests, persistence,
|
||||
and regional travel do not yet exist.
|
||||
|
||||
@@ -1,5 +1,40 @@
|
||||
# The Steward — ResourceNode Migration Plan
|
||||
|
||||
## Progress Overview
|
||||
|
||||
| Phase | Description | Status |
|
||||
|-------|-------------|--------|
|
||||
| **1** | ResourceNode scene + registration | ✅ Complete |
|
||||
| **2** | Food target selection + reservation | ✅ Complete |
|
||||
| **3** | Authoritative extraction on completion | ✅ Complete |
|
||||
| **4a** | Wood target selection (NPC) | ✅ Complete |
|
||||
| **4b** | Player parity (extraction contract) | ⏳ Not started |
|
||||
| **5** | Jajce world placement | ❌ Not started |
|
||||
| **6** | Remove remaining zone model | ❌ Not started |
|
||||
|
||||
### Key divergences from the original plan
|
||||
|
||||
- **Zone fallback removed** (Phase 3): `gather_food`/`gather_wood` no longer fall back to `FarmZone`/`ForestZone` markers when no resource node is available. The original plan called for a logged fallback; instead, the NPC goes idle (via `navigation_failed` → wander) to guarantee resource conservation. The zone markers are still available for player interaction.
|
||||
- **`navigation_failed` signal** (discovered during Phase 4): Added a separate signal pathway to distinguish genuine arrival from navigation failure. The original plan treated all "arrivals" uniformly.
|
||||
- **Stale-path prevention** (discovered during Phase 4): Added `path_request_id` + `path_pending` to reject async path results that arrive after a new target was set or the NPC died.
|
||||
- **Duplicate node_id detection** (discovered during Phase 4): Added startup validation that disables nodes with duplicate IDs and pushes an error.
|
||||
|
||||
### Bugs found and fixed
|
||||
|
||||
| # | Bug | Phase found | Fix |
|
||||
|---|-----|-------------|-----|
|
||||
| 1 | Navigation failure: empty path caused NPC to idle permanently | Phase 3 stump | `_report_arrival_once()` on empty path (later replaced by `navigation_failed` signal) |
|
||||
| 2 | Unavailable-target deadlock: replan didn't trigger `npc_task_changed` | Phase 3 | Set `current_task = ""` so tick detects task change and emits signal |
|
||||
| 3 | Zone fallback broke conservation (fixed during Phase 4 removal) | Phase 3 | Removed zone fallback for gather tasks; NPC stays idle if no node available |
|
||||
| 4 | NPC collision blocking: NPCs physically blocked each other at shared destinations | Phase 3 | `collision_layer=2`, `collision_mask=1` on NpcVisual; `arrival_distance` 0.6→1.5 (later reverted to 0.6 after navigation_failed signal) |
|
||||
| 5 | Repetitive task selection: NPC chose same task every tick | Phase 3 | `last_task` tracking with -1.5 score penalty when same task repeats |
|
||||
| 6 | Wander didn't wander: wandered to rest marker instead of random offset | Phase 3 | Random ±6 unit offset from current position |
|
||||
| 7 | `:=` infers from Variant: warnings treated as errors from `odig` | Phase 2-3 | Use `=` instead of `:=` for calls returning `Variant` |
|
||||
| 8 | `Variant as StringName`: invalid cast | Phase 2-3 | Check for `null` on Dictionary `.get()` instead of casting |
|
||||
| 9 | Empty-path re-entrancy: immediate arrival report caused re-entrant signal chain | Phase 4 | Defer to `stuck_counter`/`stuck_time` in `_physics_process` instead |
|
||||
| 10 | Stale async path: `await physics_frame` result used after target or death changed | Phase 4 | `path_request_id`/`path_pending` guard |
|
||||
| 11 | Stolen extraction: NPC extracted from node after reservation was lost | Phase 4 | Guard extraction with `node.reserved_by == npc.id` |
|
||||
|
||||
## Decision
|
||||
|
||||
The current task zones are temporary prototype scaffolding.
|
||||
@@ -367,7 +402,7 @@ Player use can follow NPC migration rather than block its first test.
|
||||
|
||||
## Migration phases
|
||||
|
||||
### Phase 1 — ResourceNode scene and registration
|
||||
### ✅ Phase 1 — ResourceNode scene and registration *[complete]*
|
||||
|
||||
- create `ResourceNode.gd` and `ResourceNode.tscn`;
|
||||
- create a `ResourceNodes` parent in `main.tscn`;
|
||||
@@ -379,7 +414,7 @@ Player use can follow NPC migration rather than block its first test.
|
||||
**Exit:** nodes register, validate IDs, change amount, deplete, and update debug
|
||||
presentation without involving NPC logic.
|
||||
|
||||
### Phase 2 — Food target selection and reservation
|
||||
### ✅ Phase 2 — Food target selection and reservation *[complete]*
|
||||
|
||||
- migrate only `gather_food`;
|
||||
- find nearest available bush;
|
||||
@@ -387,12 +422,13 @@ presentation without involving NPC logic.
|
||||
- store its ID on the NPC;
|
||||
- navigate to its interaction point;
|
||||
- release on interruption and death;
|
||||
- retain `FarmZone` fallback with a visible warning.
|
||||
- ~~retain `FarmZone` fallback with a visible warning~~ *(removed in Phase 4,
|
||||
see divergences above)*
|
||||
|
||||
**Exit:** two NPCs do not select the same single-user bush, and an NPC can
|
||||
replan when its chosen bush becomes unavailable.
|
||||
|
||||
### Phase 3 — Authoritative completion
|
||||
### ✅ Phase 3 — Authoritative completion *[complete]*
|
||||
|
||||
- extract only after work duration completes;
|
||||
- return actual extracted amount;
|
||||
@@ -409,15 +445,22 @@ total bush decrease == total village food increase
|
||||
|
||||
for the initial gather-food scenario.
|
||||
|
||||
### Phase 4 — Wood and player parity
|
||||
### 🔶 Phase 4 — Wood and player parity *(partially complete)*
|
||||
|
||||
- migrate `gather_wood`;
|
||||
- configure tree visuals and yields;
|
||||
- route player interaction through the same extraction contract;
|
||||
- add clear feedback for unavailable or depleted targets.
|
||||
**Wood migration** ✅ complete:
|
||||
- `gather_wood` uses `ResourceNode.find_available("gather_wood")` in WVM
|
||||
- Tree_01 (15 wood, yield 3.0) and Tree_02 (12 wood, yield 3.0) placed
|
||||
- Extraction follows same path as food (reserve → travel → work → extract → village resource delta)
|
||||
- Zone fallback removed; NPC goes idle if no tree available
|
||||
|
||||
**Exit:** food and wood no longer require their abstract zones during normal
|
||||
play. NPC and player extraction obey the same availability and depletion rules.
|
||||
**Player parity** ⏳ not started:
|
||||
- Player currently still uses zone-marker interaction in `player.gd`
|
||||
- Player should use `ResourceNode.extract()` via proximity detection or raycast
|
||||
- Player interaction bypasses reservation (player presses E at a node → extract if available)
|
||||
- `PlayerInteraction.gd` exists as an empty stub
|
||||
|
||||
**Updated exit:** food and wood no longer require their abstract zones during
|
||||
normal play *for NPCs*. Player parity is required to fully exit this phase.
|
||||
|
||||
### Phase 5 — Jajce world placement
|
||||
|
||||
@@ -484,34 +527,37 @@ The migration naturally creates strong short-form demonstrations:
|
||||
Show the beautiful result first, then reveal target selection, reservation, and
|
||||
resource conservation through debug presentation.
|
||||
|
||||
## Immediate implementation order
|
||||
## Implementation status
|
||||
|
||||
1. Create `world/resource_nodes/ResourceNode.gd`.
|
||||
2. Create `world/resource_nodes/ResourceNode.tscn`.
|
||||
3. Add `Main/ResourceNodes`.
|
||||
4. Place `BerryBush_01`, `BerryBush_02`, `Tree_01`, and `Tree_02`.
|
||||
5. Add stable IDs and registration validation.
|
||||
6. Verify extraction and depletion manually.
|
||||
7. Add target ID to `SimNPC`.
|
||||
8. Migrate `gather_food` target selection.
|
||||
9. Add reservation and cleanup.
|
||||
10. Apply actual extracted yield on completion.
|
||||
11. Add fixed-seed regression scenarios.
|
||||
12. Migrate wood.
|
||||
13. Give the player the same extraction path.
|
||||
14. Continue with the Jajce world scaffold.
|
||||
| # | Task | Status | Commits |
|
||||
|---|------|--------|---------|
|
||||
| 1 | Create `ResourceNode.gd` and `ResourceNode.tscn` | ✅ Done | `9cd38a1` |
|
||||
| 2 | Add `Main/ResourceNodes` | ✅ Done | `9cd38a1` |
|
||||
| 3 | Place BerryBush_01, BerryBush_02, Tree_01, Tree_02 | ✅ Done | `9cd38a1` |
|
||||
| 4 | Add stable IDs and registration validation | ✅ Done | `9cd38a1`, `1837bc0` |
|
||||
| 5 | Verify extraction and depletion manually | ✅ Done | `9cd38a1` |
|
||||
| 6 | Add target ID to `SimNPC` | ✅ Done | `9cd38a1` |
|
||||
| 7 | Migrate `gather_food` target selection | ✅ Done | `9cd38a1`, `c6033b6` |
|
||||
| 8 | Add reservation and cleanup | ✅ Done | `9cd38a1`, `b8752f8` |
|
||||
| 9 | Apply actual extracted yield on completion | ✅ Done | `c6033b6` |
|
||||
| 10 | Add navigation failure handling (replaces regression scenarios) | ✅ Done | `b8752f8` |
|
||||
| 11 | Migrate wood | ✅ Done | `c6033b6`, `8049c52` |
|
||||
| 12 | Give the player the same extraction path | ⏳ Not started | — |
|
||||
| 13 | Continue with the Jajce world scaffold | ❌ Not started | — |
|
||||
|
||||
## Definition of done for the first migration
|
||||
|
||||
- Food and wood use actual finite world objects.
|
||||
- NPCs select available targets and reserve them.
|
||||
- NPC state stores stable target IDs rather than nodes or scene paths.
|
||||
- Active visuals navigate to explicit interaction points.
|
||||
- Work duration completes before extraction.
|
||||
- Village resources increase only by the amount actually extracted.
|
||||
- Depletion changes availability and presentation.
|
||||
- Failure, interruption, and death release reservations.
|
||||
- Old food and forest zones remain only as logged fallbacks.
|
||||
- The player and NPCs can use the same extraction contract.
|
||||
- Behavior is inspectable and covered by reproducible scenarios.
|
||||
| Criterion | Status |
|
||||
|-----------|--------|
|
||||
| Food and wood use actual finite world objects | ✅ (NPCs) / ⏳ (player) |
|
||||
| NPCs select available targets and reserve them | ✅ |
|
||||
| NPC state stores stable target IDs rather than nodes or scene paths | ✅ |
|
||||
| Active visuals navigate to explicit interaction points | ✅ |
|
||||
| Work duration completes before extraction | ✅ |
|
||||
| Village resources increase only by the amount actually extracted | ✅ |
|
||||
| Depletion changes availability and presentation | ✅ |
|
||||
| Failure, interruption, and death release reservations | ✅ |
|
||||
| Old food and forest zone fallbacks are no longer used by NPCs | ✅ (fallback removed by design) |
|
||||
| The player and NPCs can use the same extraction contract | ⏳ (player side not started) |
|
||||
| Behavior is inspectable and covered by reproducible scenarios | ✅ (debug logging, debug overlay on nodes) |
|
||||
|
||||
|
||||
Reference in New Issue
Block a user