docs(runicnpc): record the org lead's answers, D221-D228
Standalone use too (D221), placements live on the server (D222), our own scientist subclass and brain (D223), installer and egg ship it plus a Gitea release and possibly other download sites (D224), per-profile kills public and in titles (D225), edge to main (D226), no default caps but a measured cost warning wherever NPCs are added (D227), and the names RunicNPC, /rnpc, runicnpc.* (D228). The sections they change are updated: standalone profiles, the console profile verb, cost warnings, stage 1's measurements, and publishing. 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–D220), and the rest of this plan waits for it.**
|
||||
[`../../runicnpc/PLAN.md`](../../runicnpc/PLAN.md) (D214–D228), 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**.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# RunicNPC — the plan
|
||||
|
||||
**Status:** plan, written 2026-09-30. No code yet. **Its questions (§11) are open.**
|
||||
**Status:** plan, written 2026-09-30. No code yet. **Its eight questions (§11) were answered the same day: D221–D228 (§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
|
||||
@@ -30,6 +30,14 @@ architectural or design decision is implemented.
|
||||
| **D218** | **Loot tables are RunicNPC's own for now.** Links to other loot plugins can come later. | AlphaLoot, CustomLoot, Loottable or LootManager as a dependency. |
|
||||
| **D219** | **Rust's own navmesh is used. A custom navigation mesh is a later stage, built only if a real need appears** (§8, stage 10). | Shipping NpcSpawn-style point meshes from the start. |
|
||||
| **D220** | **The plugin is built and tested in stages before the Rust plan resumes, and it then becomes a plugin `module-rust` requires.** | Building it alongside the remaining redesigns. |
|
||||
| **D221** | **RunicNPC works without Runic Gateway too** (Q1). Standalone, its profiles live in its data file and console commands edit them. On a Runic Gateway server, the site's profiles replace that file on every push, and in-game profile edits are refused with "this server's profiles are managed by its website". | Runic Gateway only. |
|
||||
| **D222** | **Placements live on the server** (Q2). They keep respawning while the site is offline; the site catches up when it returns, and lists and edits them from then on. | The site as the only record. |
|
||||
| **D223** | **Our NPC is its own subclass of Rust's scientist, with its own brain** (Q3). The brain is kept small and tested on Rust's `staging` branch before each forced wipe. | Rust's scientist plus patches. |
|
||||
| **D224** | **The installer and the egg ship it from the bundle, pinned and checksummed** (Q6). It is also published as a release on Gitea, and possibly on other sites for anyone to download. | Operators installing it themselves. |
|
||||
| **D225** | **Per-profile kills are public and usable in titles** (Q4), like the NPC kills column today. | Admins only. |
|
||||
| **D226** | **`edge` → `main`**, like the other Rust repositories (Q5, D18). | PRs straight to `main`. |
|
||||
| **D227** | **No default caps.** Instead, a realistic warning of what a number of NPCs costs and its impact on the server, measured in stage 1, shown wherever NPCs are added (Q7). Caps exist only when an admin sets them. | 100 / 50 / 10 per second by default. |
|
||||
| **D228** | **`RunicNPC.cs`, console name `RunicNPC`, chat command `/rnpc`, permissions `runicnpc.*`** (Q8). | — |
|
||||
|
||||
**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
|
||||
@@ -132,6 +140,11 @@ Stage 1 proves the swap on both frameworks before anything is built on it.
|
||||
This split is what HumanNPC got wrong: the *placement* is persistent data, the *NPC* never is. There is exactly one
|
||||
save path, a flag marks it dirty on every change (including removal), and nothing else is written.
|
||||
|
||||
**Standalone or managed (D221).** Without a site, RunicNPC reads its profiles from its own data file and console
|
||||
commands edit them. With a site, the bridge pushes the site's profiles, which replace the file; the file records that
|
||||
it is managed, and in-game profile edits are refused with "this server's profiles are managed by its website".
|
||||
Placements stay the server's either way (D222): the site reads them and edits them through the bridge.
|
||||
|
||||
**A profile is a named description of an NPC:**
|
||||
|
||||
- **Appearance:** name (or a list to pick from), the kits it wears, body type, and the prefab it starts from.
|
||||
@@ -183,7 +196,7 @@ Borrowed ideas are marked with their source; everything else is new. Stage numbe
|
||||
| **Admin placement in game** by chat command (§5), persistent, with respawn delays; the site lists and edits the placements | 3, 4 |
|
||||
| **Correct accounting**: an NPC is never counted as a player; its name reaches the killfeed, event log and death screen; kills are counted per profile | 2, 4 |
|
||||
| **Per-profile stats and titles**: "Warden kills", boss kills; the killing blow and every player who did damage | 4 |
|
||||
| **Caps**: per server, per owner, per profile, a spawn-rate limit, and a performance budget | 2 |
|
||||
| **Cost warnings, not default caps (D227)**: what N NPCs cost the server, measured in stage 1, shown when an admin places them, on the site's profile and placement pages, and in `doctor`. Caps (per server, owner or profile, and a spawn rate) exist only when an admin sets them | 2, 4 |
|
||||
| **Event ownership**: run-owned NPCs with the bridge's restart and teardown guarantees | 4 |
|
||||
| **Waves and phases** without a core change: a phase advances on "n NPCs of profile X died", and on "the boss fell below 50%" | 4, 6 |
|
||||
| **Zone tethering**: an NPC held inside a ZoneManager zone (from redesign §3) | 5 |
|
||||
@@ -193,7 +206,7 @@ Borrowed ideas are marked with their source; everything else is new. Stage numbe
|
||||
| **Quest-giver or vendor**: passive, press E for a site-written message | 6 |
|
||||
| **The live map and the app**: markers for event NPCs and bosses, "guards left: 3/8" | 8 |
|
||||
| **Operator-friendly**: shipped in the bundle, no phone-home, no image files, no boot scan; `doctor` reports it; RunicNPC's permissions appear in the site's permission manager like any plugin's | 2, 4 |
|
||||
| **An API for other plugins**, versioned, documented, and usable without Runic Gateway at all if §11 Q1 says so | 2, 9 |
|
||||
| **An API for other plugins**, versioned, documented, and usable without Runic Gateway at all (D221) | 2, 9 |
|
||||
|
||||
---
|
||||
|
||||
@@ -209,7 +222,7 @@ matched by accident. The first draft, fixed in stage 2 and published as `docs/ru
|
||||
| `RunicNpc_Spawn(Vector3 at, string profile, string owner, JObject overrides)` → `BasePlayer` | Spawns one NPC, or returns null and logs why. `overrides` may change any profile value for this NPC only. |
|
||||
| `RunicNpc_Despawn(ulong netId)` / `RunicNpc_DespawnOwner(string owner)` → `int` | Removes one, or all of an owner's. |
|
||||
| `RunicNpc_List(string owner)` → `List<Dictionary<string, object>>` | The owner's live NPCs: id, profile, name, position, health. |
|
||||
| `RunicNpc_Profiles()` / `RunicNpc_SetProfiles(JObject all)` | Reads, or replaces, the profile set (§11 Q1 decides who may). |
|
||||
| `RunicNpc_Profiles()` / `RunicNpc_SetProfiles(JObject all)` | Reads, or replaces, the profile set. Replacing marks the server as managed by a site (D221). |
|
||||
| `RunicNpc_Placements()` / `RunicNpc_SetPlacement(...)` / `RunicNpc_RemovePlacement(string id)` | The persistent placements (§2). |
|
||||
| `RunicNpc_IsRunicNpc(BaseEntity e)` → `bool`, `RunicNpc_ProfileOf(BaseEntity e)` → `string` | Lets another plugin tell our NPCs apart. |
|
||||
|
||||
@@ -236,11 +249,15 @@ permissions reach the site's permission manager through the inventory, like any
|
||||
| `/rnpc near [radius]` | Lists placements and live NPCs near you | `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` |
|
||||
| `/rnpc tp <placement>` | Teleports you to a placement | `runicnpc.admin` |
|
||||
| `/rnpc respawn [placement\|all]` | Respawns a placement's NPC now | `runicnpc.admin` |
|
||||
| `/rnpc clear <owner>` | Removes every NPC of an owner (e.g. a stuck run) | `runicnpc.admin` |
|
||||
|
||||
**Every placement is checked against Rust's navmesh (D219).** On the navmesh, the NPC roams, chases and fights
|
||||
**Every placement is checked against Rust's navmesh (D219).** Every placement also answers with the
|
||||
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).
|
||||
|
||||
@@ -303,7 +320,7 @@ needs a player in game writes that walk down, and it is done before the stage cl
|
||||
|
||||
- `LICENSE.md` (GPL-3.0-or-later), `CODE_OF_CONDUCT.md`, `CONTRIBUTING.md` (with the AI-disclosure rule),
|
||||
`SECURITY.md`, `README.md`, PR template.
|
||||
- Branches `main` and `edge` (§11 Q5).
|
||||
- Branches `main` and `edge` (D226).
|
||||
- **CI on every PR:** a static reader like Rust-Plugins' `checkPlugin.js`: every hook it declares is known, none
|
||||
returns a value where one would cancel a game action, and the API version in the source equals the manifest's.
|
||||
- **Release on `main`:** `runicnpc-<ver>.tar.gz` holding `runicnpc/RunicNPC.cs` and a `manifest.json` (version, API
|
||||
@@ -324,7 +341,8 @@ A harness plugin (`tools/RunicNpcHarness.cs`) answers, on **both** rigs, what st
|
||||
2. `enableSaving = false` holds across a hard kill and restart (§1.3 did this for NpcSpawn only).
|
||||
3. Which ranges and scales hold on the brain without our own states, and which need them.
|
||||
4. Navmesh coverage: a placement check at every monument of the 6000 map, and on a roof.
|
||||
5. The cost of spawning 1, 10 and 100, and of 100 idle and 100 fighting, as the server's frame time.
|
||||
5. The cost of spawning 1, 10 and 100, and of 100 idle and 100 fighting, as the server's frame time. These numbers
|
||||
are the cost warning's (D227), so they are measured on both rigs and on the 6000 map.
|
||||
6. The name in the death screen, and what the bridge publishes for a kill by and of our NPC.
|
||||
|
||||
**Done when** each has a measured answer written into this plan, and the org lead has picked anything the answers
|
||||
@@ -334,7 +352,8 @@ leave open.
|
||||
|
||||
- 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; caps and a spawn-rate limit.
|
||||
- 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`.
|
||||
|
||||
**Tested by** the harness asserting each call's result (PASS/FAIL lines read back over the panel), plus restart
|
||||
@@ -369,7 +388,7 @@ Across four repositories, split into 4a–4c if it grows:
|
||||
- per-profile stats and titles.
|
||||
- **Installer and egg:**
|
||||
- RunicNPC becomes a third artefact in the Rust bundle, pinned and checksummed like the plugin and the sidecar
|
||||
(§11 Q6);
|
||||
(D224);
|
||||
- `doctor` reports it missing or edited;
|
||||
- the egg installs it.
|
||||
|
||||
@@ -415,6 +434,8 @@ in the Android app.
|
||||
- **The whole acceptance walk on both rigs, with a player.**
|
||||
- **Operator documentation:** `docs/runicnpc/` gets INSTALL and a command reference; `module-rust`'s OPERATING notes
|
||||
list it as required.
|
||||
- **Publishing (D224):** the Gitea release is the source of record. Other download sites (uMod, Codefling) are
|
||||
decided then, each against its own rules, for example uMod's review guidelines.
|
||||
- **v1.0.0 released, and `module-rust` then requires it:**
|
||||
- the bundle lists it;
|
||||
- the module refuses NPC steps on a server without it, saying why;
|
||||
@@ -444,6 +465,9 @@ does not wait for a bridge release, or the reverse.
|
||||
|
||||
## 11. Questions for the org lead
|
||||
|
||||
**All eight were answered on 2026-09-30, as recommended except Q6 (D224 adds Gitea and other download sites)
|
||||
and Q7 (D227: no default caps, a cost warning instead). They are kept as asked.**
|
||||
|
||||
**Q1. Can RunicNPC be used without Runic Gateway?** Picture a server owner who installs only RunicNPC, from uMod.
|
||||
|
||||
- **(a, recommended) Yes.** Without a site, profiles live in RunicNPC's data file and console commands edit them.
|
||||
|
||||
Reference in New Issue
Block a user