Files
link/patches/README.md
Claude 11169c52a6 feat(admin): forward in-game moderation to the website (bidirectional audit)
Phase C / §5.5: so the site's moderation log is complete regardless of origin,
in-game uses of the write-plane verbs are forwarded as admin.audit
(origin:"in-game").

- patches/commandlogging-event.patch: adds CommandLogging.OnWrite, raised in
  WriteLine before the m_Enabled guard so it fires even when file logging is
  off. Scripts-layer file -> dynamic build, no core rebuild.
- patches/BridgeModerationAudit.cs: subscriber. Taps OnWrite for resolved
  ban/kick (parsing the target from the log line) and EventSink.Command for
  [bcast. Lives in patches/ (not overlay/) because it references OnWrite,
  which only exists post-patch — same rule as BridgeVendorSale.cs.
- tools/scaffolding/BridgeAuditProbe.cs: gated headless verification.

Verified live: a genuine [bcast plus simulated ban/kick log lines produced
admin.audit frames with origin=in-game, actor, and the target parsed
(seed_010); a non-moderation line was correctly ignored.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0114TpmrNW4wNXsHq5CR72jQ
2026-07-13 02:12:30 -05:00

4.3 KiB

patches

Unified diffs against stock ServUO 57.4 for files the bridge must modify rather than add. Anything that can be shipped as a whole file belongs in overlay/ instead.

Apply from the server root:

git apply --check patches/<name>.patch   # dry run
git apply         patches/<name>.patch

Phase 7 — player-vendor sale (a coupled unit)

Player-vendor purchases raise no EventSink. ValidVendorPurchase / ValidVendorSell cover NPC vendors only. The commit point is PlayerVendorBuyGump.OnResponse, the only place where buyer, vendor owner, price, and commission are all in scope — exactly what cheat detection needs. See docs/PLAN.md §6.

This is the one non-drop-in piece. Apply all three together:

Item Target What
playervendor-sale-eventsink.patch Server/EventSink.cs Adds the PlayerVendorSale delegate, PlayerVendorSaleEventArgs { Buyer, Vendor, Owner, Item, Price, Commission }, the event field, and InvokePlayerVendorSale.
playervendor-sale-gump.patch Scripts/Gumps/PlayerVendorGumps.cs One InvokePlayerVendorSale(...) call right after the committed HoldGold +=.
BridgeVendorSale.cs copy to Scripts/Custom/Bridge/ The subscriber that emits vendor.sale. Not in overlay/ because it references PlayerVendorSaleEventArgs, which does not exist until the EventSink patch is applied — shipping it in overlay would break the build on any unpatched install.
cd <servuo root>
git apply --check patches/playervendor-sale-eventsink.patch patches/playervendor-sale-gump.patch  # dry run
git apply         patches/playervendor-sale-eventsink.patch patches/playervendor-sale-gump.patch
cp patches/BridgeVendorSale.cs Scripts/Custom/Bridge/BridgeVendorSale.cs

Both patches are git-format and verified with git apply --check against stock ServUO 57.4. Modifying EventSink.cs means the core rebuilds, so ScriptCompiler's dynamic script build is not enough — rebuild the solution (dotnet build ServUO.sln) or the server binary.

Not applicable to a non-git shard? git apply works in a plain directory too. If patch is used instead, note the core files are CRLF; use patch --binary.

In-game moderation audit (admin controls §5.5)

So the website's moderation log stays complete, in-game uses of the write-plane verbs are forwarded to it as admin.audit (origin:"in-game"). Broadcasts already surface through EventSink.Command, but resolved bans/kicks only carry their target inside the command's own CommandLogging.WriteLine call — which has no event to subscribe to. One small change fixes that:

Item Target What
commandlogging-event.patch Scripts/Commands/Logging.cs Adds a public static event Action<Mobile,string> OnWrite, raised in WriteLine before the m_Enabled guard so it fires even when file logging is off.
BridgeModerationAudit.cs copy to Scripts/Custom/Bridge/ The subscriber: taps OnWrite for ban/kick (parsing the target out of the log line) and EventSink.Command for [bcast, emitting admin.audit. Not in overlay/ because it references CommandLogging.OnWrite, which does not exist until the patch is applied.
cd <servuo root>
git apply --check patches/commandlogging-event.patch   # dry run
git apply         patches/commandlogging-event.patch
cp patches/BridgeModerationAudit.cs Scripts/Custom/Bridge/BridgeModerationAudit.cs

Logging.cs is a Scripts file, so this is picked up by the dynamic script build — no core/solution rebuild needed (unlike the Phase 7 EventSink.cs patch). Verified end-to-end with tools/scaffolding/BridgeAuditProbe.cs (gated by Bridge.AuditProbeOnStart): a genuine [bcast plus simulated ban/kick log lines produced the expected admin.audit frames, target parsed, with non-moderation lines ignored.

Note on Scripts.csproj

Phase 0 modifies an existing file but ships as a whole-file overlay (overlay/Scripts/Scripts.csproj) because the file is small, we own it operationally, and a copy is less fragile than a diff against a project file. Revisit if it starts drifting from upstream.

Note on shard repairs

The deletions and edits described in docs/SHARD_PREREQS.md are one-time repairs to a specific broken install, not part of the bridge. They are not shipped here.