docs(runicnpc): stage 3's design, D239–D242

The org lead answered stage 3's four questions on 2026-09-30:

- D239: a roamer may stand on a player-built floor (Rust's mesh covers it
  a moment after it is built, stage 2), with a warning in the answer.
  §5, §8 and stage 10 now follow it; stage 2's open item is closed.
- D240: routes are recorded point by point (record, point, undo,
  save loop|back, cancel), with nothing drawn on screen.
- D241: placements made in game are named <profile>-<n>, renamable.
- D242: /rnpc place and /rnpc here take key=value options in any order.

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 01:49:48 -05:00
parent 3f358bba76
commit 791ac75b14
3 changed files with 33 additions and 18 deletions

View File

@@ -98,7 +98,7 @@ requires it once it releases (D220).
| Doc | What it covers |
|---|---|
| [PLAN.md](runicnpc/PLAN.md) | **The plan** — what the 2026-09-30 spike found (route A, HumanNPC, NpcSpawn), the org lead's decisions D214–D238, the features, the API, the chat commands, and stages 0–10 with how each is tested and what each found |
| [PLAN.md](runicnpc/PLAN.md) | **The plan** — what the 2026-09-30 spike found (route A, HumanNPC, NpcSpawn), the org lead's decisions D214–D242, the features, the API, the chat commands, and stages 0–10 with how each is tested and what each found |
| [API.md](runicnpc/API.md) | **The API** other plugins call (version 2): owners, every `RunicNpc_*` call, the hooks it raises, and the profile, placement and route shapes |
### `android/`

View File

@@ -8,7 +8,7 @@ they can be read together. **Built so far:** §1, walked 2026-09-28 (§1.9); §5
rig walk still to come (§5.8, D209); §3, built and walked on the rigs and the site 2026-09-29, its in-game
rows still to come (§3.4); §4, built 2026-09-29 (§4.1). **§6 was spiked on 2026-09-30, and the org lead
chose neither route: Runic Gateway writes its own NPC plugin, RunicNPC, planned in
[`../../runicnpc/PLAN.md`](../../runicnpc/PLAN.md) (D214–D238), and the rest of this plan waits for it.**
[`../../runicnpc/PLAN.md`](../../runicnpc/PLAN.md) (D214–D242), and the rest of this plan waits for it.**
This is a companion to [`PLAN_FIXES.md`](PLAN_FIXES.md) and [`PLAN.md`](PLAN.md). Where they disagree, this
document is later and wins. Its decisions continue PLAN_FIXES' numbering at **D188**.

View File

@@ -4,7 +4,8 @@
**Stage 0 closed 2026-09-30** (runicnpc-rust#1/#2, §9): v0.1.0 released and loaded on both rigs. D229–D230 were
decided with it. **Stage 1 measured 2026-09-30** (§9): six answers on both rigs; D231 was decided with it.
**Stage 2's design answered 2026-09-30:** D232–D238 (§0), which reshape stage 2 (§9). **Stage 2 built and tested
2026-09-30** on both rigs (§9); its API is [API.md](API.md).
2026-09-30** on both rigs (§9); its API is [API.md](API.md). **Stage 3's design answered 2026-09-30:** D239–D242
(§0).
RunicNPC is Runic Gateway's own NPC plugin for Rust servers, in its own repository,
[`RunicGateway/runicnpc-rust`](https://gitea.whitlocktech.com/RunicGateway/runicnpc-rust). It runs on Oxide and
@@ -52,6 +53,10 @@ architectural or design decision is implemented.
| **D236** | **Respawn is chosen per placement:** `each` (the default: every NPC returns its delay after its own death) or `group` (none return until all are dead, then all return together). | One fixed rule. |
| **D237** | **A deleted profile leaves its placements waiting.** Their NPCs despawn; the placements are kept and shown as "profile missing" in game and on the site; they spawn again if the profile returns. | Refusing the delete; deleting the placements with it. |
| **D238** | **A profile's shape** is §2's, as the org lead approved it: `names`, `kits`, `prefab`, `role`, `movement`, `health`, `damageDealt`, `damageTaken`, `aimCone`, `ranges`, `visionCone`, `sleepDistance`, `healthThresholds`, in `data/RunicNPC/profiles.json` with the `managed` flag. Placements and routes have their own files beside it; the optional caps (D227) are in the plugin's config. Stages 5–7 add their own sections. | A smaller stage-2 profile, combat values deferred to stage 5. |
| **D239** | **A roamer may be placed wherever Rust's navmesh reaches, a player-built floor included, and the answer warns when it is one** ("this spot is on a player-built structure; if it is destroyed, the NPC falls back to the nearest navmesh"). Sentry-only stays the rule for a spot that is truly off the mesh. Stage 10 shrinks to pasted or custom prefabs and moving platforms (stage 2's finding). | Allowing it silently; keeping anything player-built sentry-only even where the mesh covers it. |
| **D240** | **A route is recorded point by point:** `/rnpc path record <name>` starts it, `/rnpc path point` adds where the admin stands (checked against the navmesh; a bad point is refused with the reason), `/rnpc path undo` drops the last, `/rnpc path save [loop\|back]` writes it, `/rnpc path cancel` discards it. Nothing is drawn on screen (D216). | The same flow with the points drawn on screen; a point dropped every few metres as the admin walks. |
| **D241** | **A placement made in game is named after its profile and a number** (`/rnpc place bandit` answers "Placed bandit-3"), and `/rnpc rename <id> <new>` renames it. `/rnpc near` lists the names. | Bare numbers; the admin naming every placement. |
| **D242** | **`/rnpc place` and `/rnpc here` take `key=value` options in any order after the profile:** `count=`, `respawn=`, `mode=each\|group`, `move=wander\|monument\|route:<name>`, `radius=`. Anything left out takes the profile's default. | `/rnpc place bandit 3 300 group route:gate`; `/rnpc place` then `/rnpc set`. |
**Borrowing, not copying.** NpcSpawn states no licence at all, so its source grants us nothing and is read only as a
description of *what* can be done in Rust. HumanNPC is MIT on uMod, which is GPL-compatible, but §1.2 rules out its
@@ -290,10 +295,13 @@ permissions reach the site's permission manager through the inventory, like any
| Command | Does | Permission |
|---|---|---|
| `/rnpc place <profile> [count] [respawn]` | Places at the spot you are looking at, persistent | `runicnpc.place` |
| `/rnpc here <profile> [count]` | The same, where you stand | `runicnpc.place` |
| `/rnpc remove` | Removes the placement of the NPC you are looking at | `runicnpc.place` |
| `/rnpc near [radius]` | Lists placements and live NPCs near you | `runicnpc.place` |
| `/rnpc place <profile> [key=value ...]` | Places at the spot you are looking at, persistent, and answers with its name (D241). Options in any order (D242): `count=`, `respawn=` (seconds), `mode=each\|group`, `move=wander\|monument\|route:<name>`, `radius=` | `runicnpc.place` |
| `/rnpc here <profile> [key=value ...]` | The same, where you stand | `runicnpc.place` |
| `/rnpc remove [placement]` | Removes a placement and its NPCs: the one named, or that of the NPC you are looking at | `runicnpc.place` |
| `/rnpc rename <placement> <new>` | Renames a placement (D241) | `runicnpc.place` |
| `/rnpc near [radius]` | Lists placements (by name) and live NPCs near you | `runicnpc.place` |
| `/rnpc path record <name>` · `point` · `undo` · `save [loop\|back]` · `cancel` | Records a route where you walk, point by point (D240) | `runicnpc.place` |
| `/rnpc path list` · `delete <name>` | Lists or deletes routes; a placement on a deleted route waits, as for a deleted profile (D237) | `runicnpc.place` |
| `/rnpc info` | The NPC you are looking at: profile, owner, health, target, state | `runicnpc.place` |
| `/rnpc profiles` | The profiles this server has | `runicnpc.place` |
| `rnpc.profile <create\|set\|delete> ...` (console) | Edits a profile on a standalone server; refused when the site manages them (D221) | `runicnpc.admin` |
@@ -305,8 +313,11 @@ permissions reach the site's permission manager through the inventory, like any
cost warning (D227): how many RunicNPC NPCs the server now has and what stage 1 measured that number to cost.
On the navmesh, the NPC roams, chases and fights
normally. Off it (a roof, inside a base, a pasted structure), a **stationary** profile is placed and a roaming one
is refused with the reason. An event step gets the same answer, as a blocked RaidableBases spot does (D208).
normally, and that includes a player-built floor, which Rust's mesh covers a moment after it is built (stage 2).
**On a player-built structure the placement is made with a warning** (D239): if the structure is destroyed, the
NPC falls back to the nearest navmesh. Off the mesh (a pasted structure, a custom prefab), a **stationary** profile
is placed and a roaming one is refused with the reason. An event step gets the same answer, as a blocked
RaidableBases spot does (D208).
---
@@ -349,7 +360,8 @@ shipped no custom mesh. Where it does not reach, a profile is a sentry (§5).
**Stage 10, only if needed:** a point graph recorded in game. An admin walks the route, `/rnpc mesh record <name>`
samples it, and NPCs move between the points directly, as NpcSpawn's custom meshes do, for:
- pasted or player-built bases, and roofs;
- pasted structures, and roofs the mesh does not reach (a player-built floor needs none: Rust's mesh covers it
a moment after it is built, stage 2 and D239);
- custom map prefabs Rust's mesh does not cover;
- moving platforms, together with parenting.
@@ -479,8 +491,8 @@ boots load the saved `proceduralmap.<size>.<seed>.<n>.navmesh`. **Placements tha
| A player-built floor 4 m up | **not on the mesh** in the frame it spawned; **on it 0.1–0.3 s later** (stage 2) | the same |
| One check | 13.6 µs | 8.3 µs |
Monument roofs (Launch Site, Airfield, Trainyard, the warehouses) are mostly walkable. Player-built floors and
roofs never are: that is §5's sentry rule, and stage 10.
Monument roofs (Launch Site, Airfield, Trainyard, the warehouses) are mostly walkable. This stage read
player-built floors and roofs as never walkable; stage 2 corrected that (the row above), and D239 follows from it.
**5. The cost (D227's numbers).** Seven 60 s phases on a field 400 m from any monument: a baseline, 1, 10 and 100
of ours idle, the same 100 shooting 20 stand-ins (whose damage the harness zeroes, so none die), a fresh 100 set to
@@ -584,7 +596,7 @@ What building it found:
- **Rust's navmesh covers a new player-built floor in 0.1–0.3 s** (2–3 frames), on both rigs. Stage 1's "a
player-built floor is never on the mesh" (Q4) sampled in the same frame the floor spawned, so it is wrong: a
roamer can stand on a player-built floor a moment after it exists. §5's sentry rule, §8 and stage 10 were
written on stage 1's reading. **Open for the org lead.**
written on stage 1's reading; the org lead answered with D239, and those sections now follow it.
- **Rust's navmesh sampler reaches further down than across.** A roamer asked to stand on a roof found the
ground 4.7 m below. A roamer's spot must now be within 2 m, up or down, of the navmesh it is put on.
- **A brain can think before Unity has started it.** For that moment it has no navigator, so RunicNPC leaves that
@@ -596,12 +608,15 @@ What building it found:
### Stage 3 — In game
The chat and console commands (§5), their permissions, the navmesh placement check, respawn delays, and recording
routes in game (`/rnpc path record`, then setting points, D234). A placement may name a movement override and a
respawn mode (D233, D236).
The chat and console commands (§5), their permissions, the navmesh placement check with D239's warning on a
player-built structure, respawn delays, and recording routes in game point by point (D234, D240). Placements made
in game are named after their profile and a number, and renamable (D241). `/rnpc place` and `/rnpc here` take
`key=value` options, a movement override and a respawn mode among them (D233, D236, D242).
**Tested by** a written in-game walk: place, remove, look-at info, respawn, record a route and place a patrol on it,
restart. **This is the first stage that needs a player on a rig.**
**Tested by** the harness for everything a console can reach (the commands' parsing, refusals, names, and the
route file a recording writes), then a written in-game walk: place, remove, rename, look-at info, respawn, record a
route and place a patrol on it, place on a player-built floor and destroy it, restart. **This is the first stage
that needs a player on a rig.**
### Stage 4 — Runic Gateway integration