docs(runicnpc): stage 2 as built, and API.md
runicnpc/API.md is the reference for other plugins: owners, every RunicNpc_* call, the four hooks, and the profile, placement and route shapes. PLAN.md records stage 2's results on both rigs and what building it found: Rust's chase needs an AI zone like its roam, and a player-built floor joins the navmesh 0.1-0.3 s after it spawns, which corrects stage 1's Q4 (left open for the org lead). README indexes API.md. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
This commit is contained in:
@@ -3,7 +3,8 @@
|
||||
**Status:** plan, written 2026-09-30. Its eight questions (§11) were answered the same day: D221–D228 (§0).
|
||||
**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'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).
|
||||
|
||||
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
|
||||
@@ -460,7 +461,7 @@ it. That is the other reason our NPC must never be saved (§2).
|
||||
| Health, name, aim cone | Hold: set on the NPC and read back (400/400, the name, 0.5). |
|
||||
| Sense range, target-lost range, vision cone, listen range, hostile-only, sense types | **Only if set before the brain starts.** `Senses.Init` copies them once. At 35 m, a range of 50 set before the start saw the target, and the same range set afterwards did not. |
|
||||
| The prefab's own values | Sense 30 m, lose target 40 m, vision cone −0.8, listen 10 m, memory 10 s, line-of-sight checks on, hostile-only off, senses players only, health 150, aim cone 2. |
|
||||
| Roaming | **Rust's roam only follows an AI zone's move points.** In a monument's zone (Desert Military Base) ours roamed 36–47 m in 60 s. In an open field it stood still (0 m). **A roamer anywhere but a monument needs our own roam state, so stage 2's roamer role includes one.** |
|
||||
| Roaming | **Rust's roam only follows an AI zone's move points** (and so does its chase: stage 2). In a monument's zone (Desert Military Base) ours roamed 36–47 m in 60 s. In an open field it stood still (0 m). **A roamer anywhere but a monument needs our own roam state, so stage 2's roamer role includes one.** |
|
||||
| Sleep | An NPC outside an AI zone is never put to sleep, and `ai_dormant` does not apply to this AI. So an idle NPC keeps thinking with nobody near, which is what the costs below measure. |
|
||||
| **Fighting NPCs** | **Rust's scientist AI never attacks an NPC.** `HumanNPC.IsTarget` is true only for non-NPC players, pets and scarecrows. `IsFriendly` means "same prefab id", which the swap copies, so every stock scientist counts ours as a friend. Re-implementing Rust's internal `IAISenses` puts a scientist in our NPC's target list. But Rust's AI design never runs its attack event for an NPC target. Calling `AttackTick` directly passed line of sight every time and still fired no shot, because the design's cover and facing states win. **NPC-versus-NPC combat needs our own combat state, and sensing NPCs needs our own sensing** (see the cost below). D231 makes it a profile setting, so stage 5 opens with its own spike. |
|
||||
|
||||
@@ -475,7 +476,7 @@ boots load the saved `proceduralmap.<size>.<seed>.<n>.navmesh`. **Placements tha
|
||||
| Monuments probed (9 points each) | 144 | 144 |
|
||||
| Points on the navmesh | 1,152 / 1,296 (89%) | 1,151 / 1,296 (89%) |
|
||||
| Of those on a structure (a roof or raised floor) | 132 / 209 (63%) | 130 / 211 (62%) |
|
||||
| A player-built floor 4 m up | **not on the mesh** | **not on the mesh** |
|
||||
| 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
|
||||
@@ -553,6 +554,46 @@ and reload checks on both rigs: no NPC saved, every placement back, nothing left
|
||||
also checks each movement mode, sleep and the walk home, both respawn modes, and a placement whose profile is
|
||||
deleted and restored.
|
||||
|
||||
**Built (2026-09-30, runicnpc-rust#4, API version 2).** The API as built is [API.md](API.md). What else landed:
|
||||
|
||||
- `tools/fieldlist` generates the swap's field list from the Carbon rig's assemblies (`tools/managed.js`
|
||||
downloads them). It picks **64 NPC and 32 brain fields**, exactly stage 1's Carbon count. On both rigs every
|
||||
name resolves, and Carbon's boot check finds no field Rust has added.
|
||||
- `tools/RunicNpcTest.cs`, the harness: `rnt.run api|hooks|move|sentry|sleep|place|all`, then `rnt.after` after a
|
||||
reload or restart.
|
||||
|
||||
| Group | What it proves | Oxide | Carbon |
|
||||
|---|---|---|---|
|
||||
| api | every call's answer; seven refusals (bad owner, `placement:` owner, unknown or refused profile, bad override, off the navmesh) | 24/24 | 24/24 |
|
||||
| hooks | spawned, a health threshold once, body damage ×0.5, died with contributors (250 of 250), despawned | 8/8 | 8/8 |
|
||||
| move | wander within its radius; a route in order (3>0>1>2>3>0); a monument roamer 36 m on Rust's roam; our chase to 9.6–9.8 m of a 10 m chase range, and giving up twice | 8/8 | 8/8 |
|
||||
| sentry | holds 0.00 m for 40 s and hits a target 12 m off 29–34 times; stands 40 m up, off the navmesh, for 20 s | 7/7 | 7/7 |
|
||||
| sleep | wanders 8.6 m off, walks home at ≤2.8 m/s when no player is within 160 m, sleeps 1.7 m from its spot, stays still, wakes | 7/7 | 7/7 |
|
||||
| place | `each` returns only the dead one; `group` waits for all, then all return; a deleted profile waits and returns; a missing route waits | 14/14 | 14/14 |
|
||||
| a plugin unloads | its NPCs are removed with it | pass | pass |
|
||||
| RunicNPC reloads | every placement back, the world equals the registry, no plain scientists at the spots | 5/5 | 5/5 |
|
||||
| the server restarts | the same, after `server.save`, a restart, and the navmesh load | 5/5 | 5/5 |
|
||||
|
||||
What building it found:
|
||||
|
||||
- **Outside a monument, Rust's scientists never chase.** Rust's chase state looks for an AI zone's move points and
|
||||
returns an error without them, as its roam does (stage 1, Q3). A `wander` or `route` roamer therefore has our
|
||||
own chase. It closes to three quarters of the attack range, never past the profile's chase range from home, and
|
||||
if the target stays out of reach at that edge for 5 s it gives up and walks home. A `monument` roamer keeps
|
||||
Rust's chase.
|
||||
- **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.**
|
||||
- **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
|
||||
think to Rust.
|
||||
- **A hit with no body part reports every part at once** (`(HitArea)(-1)`: fire, explosions, falls). Only an
|
||||
exact head or leg hit uses those scales; everything else is body.
|
||||
- **The game manifest's entity list leaves out the NPC prefabs.** A profile's `prefab` is looked up in its prefab
|
||||
list instead.
|
||||
|
||||
### Stage 3 — In game
|
||||
|
||||
The chat and console commands (§5), their permissions, the navmesh placement check, respawn delays, and recording
|
||||
|
||||
Reference in New Issue
Block a user