fix(bridge): protocol 13 step 2 — expiry, gathering, raids, plugin loads, and a ZoneManager helper (F1 F3 F4 F8 F12 F13) #18

Merged
whitlocktech merged 2 commits from fix/protocol-13-step2 into edge 2026-09-27 01:11:48 -05:00
Member

The bridge's half of PLAN_FIXES §6 step 2. Decisions D181–D185 are in docs#288; the spec is in the step-2 docs PR (PROTOCOL.md §19.4–19.7).

Fixes

  • F13: world.expired carries the entity's kind as what. It used to write that over the frame's own kind, so every expiry was filed as "zone".
  • F1 (D159): gathered also counts OnDispenserBonus, OnCollectiblePickup and OnGrowableGathered. All three are void and listed in ExpectedHooks.
  • F3: your own building block, or one on a cupboard you're authorised on, no longer counts toward structures. The frame still goes out.
  • F4: every remaining UserIDString now goes through SteamIdOf(userID).
  • F8 (D184): plugin.loaded / plugin.unloaded carry the permissions that plugin added or removed, as a diff taken one tick after the hook. They are sent only after the world is ready.
  • F12 (D181, D182): new helper RunicGatewayZones.cs. It Harmony-postfixes ZoneManager's Zone.InitializeZone, then one tick later enters every connected player that ZoneManager's IsPositionInZone puts inside, through ZoneManager's own OnPlayerEnterZone. Without it, the bridge scores its zones by IsPositionInZone. Hello carries zoneHelper: { state, version?, reason? }.
  • Release: release.yml stages the helper beside the bridge and lists every .cs with its sha256 in manifest.files. The installer (installer PR) and the egg (Rust-Link PR) place them all.

Walked on both rigs, 2026-09-27

  • The bridge compiled and connected on Oxide (2.7 s) and on Carbon.
  • The helper compiled on both after one fix: ListHashSet has no ToArray. It logged patched ZoneManager 3.1.14 on both. HarmonyLib resolved with no reference directive.
  • The site read zoneHelper: {"state":"patched","version":"0.1.0"} from both hellos.
  • F8: unloading and loading Kits sent ["kits.admin","kits.rgreward"] on both frameworks, and the helper's own load sent []. A Carbon c.reload (unload and load in one tick) sends [] on both frames, which is correct: the registered list didn't change.

Not walked yet (needs a player in game): F12 with somebody standing in a zone (created, and across a restart), F1 wood and hemp, F3 own wall, F13 end to end with a zone expiring into a site that records it. These are the new PLAYER_WALK section's rows 3–9.

Tracking: Module-Rust#21.

  • AI-assisted (Claude Code)

🤖 Generated with Claude Code

https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY

The bridge's half of PLAN_FIXES §6 step 2. Decisions D181–D185 are in docs#288; the spec is in the step-2 docs PR (PROTOCOL.md §19.4–19.7). **Fixes** - **F13:** `world.expired` carries the entity's kind as `what`. It used to write that over the frame's own `kind`, so every expiry was filed as "zone". - **F1 (D159):** `gathered` also counts `OnDispenserBonus`, `OnCollectiblePickup` and `OnGrowableGathered`. All three are void and listed in `ExpectedHooks`. - **F3:** your own building block, or one on a cupboard you're authorised on, no longer counts toward `structures`. The frame still goes out. - **F4:** every remaining `UserIDString` now goes through `SteamIdOf(userID)`. - **F8 (D184):** `plugin.loaded` / `plugin.unloaded` carry the permissions that plugin added or removed, as a diff taken one tick after the hook. They are sent only after the world is ready. - **F12 (D181, D182):** new helper **`RunicGatewayZones.cs`**. It Harmony-postfixes ZoneManager's `Zone.InitializeZone`, then one tick later enters every connected player that ZoneManager's `IsPositionInZone` puts inside, through ZoneManager's own `OnPlayerEnterZone`. Without it, the bridge scores its zones by `IsPositionInZone`. Hello carries `zoneHelper: { state, version?, reason? }`. - **Release:** `release.yml` stages the helper beside the bridge and lists every `.cs` with its sha256 in `manifest.files`. The installer (installer PR) and the egg (Rust-Link PR) place them all. **Walked on both rigs, 2026-09-27** - The bridge compiled and connected on Oxide (2.7 s) and on Carbon. - The helper compiled on both after one fix: `ListHashSet` has no `ToArray`. It logged `patched ZoneManager 3.1.14` on both. `HarmonyLib` resolved with no reference directive. - The site read `zoneHelper: {"state":"patched","version":"0.1.0"}` from both hellos. - **F8:** unloading and loading Kits sent `["kits.admin","kits.rgreward"]` on both frameworks, and the helper's own load sent `[]`. A Carbon `c.reload` (unload and load in one tick) sends `[]` on both frames, which is correct: the registered list didn't change. **Not walked yet (needs a player in game):** F12 with somebody standing in a zone (created, and across a restart), F1 wood and hemp, F3 own wall, F13 end to end with a zone expiring into a site that records it. These are the new PLAYER_WALK section's rows 3–9. Tracking: Module-Rust#21. - [x] AI-assisted (Claude Code) 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
wtclaude added 2 commits 2026-09-26 21:47:03 -05:00
The bridge's half of PLAN_FIXES §6 step 2 (decisions D181-D185, docs#288).

- F13: `world.expired` carries the entity's kind as `what`. It used to write
  it over the frame's own `kind`, so every expiry left filed as "zone".
- F1 (D159): `gathered` also counts OnDispenserBonus (the final-hit bonus),
  OnCollectiblePickup (hemp, mushrooms, stones off the ground) and
  OnGrowableGathered (farmed plants); all three are void and in ExpectedHooks.
- F3: taking down a building block you own, or one on a cupboard you are
  authorised on, no longer counts toward `structures`. The frame still goes.
- F4: every remaining UserIDString is SteamIdOf(userID), so a player another
  plugin spawned is never `steamId: null`.
- F8 (D184): `plugin.loaded` / `plugin.unloaded`, once the world is ready,
  with the permissions that plugin added or removed (a diff of the registered
  list, taken a tick after the hook).
- F12 (D181, D182): RunicGatewayZones.cs, a D168 helper shipped beside the
  bridge, Harmony-postfixes ZoneManager's Zone.InitializeZone and, a tick
  later, enters every connected player ZoneManager's own IsPositionInZone
  places inside, through ZoneManager's own OnPlayerEnterZone. Without it (or
  when it cannot find what it patches) the bridge scores its zones by
  IsPositionInZone. Hello reports `zoneHelper: { state, version?, reason? }`.
- release.yml stages every helper beside the bridge and lists each .cs with
  its sha256 in manifest.files; the installer and the egg place them all.

Not yet compiled: this is walked on both rigs before it merges.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
fix(bridge): the ZoneManager helper copies the player list without ToArray
All checks were successful
PR Checks / plugin-checks (pull_request) Successful in 10s
d1d4a00d1d
Found compiling on the rust-oxide rig: BasePlayer.activePlayerList is
Facepunch's ListHashSet, which has no ToArray, so the helper did not compile.
It now copies into a List, which it needs anyway: entering a player can eject
or kill them and change the live list mid-loop. HarmonyLib itself resolved on
Oxide with no reference directive, and the helper patched ZoneManager 3.1.14 on
both frameworks once this compiled.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
whitlocktech merged commit 7a1f5aa072 into edge 2026-09-27 01:11:48 -05:00
whitlocktech deleted branch fix/protocol-13-step2 2026-09-27 01:11:49 -05:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: RunicGateway/Rust-Plugins#18
No description provided.