docs(rust): stage 6 built — Guarded Crate (PROTOCOL §20.9, PLAN_REDESIGNS §14.3.19, D380)
- rust-link/PROTOCOL.md §20.9: hello's guardedCrate with npcSpawn and events, gc.started/ended/failed, gc.place and gc.error's reasons, guardedWon, map.live's guarded rows and how they are kept, POST /gc/place, and the website side. §17.3's world row gains guarded. - modules/rust/PLAN_REDESIGNS.md: D380 (the kept crate's run-log note at placement), §14.3.19 the stage record, pointers from §9 and §14.3.5. - modules/rust/OPERATING.md: Runic Gateway's own section on Guarded Crate and NpcSpawn (install, images, what it contacts at load), after the uMod mirror. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
This commit is contained in:
@@ -5,6 +5,8 @@ configure and permission plugins. This is the surface our own deployment story h
|
||||
of, the way [`installer/INSTALL.md`](../../installer/INSTALL.md) sits on top of ServUO.
|
||||
|
||||
> **Mirrored verbatim from uMod on 2026-09-15** — 6 pages. uMod is upstream and normative.
|
||||
> The last section, [Guarded Crate and NpcSpawn](#guarded-crate-and-npcspawn), is Runic Gateway's own and
|
||||
> is not part of the mirror.
|
||||
|
||||
---
|
||||
|
||||
@@ -16,6 +18,7 @@ of, the way [`installer/INSTALL.md`](../../installer/INSTALL.md) sits on top of
|
||||
- [Plugin configuration](#plugin-configuration-plugins-configuration) — Editing a plugin's config file
|
||||
- [Data Files](#data-files-plugins-data-files) — Where plugin data lives on disk
|
||||
- [Permissions](#permissions-plugins-permissions) — Granting permissions and managing groups in-game
|
||||
- [Guarded Crate and NpcSpawn](#guarded-crate-and-npcspawn) — Runic Gateway's note on an optional plugin that needs a Codefling extension
|
||||
|
||||
---
|
||||
|
||||
@@ -369,3 +372,41 @@ That's the basics to permissions for Oxide. Permissions give you a fantastic way
|
||||
---
|
||||
|
||||
<sub>Mirrored from uMod, 2026-09-15.</sub>
|
||||
|
||||
---
|
||||
|
||||
<a id="guarded-crate-and-npcspawn"></a>
|
||||
|
||||
## Guarded Crate and NpcSpawn
|
||||
|
||||
<sub>Runic Gateway's own section, not mirrored. Design: [PLAN_REDESIGNS.md](PLAN_REDESIGNS.md) §14.3.5 (D361,
|
||||
D364); wire: [PROTOCOL.md](../../rust-link/PROTOCOL.md) §20.9.</sub>
|
||||
|
||||
Bazz3l's **Guarded Crate** (uMod) is one of the optional plugins Runic Gateway reports and drives: a guarded
|
||||
crate landing and being cleared reach the site's feed, map and *Warden* title, and an event can place one. It
|
||||
**needs NpcSpawn** for its guards, and NpcSpawn is not on uMod. Runic Gateway never ships or modifies either
|
||||
(D351, D361); an operator who wants guarded crates installs both.
|
||||
|
||||
**Installing NpcSpawn.**
|
||||
|
||||
1. Download NpcSpawn from Codefling (<https://codefling.com/extensions/npc-spawn>), a free download.
|
||||
2. Put `NpcSpawn.cs` in the plugins directory (`oxide/plugins`, or `carbon/plugins` on Carbon).
|
||||
3. Put the archive's `data/Images/` files in the data directory's `Images` folder (`oxide/data/Images`, or
|
||||
`carbon/data/Images`). **Without them NpcSpawn unloads itself.**
|
||||
4. Leave `data/NpcSpawn/` for NpcSpawn to create. On Carbon, a folder made by a panel's file manager may not be
|
||||
writable by the game, and NpcSpawn then fails until that folder is deleted and left to it.
|
||||
5. Install Guarded Crate from uMod as any other plugin.
|
||||
|
||||
**What NpcSpawn does at load: it contacts its author's server.** It calls a version server at a bare IP
|
||||
address (seen as `37.153.157.216:5000` in the §14.2 test) and downloads clothing images. An operator whose
|
||||
server may not reach the internet, or who does not want it to, should know this before installing it.
|
||||
|
||||
**Without NpcSpawn,** Guarded Crate unloads itself the next time its own schedule starts an event, and Runic
|
||||
Gateway's *Place a guarded crate* step is refused with *"Guarded Crate is loaded but NpcSpawn is missing: its
|
||||
events cannot start"*. The bridge refuses that placement itself, because Guarded Crate's `position` command does
|
||||
not check and would drop a crate with no guards. Admin → Rust servers shows NpcSpawn beside Guarded Crate.
|
||||
|
||||
**Its events** are rows in Guarded Crate's **data** file, `data/GuardedCrate.json` (Easy, Medium, Hard and Elite
|
||||
as it ships), not its config. The site offers whatever names that file holds. A crate placed by an event is
|
||||
**kept when the event ends** (D373): Guarded Crate has no way to end one event, and `gcrate stop all` ends every
|
||||
one on the server.
|
||||
|
||||
@@ -930,7 +930,7 @@ pulls) is research, not a walk, so it still comes first:
|
||||
answered before code: **written on 2026-10-14 as §14.3**, from D361–D369, and answered as D370–D376. Then the
|
||||
build, in §14.3.11's nine stages (two of them core), §13 first. **Stage 1, §13, was built on 2026-10-15
|
||||
(§14.3.14)**, with D378 and D379. **Stage 2, core's `retryAfterMs` (MODULE_API 1.15.0), was built on
|
||||
2026-10-15 (§14.3.15).** **Stage 3, TruePVE in the zone step, was built on 2026-10-15 (§14.3.16)**, and **stage 4, Dynamic PVP, the same day (§14.3.17)**, and **stage 5, Dangerous Treasures, the same day (§14.3.18).**
|
||||
2026-10-15 (§14.3.15).** **Stage 3, TruePVE in the zone step, was built on 2026-10-15 (§14.3.16)**, and **stage 4, Dynamic PVP, the same day (§14.3.17)**, and **stage 5, Dangerous Treasures, the same day (§14.3.18)**, and **stage 6, Guarded Crate, the same day (§14.3.19).**
|
||||
|
||||
**Then one walk, on Oxide and Carbon, of everything still owed (D331):** §2.7; §11's rows; §12.9; §13's and
|
||||
§14's rows; the in-game rows
|
||||
@@ -1094,6 +1094,7 @@ The org lead answered §14.3's Q26–Q32 on 2026-10-14:
|
||||
| **D377** | **The leaderboard changes only for something new and substantial.** A new title may add its column (*Safecracker*, *Scavenger*, *Treasure Hunter*, *Warden*, *Hoarder* do), but a small plugin's own numbers, such as ZLevels' levels, never become columns (org lead, 2026-10-14, confirming D374 beside D375). | Adding a column for every number a plugin reports. | 14.3.1, 14.3.6 |
|
||||
| **D378** | **The Chinook is called with no position.** It drops only at the map's own drop zones (seven on the rigs' map, all at monuments), and the one route that sends it to a chosen zone borrows the Airfield call terminal's shared state, so a player at the real terminal and a step calling at once would race for one Chinook (stage 1's spike, org lead 2026-10-15). The airdrop and the patrol helicopter take a position. | A position snapped to the nearest drop zone through the terminal's state, refused while a real Airfield call is active. | 14.3.1, 14.3.14 |
|
||||
| **D379** | **`chinook.downed` is a 24th world event**, with the credit block and the operator's rule, and counts toward *Rotorbane*: D174 counted Chinook kills there, and the plan's first draft would have dropped them (org lead, 2026-10-15). | Counting Chinook kills through the old tally, with no line; patrol helicopters only. | 14.3.1, 14.3.14 |
|
||||
| **D380** | **A guarded crate left standing is noted in the run log when it is placed, not when the run ends:** the *Place a guarded crate* step's success line says the crate is kept when the run ends and how it ends (org lead, 2026-10-15). Core gives a module no hook at a run's end for a step that is kept, so D373's note at the end would need new core work. | A run-end hook in core now (a MODULE_API minor, with the Module-uo proof), or filed for later. | 14.3.5, 14.3.19 |
|
||||
|
||||
## 11. First-class optional plugins (D199–D202)
|
||||
|
||||
@@ -2627,6 +2628,10 @@ the bridge already reads Kits' and Economics' (PROTOCOL.md §16.3), and absent w
|
||||
column and the trigger; let one time out; cancel the run and see the crate stay; unload NpcSpawn and see the
|
||||
step refused with the reason. On Carbon: refused (D363).
|
||||
|
||||
> **Built on 2026-10-15** (§14.3.19), specified in PROTOCOL.md §20.9. The events are in Guarded Crate's data
|
||||
> file, not its config; the location is a world call's (monument or point, no grid); the run-log note is written
|
||||
> at placement (D380); and the Carbon row now expects the step to work. §14.3.19 says how.
|
||||
|
||||
#### 14.3.6 ZLevels Remastered (D369, D374)
|
||||
|
||||
**Hello.** `integrations.zLevels`: `{ loaded, version }`.
|
||||
@@ -3098,6 +3103,81 @@ actions, 11 budgets, 21 option sources; the 89 routes unchanged.
|
||||
hotload the bridge while a chest stands and see it still on the map (the seed); and start one from a run and
|
||||
read its `dt.started` row's `key` from the staff events API (the web client has no staff feed view).
|
||||
|
||||
#### 14.3.19 Stage 6, built: Guarded Crate, with NpcSpawn (2026-10-15)
|
||||
|
||||
Built in Rust-Plugins, Rust-Link and Module-Rust, specified in [PROTOCOL.md](../../rust-link/PROTOCOL.md) §20.9
|
||||
and §17.3, with the operator's section in [OPERATING.md](OPERATING.md). `PROTOCOL_VERSION` stays 14. Builds:
|
||||
Rust 25902425 (changeset 167781), Oxide 2.0.7830, Carbon 2.0.262 production (the latest of each that day); the
|
||||
code read is Guarded Crate 2.0.17, still the newest on uMod, and NpcSpawn 3.4.8. **D380** answers the one point of
|
||||
§14.3.5 that could not be built as written. No MODULE_API change: `coreApi` stays `^1.15.0`.
|
||||
|
||||
**What §14.3.5 had wrong or unsaid, found in Guarded Crate's source and on the rigs:**
|
||||
|
||||
1. **The events are in its data file, not its config.** `data/GuardedCrate.json`'s `CrateEventEntries`, each
|
||||
name under the key `event display name)` (the stray bracket is Guarded Crate's). Its console command is a
|
||||
config value, read from the config.
|
||||
2. **`gcrate position` does not check NpcSpawn** (only `start` does). Without NpcSpawn a placed crate lands with
|
||||
no guards and nothing stops a hack, so `npcspawn-missing` is the bridge's own refusal, not a courtesy.
|
||||
3. **The key's join is exact**, as Dangerous Treasures' is (§14.3.18): the start hook fires inside the call that
|
||||
creates the event. §14.3.9's "first start within ten seconds" is not needed for either.
|
||||
4. **Its unload and `stop all` raise no hook**, and the ended hook does not say which event ended. The bridge
|
||||
reads Guarded Crate's private list of running events by reflection (it has no API that lists them) to seed
|
||||
the map after a hotload, to drop events `stop all` ended, and to tell which event a clearing ended.
|
||||
5. **Its cargo plane was an airdrop.** Stage 1 announces every cargo plane's spawn as `airdrop.called`, so each
|
||||
guarded crate also said *"An airdrop was called"*; found on the rig, fixed here with Guarded Crate's own
|
||||
`API_IsGuardedCrateCargoPlane`. §14.3.1's walk row *"a Guarded Crate crate raising no Rust frame"* now holds
|
||||
for the plane as well as the crate.
|
||||
6. **The run-log note is written at placement (D380):** core has no run-end hook for a kept step.
|
||||
7. **The location is a world call's**: a monument with offsets, or a point. §14.3.5 said "monument, grid or
|
||||
point", but no step takes a grid; the zone and call steps take these two.
|
||||
8. **The Carbon row is out of date**, as §14.3.18 found for DT: the console probe is true on the Carbon rig, and
|
||||
`gcrate` ran there. The step is expected to work on Carbon.
|
||||
|
||||
**Settled in the code, and overrulable:**
|
||||
|
||||
1. **A clearing counts only for a player.** A last guard killed by another NPC (RunicNPC's, say) or by nothing
|
||||
is `gc.ended` with no winner: no *Warden* count, no trigger.
|
||||
2. **`rust.gc.ended` fires only for a crate a player cleared**; an ending with nobody, and a timeout, raise no
|
||||
trigger. Both are still feed lines (*"A guarded crate ended with nobody clearing it"* public, the timeout
|
||||
staff's).
|
||||
3. **Whether anybody cleared it (`won`) is public**; the clearer's name is the presence audience's, the Steam
|
||||
id, the position and a step's key staff's.
|
||||
4. **The event param is a name, not `server/name`.** The location already names the server; the list offers
|
||||
every server's names once each, with the servers that have them, and Guarded Crate's four defaults where no
|
||||
server has said. Verify refuses a name the chosen server's report does not list.
|
||||
5. **`gc-too-close` is retried** on core's ordinary delay (the other crate may be cleared); every other plugin
|
||||
refusal is permanent.
|
||||
6. **A height is not sent**: the crate falls to the ground and its guards stand on it.
|
||||
7. **The column is *Crates cleared***, shown where the server reports Guarded Crate or a row counts one, as
|
||||
Treasures is.
|
||||
8. **Where Guarded Crate's list cannot be read** (its shape changed), the hooks alone keep the set, and the log
|
||||
says so once.
|
||||
|
||||
**Tests.** Bridge: `checkPlugin.js` (84 hooks, every one void and listed), 18 tests. Sidecar: 73 tests (one new,
|
||||
the stamp), `fmt` and `clippy` clean. Module-Rust server: `test/guardedCrate.test.js`, 16 new (the public read
|
||||
the grid, never the position or the key; the clearer's name for the presence audience and the Steam id for
|
||||
staff; an ending with nobody is not a win; the feed reads a stored clearing per viewer; the report read
|
||||
leniently; the step kept, priced and without a revert; the event list from every server and the defaults; the
|
||||
dry run's refusals for Guarded Crate absent, NpcSpawn missing, the console unavailable and an unknown event,
|
||||
ignoring case, and a server that has not said left to the plugin; the key, event and location on the wire and
|
||||
the kept note; retries and permanent refusals; a repeat; the tally's count; the column's sort; the triggers and
|
||||
their variables; a crate nobody cleared and a timeout firing nothing; an old crate telling nobody), and the
|
||||
catalogue, title and registration tests extended: 643/643, imports, bundle, swagger and engagement checks.
|
||||
Client: three new in `feed.test.js`, 95/95, the build and externals. Booted against the pinned core: 47 triggers,
|
||||
14 actions, 12 budgets, 22 option sources; the 89 routes unchanged.
|
||||
|
||||
**On the rigs**, both: the bridge compiled and loaded; with Guarded Crate 2.0.17 and NpcSpawn 3.4.8 loaded,
|
||||
`rg.world` read the four events from the data file and Guarded Crate's list as readable; `gcrate start` and
|
||||
`gcrate position` (in the fully quoted form `ConsoleSystem.Run` sends) each counted a running crate and said
|
||||
`gc.started`, with no `airdrop.called` after the fix; a hotload of the bridge found the running crate again
|
||||
(*"1 guarded crate(s) after load"*); and `gcrate stop all` took it off. Both rigs were then cleaned of the two
|
||||
plugins and their files, and put back on the protocol-13 bridge. The clearing, the timeout, the step through
|
||||
the sidecar and the site are §14.3.5's walk rows, at the end walk (D331, D359).
|
||||
|
||||
**Walk rows** are §14.3.5's, with the Carbon row expecting the step to work, and three more: a Guarded Crate
|
||||
placement raising no airdrop line; `gcrate stop all` taking a crate off the map; and a crate's guards killed by
|
||||
a RunicNPC NPC, which clears it for nobody.
|
||||
|
||||
### 14.4 Questions for the org lead
|
||||
|
||||
**Answered on 2026-10-14:** Q17 as proposed, out (D358). **Q18 against the proposal: the end walk waits for
|
||||
|
||||
Reference in New Issue
Block a user