docs(rust): stage 5 built — Dangerous Treasures (PROTOCOL §20.8, PLAN_REDESIGNS §14.3.18)
- rust-link/PROTOCOL.md §20.8: hello's integrations.dangerousTreasures; the dt.started / dt.won / dt.ended events and their fields; dt.start, dt.opened and the dt.error reasons (dt-not-ready, dt-no-spot, refused among them); the tally's treasuresWon; map.live's treasure rows and their seed; the sidecar's POST /dt/start; and the website side (classes, per-viewer reading, triggers, the step, Treasure Hunter). §17.3's world row gains `treasure`. - modules/rust/PLAN_REDESIGNS.md §14.3.18: the stage-5 record. Three things §14.3.4 had wrong or unsaid (the key's join is exact; "started" is the hook, never DT's text, with a fourth outcome `refused`; the Carbon walk row now expects the step to work), ten points settled in code, the tests, the rig compile and the walk rows. Pointers from §9's summary and §14.3.4. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
This commit is contained in:
@@ -1805,7 +1805,7 @@ drawing a second time. A new map key makes the file stale, and it is ignored.
|
||||
|
||||
| Field | Rows |
|
||||
|---|---|
|
||||
| `world` | `kind` (`cargo`, `heli`, `chinook`, `bradley`, `supply`, `crate`, `boss`), `x`, `z`; a locked crate being hacked adds `hackLeftSec`, a hacked one `hacked: true`; a `boss` (protocol 13, RunicNPC D302) is one of RunicNPC's bosses placed outside any event, with its `name` |
|
||||
| `world` | `kind` (`cargo`, `heli`, `chinook`, `bradley`, `supply`, `crate`, `boss`, `treasure`), `x`, `z`; a locked crate being hacked adds `hackLeftSec`, a hacked one `hacked: true`; a `boss` (protocol 13, RunicNPC D302) is one of RunicNPC's bosses placed outside any event, with its `name`; a `treasure` (protocol 14, §20.8) is a running Dangerous Treasures chest |
|
||||
| `events` | what this site's events placed (§15.2): `kind` (`zone`, `crate`, `npc`), `runId`, `x`, `z`, and a zone's `radius` and `name` or a thing's `prefab` and `key` (the step that placed it). Protocol 13 adds, for one of RunicNPC's NPCs, its `name`, and for a boss `boss: true` and `health` (0–1); and a boss's **adds**, which no step placed, under their boss's run with `add: true` |
|
||||
| `players` | `steamId`, `name`, `x`, `z`, `sleeping`, `online`. Connected players, then offline sleepers |
|
||||
| `bases` | `kind` (`tc`, `vending`), `x`, `z`. **Positions only**: no owner, no authorised list, no shop name |
|
||||
@@ -3141,3 +3141,111 @@ it changed.
|
||||
(`map.layer.pvp.audience`), **public by default**: the game shows the zones to everybody near one, and they
|
||||
name nobody. It is drawn as a red ring with its event's name.
|
||||
- Server settings' plugin line says whether Dynamic PVP is loaded.
|
||||
|
||||
### 20.8 Dangerous Treasures — `dt.started`, `dt.won`, `dt.ended`, `dt.start` (§14.3.4, D363, D365, D371, D375)
|
||||
|
||||
nivex's **Dangerous Treasures** (3.0.0, uMod), optional like Economics (D199) and not in `overlay.toml`. It
|
||||
opens a guarded, burning treasure chest somewhere on the map, with its own NPCs, fire and marker, unlocks it
|
||||
after 300–480 s and despawns it 900 s after that if nobody empties it. The bridge reports its events, and opens
|
||||
one for a run's step through DT's own console command. The design is
|
||||
[`PLAN_REDESIGNS.md`](../modules/rust/PLAN_REDESIGNS.md) §14.3.4; what the §14.2 test found is §14.2.1 there,
|
||||
and what the build found in DT's own source is §14.3.18.
|
||||
|
||||
**Hello and status.** `integrations` gains `dangerousTreasures`:
|
||||
|
||||
```json
|
||||
"dangerousTreasures": { "loaded": true, "version": "3.0.0" }
|
||||
```
|
||||
|
||||
Hello is sent again when DT loads or unloads. Opening one also needs hello's `console.plugins` (§20.5, D363).
|
||||
`rg.world` prints `dangerousTreasures=`, `treasures=` (the running chests the bridge knows), `dtStarts=` (keys
|
||||
remembered) and `dtWarmingUp=`.
|
||||
|
||||
**Three events**, from DT's own hooks:
|
||||
|
||||
```json
|
||||
{"kind":"dt.started","type":"event","x":812.4,"z":-340.5,"key":"12:3"}
|
||||
{"kind":"dt.won","type":"event","steamId":"76561198000000001","name":"Alice",
|
||||
"invaders":["76561198000000001","76561198000000002"],"invaderCount":2,"x":812.4,"z":-340.5}
|
||||
{"kind":"dt.ended","type":"event","x":812.4,"z":-340.5}
|
||||
```
|
||||
|
||||
- **`dt.started`** is `OnDangerousEventStarted(position)`, the chest's position. **`key` is set when the start
|
||||
answers one of our `dt.start` commands.** DT raises the hook *inside* the call that opens the chest, so a
|
||||
start our `dtevent` caused is heard before the console call returns: the join is exact, not the plan's "first
|
||||
start within ten seconds".
|
||||
- **`dt.won`** is `OnDangerousEventWon(looter, invaders)`, raised when the chest is emptied, for the player who
|
||||
emptied it. `invaders` are the players who entered the event, at most 32 by Steam id; `invaderCount` counts
|
||||
them all. The hook does not say which chest, so `x`, `z` are those of the running chest nearest the winner
|
||||
(within 100 m), else the winner's own.
|
||||
- **`dt.ended`** is `OnDangerousEventEnded(position)`: won, despawned, or DT unloading.
|
||||
- **None is sent while the world is not live** (§20.5's rule). A win is still counted.
|
||||
|
||||
**The tally** gains **`treasuresWon`**, the chests a player emptied (*Treasure Hunter*, D375).
|
||||
|
||||
**`map.live`'s `world`** (§17.3) gains `kind: "treasure"` for each running chest, `x`, `z`. The bridge keeps
|
||||
the set by the start and end hooks, and **seeds it at the world's ready and at DT's load** by finding DT's
|
||||
chests in the world (a large wooden box carrying DT's `TreasureChest` component), since DT has no API that
|
||||
lists them and a hotload of the bridge hears no starts.
|
||||
|
||||
**`dt.start` — open one Dangerous Treasures event for a run (D365).**
|
||||
|
||||
```json
|
||||
{"cmd":"dt.start","reqId":"r-60","key":"12:3","level":1}
|
||||
```
|
||||
|
||||
`level` is 0 (Easy), 1 (Medium) or 2 (Hard). The bridge runs `dtevent <level>` through
|
||||
`ConsoleSystem.Run`; DT picks the spot. The answer is:
|
||||
|
||||
```json
|
||||
{"kind":"dt.opened","type":"reply","reqId":"r-60","key":"12:3","level":1,"repeat":false,"x":812.4,"z":-340.5}
|
||||
```
|
||||
|
||||
**A key already answered is answered again with its first start, `repeat: true`, and opens nothing.** Keys are
|
||||
kept seven days in `data/RunicGateway/dt-starts.json`, as a world call's are. Refusals are
|
||||
`{"kind":"dt.error","reason":…,"message":…}`:
|
||||
|
||||
| `reason` | When |
|
||||
|---|---|
|
||||
| `malformed` | No key, or one over 128 characters |
|
||||
| `bad-level` | `level` is not 0, 1 or 2 |
|
||||
| `dt-missing` | DT is not loaded |
|
||||
| `console-unavailable` | Hello's `console.plugins` is false (D363, Rust-Plugins#34) |
|
||||
| `dt-not-ready` | Nothing opened, DT's answer was its own "Manual Event Failed" message (or empty), and DT loaded under fifteen minutes ago: it is still building its spawn grid (§14.2.1) |
|
||||
| `dt-no-spot` | The same, fifteen minutes or more after DT loaded |
|
||||
| `refused` | Nothing opened and DT answered something else, in its own words: a level its config no longer has, or its console command renamed |
|
||||
|
||||
`events-disabled` and the world's `not-ready` come first, as `world.error`, as for every world verb (§15).
|
||||
"Opened" is the start hook firing, never DT's text: DT words its replies from its lang file, so the bridge
|
||||
reads DT's own "Manual Event Failed" message from DT's lang to recognise a start that found no spot. **DT's
|
||||
load is when the bridge first saw DT loaded**: DT's own load, or the bridge's when DT was already there, which
|
||||
can only make the window start late. DT's console command is a config value; the bridge runs its default,
|
||||
`dtevent`.
|
||||
|
||||
**Hooks.** `OnDangerousEventStarted`, `OnDangerousEventWon` and `OnDangerousEventEnded` join `rg.hooks`' list.
|
||||
|
||||
**The sidecar** adds `POST /dt/start`, a thin forward that keeps nothing, and stores and forwards the three
|
||||
events like any other.
|
||||
|
||||
**The website (Module-Rust).** Module-Rust needs MODULE_API 1.15.0 for this (`coreApi ^1.15.0`).
|
||||
|
||||
- **`dt.started` and `dt.won` are public kinds, `dt.ended` a staff kind.** Each row is read per viewer by
|
||||
`dangerousTreasures.shapeFor`, as a world event is (§20.5, D376): everyone gets `grid`, and for a win
|
||||
`invaderCount`; **the winner's `name` only for the presence audience**; and **`x`, `z`, `key`, the winner's
|
||||
`steamId` and the `invaders` only for staff**. The public lines read *"A Dangerous Treasures event has started ·
|
||||
K12"* and *"Alice won the treasure · K12 · 3 players fought for it"* (*"The treasure was won"* below the
|
||||
presence audience). Both are in the feed's *World events* filter.
|
||||
- **Triggers `rust.dt.started` and `rust.dt.won`** (§14.3.9): public, `everyone` the ceiling, the cooldown
|
||||
subject the server; `byEvent` on a start one of the site's steps made; the winner by in-game name only.
|
||||
- **The step `rust.dt.start`**, *Start a Dangerous Treasures event* (`risk: 'change'`, `reversible: 'none'`,
|
||||
budget `rust.dt.events`, one per step): server and difficulty. It is refused at verify where the server said
|
||||
DT is not loaded, or that `console.plugins` is false (naming Rust-Plugins#34); a server that has not said is
|
||||
left to the plugin. **`dt-not-ready` answers *"Dangerous Treasures is not ready yet"* with `retryAfterMs:
|
||||
600000`** (MODULE_API 1.15.0, D371), so core tries once more ten minutes later; `dt-no-spot` retries on core's
|
||||
ordinary delay; `malformed`, `bad-level`, `dt-missing`, `console-unavailable`, `events-disabled` and `refused`
|
||||
are not retried.
|
||||
- **Treasure Hunter (D375):** `treasuresWon` → `rust_player_wipe_stats.treasures_won`, the title category
|
||||
`treasureswon` (default *Treasure Hunter*), and the leaderboard's **Treasures** column (`sort=treasuresWon`),
|
||||
shown where the server reports DT or a row counts one (`dangerousTreasures: true` on the answer).
|
||||
- The map draws a running chest on the world layer. Server settings' plugin line says whether DT is loaded, and
|
||||
whether a step can start one; `GET /admin/rust/servers/{id}/integrations` gains `console` for it.
|
||||
|
||||
Reference in New Issue
Block a user