feat: stage 0, an empty RunicNPC that releases through CI
All checks were successful
PR Checks / plugin-checks (pull_request) Successful in -1m44s

The repository RunicNPC is built in (docs/runicnpc/PLAN.md §9, stage 0):

- plugin/RunicNPC.cs: `// Requires: Kits` (D217), `[Info]` with the 0.0.0
  placeholder the release stamps, `RunicNpc_ApiVersion()` (API 1), and
  `rnpc.status`, which reports the version and which hooks have fired. It
  spawns nothing.
- plugin.toml: the API version, the framework floors it was loaded on
  (Oxide 2.0.7726, Carbon 2.0.259) and requires_plugins = ["Kits"].
- scripts/checkPlugin.js, adapted from Rust-Plugins': every hook listed and
  void unless written down; chat-command signatures; every RunicNpc_ call
  reachable by Call (the HumanNPC trap, PLAN.md §1.2); ApiVersion,
  `// Requires:` and [Info] agreeing with plugin.toml. 23 self-tests, including
  the real plugin and a CRLF checkout.
- PR Checks on PRs into main and edge; the release workflow on main, with
  Rust-Plugins' release engine unchanged and an adapter that ships
  runicnpc-<ver>.tar.gz (runicnpc/RunicNPC.cs + manifest.json) and SHA256SUMS.
  No bundle dispatch until stage 4.
- tools/: the rig panel scripts, with the panel and server ids moved into a
  git-ignored tools/rigs.json. `con.js` became `console.js`: CON is a reserved
  device name on Windows, and git there cannot open the file.
- README, CONTRIBUTING (edge-based flow, AI disclosure, borrow-not-copy),
  SECURITY, the code of conduct, issue and PR templates.

`feat:` so the cutover to main cuts the first release, 0.1.0.

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-29 21:01:49 -05:00
parent 8641d8fb2e
commit 249f2e513f
19 changed files with 2027 additions and 4 deletions

View File

@@ -1,9 +1,82 @@
# RunicNPC
Runic Gateway's own NPC plugin for [Rust](https://rust.facepunch.com/), on Oxide and Carbon.
Runic Gateway's own NPC plugin for [Rust](https://rust.facepunch.com/), on **Oxide and Carbon**.
The plan of record is
Other plugins drive it through an API, and admins use it directly in game through chat commands. It
works on its own, and on a [Runic Gateway](https://gitea.whitlocktech.com/RunicGateway) server the
website authors its NPC profiles and events use its NPCs. The plan of record, stage by stage, is
[`docs/runicnpc/PLAN.md`](https://gitea.whitlocktech.com/RunicGateway/docs/src/branch/main/runicnpc/PLAN.md).
This repository is being set up (stage 0); work lands on `edge` and is cut over to `main` for releases.
Licensed GPL-3.0-or-later — see [LICENSE.md](LICENSE.md).
> **Status: stage 0.** The plugin loads, answers its API version, and reports on itself. It spawns
> nothing yet. Stage 1 is a measuring spike; the NPC and its API arrive in stage 2.
## Requirements
- **[Kits](https://umod.org/plugins/kits)** — required. A profile names kits, and that is how every
RunicNPC NPC is equipped (D217). The plugin declares `// Requires: Kits`, so neither framework
loads it without Kits.
- Oxide **2.0.7726** or Carbon **2.0.259**, or newer: the builds it has been loaded on
(`plugin.toml`).
## Installing it
On a Runic Gateway server, the [installer](https://gitea.whitlocktech.com/RunicGateway/installer)
and the Pterodactyl egg will install it from the Rust bundle, pinned and checksummed (D224, from
stage 4). Until then, and on any other server:
1. Download `runicnpc-<version>.tar.gz` and `SHA256SUMS` from this repository's
[releases](https://gitea.whitlocktech.com/RunicGateway/runicnpc-rust/releases), and check the
tarball against it (`sha256sum -c SHA256SUMS`).
2. Copy `runicnpc/RunicNPC.cs` into `oxide/plugins/` or `carbon/plugins/`. The framework compiles
and loads it on the write.
`runicnpc/manifest.json`, beside it, states the release's version, commit, API version, framework
floors, required plugins, and the sha256 of every file it ships.
## Checking it
```
rnpc.status
```
Answers at the server console and over RCON: the version, the API version, and which of the
plugin's hooks have fired. A hook that never fires is the first sign a Rust or framework update has
renamed it, because neither framework reports a hook that matches nothing.
## For other plugins
Every call is prefixed `RunicNpc_` and reached through `Call`:
```csharp
[PluginReference] private Plugin RunicNPC;
int api = RunicNPC?.Call<int>("RunicNpc_ApiVersion") ?? 0;
```
Stage 0 has only `RunicNpc_ApiVersion()`. The full API is planned in PLAN.md §4 and will be
documented as `docs/runicnpc/API.md` in stage 2. The API version moves when a call or a raised hook
changes shape, not on every release.
## Repository layout
| Path | What |
|---|---|
| `plugin/RunicNPC.cs` | The plugin. The only file a server gets. |
| `plugin.toml` | Its declarations: API version, framework floors, required plugins. The release copies them into the manifest. |
| `scripts/checkPlugin.js` | The static checks run on every pull request and again before a release (see its header). |
| `tools/` | Developer scaffolding for the test rigs, never shipped (see `tools/rigs.example.json`). |
## Releases
Work lands on `edge` and is cut over to `main`; every releasable push to `main` tags and publishes a
release (`.gitea/workflows/release.yml`). The version comes from Conventional Commits since the
last tag. `v1.0.0` is stage 9's release, the one `module-rust` then requires.
## Contributing
See [CONTRIBUTING.md](CONTRIBUTING.md) — including the AI-disclosure rule — and report security
problems privately as [SECURITY.md](SECURITY.md) describes.
## License
GPL-3.0-or-later — see [LICENSE.md](LICENSE.md).