feat: stage 0, an empty RunicNPC that releases through CI
All checks were successful
PR Checks / plugin-checks (pull_request) Successful in -1m44s
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:
107
CONTRIBUTING.md
Normal file
107
CONTRIBUTING.md
Normal file
@@ -0,0 +1,107 @@
|
||||
# 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`](https://gitea.whitlocktech.com/RunicGateway/docs/src/branch/main/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](CODE_OF_CONDUCT.md).
|
||||
|
||||
## Ways to contribute
|
||||
|
||||
- **Report a bug** or **request a feature** through the
|
||||
[issue tracker](https://gitea.whitlocktech.com/RunicGateway/runicnpc-rust/issues)
|
||||
(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](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:
|
||||
|
||||
```bash
|
||||
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
|
||||
|
||||
```bash
|
||||
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 `ExpectedHooks`** in the plugin, so `rnpc.status` can report whether it
|
||||
fires.
|
||||
- **A hook that returns a value** changes what the game does. Add it to `ANSWERS_DELIBERATELY` in
|
||||
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
|
||||
|
||||
1. Branch from an up-to-date **`edge`** with a descriptive name (`feat/…`, `fix/…`, `docs/…`,
|
||||
`chore/…`).
|
||||
2. Keep changes focused; small PRs are easier to review.
|
||||
3. Open a pull request against `edge`. Fill out the PR template, including the **AI-assisted
|
||||
contributions** disclosure.
|
||||
4. A maintainer reviews it. `edge` is cut over to `main` for releases.
|
||||
|
||||
### Commit messages
|
||||
|
||||
We use [Conventional Commits](https://www.conventionalcommits.org/) — `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>` or
|
||||
`Assisted-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](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.
|
||||
Reference in New Issue
Block a user