Merge pull request 'docs(runicnpc): stage 0 as built, D229–D230' (#299) from docs/runicnpc-stage0 into main

Reviewed-on: #299
This commit is contained in:
2026-09-30 02:05:26 +00:00
2 changed files with 35 additions and 2 deletions

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–D228), and the rest of this plan waits for it.**
[`../../runicnpc/PLAN.md`](../../runicnpc/PLAN.md) (D214–D230), 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

@@ -1,6 +1,8 @@
# RunicNPC — the plan
**Status:** plan, written 2026-09-30. No code yet. **Its eight questions (§11) were answered the same day: D221–D228 (§0).**
**Status:** plan, written 2026-09-30. Its eight questions (§11) were answered the same day: D221–D228 (§0).
**Stage 0 built 2026-09-30** (runicnpc-rust#1, §9): an empty plugin that loads on both rigs. It is closed by the
first release, v0.1.0, at the `edge`→`main` cutover. D229–D230 were decided with it.
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
@@ -38,6 +40,8 @@ architectural or design decision is implemented.
| **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). | — |
| **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`. |
**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
@@ -332,6 +336,35 @@ needs a player in game writes that walk down, and it is done before the stage cl
**Done when** an empty plugin releases through CI and loads on both rigs.
**As built (2026-09-30, runicnpc-rust#1):**
- **The plugin** has `// Requires: Kits` and `[Info("RunicNPC", "Runic Gateway", "0.0.0")]`, whose version the
release replaces. It answers `RunicNpc_ApiVersion()` (API 1) and `rnpc.status` (version, API version, which
hooks have fired). It spawns nothing.
- **`plugin.toml`** (D230) declares `api = 1`, `requires_plugins = ["Kits"]` and the floors it was loaded on:
**Oxide 2.0.7726** and **Carbon 2.0.259**. The Oxide floor is newer than the bridge's 2.0.7585, because the rig
runs 7726 and RunicNPC has never run on anything older.
- **`scripts/checkPlugin.js`** runs the bridge's checks (every hook listed in `ExpectedHooks` and void unless
listed in `ANSWERS_DELIBERATELY`; chat-command signatures). It adds three of its own:
- no `RunicNpc_*` call may be public without `[HookMethod]`, because `Call` cannot reach it (the trap in §1.2);
- `// Requires:` must equal `requires_plugins`, and Kits must be in it;
- there must be exactly one `[Info]` line, because the release stamps that line.
It has 23 self-tests, including the real plugin and a CRLF checkout: on Windows, an attribute pattern that
only knew `\n` stopped seeing `[HookMethod]`.
- **The release** reuses Rust-Plugins' release engine unchanged. Its packaging step ships
`runicnpc-<ver>.tar.gz`, holding `runicnpc/RunicNPC.cs` and `manifest.json`, whose fields are component,
version, commit, repo, **`api`**, the floors, `requires_plugins` and `files` with each file's sha256. It ships
`SHA256SUMS` beside it. It does not ask the installer to rebuild its bundle until stage 4 makes RunicNPC part of
that bundle.
- **`tools/`**: `rig.js` and **`console.js`**, not `con.js`. `CON` is a reserved device name on Windows, so git
there cannot open a file of that name, even with an extension. The panel address and server ids moved into
a git-ignored `tools/rigs.json`.
- **Loaded from the branch on both rigs:** `rnpc.status` answered `api=1 hooks=1 fired=1` on Oxide and on Carbon
(Carbon compiled it in 217 ms).
- Also updated: the workspace `CLAUDE.md` repository table, which now lists every org repository, and the org
landing page (`.profile#7`).
### Stage 1 — The spike
A harness plugin (`tools/RunicNpcHarness.cs`) answers, on **both** rigs, what stage 2 depends on: