docs(rust): stage 1 built — world events on protocol 14 (PROTOCOL §20.5, D378, D379)
- rust-link/PROTOCOL.md §20.5: `world.event` and its 24 types (the type in `event`, not the envelope's `type`), the credit block, the tally's two counts, `world.call`, hello's `console`, the sidecar forward and the site. - modules/rust/PLAN_REDESIGNS.md: D378 (the Chinook is called with no position) and D379 (`chinook.downed` counts toward Rotorbane), both the org lead's on 2026-10-15; §14.3.14, the stage-1 record: the placement spike, the seven changes the build found (among them a correction to §14.2.1: Carbon refuses plugin console commands only inside a console command, so the bridge's own path works), what was settled in the code, the tests and the walk rows it adds; pointers from §14.3.1 and §14.3.8. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
This commit is contained in:
@@ -928,7 +928,8 @@ pulls) is research, not a walk, so it still comes first:
|
|||||||
9. **Rust's own world events and six more optional plugins** (§13, §14). First comes one test phase covering
|
9. **Rust's own world events and six more optional plugins** (§13, §14). First comes one test phase covering
|
||||||
all of them on both rigs (§14.2, D352); **it ran on 2026-10-14 (§14.2.1)**. Then one integration plan,
|
all of them on both rigs (§14.2, D352); **it ran on 2026-10-14 (§14.2.1)**. Then one integration plan,
|
||||||
answered before code: **written on 2026-10-14 as §14.3**, from D361–D369, and answered as D370–D376. Then the
|
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.
|
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.
|
||||||
|
|
||||||
**Then one walk, on Oxide and Carbon, of everything still owed (D331):** §2.7; §11's rows; §12.9; §13's and
|
**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
|
§14's rows; the in-game rows
|
||||||
@@ -1090,6 +1091,8 @@ The org lead answered §14.3's Q26–Q32 on 2026-10-14:
|
|||||||
| **D375** | **Three new titles (Q31):** *Treasure Hunter* (DT treasures won), *Warden* (guarded crates cleared), *Hoarder* (the most RP, above 0), renamable, each with a column on servers that report the plugin. | No titles for the plugins' counts. | 14.3.4, 14.3.5, 14.3.7 |
|
| **D375** | **Three new titles (Q31):** *Treasure Hunter* (DT treasures won), *Warden* (guarded crates cleared), *Hoarder* (the most RP, above 0), renamable, each with a column on servers that report the plugin. | No titles for the plugins' counts. | 14.3.4, 14.3.5, 14.3.7 |
|
||||||
| **D376** | **A public line names a player only for the presence audience (Q32):** the event and its grid are public (*"Patrol helicopter downed at G8"*), and the name shows only to the audience the operator chose for presence. | The name always public (D353 as written); the whole line hidden below the presence audience. | 14.3.1 |
|
| **D376** | **A public line names a player only for the presence audience (Q32):** the event and its grid are public (*"Patrol helicopter downed at G8"*), and the name shows only to the audience the operator chose for presence. | The name always public (D353 as written); the whole line hidden below the presence audience. | 14.3.1 |
|
||||||
| **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 |
|
| **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 |
|
||||||
|
|
||||||
## 11. First-class optional plugins (D199–D202)
|
## 11. First-class optional plugins (D199–D202)
|
||||||
|
|
||||||
@@ -2361,6 +2364,11 @@ not touched:** `requires_plugins` stays Kits, ZoneManager and RunicNPC, and none
|
|||||||
|
|
||||||
#### 14.3.1 Rust's own world events (§13; D349, D353–D356, D366, D367)
|
#### 14.3.1 Rust's own world events (§13; D349, D353–D356, D366, D367)
|
||||||
|
|
||||||
|
> **Built as stage 1 (§14.3.14), with seven changes the build found.** The one that matters to a reader of the
|
||||||
|
> examples below: **a world event's type is in `event`, not `type`**, which is the envelope's. There are
|
||||||
|
> **24 types** with `chinook.downed` (D379); the Chinook takes no position (D378); `airdrop.called` comes
|
||||||
|
> from the plane's spawn. [PROTOCOL.md](../../rust-link/PROTOCOL.md) §20.5 is the wire as built.
|
||||||
|
|
||||||
**Hello.** Nothing new: the events need no plugin. Hello gains one fact the steps below need, **`console`**:
|
**Hello.** Nothing new: the events need no plugin. Hello gains one fact the steps below need, **`console`**:
|
||||||
`{ plugins: true | false }`, found at load by running one of the bridge's own read-only commands through
|
`{ plugins: true | false }`, found at load by running one of the bridge's own read-only commands through
|
||||||
`ConsoleSystem.Run`, the route a plugin command takes. On Carbon 2.0.262 it is `false` (D363), and the site
|
`ConsoleSystem.Run`, the route a plugin command takes. On Carbon 2.0.262 it is `false` (D363), and the site
|
||||||
@@ -2673,7 +2681,7 @@ in the app; wipe and see the points stay.
|
|||||||
| Kind | New in protocol 14 |
|
| Kind | New in protocol 14 |
|
||||||
|---|---|
|
|---|---|
|
||||||
| Hello | `console.plugins`; `integrations.truePve`, `dynamicPvp`, `dangerousTreasures`, `guardedCrate` (with `npcSpawn`, `events`), `zLevels`, `serverRewards` |
|
| Hello | `console.plugins`; `integrations.truePve`, `dynamicPvp`, `dangerousTreasures`, `guardedCrate` (with `npcSpawn`, `events`), `zLevels`, `serverRewards` |
|
||||||
| Events | `world.event` (23 types); `pvp.zone.created` / `deleted`; `dt.started` / `won` / `ended`; `gc.started` / `ended` / `failed` |
|
| Events | `world.event` (24 types with `chinook.downed`, D379; the type in `event`, §14.3.14); `pvp.zone.created` / `deleted`; `dt.started` / `won` / `ended`; `gc.started` / `ended` / `failed` |
|
||||||
| Commands | `world.call`; `dt.start`; `gc.place`; `points.pay` / `balances` / `adjust`; `world.zone`'s `truePve` |
|
| Commands | `world.call`; `dt.start`; `gc.place`; `points.pay` / `balances` / `adjust`; `world.zone`'s `truePve` |
|
||||||
| Tally | `cratesHacked`, `dropsLooted`, `treasuresWon`, `guardedWon`; `points` (a value). **`heliKills` and `apcKills` leave the tally**: the site counts them from `world.event`'s `credit` (D372) |
|
| Tally | `cratesHacked`, `dropsLooted`, `treasuresWon`, `guardedWon`; `points` (a value). **`heliKills` and `apcKills` leave the tally**: the site counts them from `world.event`'s `credit` (D372) |
|
||||||
| `map.live` | `world` kinds `treasure` and `guarded`; the `pvp` layer |
|
| `map.live` | `world` kinds `treasure` and `guarded`; the `pvp` layer |
|
||||||
@@ -2814,6 +2822,79 @@ ten minutes"*.
|
|||||||
**Tests (website).** The delay honoured; clamped at both ends; counted as an attempt; no retry for a run paused
|
**Tests (website).** The delay honoured; clamped at both ends; counted as an attempt; no retry for a run paused
|
||||||
or cancelled in the wait; `MODULE_API.md` and the classify rules updated.
|
or cancelled in the wait; `MODULE_API.md` and the classify rules updated.
|
||||||
|
|
||||||
|
#### 14.3.14 Stage 1, built: Rust's own world events (2026-10-15)
|
||||||
|
|
||||||
|
Built on `edge` in Rust-Plugins, Rust-Link and Module-Rust, specified in
|
||||||
|
[PROTOCOL.md](../../rust-link/PROTOCOL.md) §20.5, on Rust 25902425, Oxide 2.0.7830 and Carbon 2.0.262 (the
|
||||||
|
latest of each that day). Walked at the end with everything else (D331).
|
||||||
|
|
||||||
|
**The placement spike (research, D331).** A throwaway plugin on both rigs called each event at a chosen point by
|
||||||
|
the routes the game itself has, and measured where it went:
|
||||||
|
|
||||||
|
| Event | Route | Result |
|
||||||
|
|---|---|---|
|
||||||
|
| Airdrop | `CreateEntity(cargo_plane)`, `InitDropPosition(point)`, then `Spawn()` | Released **0–1 m** above the point on both rigs; lands there. The plane crosses a 6000 map in about 480 s and drops at half way |
|
||||||
|
| Patrol helicopter | `PatrolHelicopterAI.SetInitialDestination(point)` **before** `Spawn()`, so `ServerInit` skips its random start | Came within **10–54 m** of the point after 65–165 s, then patrolled as usual |
|
||||||
|
| Chinook | It drops only at the map's `CH47DropZone`s (seven, all at monuments). Its brain's interest point: it orbited the zone 110 s and left without dropping (a drop needs it five minutes old). The Airfield terminal's statics, set 5 s after spawn: dropped 5 m from the zone. Set before spawn: it dropped at its offshore spawn and vanished | **No position (D378)**: the working route is the real terminal's shared state |
|
||||||
|
| Cargo leaving | `cargoship.egress` | **`OnCargoShipEgress` fires** on both frameworks (a natural one was seen on Oxide); the kill follows after `egress_duration_minutes`. So `cargo.left` is the egress |
|
||||||
|
|
||||||
|
**What changed from §14.3.1 as planned, each found by the build:**
|
||||||
|
|
||||||
|
1. **The type is `event`, not `type`.** §14.3.1's example wrote `"type":"heli.downed"`, but `type` is the
|
||||||
|
envelope's and the sidecar files on it: the rig's sidecar dropped every world event as untyped, the same
|
||||||
|
collision protocol 13's `world.expired` had (§19). Every frame says `"type":"event","event":"heli.downed"`.
|
||||||
|
2. **`airdrop.called` comes from the cargo plane's spawn.** The console's `supply.call` raised neither
|
||||||
|
`OnAirdrop` nor `OnCargoPlaneSignaled`, so a line from those hooks would miss it. They now only say who and
|
||||||
|
where; the drop point is otherwise read from the plane.
|
||||||
|
3. **A Bradley's `where` is told by the game's spawners**, not by `RoadSpawned`, which defaults to true (a
|
||||||
|
plugin's Bradley would read as a road one): Launch Site's when `BradleySpawner.singleton` holds it, road when
|
||||||
|
the road event's list does. **A Bradley neither holds is `other`**; its spawn says nothing, but its death is
|
||||||
|
sent and counts toward Tankbreaker, as it did under D174.
|
||||||
|
4. **`chinook.downed` (D379).** D174 counted Chinook kills toward Rotorbane; they keep counting, by the rule.
|
||||||
|
5. **The Chinook's drop is joined at the crate's landing.** The crate a Chinook drops has no net id when
|
||||||
|
`OnCrateDropped` fires (it is made just before its spawn), so the drop is joined to the crate that lands
|
||||||
|
under it within 40 m and 120 s.
|
||||||
|
6. **`world.call` runs one of the schedule's events at random, as `EventSchedule.Trigger` does, but not
|
||||||
|
`Trigger`**, which would also reset the schedule's clock: calling an airdrop must not delay the next natural
|
||||||
|
one. The schedule is found whether or not it is enabled.
|
||||||
|
7. **Carbon's console, corrected.** §14.2.1 found Carbon 2.0.262's `ConsoleSystem.Run` answers "not found" to
|
||||||
|
every plugin command. Stage 1 found that holds only for a call **inside a console command**, or in a
|
||||||
|
`NextTick` a console command queued, which is how §14.2's spike ran every test (`rgs.cmd …`). From a timer,
|
||||||
|
and from a `NextTick` queued by a background thread — **the bridge's own path for every website command** —
|
||||||
|
Carbon finds plugin commands, `c.version` included. So the console probe (D363) runs from a timer, and reads
|
||||||
|
**true on both rigs**. It also suggests D180's Carbon reload works from the website after all, and that
|
||||||
|
Rust-Plugins#34 describes the spike's context rather than the bridge's; the end walk confirms it.
|
||||||
|
|
||||||
|
**Settled in the code, and overrulable:**
|
||||||
|
|
||||||
|
- **A position never leaves the module.** The feed sends a grid; `x` and `z` reach staff only, because the map
|
||||||
|
has its own audience for where things are (D111).
|
||||||
|
- **`EventsMaxWorldCalls`** defaults to its ceiling, 10 per run per server.
|
||||||
|
- **The credit rule is on the server's settings** (Admin → Rust → the server, *World events*), and an unknown
|
||||||
|
stored word reads as the default, the killing blow.
|
||||||
|
- **`damage` is the damage each hit reported**, summed, and a credit block names at most 32 damagers.
|
||||||
|
- **The feed gains a *World events* filter**, and the two leaderboard columns sort.
|
||||||
|
- **A trigger's `player`, for a downed one, is the credited names as a phrase** (*"Alice, Bob and 2 others"*),
|
||||||
|
by the server's rule; `credited` is how many.
|
||||||
|
- **A step's answer** says how many the game started (`called`), and a note when it started fewer than asked.
|
||||||
|
|
||||||
|
**Tests.** Bridge: `checkPlugin.js` (76 hooks, every one void and listed) and a new check that the console probe
|
||||||
|
names a command the plugin declares, 18 tests. Compiled and loaded on both rigs; `heli.arrived`,
|
||||||
|
`cargo.arrived` and `airdrop.called` read back from each rig's sidecar store, and hello's
|
||||||
|
`console.plugins` on both. Sidecar: 71 tests, `fmt` and `clippy` clean. Module-Rust: 585 server tests (22 new
|
||||||
|
in `test/worldEvents.test.js`: the catalogue against the protocol's 24 types, D372's four rules against one
|
||||||
|
block and against one with nobody, the line and the count agreeing under every rule, the per-viewer reading,
|
||||||
|
the grid off the map, ingest, the triggers and their variables, the step's bounds and refusals), 84 client
|
||||||
|
tests, every check, and a boot against the pinned core (43 triggers, 12 actions, 10 budgets, 20 option sources;
|
||||||
|
the 89 routes unchanged).
|
||||||
|
|
||||||
|
**Walk rows added to §14.3.1's:** the Travelling Vendor (the spike's schedule run raised no spawn on the rig);
|
||||||
|
the road Bradleys' line (twelve were already out, so none came); the console probe after a `c.reload` typed in
|
||||||
|
Carbon's console; and a configuration save's reload from the website on Carbon (D180), which settles item 7.
|
||||||
|
|
||||||
|
**Not changed:** the Android app. It reads the API leniently, so it shows neither world events nor the two
|
||||||
|
columns until it learns them.
|
||||||
|
|
||||||
### 14.4 Questions for the org lead
|
### 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
|
**Answered on 2026-10-14:** Q17 as proposed, out (D358). **Q18 against the proposal: the end walk waits for
|
||||||
|
|||||||
@@ -2873,3 +2873,149 @@ through the `rust.backpack.size` step (*Bigger backpack*, `risk: 'change'`, `rev
|
|||||||
`rust.backpacks`): one `rust_perm_run_grants` row per recipient with `backpacks.size.N` as its permission and no
|
`rust.backpacks`): one `rust_perm_run_grants` row per recipient with `backpacks.size.N` as its permission and no
|
||||||
kit, pushed by the next `perm.sync` and revoked when the run's revert deletes the rows. Its message, a §20.2
|
kit, pushed by the next `perm.sync` and revoked when the run's revert deletes the rows. Its message, a §20.2
|
||||||
notice, defaults to a warning about the take-back.
|
notice, defaults to a warning about the take-back.
|
||||||
|
|
||||||
|
### 20.5 Rust's own world events — `world.event`, `world.call`, the console probe (§14.3.1, D349, D353–D356, D363, D366, D367, D372, D376, D378, D379)
|
||||||
|
|
||||||
|
The patrol helicopter, Bradley, the cargo ship, the Chinook, airdrops, locked crates, the Travelling Vendor,
|
||||||
|
the satellite and the Deep Sea, **with no plugin** (D349). The design is
|
||||||
|
[`PLAN_REDESIGNS.md`](../modules/rust/PLAN_REDESIGNS.md) §14.3.1; what the test phase and stage 1's spike found
|
||||||
|
is §14.2.1 and §14.3.14 there.
|
||||||
|
|
||||||
|
**`world.event` — one event kind, told apart by `event`.** It is rare (a few an hour), so it is one frame per
|
||||||
|
world event. **The type is in `event`, never in `type`:** `type` is the envelope's (§8.1), and the sidecar files
|
||||||
|
a frame on it. The plan's first example put the world event's type there, and the sidecar dropped every one as
|
||||||
|
untyped on the rig — protocol 13's `world.expired` lesson again (§19).
|
||||||
|
|
||||||
|
```json
|
||||||
|
{"kind":"world.event","type":"event","t":1792041350288,"serverId":"main","wipeId":"w-20261005T165054Z",
|
||||||
|
"event":"heli.arrived","x":3900.0,"z":-1714.5}
|
||||||
|
```
|
||||||
|
|
||||||
|
Positions are `x` and `z`, rounded to 0.1 m. **The site works out the grid** from them and the map's own
|
||||||
|
geometry (§17), so the grid has one source. A player is `steamId` and `name`, only where the table says.
|
||||||
|
**Nothing is said until the world is loaded, nor while the server is quitting**: a booting server spawns the
|
||||||
|
cargo ship and the vendor it saved, and that is not either of them arriving.
|
||||||
|
|
||||||
|
| `event` | Raised from | Carries |
|
||||||
|
|---|---|---|
|
||||||
|
| `heli.arrived` | `OnEntitySpawned(PatrolHelicopter)` | `x`, `z` |
|
||||||
|
| `heli.left` | `OnHelicopterRetire` | `x`, `z` (last seen) |
|
||||||
|
| `heli.downed` | `OnEntityDeath(PatrolHelicopter)` at the crash | `credit`, `names`, `x`, `z` |
|
||||||
|
| `bradley.spawned` | `OnBradleyApcInitialize`, next tick. Road Bradleys spawned within a second are one frame | `where`: `launch_site` \| `road`; `count` |
|
||||||
|
| `bradley.destroyed` | `OnEntityDeath(BradleyAPC)` (D366) | `where`: `launch_site` \| `road` \| `other`; `credit`, `names`, `x`, `z` |
|
||||||
|
| `cargo.arrived` | `OnEntitySpawned(CargoShip)` | `x`, `z` |
|
||||||
|
| `cargo.docking` / `cargo.docked` / `cargo.undocked` | `OnCargoShipHarborApproach` / `…Arrived` / `…Leave` | `x`, `z`, `harbour`, `harbourName` |
|
||||||
|
| `cargo.left` | `OnCargoShipEgress`: it turns for the edge with its radiation on. The kill follows when it is gone | `x`, `z` |
|
||||||
|
| `chinook.arrived` | `OnEntitySpawned(CH47HelicopterAIController)`, a second later; **not** an oil rig's reinforcement (it has a landing target, or comes within 10 s of a rig's hack) | `x`, `z` |
|
||||||
|
| `chinook.dropped` | `OnHelicopterDropCrate`, joined to the `OnCrateLanded` of the crate under it (within 40 m and 120 s) | `monument`, `monumentName`, `x`, `z` |
|
||||||
|
| `chinook.downed` (D379) | `OnEntityDeath(CH47Helicopter)` | `credit`, `names`, `x`, `z` |
|
||||||
|
| `airdrop.called` | **a cargo plane's spawn**, next tick, once per plane | `steamId`/`name` of a supply signal's thrower; `x`, `z` (the drop point) |
|
||||||
|
| `airdrop.landed` | `OnSupplyDropLanded`, **once per drop** | `steamId`/`name` of the caller, `x`, `z` |
|
||||||
|
| `airdrop.looted` | the **first** `OnLootEntity` on a drop | `steamId`/`name`, `x`, `z` |
|
||||||
|
| `crate.hack.started` | `CanHackCrate` (who), joined to the `OnCrateHack` that follows within 2 s | `where`, `steamId`/`name`, `x`, `z` |
|
||||||
|
| `crate.unlocked` | `OnCrateHackEnd` | `where`, `steamId`/`name` (the hacker), `x`, `z` |
|
||||||
|
| `crate.looted` | the first `OnLootEntity` on an unlocked crate | `where`, `steamId`/`name`, `x`, `z` |
|
||||||
|
| `vendor.arrived` / `vendor.left` | `OnEntitySpawned` / `OnEntityKill(TravellingVendor)` | `x`, `z` |
|
||||||
|
| `satellite.crashed` | the `SatelliteCrashRemains` spawn at the impact (no hook of its own) | `x`, `z` |
|
||||||
|
| `deepsea.opened` / `deepsea.closed` | `OnDeepSeaOpened` / `OnDeepSeaClosed` | nothing: the Deep Sea is off the map |
|
||||||
|
|
||||||
|
- **`airdrop.called` comes from the plane's spawn**, because the console's `supply.call` raised neither
|
||||||
|
`OnAirdrop` nor `OnCargoPlaneSignaled` (stage 1). Those two only say who and where: a signal's thrower and its
|
||||||
|
position, the schedule's drop point. Otherwise the drop point is the plane's own, read from it.
|
||||||
|
- **`where` for a locked crate** is `oilrig_large`, `oilrig_small` (the `_oilrig` prefab and the nearest
|
||||||
|
`oilrig_1` / `oilrig_2`), `cargo` (a `CargoShip` parent), `ghostship` (the `_ghostship` prefab) or `chinook`
|
||||||
|
(a crate seen landing under a Chinook's drop). **Anything else is `other` and says nothing** — Guarded Crate's
|
||||||
|
crate is an ordinary locked crate — and a crate one of our own steps placed (§15's ledger) is skipped.
|
||||||
|
- **`where` for a Bradley** is `launch_site` when `BradleySpawner.singleton.spawned` is it, `road` when the road
|
||||||
|
event's own list holds it, and `other` otherwise. `RoadSpawned` cannot say: it defaults to true, so a plugin's
|
||||||
|
Bradley would read as a road one. An `other` Bradley's spawn is not news, but its death is sent: it counted
|
||||||
|
toward Tankbreaker under D174 and still does.
|
||||||
|
- **`harbour` and `monument`** are the nearest monument's kind (the world verbs' vocabulary, §15) and
|
||||||
|
`harbourName` / `monumentName` the game's English name for it; absent where the map has none.
|
||||||
|
- **"Oil rig scientists called" is not a type**: starting a hack on a rig calls them at once, so
|
||||||
|
`crate.hack.started` with `where: oilrig_*` says it. **Not subscribed:** `OnHelicopterOutOfCrates` (every
|
||||||
|
tick), `OnPatrolHelicopterTakeDamage` (every hit), `OnDeepSeaTeleport`, the F-15 (D367).
|
||||||
|
- **The joins are memory only** — plane to thrower, drop to caller, crate to hacker, looted once, a Chinook's
|
||||||
|
drop — keyed by the entity, dropped when it goes and swept every ten minutes. Nothing is written to disk, so a
|
||||||
|
reload forgets a crate's hacker and that line goes without a name.
|
||||||
|
|
||||||
|
**The credit block (D372, D379).** For a patrol helicopter, a Chinook and a Bradley the plugin keeps a damage
|
||||||
|
table from `OnEntityTakeDamage` (the hook D174's last-hitter already used, after the same type test, for those
|
||||||
|
classes only) and sends every candidate. **It credits nobody itself.**
|
||||||
|
|
||||||
|
```json
|
||||||
|
{"kind":"world.event","type":"event","event":"heli.downed","x":812.0,"z":-340.5,
|
||||||
|
"credit":{"blow":"76561190000000001","last":"76561190000000002","most":"76561190000000002",
|
||||||
|
"damagers":[{"steamId":"76561190000000002","damage":6120.0},{"steamId":"76561190000000001","damage":3880.0}]},
|
||||||
|
"names":{"76561190000000001":"Alice","76561190000000002":"Bob"}}
|
||||||
|
```
|
||||||
|
|
||||||
|
- `blow` is the killing blow: for the patrol helicopter, the player the first `OnPatrolHelicopterKill` names (the
|
||||||
|
crippling hit, seconds before a crash that names nobody); for a Bradley or a Chinook, its death's
|
||||||
|
`InitiatorPlayer`. `last` is the last player to hurt it, with no window. `most` is the most damage. Each is
|
||||||
|
absent when nobody qualifies, and a death nobody touched carries `"damagers": []`.
|
||||||
|
- `damage` is the damage as each hit reported it, summed; at most 32 `damagers`, by damage.
|
||||||
|
- **The site applies the server's rule** (`creditRule`, below) to the feed line and to the count alike.
|
||||||
|
|
||||||
|
**The tally.** `player.tally` gains **`cratesHacked`** (a hack counts for its starter at `crate.hack.started`,
|
||||||
|
once per crate, from any location but `other`) and **`dropsLooted`** (a drop counts for its first looter),
|
||||||
|
both sums (D356). **`apcKills` and `heliKills` are no longer sent**: the site counts them from `world.event`'s
|
||||||
|
credit block. A protocol-13 plugin still sends them, and the site still adds them.
|
||||||
|
|
||||||
|
**`world.call` — run one of the game's own world events now, for a run (D354, D367).**
|
||||||
|
|
||||||
|
```json
|
||||||
|
{"cmd":"world.call","reqId":"r-40","runId":"9","key":"9:2","event":"airdrop","count":3,"x":-412.0,"z":1180.5}
|
||||||
|
{"kind":"world.called","type":"reply","reqId":"r-40","key":"9:2","event":"airdrop","repeat":false,"called":3}
|
||||||
|
```
|
||||||
|
|
||||||
|
- `event` is a schedule's key — `patrol_heli`, `cargo`, `chinook`, `airdrop`, `travelling_vendor`,
|
||||||
|
`bradley_road`, `f15` — or `satellite`. The plugin runs **one of that schedule's `TriggeredEvent`s at random,
|
||||||
|
as `EventSchedule.Trigger` does, but not `Trigger` itself**, which would also reset the schedule's own clock.
|
||||||
|
The schedule is found whether or not it is enabled. The satellite is the game's own `satellite.random`. **No
|
||||||
|
plugin console command is used**, so it works the same on Carbon.
|
||||||
|
- **A position**, as `x`/`z` or `monument`/`offsetX`/`offsetZ` (§15's location), **only for `airdrop` and
|
||||||
|
`patrol_heli`**, which stage 1's spike placed: the airdrop by `InitDropPosition` before it spawns (it releases
|
||||||
|
0–1 m above the point and lands there), the patrol helicopter by `SetInitialDestination` before it spawns (it
|
||||||
|
reaches the point within about 50 m, then patrols as usual). **The Chinook takes none (D378)**: it drops only
|
||||||
|
at the map's drop zones, and the one route to a chosen zone borrows the Airfield call terminal's shared state.
|
||||||
|
The rest go where the game puts them. A position for any of them is `not-placeable`.
|
||||||
|
- **Kept.** Nothing a call starts is removed at teardown. The plugin remembers the call only — its key, its run,
|
||||||
|
what it called — in `data/RunicGateway/world-calls.json` for seven days, so a retried key answers
|
||||||
|
`repeat: true` with the first answer and calls nothing.
|
||||||
|
- **Bounds:** `count` 1–5, and 1 for `cargo`, `travelling_vendor` and `bradley_road`; at most
|
||||||
|
**`EventsMaxWorldCalls`** (config, default and ceiling 10) world events per run, counted over every call the
|
||||||
|
run made; behind `EventsEnabled`. A count the game partly ran answers `called` below `count`.
|
||||||
|
- Refusals are `world.error`: `not-ready`, `events-disabled`, `malformed` (no key or run, or a key over 128
|
||||||
|
characters), `bad-event`, `bad-count`, `not-placeable`, `too-many`, §15's location refusals, and `refused`
|
||||||
|
(the game had nothing to run).
|
||||||
|
- `world.monuments` gains `maxWorldCalls`.
|
||||||
|
|
||||||
|
**Hello and status gain `console`: `{ "plugins": true | false }` (D363).** Whether this framework runs a plugin's
|
||||||
|
console command from code, found at every load by running the bridge's own `rg.probe` through
|
||||||
|
`ConsoleSystem.Run`. The steps that drive another plugin through its console command refuse while it is false.
|
||||||
|
**The probe runs from a timer**, because stage 1 found Carbon 2.0.262 refuses ("not found") every plugin command
|
||||||
|
run from *inside* a console command, and from a `NextTick` that a console command queued — which is how §14.2's
|
||||||
|
spike ran every test — while it finds them from a timer and from the `NextTick` the link's reader queues, which
|
||||||
|
is every website command's path. On both rigs it reads `true`. Hello is sent again when the answer changes.
|
||||||
|
|
||||||
|
**The sidecar** adds `POST /world/call`, a thin forward that keeps nothing.
|
||||||
|
|
||||||
|
**The website (Module-Rust).**
|
||||||
|
|
||||||
|
- **The feed** serves `world.event` (a public kind), read per viewer by `worldEvents.shapeFor`: an `event` this
|
||||||
|
build does not know is staff's alone; the event and its **`grid`** are public; a player's **`name`** (and the
|
||||||
|
names in `credited`) only for the operator's presence audience (D376); a **Steam id and a position only for
|
||||||
|
staff** (D353). A downed one carries `credited` (`[{ name, steamId? }]`), `creditedCount` and `creditRule`.
|
||||||
|
- **`rust_servers.credit_rule`**: `blow` (the default: the killing blow, else the last hit), `last`, `most` or
|
||||||
|
`all` (everyone who hurt it, one each), set on the server's settings. The same rule writes the line and adds
|
||||||
|
`heli_kills` (patrol helicopters and Chinooks, *Rotorbane*) and `apc_kills` (*Tankbreaker*). A change applies
|
||||||
|
from then on; counts already written are not recounted.
|
||||||
|
- **Triggers** `rust.world.<event>`, one per type (D355), ceiling `everyone`, cooldown subject the server and
|
||||||
|
the event (the crate types add `where`), with `grid`, `player`, `where`, `harbour`, `monument`, `count` and,
|
||||||
|
for a downed one, `credited`. No Steam id.
|
||||||
|
- **The step `rust.world.call`**, *Call a world event* (`risk: 'change'`, `reversible: 'none'`, budget
|
||||||
|
`rust.world.calls`).
|
||||||
|
- **The tally's two counts** in `rust_player_wipe_stats.crates_hacked` and `.drops_looted`; title categories
|
||||||
|
`crateshacked` (*Safecracker*) and `dropslooted` (*Scavenger*); leaderboard columns *Crates hacked* and *Drops
|
||||||
|
looted*, sortable (`sort=cratesHacked`, `sort=dropsLooted`).
|
||||||
|
|||||||
Reference in New Issue
Block a user