Overlay BridgePresence (new):
- presence.online sweep over online PlayerMobiles: total plus per-facet and
per-region counts, emitted only when the population changes.
- region.enter real-time from EventSink.OnEnterRegion (player-filtered), the
cheap location signal PLAN.md prefers over Movement.
- PresenceSweepSeconds (30s); wired into [bridge reload|sweepnow|status.
Sidecar:
- GET /online serves the latest presence.online snapshot from the event store
(survives restart); population time series via /history?kind=presence.online.
Docs: INTEGRATION.md presence events + /online endpoint; PROTOCOL_2 ph.2 built.
Verified: sidecar cargo check clean; overlay compiles in the full ServUO
Scripts tree (0 errors, 0 warnings). Live run pending.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds the first Part B streams from docs/PROTOCOL_2.md: guild rosters and
town governors ("mayors"), both outbound diff-board sweeps mirroring the
existing champ board.
Overlay:
- BridgeSocial (new): guild sweep+diff over BaseGuild.List -> guild.update /
guild.remove (full-state upsert; disband detected via Disbanded), plus a
real-time guild.join from EventSink.JoinGuild. (EventSink.CreateGuild is only
the load-time factory, so creation is derived sidecar-side from a first-seen
id, as champs do.)
- BridgeGovernance (new): city sweep over CityLoyaltySystem.Cities -> city.update
(governor / governor-elect / election phase), gated on CityLoyaltySystem.Enabled.
- BridgeJson.Actor: shared serial/name/acct/webId/player writer used by both.
- BridgeConfig: GuildSweepSeconds (60s), CitySweepSeconds (300s).
- BridgeBoot: both wired into [bridge reload|sweepnow|status.
Sidecar:
- store: guilds + governors board tables with upsert/delete/all.
- main: route guild.update/remove and city.update into the boards.
- web: GET /guilds, GET /governors served from the store (snapshot-companion
rule, so a fresh page or a restarted sidecar hydrates without the shard).
Docs: INTEGRATION.md event catalog (guild.*, city.update) + board endpoints;
PROTOCOL_2.md Part B phase 1 marked built.
Verified: sidecar cargo check clean; overlay compiles in the full ServUO
Scripts tree (0 errors, 0 warnings). Live end-to-end run still pending.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds the account-provisioning plane from docs/PROTOCOL_2.md Part A: the
website can create game accounts and unlink them, gated by a shard-wide
signup mode. The existing [link flow is unchanged.
Overlay:
- BridgeConfig: SignupMode (website|game|hybrid, default hybrid; unrecognized
falls back to game), AccountCreateEnabled (mode-following default),
RequireIpForCreate, name/password caps, and a boot warning when the core
Accounts.AutoCreateAccounts setting contradicts the mode.
- BridgeAccounts (new): account.create (mode gate, actor required, char-safety
mirrored from AccountHandler, collision check, per-IP cap via CanCreate/
LogAccess with fail-closed missing/loopback IP, create + WebsiteUserId link,
account.audit; password never logged or echoed) and account.unlink (Owner
floor via BridgeAdmin.Protected, clears the tag).
- BridgeAccountLink: in-game [unlink command, emits account.unlinked.
- BridgeAdmin: Protected / ResolveTargetAccount promoted to public for reuse.
Sidecar:
- POST /accounts/create, DELETE /link/:account, respond_account status mapping
(409 collision / 429 ip cap / 403 disabled|protected / 404 not-linked / 400).
- store.record_unlink drops the mirrored link row.
- PROTOCOL_VERSION -> 2 (outbound events additive; new endpoints need v2).
Docs: INTEGRATION.md protocol bump, account.* events, endpoints, 409/429;
PROTOCOL_2.md Part A marked built.
Verified: sidecar cargo check clean; overlay compiles in the full ServUO
Scripts tree (0 errors, 0 warnings). Live end-to-end run still pending.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Champion spawns have no ServUO EventSink, so add a fourth polled stream
(BridgeChamps) modeled on BridgeSweeps: enumerate every spawn each tick,
fold to a small record, and emit champ.update only on change. No core
patch — every field used is public.
Covers all three families via a `category` field:
- champion: ChampionSpawn (type/level/kills/boss/cooldown ETA)
- mini: MiniChamp (type/level; auto-restarts, no kill counter)
- sea: BaseSeaChampion (a High Seas world-boss mobile, alive only
while summoned; removed via champ.remove when slain)
Status folds to active/cooldown/dormant. A (re)connection clears the diff
cache so the next sweep re-emits the full board, rebuilding a sidecar that
restarted on its own. Transient entries leave via champ.remove.
Sidecar: a `champs` current-state table (one row per serial) fed by
champ.update (upsert) and champ.remove (delete), exposed at GET /champs as
the live board. New ChampSweepSeconds config (default 10s), wired into
[bridge reload/sweepnow/status. Documented in docs/INTEGRATION.md.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0114TpmrNW4wNXsHq5CR72jQ
Phase 2 of docs/ADMIN_CONTROLS.md: surface the in-game help-page queue to the
website.
- BridgePages.cs: the queue has no EventSink, so it is polled (PageSweepSeconds,
default 5s) and diffed, keyed by sender serial (one page per player) ->
page.new / page.updated / page.closed. Inbound pages.snapshot -> pages.list;
page.respond delivers a staff reply to the player (online: a gump now; offline:
queued for next login; shows as "Staff") and can close; page.close removes it.
- BridgeConfig/Bridge.cfg: PageSweepSeconds. BridgeBoot: reload re-arms the poll,
status reports it.
- sidecar/src/web.rs: GET /pages, POST /pages/{id}/respond, POST /pages/{id}/close.
- INTEGRATION.md: page events (§4) and endpoints (§6).
- tools/scaffolding/BridgePageProbe.cs: gated headless verification.
Verified live (probe-seeded tickets): snapshot returns the queue, the poll emits
page.new for both and page.closed on removal, respond -> 200, close removes the
page, unknown page -> 404.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0114TpmrNW4wNXsHq5CR72jQ
Phase 1 (sidecar side): POST /admin/{kick,ban,unban,broadcast} forward to the
shard, correlated on a fresh reqId, with an admin-specific status mapping —
unknown target -> 404, protected target / plane-disabled -> 403, missing actor
/ bad body -> 400. actor is required and checked up front. Documents the
endpoints and the admin.audit event in INTEGRATION.md.
Verified end-to-end (real sidecar + booted shard): 200 on success, 403 on the
Owner floor, 404 unknown target, 400 missing actor, 401 no token.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0114TpmrNW4wNXsHq5CR72jQ
docs/INTEGRATION.md is the API reference for building the front end against the
sidecar: base URL, auth (Bearer / X-Api-Key / ?token=), protocol versioning, the
rich /health, the WebSocket live feed with a full event catalog, every REST query
and command (char/roster/vendors/link/towncrier/history/economy), the status-code
table, a worked character-page example, and current caveats. Payloads are the real
shapes captured during testing. Linked from the top-level README.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>