docs(rust): the RaidableBases spike, and D203-D205
The free edition (3.2.0) on both rigs with CopyPaste: its public API, the 17-argument lifecycle hooks, spawning only through `rbevent` at a spot the plugin picks, base ids always "0", despawn only all-at-once, the boot hitch and grid wait, and the profile options. Section 11.4.2 is left for the paid edition the org lead supplies later in the week. D203 RaidableBases picks where; D204 a helper despawns only the event's base; D205 profile + difficulty + per-event overrides, and the site edits RaidableBases' profiles as a named exception. Refs RunicGateway/Module-Rust#21 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
# `module-rust` — the redesigns, planned
|
||||
|
||||
**Status:** plan, written 2026-09-27. **Its eleven questions were answered the same day: D188–D198 (§10).**
|
||||
On 2026-09-28 the org lead added the first-class optional plugins (§11, D199–D202).
|
||||
On 2026-09-28 the org lead added the first-class optional plugins (§11, D199–D202), and after the RaidableBases spike, D203–D205 (§11.4).
|
||||
It is step 3 of [`PLAN_FIXES.md`](PLAN_FIXES.md) §6: the six changes the org lead decided during the first
|
||||
player walk, each "planned in detail before code". The org lead asked for all six in one plan (2026-09-27), so
|
||||
they can be read together. No code has been written for any of them yet.
|
||||
@@ -632,6 +632,9 @@ The org lead added §11 on 2026-09-28 and answered its questions the same day:
|
||||
| **D200** | **Economics: all four uses.** Coins as an event reward (withdrawn on revert); balances shown to the player (site and app) and to staff; staff deposit, withdraw and set a balance, with an activity row; and a *richest* leaderboard column and chat-title condition. | — | 11.2 |
|
||||
| **D201** | **Backpacks: staff view any player's backpack, a player views their own (site and app), and an event can grant extra capacity for a time**, taken back at the end. | Showing backpack sizes as named tiers on the permission screen. | 11.3 |
|
||||
| **D202** | **RaidableBases: all four uses, and the paid edition too.** Active bases on the live map and in the feed; an event step that spawns a base at a difficulty and despawns it at the end; bases raided per player on the leaderboard and as a title condition; and the paid edition's extras (five difficulties, lockouts) where it is installed, falling back to what both editions share. | Supporting only what the free edition has. | 11.4 |
|
||||
| **D203** | **RaidableBases picks where an event's base goes**; the site learns the spot from `OnRaidableBaseStarted` and shows it. The paid edition's placement, if it has one, is offered where installed. | A helper that places a base at a chosen monument. | 11.4.3 |
|
||||
| **D204** | **At an event's end, a helper (`RunicGatewayRaids.cs`, D168) despawns only that event's base.** Without the helper the base despawns on its own timer, and the run records it as expiring on its own. | Leaving every base to its timer; RaidableBases' "despawn all". | 11.4.3 |
|
||||
| **D205** | **An event picks a RaidableBases profile and a difficulty, may override a bounded set of settings for that spawn (through the helper), and the site edits RaidableBases' profiles** — a named exception to the editor never walking a data directory. | Profile and difficulty only; overrides without profile editing. | 11.4.3 |
|
||||
|
||||
## 11. First-class optional plugins (D199–D202)
|
||||
|
||||
@@ -702,6 +705,129 @@ Personal GitHub mirrors are not a source: k1lly0u's mirror of Kits is two major
|
||||
- **The spike first:** pull the free source, confirm every hook and API signature above, and find the listing
|
||||
and despawn calls. Then load it on both rigs, with TruePVE, and raid one base.
|
||||
|
||||
#### 11.4.1 The free edition, as the spike found it (2026-09-28)
|
||||
|
||||
The source is RaidableBases 3.2.0 (free, `umod.org/plugins/RaidableBases.cs`), and it was loaded on both rigs
|
||||
with CopyPaste 4.3.0. A throwaway spike plugin made one base file from the walk hut and logged every
|
||||
lifecycle hook. It was deleted afterwards, and so were the three plugins on both rigs.
|
||||
|
||||
**What it needs.** **CopyPaste is a hard dependency.** A base is a CopyPaste building file in
|
||||
`data/copypaste/`, and **none ship with the free edition**: the default profile `RaidBases` names
|
||||
`RaidBase1`–`RaidBase5`, and none of them exist. A base with no storage box is thrown away as soon as it is
|
||||
pasted ("No usable boxes found"). A PvE plugin (TruePVE, SimplePVE, NextGenPVE, Imperium or AegisPVE) is
|
||||
optional.
|
||||
|
||||
**What it costs at boot.** `OnServerInitialized` took 6.7 s (Oxide) and 7.9 s (Carbon) on the main thread.
|
||||
The spawn grid then builds for about a minute: 52 s for 1,172 points on the rigs' 3000 map. **During that
|
||||
minute a spawn is refused** ("grid is loading").
|
||||
|
||||
**Its public API** (`[HookMethod]`):
|
||||
|
||||
| Call | Returns | Use to us |
|
||||
|---|---|---|
|
||||
| `IsPremium()` | `false` on the free edition | hello's edition field |
|
||||
| `GetAllDifficulties()` | `[("Normal", 512)]` on the free edition | the step's difficulty list, read from the installed plugin rather than hard-coded |
|
||||
| `GetAllEventsCount()`, `GetActiveEventCount()` | ints | the servers page |
|
||||
| `GetAllEvents()` / `GetAllEventsNonAlloc(list)` | an 18-field tuple per base: position, mode, level, PvP, owner, raiders, intruders, entities, base name, spawn and despawn time, radius, loot left | the live map layer. **The plugin warns that `GetAllEvents` changes shape in the next update.** |
|
||||
| `EventTerritory(pos)`, `…Any`, `…All`, `GetPlayersFrom`, `GetOwnerFrom`, `HasPVPDelay` | | not needed |
|
||||
|
||||
**Nothing in the API spawns, despawns, or lists profiles.**
|
||||
|
||||
**The hooks it raises.** `OnRaidableBaseStarted`, `Ended`, `Completed`, `Despawn`, `Despawned` and
|
||||
`PrivilegeDestroyed` all carry the same 17 arguments:
|
||||
|
||||
```
|
||||
(Vector3 location, int level, bool allowPVP, string id, float, float, float loadTime, ulong ownerId,
|
||||
BasePlayer owner, List<BasePlayer> raiders, List<BasePlayer> intruders, List<BaseEntity> entities,
|
||||
string baseName, DateTime spawn, DateTime despawn, float protectionRadius, int lootRemaining)
|
||||
```
|
||||
|
||||
A plugin method with exactly that signature binds on both frameworks. `Started` also has a one-argument
|
||||
overload carrying the plugin's own class, which the bridge cannot name and does not need. Other hooks:
|
||||
`OnPlayerEnteredRaidableBase` / `Exited` (14 arguments, the player first), `OnRaidableBaseUnlocked`,
|
||||
`OnRaidableAwardGiven` / `Owner`, the PvP-delay hooks and loot hooks.
|
||||
|
||||
**How another plugin spawns a base: only through the server console.**
|
||||
|
||||
- `rbevent [baseName]` queues a base, and **RaidableBases chooses where**. On the rigs, three spawns landed at
|
||||
Q6, C13 and C4, and none of them was named by the command. There is no position, no monument and no
|
||||
difficulty argument, and **nothing comes back** to the caller.
|
||||
- `rbe` pastes where a player is looking, so it needs a player in the game.
|
||||
- **Every base's `id` is `"0"`** on the free edition. The only way to know which base the event made is the
|
||||
next `Started` for that base name after the command. That is safe while events make one base at a time.
|
||||
|
||||
**How another plugin despawns a base: all or nothing.** `rbevent despawnall` removes every base on the
|
||||
server, including ones the event did not make, and `rbevent despawn_inactive` removes every inactive one.
|
||||
Despawning **one** base needs a player standing at it. Left alone, a base despawns on its profile's own
|
||||
timer: 45 minutes in the default profile, as `despawn` in `Started` said.
|
||||
|
||||
**Its options.** Each profile has well over a hundred settings. Among them: NPCs, turrets, loot rules,
|
||||
despawn timers, the plugins to block, where bases may spawn (beaches, roads, monuments), what players may
|
||||
do, and backpacks. The global config has its own schedulers (Maintained, Scheduled and Manual events), map
|
||||
markers, ZoneManager zones, a ranked ladder and messages. **Profiles live in the plugin's data directory**,
|
||||
which the site's configuration editor deliberately never walks. The global config is in the config
|
||||
directory, where the editor already reaches it.
|
||||
|
||||
**What that means for D202's event step.** "Spawn a base at a difficulty near a monument, and despawn it at
|
||||
the end" is not possible on the free edition through anything RaidableBases offers another plugin. What
|
||||
it does offer is: spawn a named base, somewhere, now; learn where and when it will despawn from the hook;
|
||||
and remove every base at once. §11.4.3 asks which way to go.
|
||||
|
||||
#### 11.4.2 The paid edition — to be filled when the licensed copy arrives
|
||||
|
||||
The org lead supplies a licensed copy later in the week of 2026-09-28. The same spike runs against it on
|
||||
both rigs, and this section records:
|
||||
|
||||
- `IsPremium()` and `GetAllDifficulties()` (expected: five tiers);
|
||||
- whether it adds a spawn at a position, a monument or a difficulty, a despawn of one base, or real base
|
||||
ids — by API or console command;
|
||||
- whether the 17-argument hooks and `GetAllEvents` have the same shape (the free edition warns that the
|
||||
latter is changing), and what `level` carries per difficulty;
|
||||
- lockouts, buyable events and the ranked ladder: the hooks they raise and what the feed could say;
|
||||
- anything in it that needs a D168 helper, and anything the free edition's answer in §11.4.3 would get
|
||||
wrong for it.
|
||||
|
||||
The design in §11.4.3 is written so the paid edition extends it rather than replaces it. The step reads
|
||||
what the installed edition offers — difficulties, and any placement or despawn it supports — and offers
|
||||
exactly that.
|
||||
|
||||
#### 11.4.3 Decided (2026-09-28)
|
||||
|
||||
The org lead answered the spike's three questions the same day:
|
||||
|
||||
- **D203: where a base goes — RaidableBases picks.** The step spawns the chosen base with `rbevent`, and
|
||||
RaidableBases places it wherever its grid allows. The bridge learns the spot from the next
|
||||
`OnRaidableBaseStarted` for that base name. The site then shows it on the live map and in the run log, and
|
||||
records it on the run's ledger. If the paid edition offers placement, the step offers it there too
|
||||
(§11.4.2).
|
||||
- **D204: at the end — a helper removes only the event's base.** Teardown, a revert, and an operator's stop
|
||||
each despawn exactly the base the run made, never another. The free edition cannot do that from outside
|
||||
(§11.4.1), so a D168 helper, **`RunicGatewayRaids.cs`**, finds the run's base by the position and spawn time
|
||||
`Started` reported, and calls RaidableBases' own despawn on that one base. Like the zone helper
|
||||
(D181, D182), it is optional and default-installed, and it reports at hello. **Without it, the step still
|
||||
spawns, and the base despawns on its own timer.** The site says so on the step, and the run records the
|
||||
base as expiring on its own, like D170's zones. A base the plugin despawns first is marked `expired`.
|
||||
- **D205: what an event can choose — a profile, a difficulty, and per-event overrides; and the site edits
|
||||
profiles.**
|
||||
- **Profile and difficulty.** The step picks a RaidableBases profile, and a difficulty from the installed
|
||||
plugin's `GetAllDifficulties()`. The free edition offers "Normal"; the paid edition offers its five.
|
||||
- **Per-event overrides.** The step may override a bounded set of a profile's settings for this spawn
|
||||
only. The first set is PvP on/off, despawn minutes, NPCs on/off and count, and the lock-to-first-attacker
|
||||
rule; the build's spike settles which of them the plugin lets a helper change after `Started`. The free
|
||||
API has no way to do this, so the helper applies them. **Without the helper there are no overrides**, and
|
||||
the step says so.
|
||||
- **The site edits profiles.** The configuration page gains RaidableBases' profile files,
|
||||
`data/RaidableBases/Profiles/*.json`. This is a **named exception** to the rule that the editor never
|
||||
walks a plugin's data directory, which exists because that directory holds live state and the
|
||||
permission stores. The exception is that one folder, for that one plugin. It gets the editor's usual
|
||||
guarantees: the write is recorded, a reload is watched, and a failed load rolls back (D178, D179). The
|
||||
reload is `rb.reloadprofiles`, which the spike ran on both rigs, not a plugin reload.
|
||||
|
||||
**Still to settle in the build's own spike:** exactly which internal routine the helper calls to despawn one
|
||||
base, and which settings it can override after `Started`, on both editions. Also the one-at-a-time rule: the
|
||||
step refuses to spawn a second base of the same name on a server while a first one is waiting to start,
|
||||
because the free edition's bases have no ids to tell them apart.
|
||||
|
||||
### 11.5 Protocol
|
||||
|
||||
These are new verbs, events and hello fields. If they are built before the cutover they join the unreleased
|
||||
|
||||
Reference in New Issue
Block a user