feat(champ): stream champion-spawn state to the sidecar board #3

Merged
whitlocktech merged 2 commits from feature/champ-spawns into main 2026-07-14 16:47:15 +00:00
Member

What

Adds a live champion-spawn board to the link. Champion spawns have no ServUO EventSink, so this adds a fourth polled stream (BridgeChamps) modeled on the existing BridgeSweeps: enumerate every spawn each tick, fold it to a small record, and emit champ.update only on change. No core patch — every field used is public.

Answers the goal: when/where a spawn is up, its basic details, and whether it's active or on cooldown.

Coverage — three families via a category field

category source details
champion ChampionSpawn type, level, kills/maxKills, boss, cooldown ETA (restartAt), level-expiry ETA (expireAt)
mini MiniChamp (TerMur) type, level, maxLevel; auto-restarts, no kill counter
sea BaseSeaChampion a High Seas world-boss mobile, alive only while summoned; carries hits/hitsMax and roams

status folds to active / cooldown / dormant. Transient entries (a slain sea boss, a deleted controller) leave the board via champ.remove. A sidecar (re)connection clears the diff cache so the next sweep re-emits the full board, rebuilding a sidecar that restarted on its own.

Sidecar

  • champs current-state table (one row per serial), fed by champ.update (upsert) and champ.remove (delete).
  • New GET /champs returns the live board (served from SQLite — no shard round-trip, survives shard outage).
  • New ChampSweepSeconds config (default 10s), wired into [bridge reload / sweepnow / status.

Files

  • overlay/Scripts/Custom/Bridge/BridgeChamps.cs (new) — the sweep.
  • overlay/Scripts/Custom/Bridge/{BridgeConfig,BridgeBoot}.cs, overlay/Config/Bridge.cfg — config + command wiring.
  • sidecar/src/{store,main,web}.rs — board table, event folding, endpoint.
  • docs/INTEGRATION.md — documented champ.update / champ.remove events and GET /champs.

Verification

  • Sidecar: cargo build + cargo test clean.
  • C#: BridgeChamps.cs isolate-compiled against the real ServUO.exe + Scripts.dll — the only errors were the two ChampSweepSeconds references (expected; the deployed DLL predates the config change and compiles together in a real deploy). ChampionSpawn, MiniChamp, MiniChampInfo, BaseSeaChampion and all members resolved.
  • End-to-end: ran the sidecar, fed champ.update lines over a simulated shard socket → all three categories appeared on /champs; a same-serial update upserted in place (no dupes); champ.remove dropped the slain sea boss (3 → 2 rows); unauthenticated request → 401.

🤖 Generated with Claude Code

## What Adds a live **champion-spawn board** to the link. Champion spawns have no ServUO `EventSink`, so this adds a fourth polled stream (`BridgeChamps`) modeled on the existing `BridgeSweeps`: enumerate every spawn each tick, fold it to a small record, and emit `champ.update` **only on change**. No core patch — every field used is public. Answers the goal: **when/where a spawn is up, its basic details, and whether it's active or on cooldown.** ## Coverage — three families via a `category` field | category | source | details | |----------|--------|---------| | `champion` | `ChampionSpawn` | type, level, kills/maxKills, boss, cooldown ETA (`restartAt`), level-expiry ETA (`expireAt`) | | `mini` | `MiniChamp` (TerMur) | type, level, maxLevel; auto-restarts, no kill counter | | `sea` | `BaseSeaChampion` | a High Seas world-boss **mobile**, alive only while summoned; carries `hits`/`hitsMax` and roams | `status` folds to **active / cooldown / dormant**. Transient entries (a slain sea boss, a deleted controller) leave the board via `champ.remove`. A sidecar (re)connection clears the diff cache so the next sweep re-emits the full board, rebuilding a sidecar that restarted on its own. ## Sidecar - `champs` current-state table (one row per serial), fed by `champ.update` (upsert) and `champ.remove` (delete). - New `GET /champs` returns the live board (served from SQLite — no shard round-trip, survives shard outage). - New `ChampSweepSeconds` config (default 10s), wired into `[bridge reload` / `sweepnow` / `status`. ## Files - `overlay/Scripts/Custom/Bridge/BridgeChamps.cs` *(new)* — the sweep. - `overlay/Scripts/Custom/Bridge/{BridgeConfig,BridgeBoot}.cs`, `overlay/Config/Bridge.cfg` — config + command wiring. - `sidecar/src/{store,main,web}.rs` — board table, event folding, endpoint. - `docs/INTEGRATION.md` — documented `champ.update` / `champ.remove` events and `GET /champs`. ## Verification - **Sidecar**: `cargo build` + `cargo test` clean. - **C#**: `BridgeChamps.cs` isolate-compiled against the real `ServUO.exe` + `Scripts.dll` — the only errors were the two `ChampSweepSeconds` references (expected; the deployed DLL predates the config change and compiles together in a real deploy). `ChampionSpawn`, `MiniChamp`, `MiniChampInfo`, `BaseSeaChampion` and all members resolved. - **End-to-end**: ran the sidecar, fed `champ.update` lines over a simulated shard socket → all three categories appeared on `/champs`; a same-serial update **upserted in place** (no dupes); `champ.remove` dropped the slain sea boss (3 → 2 rows); unauthenticated request → 401. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
wtclaude added 3 commits 2026-07-14 10:47:04 +00:00
Format the sidecar source with `cargo fmt` so the new `cargo fmt --check`
CI gate passes on the first run. No behavior change.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0114TpmrNW4wNXsHq5CR72jQ
Auto-build and release the Rust sidecar on every push to main.

A language-agnostic "release engine" computes the next version from
conventional-commit subjects since the last v* tag (feat!/BREAKING ->
major, feat -> minor, fix|perf -> patch; first run ships the current
Cargo.toml version). An isolated "Rust adapter" runs cargo fmt --check /
test, builds x86_64-unknown-linux-gnu, and cross-builds
x86_64-pc-windows-gnu via MinGW (libsqlite3-sys is the only native dep).
It then commits the version bump ([skip ci]), tags vX.Y.Z, pushes, and
creates the Gitea release with the linux binary, windows .exe, and
SHA256SUMS.

Reuses the REGISTRY_USER / REGISTRY_TOKEN secrets; the token additionally
needs write:repository scope and main must accept a direct push.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0114TpmrNW4wNXsHq5CR72jQ
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
whitlocktech approved these changes 2026-07-14 16:46:51 +00:00
whitlocktech added 1 commit 2026-07-14 16:47:00 +00:00
whitlocktech merged commit 4badd15f91 into main 2026-07-14 16:47:15 +00:00
whitlocktech deleted branch feature/champ-spawns 2026-07-14 16:47:15 +00:00
Sign in to join this conversation.
No Reviewers
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: RunicGateway/link#3
No description provided.