Protocol 2 could say how many members a guild had, not who they were, and there is no EventSink for leaving a guild — so PROTOCOL_2.md §10.1 deferred the whole membership half. This closes it. The sweep now holds each guild's member serial **set** instead of folding it into the signature as a sum. That buys two things. A set comparison cannot collide, where a sum could: one member joining and another leaving between two passes offset each other and the guild looked unchanged. And a set can be *differenced*, which is what makes a per-member `guild.leave` possible without a core tap — departures are simply the prior set minus the current one. A changed set also re-emits `guild.roster`, the full member list. That is what lets the departure events stay advisory: a consumer building a "so-and-so left" feed wants them, but a consumer holding a membership table only needs the roster, so nothing downstream has to replay deltas to stay correct. On a guild's first sweep there is no prior set, so nothing is reported as leaving — an unknown roster becoming known is not 155 people leaving at once. A roster is the only fat frame this plugin emits — measured at roughly 69 bytes per member against a real 155-member guild — and the sidecar reads a line with no length bound. So members per frame are capped (default 500, about 35 KB), and a guild over the cap is split into frames carrying `seq`, `more` and `total`. Every realistic guild emits exactly one frame with `seq` 0 and `more` false, which is the same shape as if chunking did not exist. Verified against the real sidecar with the cap forced down to 50, which produced 50/50/50/5 across four frames. The reconnect baseline is spread rather than fired in one pass. `OnConnected` clears the diff caches, so every guild looks changed at once, and building hundreds of fat frames in a single Core-thread tick is exactly the stall this bridge exists to avoid. At most GuildRosterGuildsPerTick guilds emit a roster per sweep; a guild over budget keeps its old member set, so it still reads as changed next pass. The sweep re-arms itself after 2s while a baseline is draining, so catch-up takes seconds rather than one full sweep interval per batch. BridgeJson gained the array writer it never had — there was no way to express a list of objects at all. Every field helper emits a leading `,"name":`, so Actor is split into a bare-object writer that both the single and array forms use. overlay.toml protocol -> 4, in this commit rather than a later one: CI folds it into the release manifest and the installer refuses to pair an overlay and a sidecar that disagree, so a bump landing separately from the emitters would silently fail to compose into a bundle. Verified on a live ServUO shard against the real Rust sidecar (not a stub): 155 members seeded from real PlayerMobiles, four roster frames reassembled to 153 entries on the board after two members were removed, two guild.leave frames with the correct serials, and the departed serials absent from the re-emitted roster. Refs: docs/website/TEAMS.md Part 12 Phase 1 Co-Authored-By: Claude <noreply@anthropic.com>
43 lines
2.3 KiB
TOML
43 lines
2.3 KiB
TOML
# Release metadata for the deployable overlay.
|
|
#
|
|
# Consumed by .gitea/workflows/release.yml, which folds these values into the
|
|
# manifest.json shipped inside runicgateway-overlay-<ver>.tar.gz. The Runic
|
|
# Gateway installer reads that manifest to decide what it is deploying and
|
|
# whether it is compatible with the sidecar it is about to install
|
|
# (docs/installer/PLAN.md §5 Phase 0, §7.1).
|
|
#
|
|
# There is deliberately NO version key here. The release version is derived from
|
|
# git tags and conventional commits by the release workflow, so there is no bump
|
|
# commit to keep in sync and no way for this file to disagree with the tag.
|
|
|
|
# ── The loopback wire-protocol version this overlay speaks ───────────────────
|
|
#
|
|
# This is the plugin half of the compatibility contract. It MUST equal the
|
|
# sidecar's PROTOCOL_VERSION (link/sidecar/src/main.rs) for a deployment to
|
|
# work: the sidecar rejects a mismatch with 409 rather than mis-parsing.
|
|
#
|
|
# The C# plugin has no queryable version before ServUO boots — it does not
|
|
# announce one on the wire — so this declaration is the only thing that lets the
|
|
# installer's bundle CI check the pair BEFORE an operator installs them
|
|
# (docs/installer/PLAN.md §2.6, §7.1 gate 1). Keeping it honest is therefore a
|
|
# manual duty: when the protocol changes, bump it here in the same PR that
|
|
# changes the emitters, exactly as link bumps PROTOCOL_VERSION.
|
|
#
|
|
# Current: 4 — see docs/link/v4.md (guild.roster, guild.leave).
|
|
protocol = 4
|
|
|
|
# ── ServUO compatibility ─────────────────────────────────────────────────────
|
|
#
|
|
# The base overlay (Config/Bridge.cfg + Scripts/Custom/Bridge/*.cs) only ADDS
|
|
# files and is expected to work on any reasonably current ServUO. This is the
|
|
# oldest version it is known good on.
|
|
min_servuo_version = "57.4"
|
|
|
|
# The patches/ tier is a different matter: those are unified diffs against STOCK
|
|
# ServUO files, so they are verified against exactly one version and nothing
|
|
# else. On any other version the installer skips the whole tier with a warning
|
|
# and completes the base install (docs/installer/PLAN.md §1, §2.2) — losing
|
|
# vendor.sale events and in-game moderation-audit forwarding, but never
|
|
# half-patching an unknown tree.
|
|
patches_verified_against = "57.4"
|