docs(runicnpc): stage 9d server-side walk; animals, heals and zone flags fixed (D320-D322)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
This commit is contained in:
2026-10-07 13:43:36 -05:00
parent d6e07b1b71
commit b2afe7598c
4 changed files with 51 additions and 5 deletions

View File

@@ -164,8 +164,10 @@ history, and the token is unchanged.
3. **The plugin:** copy `runicgateway-rust-plugin/RunicGateway.cs` from the tarball into
`oxide/plugins/` or `carbon/plugins/`, and every other `.cs` the tarball's `manifest.json` lists
in `files` beside it — from protocol 13 that is `RunicGatewayZones.cs`, which lets ZoneManager count a
player already standing in a zone when it opens or comes back after a restart. It is optional: leave
it out and events still score everybody, but ZoneManager's own flags miss that player. The second is
player already standing in a zone when it opens or comes back after a restart, and (from 0.2.0) has
ZoneManager enforce the flags of a zone opened after it loaded. It is optional: leave it out and
events still score everybody, but ZoneManager's own flags miss that player, and an event zone's
flags such as PvpGod or NoBuild may not hold at all. The second is
`RunicGatewayDomes.cs`, which lets the bridge ask ZoneDomes for a dome over an event zone; leave it
out and zones open without one. To name the server, create its config first —
`oxide/config/RunicGateway.json` or `carbon/configs/RunicGateway.json` — holding

View File

@@ -2153,6 +2153,13 @@ connected player ZoneManager's own `IsPositionInZone` places inside, through Zon
entry anyway. It fixes **every** zone on the server, not only the bridge's. It sweeps all zones once when
it patches, and re-patches when ZoneManager reloads. `rgz.status` prints its state.
**From 0.2.0 it also has ZoneManager enforce a new zone's flags** (RunicNPC D322). ZoneManager subscribes
the hooks behind its flags (`OnEntityTakeDamage` for PvpGod and the other damage flags, `OnEntityBuilt`
for NoBuild, and the rest) only for the zones it had when it loaded, so a zone made later through its
API, which is every zone an event opens, enforced none of them. On the same tick it sweeps, the helper
calls ZoneManager's own `UpdateHookSubscriptions` (private; found by reflection). A ZoneManager without it
is warned about, and `rgz.status` says "new zones' flags NOT refreshed"; the first job still works.
The bridge never depends on it. `server.hello` carries, whenever ZoneManager is loaded:
```json
@@ -2275,7 +2282,7 @@ frame from an older plugin has none:
| Field | Counted from | Notes |
|---|---|---|
| `animalKills` | `OnEntityDeath`, victim a `BaseNpc` | **Also** counted in `npcKills`, which keeps meaning every NPC and animal so the public column does not change mid-wipe. Human NPCs are the difference (D209) |
| `animalKills` | `OnEntityDeath`, victim a `Rust.Ai.Gen2.BaseNPC2` other than `ScientistNPC2`, or a `BaseNpc` | **Also** counted in `npcKills`, which keeps meaning every NPC and animal so the public column does not change mid-wipe. Human NPCs are the difference (D209). Rust's animals moved to `BaseNPC2` (stag, boar, wolf, bears, big cats, crocodile, farm animals, critters, sea life); until RunicNPC D320 the bridge tested `BaseNpc` alone and counted none of them. `ScientistNPC2` is a person: it counts in `npcKills` only |
| `weaponKills` | every credited kill, any victim | By the **same weapon short prefab name the killfeed carries** (`WeaponPrefab`, else `Weapon`). The site classifies them into bow, melee, blade and revolver lists it keeps (§5.3), so a new Rust weapon needs no plugin release |
| `headshots` | the killing blow's `HitInfo.isHeadshot`, any victim | |
| `bestPvpM`, `bestPveM` | the killfeed's distance | **This interval's maximum, not a sum.** The site keeps the running best with `GREATEST`. PvE is NPCs and animals |
@@ -2283,7 +2290,7 @@ frame from an older plugin has none:
| `crafted` | `OnItemCraftFinished`, by `item.info.category` lower-cased | Every category is sent; the site reads `attire` and `weapon`. Counts `item.amount`. The crafter is `ItemCrafter.owner` (the task carries none) |
| `built` | `OnEntityBuilt` placing a `BuildingBlock` | A deployable is not a structure |
| `repaired` | `OnStructureRepair` | The hook fires on every hammer hit **before** the game decides there is anything to repair, the resources for it, or no recent attack. So the health is read then and again next tick, and only a hit that raised it counts |
| `healed` | `OnHealingItemUse` on **another** player; `OnPlayerRevive` | Yourself never counts (D174). A syringe on a downed player raises both hooks for one use; it counts once. The heal's target is an `IMedicalToolTarget` in current Rust, so the bridge takes it as `object` and counts only a player |
| `healed` | `OnHealingItemUse` on **another** player; `OnPlayerRevive` | Yourself never counts (D174). A syringe on a downed player raises both hooks for one use, the heal first; it counts once, whichever hook comes first. The hook is `(tool, fromPlayer, toTarget)`: until RunicNPC D321 the bridge took two parameters, read the healer as the target and counted no heal at all. The target is an `IMedicalToolTarget`, so the bridge takes it as `object` and counts only a player |
| `rockets` | `OnRocketLaunched` | |
| `explosives` | `OnExplosiveThrown`, `OnExplosiveDropped` | A `TimedExplosive` that deals damage: a supply signal and a smoke grenade go through the same hooks and do not count |
| `missions` | `OnMissionSucceeded(mission, instance, assignee)` | Rust's own NPC missions (D173), credited to the hook's `assignee`. A failed or abandoned one raises a different hook and never counts |