docs(rust): record the RaidableBases helper spike (§11.4.4)

One base despawns alone; overrides go in at OpenEvent through a deep copy;
lock-to-first-attacker is main-config only; an admin-given spot and height
work through a copied profile (Clone() is shallow and leaked); the area
check misses water; reloads drop Harmony patches.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
This commit is contained in:
2026-09-28 12:18:33 -05:00
parent 6684ea5c60
commit a34b5fdbf0

View File

@@ -823,10 +823,72 @@ The org lead answered the spike's three questions the same day:
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.
**Still to settle in the build's own spike:** the same helper questions on Carbon and on the paid edition.
Also the one-at-a-time rule: while a first base of the same name is still waiting to start on a server, the
step refuses to spawn a second one, because the free edition's bases have no ids to tell them apart.
§11.4.4 may retire that rule.
#### 11.4.4 The helper spike (2026-09-28)
The org lead asked for two tests of a D168 helper before the build: can it despawn one base, and which
settings can it override? A third question came with them: can an admin give the spot, meaning x, z and a
height adjustment? The spike ran on the rust-oxide rig against the free edition, 3.2.0. Carbon and the paid
edition are still to run (§11.4.2). Every finding below reaches RaidableBases' internals by reflection and a
Harmony patch. None of it is public API, so the helper has to check the plugin's version at hello, as the
zone helper does.
- **Despawning one base works.** The plugin keeps its live bases in a list on the plugin, and each base has
its own `Despawn()`. Calling it on one base removed that base and no other. It fired the usual
`OnRaidableBaseDespawn` and `OnRaidableBaseDespawned` hooks, so the bridge's feed sees nothing new.
- **The helper can know exactly which base is the event's.** A Harmony postfix on the plugin's `OpenEvent`
receives the new base object itself. The helper can tag it for the run at birth, instead of matching the
position and spawn time `Started` reports afterwards (D204). The one-at-a-time rule above may then go,
if the build confirms it on Carbon and the paid edition.
- **Overrides go in at `OpenEvent`, not after `Started`.** At `OpenEvent` the base holds a reference to its
profile's settings object, which every base of that profile shares. The helper swaps in a deep copy (a
JSON round trip), changed for this spawn. The shared profile was checked afterwards and was untouched.
Proven on the rig:
- PvP on/off;
- despawn minutes (inactive and total, via the profile's own "override config" switch);
- NPCs on/off, and the scientist and murderer counts.
- **Lock-to-first-attacker is not a profile setting.** It lives in RaidableBases' main config, in two
pairs of switches (PvP and PvE): one pair for "Manual" bases, which is what `rbevent` and the helper
spawn, and one pair for scheduled bases. A per-event lock would need a second Harmony patch, on the
base's `BypassUseOwners()`. Not built; a question for the org lead.
- **An admin-given spot works.** The helper builds the same spawn request the plugin's own "spawn where I
look" command builds, from numbers instead of a player's view. It then calls the plugin's paste. Bases
landed at the given x and z every time.
- **Height has to go through a copy of the profile.** The plugin recomputes y at paste time from the
ground (or water), plus the building's own height, plus the profile's paste height adjustment. It
ignores any y it is handed, unless the profile forces a height. So the helper copies the profile:
- an adjustment is added to the copy's paste height adjustment;
- an absolute y turns on the copy's forced height.
Results, measured as the height of the base's building blocks:
| Request | Blocks at | Ground there |
| --- | --- | --- |
| no adjustment | 1–4 | −0.2 |
| +5 | 6–9 | −1.1 |
| absolute y = 30 | 31–34 | 0.5 |
| a plain `rbevent` spawned right after | 1–4 | −0.2 |
**Trap:** the plugin's own `BuildingOptions.Clone()` is a shallow `MemberwiseClone`. The first run changed
the height through that clone, and the change leaked into the shared profile: the next plain `rbevent`
base spawned 35 m up. The height settings sit in a nested object, so the helper must copy that too, or
use the same deep copy as the overrides. Nothing reached the file on disk, and `rb.reloadprofiles` reset
the leak.
- **The plugin's area check catches buildings, but not water.** Its safety check, run at an admin's spot,
refused a player's building and refused an existing raid base. At 25 m away from the building it passed. A
spot on the seabed 50 m under water also passed: the plugin tests water in its own location picker, not
in this check. So an admin-given spot needs the helper's own water and terrain test as well as the
plugin's check. The spike reported the check but did not enforce it; whether to enforce is a question
for the org lead.
- **A RaidableBases reload drops the helper's Harmony patches**, because the patched methods belong to the
old assembly. The helper must re-patch in `OnPluginLoaded`, as the zone helper does for ZoneManager.
- **After a server boot the plugin refuses every spawn for about 50 s**, until its log says "Grid
initialization completed". This includes the helper's spawns. The step has to wait for that, not fail
on it.
### 11.5 Protocol