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
4.7 KiB
Contributing to RunicNPC
Thanks for your interest in contributing! This repository is RunicNPC, Runic Gateway's NPC
plugin for Rust on Oxide and Carbon. What it will become, and in what order, is planned in
docs/runicnpc/PLAN.md.
Read it before proposing a feature: most are already placed in a stage.
By participating you agree to abide by our Code of Conduct.
Ways to contribute
- Report a bug or request a feature through the issue tracker (issue templates are provided).
- Improve the code or docs by opening a pull request (see below).
- Never report a security vulnerability in a public issue — see SECURITY.md.
Development setup
The plugin is deployed as source and compiled by Oxide or Carbon at load. There is no standalone build and no CI build, because compiling it needs Rust's own managed assemblies.
While developing, the loop is one copy and a wait:
cp plugin/RunicNPC.cs /path/to/rust/oxide/plugins/ # or carbon/plugins/
# The framework notices the write, recompiles, and reloads. Watch its log.
That is a developer's loop, not how a server is set up: servers get RunicNPC from a release. A change that only works when you copy it by hand is a change that does not ship.
Borrow behaviours, never code. RunicNPC may do what other NPC plugins do, but it is written from how Rust's own classes behave. NpcSpawn states no licence, so its source grants nothing and is read only as a description of what can be done (PLAN.md D214). Do not paste code from another plugin.
Checks
node scripts/checkPlugin.js
node --test scripts/checkPlugin.test.js
Dependency-free; any Node 20+ runs them. They are what CI runs on every pull request, and what the
release runs again on the commit it ships. scripts/checkPlugin.js explains each check in its
header. Two matter most when you add code:
- A new hook goes in
ExpectedHooksin the plugin, sornpc.statuscan report whether it fires. - A hook that returns a value changes what the game does. Add it to
ANSWERS_DELIBERATELYin the checker with the reason, and make it answer for RunicNPC's own NPCs only, returning null for everything else on the server.
Testing on a server
A hook binds by reflection and fails silently, so a running server is the only proof that one
fires. Every stage is tested on an Oxide server and then a Carbon server before it is
merged. tools/ holds the scaffolding used for that (see tools/rigs.example.json).
Declarations
plugin.toml and the plugin state some facts twice, and the checks hold them equal:
| What | In the plugin | In plugin.toml |
|---|---|---|
| The API version | ApiVersion |
api |
| Required plugins | // Requires: lines |
requires_plugins |
Bump the API version in both, in the same change, when a RunicNpc_* call or a raised hook changes
shape.
Branch & PR workflow
- Branch from an up-to-date
edgewith a descriptive name (feat/…,fix/…,docs/…,chore/…). - Keep changes focused; small PRs are easier to review.
- Open a pull request against
edge. Fill out the PR template, including the AI-assisted contributions disclosure. - A maintainer reviews it.
edgeis cut over tomainfor releases.
Commit messages
We use Conventional Commits — type(scope): summary (e.g.
feat(api): add RunicNpc_Spawn). The release version is derived from them: feat is a minor
release, fix and perf a patch, ! or BREAKING CHANGE a major; docs, chore, ci and
test release nothing.
AI-assisted contributions (disclosure required)
This project is developed openly with AI assistance, and we ask the same transparency of everyone. If you used an AI tool (Claude, Copilot, ChatGPT, Cursor, etc.) to help produce a contribution, you must disclose it:
- Tick the AI-usage box in the pull-request template and name the tool(s).
- Mark AI-authored commits with a trailer, e.g.
Co-Authored-By: Claude <noreply@anthropic.com>orAssisted-By: <tool>. - You remain responsible for every line you submit: review it, understand it, and make sure it is correct and that you have the right to contribute it.
Disclosed AI assistance is welcome. Undisclosed AI-generated contributions are not, and may be closed.
License
RunicNPC is licensed under the GNU General Public License v3.0 or later (see LICENSE.md). By submitting a contribution you agree that it is licensed under the same terms (inbound = outbound) and that you have the right to contribute it.