RunicNpc_AddPlacement creates a placement and names it as /rnpc place
does (D241, D246). A position without y is a map point: it is put on the
ground there (terrain and rock, never a building or a tree, D245), then
checked against the navmesh like an in-game placement. It answers the id,
the grounded position, whether the spot is player-built, and the cost
warning, or the in-game refusal sentence.
RunicNpc_RenamePlacement and RunicNpc_RespawnPlacement do what rnpc
rename and rnpc respawn do. OnRunicNpcPlacementChanged(id, change,
previous) is raised on every set, remove and rename, from the API or in
game, so the bridge can tell the site at once.
rnpc place and here now share CreatePlacement with the API, so both give
the same refusals. The test harness gains an api3 group; all 157 checks
pass on the Oxide and Carbon rigs.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
The chat command /rnpc and the same verbs as rnpc.<verb> in a console
(PLAN.md §5), behind runicnpc.place and runicnpc.admin:
- place / here with key=value options in any order (D242); placements
made in game are named <profile>-<n> and renamable (D241).
- remove, rename, near, info (the NPC you look at), profiles, tp,
respawn, clear, and rnpc.profile create|show|set|delete for a
standalone server (refused while the site manages profiles, D221).
- path record / point / undo / save [loop|back] / cancel / list /
delete (D240). A point an NPC cannot walk to from the last one is
refused, as is a loop that cannot close: Rust's path query says so.
- A roamer may stand on a player-built floor, with a warning (D239).
If the floor is destroyed under a live NPC, Rust leaves it standing
in the air, so the brain puts it on the nearest navmesh within 2 s;
a placement whose spot is off the mesh respawns on the nearest.
- The API's SetPlacement now refuses a roamer off the navmesh, as the
command does; placements report a note while they fall back.
- Pos.V and Profile.IsSentry no longer leak into the JSON files.
The harness gains the cmd and floor groups. Both rigs: 134/134 in one
rnt.run all, rnpc reload 5/5, server restart 5/5.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
RunicNPC now spawns its own NPC: Rust's scientist with its ScientistNPC and
ScientistBrain swapped for ours, copying a fixed field list generated from
Rust's unmodified assembly (D232, tools/fieldlist). Profiles live in
data/RunicNPC/profiles.json in the approved shape (D238); placements persist
with each/group respawn (D236) and wait for a missing profile or route
(D237); roamers wander, follow Rust's monument paths, or walk a route (D233,
D234), with our own chase where Rust's needs an AI zone; sentries hold their
spot; NPCs walk home and sleep past 160 m of any player (D235). Spawns wait
for the navmesh and are spread over frames; caps are off by default and the
cost warning is shown instead (D227). The whole PLAN.md section 4 API and its
hooks are in, documented in docs/runicnpc/API.md.
tools/RunicNpcTest.cs is the stage 2 harness; every group passed on both
rigs, and after a plugin reload and a server restart. checkPlugin no longer
counts an override (RunicNpcPlayer.OnDied) as a hook.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
A developer plugin, never shipped, that measured the six questions stage 2
depends on (docs/runicnpc/PLAN.md §9, stage 1) on both rigs: the subclass
swap, saving across a hard kill, what Rust's brain honours, navmesh coverage,
the cost of 1/10/100 idle and fighting, and the death screen and bridge frames.
It spawns stand-in players (player.prefab, a made-up user id, IsNpc false) as
targets, at the org lead's suggestion. It needs a hidden Kits kit, rnhrevolver.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
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
The repository was created empty, so this one commit goes to main directly to
give `edge` something to branch from (stage 0, docs/runicnpc/PLAN.md §9). A
`chore:` subject so the release workflow, when it lands, cuts nothing for it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY