feat(bridge): emit world.ruleset, the shard's published ruleset

Protocol 3.0 §5 (docs/link/v3.md). One frame describing how this shard is
actually configured — expansion, which optional systems are on, skill/stat
caps, account and house limits, champion scroll rules, the save/restart
schedule — so the website's rules page cannot drift from the server.

Modelled on BridgeBoot.EmitHello, not on the diff sweeps: the ruleset changes
only when an operator edits a .cfg, so there is nothing to poll. It subscribes
Connected_Core, so a sidecar that comes up second still learns the ruleset,
and `[bridge reload` re-emits for an operator who just edited a file.

The frame is built from an EXPLICIT ALLOWLIST of Config.Get calls. Config.Entries
is never enumerated — that would sweep in every key on the server, secrets
included — and Server.cfg, Staff.cfg, Email.cfg, DataPath.cfg, Bridge.cfg,
Compiler.cfg, Reports.cfg and Client.cfg are named as excluded both here and in
a code comment. The one connection detail published is Bridge.PublicConnectAddress,
blank by default, which an operator sets deliberately for this purpose.

`rev` is FNV-1a over the body so an unchanged reconnect is a site-side no-op.
String.GetHashCode() is deliberately not used: it is seeded per process, so it
would change on every restart and defeat the diff.

Verified by compiling the full ServUO Scripts tree (6,205 files, net48, EJ) with
this overlay substituted for the deployed Bridge copy — clean.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-07-28 11:14:36 -05:00
parent 64a89f97af
commit 3fb4b7dc9f
4 changed files with 392 additions and 1 deletions

View File

@@ -48,6 +48,25 @@ PresenceSweepSeconds=30
# house.remove (owner, region, location, decay). Houses change slowly; a few minutes is fine.
HousingSweepSeconds=300
# Shard ruleset (https://gitea.whitlocktech.com/RunicGateway/docs/src/branch/main/link/v3.md §5). One world.ruleset frame — expansion, which
# systems are on, skill/stat caps, account and house limits, champion scroll rules —
# emitted on every sidecar connect (and on [bridge reload), so the website's rules page
# cannot drift from the server. Not a sweep: it changes only when you edit a .cfg.
#
# The frame is built from an explicit allowlist of keys in BridgeRuleset.cs. Server.cfg,
# Staff.cfg, Email.cfg, DataPath.cfg, Bridge.cfg, Compiler.cfg, Reports.cfg and Client.cfg
# are never read.
RulesetEnabled=true
# The one connection detail the bridge will publish, e.g. play.myshard.com,2593. Blank
# (the default) omits it entirely. Server.cfg's Address/Listen/Port are NEVER published —
# if you want a connect string on the site, put it here deliberately.
PublicConnectAddress=
# Include the save/restart schedule (AutoSave frequency, AutoRestart hour) in the frame.
# Turn off if you would rather not advertise a predictable restart window.
RulesetIncludeSchedule=true
# Shown to a player when they run [link. The website page where they enter the code.
LinkUrl=https://yoursite/link