docs(runicnpc): stage 3 as built, and its in-game walk

- PLAN.md stage 3: what was built (runicnpc-rust#5), the results on
  both rigs (134/134, reload and restart 5/5), what building it found
  (Rust leaves an NPC in the air when its floor goes; a route leg can
  be on the navmesh and still unwalkable; a shore floor not covered;
  stage 2's JSON leak), the console-only at= option for the org
  lead's call, and the in-game walk checklist.
- API.md: SetPlacement's navmesh check and D239 fallback, the
  placements' note, List's regrounded, and SetRoute's unchecked legs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
This commit is contained in:
2026-09-30 03:19:14 -05:00
parent fdfd525bc4
commit 953044b806
2 changed files with 69 additions and 4 deletions

View File

@@ -82,6 +82,7 @@ The live NPCs of `owner`; null lists them all. Each has:
| `rest` | `string` | `Awake`, `GoingHome` or `Asleep` (D235). |
| `state` | `string` | Rust's AI state: `Idle`, `Roam`, `Chase`, `Combat` and so on. |
| `leashes` | `int` | How many times it has given up a chase at its chase range. |
| `regrounded` | `int` | How many times its ground went from under it and it was put on the nearest navmesh (D239). |
### `RunicNpc_Profiles()` → `JObject`
@@ -96,14 +97,22 @@ profile has gone waits, and spawns again when the profile returns (D237).
### `RunicNpc_Placements()` → `List<Dictionary<string, object>>`
Each placement as `{id, placement, alive, waiting, lastError}`. `placement` is the placement's JSON (below),
`alive` is how many of its NPCs are alive, and `waiting` says why it cannot spawn right now, or is null.
Each placement as `{id, placement, alive, waiting, lastError, note}`. `placement` is the placement's JSON (below),
`alive` is how many of its NPCs are alive, and `waiting` says why it cannot spawn right now, or is null. `note` is
set while its NPCs stand somewhere other than its spot because the ground there went (D239, below), or is null.
### `RunicNpc_SetPlacement(string id, JObject placement)` → `string`
Adds or replaces a persistent placement (D222). Null on success, or the reason. Replacing one despawns its NPCs and
spawns them again from the new values. Every set logs the cost warning (D227).
A roamer's spot must be on Rust's navmesh, within 2 m up or down, when it is set; otherwise the answer says how far
off it is, as `rnpc place` does (D219). The check is skipped while the map's navmesh is still being built, and
for a profile that does not exist yet. **If the ground under a placement goes later** (a player-built floor is
destroyed, D239), a live NPC is put on the nearest navmesh within 2 s, and the placement respawns its NPCs on the
nearest navmesh until its spot is walkable again; `note` says so meanwhile. Rust itself leaves such an NPC standing
in the air.
### `RunicNpc_RemovePlacement(string id)` → `bool`
Removes a placement and its NPCs.
@@ -114,7 +123,9 @@ Removes a placement and its NPCs.
### `RunicNpc_SetRoute(string name, JObject route)` → `string`
Adds or replaces a route (D234). Every point must be on Rust's navmesh. Null on success, or the reason.
Adds or replaces a route (D234). Every point must be on Rust's navmesh. Null on success, or the reason. Unlike
`rnpc path` (D240), it does not check that an NPC can walk from each point to the next: a leg Rust cannot path
leaves the NPC standing at the last point it reached, so a caller that builds routes should check its own legs.
### `RunicNpc_RemoveRoute(string name)` → `bool`