docs(runicnpc): stage 2's design, D232–D238
The org lead answered stage 2's open questions: a fixed field list for the swap, three movement modes a placement may choose (wander, Rust's monument paths, admin-recorded routes), sleep past 160 m after walking home, respawn per placement (each or group), placements that wait for a deleted profile, and the profile's shape. Stage 2 and 3 are rewritten around them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
This commit is contained in:
@@ -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–D231), and the rest of this plan waits for it.**
|
||||
[`../../runicnpc/PLAN.md`](../../runicnpc/PLAN.md) (D214–D238), 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**.
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
**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).
|
||||
|
||||
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
|
||||
@@ -43,6 +44,13 @@ architectural or design decision is implemented.
|
||||
| **D229** | **The empty repository was seeded by one `chore:` commit straight to `main`** (the licence and a stub README), `edge` was branched from it, and everything after goes by PR (stage 0). It is the only direct push. | You seeding it in the Gitea UI; the whole scaffold straight to `main`, unreviewed. |
|
||||
| **D230** | **The layout is `plugin/RunicNPC.cs` and a root `plugin.toml`**: `api`, the framework floors, `requires_plugins` (stage 0). RunicNPC is one file, not an overlay of a server tree. | Mirroring Rust-Plugins' `overlay/oxide/plugins/` and `overlay.toml`. |
|
||||
| **D231** | **Each profile (or group) decides whether its NPCs target other NPCs, and which kinds**: Rust's scientists, animals, other profiles, and so on (stage 1; the org lead's words). Rust's AI cannot do this (§9, stage 1, Q3), so it is our own combat state and sensing, and stage 5 opens with a spike for it. | Our NPCs fighting players only, as Rust's scientists do. |
|
||||
| **D232** | **The swap copies a fixed list of fields**, generated from Rust's unmodified assembly by a `tools/` script and carried in the plugin, so Oxide and Carbon copy the same fields. A boot check on Carbon, where Rust's visibility is unmodified, names any field Rust has added since; the staging drill (stage 9) regenerates the list. | Stage 1's rule as it is (Oxide copies runtime state too); the rule with Oxide-only filters. |
|
||||
| **D233** | **A roamer moves in one of three ways:** `wander` (our own: a walkable point within a radius of its spot, walk, pause, repeat), `monument` (Rust's own AI-zone paths), or `route:<name>` (points an admin records in game, walked in order). **The profile sets the default, `wander`, and each placement may override it** (the org lead: "should be both, and the ability for admins in game to make routes"). | Our wander only; Rust's paths in monuments and ours elsewhere, fixed; the mode fixed per profile. |
|
||||
| **D234** | **Routes are walked from stage 2 and recorded from stage 3.** Stage 2 builds the follower and the routes file (the harness writes its points); stage 3 adds `/rnpc path record` and setting points in game; stage 5 adds fighting and resuming the route. | Recording in stage 3 and walking in stage 5, as first planned. |
|
||||
| **D235** | **An NPC sleeps when no player is within 160 m** (Rust's own dormant distance; a profile may change it, 0 = never). **It walks back to its spot before it sleeps** (the org lead: "it should walk back home before going to sleep"), and wakes when a player comes within range. | Being put back at its spot; never sleeping unless a profile opts in. |
|
||||
| **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. |
|
||||
|
||||
**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
|
||||
@@ -161,6 +169,39 @@ Placements stay the server's either way (D222): the site reads them and edits th
|
||||
The kit list is required and non-empty; one kit is picked at random per spawn, for variety within a profile. A kit
|
||||
the server does not have refuses the profile when it is saved, not when an NPC spawns.
|
||||
|
||||
**In the data file (D238)**, `data/RunicNPC/profiles.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"managed": false,
|
||||
"profiles": {
|
||||
"warden": {
|
||||
"names": ["Warden", "Old Warden"],
|
||||
"kits": ["warden_rifle", "warden_smg"],
|
||||
"prefab": "scientistnpc_roam",
|
||||
"role": "roamer",
|
||||
"movement": { "mode": "wander", "radius": 20 },
|
||||
"health": 250,
|
||||
"damageDealt": 1.0,
|
||||
"damageTaken": { "head": 1.0, "body": 1.0, "legs": 1.0 },
|
||||
"aimCone": 2.0,
|
||||
"ranges": { "sense": 30, "loseTarget": 40, "chase": 40, "attack": 30 },
|
||||
"visionCone": -0.8,
|
||||
"sleepDistance": 160,
|
||||
"healthThresholds": [0.5]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- `role` is `roamer` or `sentry` in stage 2; the other roles of §6 arrive with their stages.
|
||||
- `movement.mode` is `wander`, `monument` or `route:<name>` (D233). A placement may override it.
|
||||
- `damageDealt` scales the kit weapon's damage. `damageTaken` scales what the NPC takes, by body part.
|
||||
- `sleepDistance` 0 means it never sleeps (D235).
|
||||
- `healthThresholds` are the fractions at which `OnRunicNpcHealth` fires (§4).
|
||||
|
||||
**A deleted profile leaves its placements waiting (D237):** their NPCs despawn, and they spawn again if it returns.
|
||||
|
||||
---
|
||||
|
||||
## 3. Features
|
||||
@@ -191,7 +232,7 @@ Borrowed ideas are marked with their source; everything else is new. Stage numbe
|
||||
|---|---|
|
||||
| Press E to talk: an NPC says a line, or opens a message, when used | 6 |
|
||||
| Lines on greet, hurt and kill | 6 |
|
||||
| Follow a player, and walk a recorded path | 5 |
|
||||
| Walk a recorded path (D234), and follow a player | 2, 3, 5 |
|
||||
|
||||
### 3.3 Runic Gateway's own
|
||||
|
||||
@@ -274,10 +315,10 @@ Each profile has a **role**, which sets its AI states and defaults:
|
||||
|
||||
| Role | Behaviour |
|
||||
|---|---|
|
||||
| **Roamer** | Wanders within its roam range of home, chases and fights. Rust's default. |
|
||||
| **Roamer** | Moves in one of three ways (D233): `wander` within a radius of its spot, `monument` (Rust's AI-zone paths), or `route:<name>`; chases and fights. The profile sets the default, a placement may override it. |
|
||||
| **Sentry** | Stationary: turns and shoots, never walks. The only role allowed off the navmesh. |
|
||||
| **Guard** | Holds a point or an entity; chases only to its leash, then returns. |
|
||||
| **Patrol** | Walks a path recorded in game (`/rnpc path record`); fights and resumes. |
|
||||
| **Patrol** | A roamer on `route:<name>` (D233): walks a route recorded in game (`/rnpc path record`); fights and resumes (stage 5). |
|
||||
| **Escort** | Follows an entity or player; defends it. |
|
||||
| **Boss** | Any of the above, plus a health bar, phases and announcements (§3.3). |
|
||||
| **Passive** | Never fights; press E to talk. Quest-givers and vendors. |
|
||||
@@ -488,22 +529,38 @@ What the numbers say:
|
||||
|
||||
### Stage 2 — The NPC and its API
|
||||
|
||||
- The subclass, profiles (read from RunicNPC's own data file for now), kits (random pick), appearance, combat values,
|
||||
roamer and sentry roles, sleep.
|
||||
- Owners and lifetimes (§2); placements persisted with one dirty flag; standalone profiles and the managed flag
|
||||
(D221); optional caps, off by default, and the cost warning from stage 1's measurements (D227).
|
||||
- The API (§4) and its hooks; `docs/runicnpc/API.md`.
|
||||
- **The NPC:** the subclass with a fixed field list (D232) and `AwakeFromInstantiate` before `Spawn` (stage 1, Q1);
|
||||
the `AttackerInfo` override, so its name reaches the death screen (stage 1, Q6); profiles read from RunicNPC's own
|
||||
data file in §2's shape (D238); a random kit and name per spawn; appearance and combat values, with the sense
|
||||
values set before the brain starts (stage 1, Q3).
|
||||
- **Roles and movement:** roamer and sentry. A roamer's three modes (D233): our own `wander`, Rust's `monument`
|
||||
paths, and `route:<name>` from the routes file (D234; the harness writes its points, stage 3 records them in
|
||||
game).
|
||||
- **Sleep (D235):** past the profile's distance from every player, the NPC walks back to its spot, then stops
|
||||
thinking; a player in range wakes it.
|
||||
- **Navmesh at boot:** nothing spawns until `RustNavigation.Instance.IsDefaultNavmeshBuilt()` (stage 1, Q4); the
|
||||
queue waits for it.
|
||||
- **Owners and lifetimes (§2):** placements persisted with one dirty flag, each with its count, delay and respawn
|
||||
mode (`each` or `group`, D236) and an optional movement override; a placement whose profile is gone waits (D237);
|
||||
standalone profiles and the managed flag (D221).
|
||||
- **Spawning in batches:** large placements and the boot respawn are spread over frames, within a per-frame time
|
||||
budget (stage 1, Q5: 100 at once is a half-second hitch).
|
||||
- **Optional caps, off by default,** in the plugin's config, and **the cost warning** from stage 1's table (D227).
|
||||
- **The API (§4) and its hooks;** `docs/runicnpc/API.md`.
|
||||
|
||||
**Tested by** the harness asserting each call's result (PASS/FAIL lines read back over the panel), plus restart
|
||||
and reload checks on both rigs: no NPC saved, every placement back, nothing left behind by an unloaded owner.
|
||||
and reload checks on both rigs: no NPC saved, every placement back, nothing left behind by an unloaded owner. It
|
||||
also checks each movement mode, sleep and the walk home, both respawn modes, and a placement whose profile is
|
||||
deleted and restored.
|
||||
|
||||
### Stage 3 — In game
|
||||
|
||||
The chat and console commands (§5), their permissions, the navmesh placement check, respawn delays, and `/rnpc
|
||||
path record` for stage 5.
|
||||
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).
|
||||
|
||||
**Tested by** a written in-game walk: place, remove, look-at info, respawn, restart. **This is the first stage that
|
||||
needs a player on a rig.**
|
||||
**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.**
|
||||
|
||||
### Stage 4 — Runic Gateway integration
|
||||
|
||||
|
||||
Reference in New Issue
Block a user