Files
servuo-plugins/overlay/Config/Bridge.cfg
Claude 9c3a33148b feat(champ): stream champion-spawn state to the sidecar board
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
2026-07-14 05:46:21 -05:00

64 lines
2.9 KiB
INI

# uo-link bridge settings.
#
# Key scope is the filename: Bridge.cfg + StatSweepSeconds => "Bridge.StatSweepSeconds".
# Read in Configure(), which runs before World.Load.
# Loopback only. The socket being local is the trust boundary for inbound commands;
# if the sidecar ever moves off-host, add a shared secret first.
Host=127.0.0.1
Port=7788
# Outbound queue cap. On overflow the plugin drops oldest and counts the drops,
# because a stalled sidecar must never OOM the shard.
QueueCap=10000
# Sweep intervals, seconds. Measured on a 150-character shard: a vitals sweep costs
# 0.0015 ms/char, so 1000 online players is ~1.5 ms per sweep. See docs/PLAN.md §1.
StatSweepSeconds=30
DecaySweepSeconds=60
EconomySweepSeconds=300
# Champion-spawn board poll. ChampionSpawn has no EventSink, so every spawn is diffed on
# this interval to emit champ.update on any status/level/kills/boss change. The world holds
# only a handful of spawns, so the pass is trivial; 5-10s is well within site tolerance.
ChampSweepSeconds=10
# Help-page queue poll. The in-game page queue has no EventSink, so it is diffed on this
# interval to emit page.new / page.closed / page.updated. A few seconds is fine for a
# support queue; the full open queue is also available on demand via pages.snapshot.
PageSweepSeconds=5
# Shown to a player when they run [link. The website page where they enter the code.
LinkUrl=https://yoursite/link
# Town-crier news pushed from the website. Caps are defense in depth on top of the
# loopback trust boundary: a buggy or compromised sidecar still cannot flood the criers.
TownCrierMaxLines=6
TownCrierMaxLineLength=200
TownCrierMaxActive=20
TownCrierMaxDurationSec=86400
# Admin write plane (staff moderation from the website). OFF by default: the whole
# feature is opt-in per shard. When enabled, inbound admin.* commands (kick/ban/unban/
# broadcast) are honored. Authorization is enforced on the website; the shard trusts the
# loopback socket and applies a hard floor below.
AdminWriteEnabled=false
# The one shard-side safety floor. An admin.* command refuses any target whose AccessLevel
# is at or above this, so even a compromised sidecar can never touch the Owner. Values are
# AccessLevel names (Player, VIP, Counselor, Decorator, Spawner, GameMaster, Seer,
# Administrator, Developer, CoOwner, Owner). Default CoOwner => only Owner/CoOwners shielded.
AdminAccessFloor=CoOwner
# Defense-in-depth caps on admin.* payloads (mirroring the town-crier caps).
AdminBroadcastMaxLength=300
AdminReasonMaxLength=400
# Clamp on a timed ban's duration, seconds. A ban with no/zero duration is indefinite.
AdminBanMaxDurationSec=31536000
# The test scaffolding in tools/scaffolding/ reads its own flags from this file
# (SeedOnStart, CensusOnStart, ProbeOnStart). They are absent here on purpose:
# Config.Get returns the default of false when a key is missing, so a deployed
# server never runs the scaffolding even if its .cs files are present.