Asset Bridge phase 1 (docs/link/v8.md §16). Sidecar half: RunicGateway/link#41. Docs half: RunicGateway/docs#236. The transport for protocol 8, plus phase 0's validator promoted into the overlay and extended to animations — which is where the interesting part is. ## 357 of the 1,144 "decodable" bodies are wrong pictures, on a STOCK client Phase 0 measured the art path and left the animation half unbuilt. It has the same defect, and it is worse: `GetAnimation` decodes through `new MemoryStream(m_StreamBuffer, false)` — the whole shared buffer, not the `length` bytes just read into it — so a truncated or absent record does not even hit end-of-stream. It sails on into the previous animation's bytes. Measured directly, because no count could tell: | Decode body 320 (`lookup 22638982, length 0`) straight after… | Comes back | |---|---| | body 12, the dragon | the dragon, 176x167, identical hash | | body 34, the wolf | the wolf's dimensions, 35x34 | | body 400, the human male | the human, 27x63, identical hash | The catalogue is **787 bodies, not 1,144**. Importing the other 357 would have written duplicate creature portraits into the site showing whichever body the walk decoded before them. The record walk refused **0** real bodies on the stock client — the false-refusal measurement §4.5 says the boundary depends on. ## And four of the twelve player bodies, not six §5.2 listed the elf ghosts (607, 608) as decoding. Their index entry is `length 0`; what came back was the elf female at her exact dimensions, because 606 is what the walk decoded immediately before. Confirmed the same way — 607 after the dragon is the dragon. Phase 4's UOP decoder now covers eight ids rather than six. ## What is here - **`overlay/Scripts/Custom/Bridge/BridgeAssets.cs`** — the plane. Accepts on the Core thread, hands off to a dedicated asset worker, returns immediately. Three rules, all answering a specific failure: - **one slot**, second request answered `bridge.busy` (425). `Emit`'s queue is bounded in *lines*, so 10,000 queued 200 KB replies is 2 GB of shard memory; the bound that holds is flow control, on the side where the memory is. - **byte budgets** (`AssetBatchBytes`, 512 KiB) under the sidecar's new 1 MiB cap. The factor of two is load-bearing: a page always admits its first item, so it may overshoot by one, and the headroom is what makes that land on the wire. - **replies, never events** — no `reqId`, no answer. An uncorrelated frame is an event by definition, and §3.1 is why none of this may be one. - **`PageBuilder`** — one paging envelope (`more`/`cursor`/`cut`) for all five families that will page, defined before the first one needs it. `cut` matters: "short page" has three meanings and only `end` means finished. - **`assets.sources`** — stage 1 of the import gate, its first user. - **`BridgeAssetValidator.cs`** — promoted from `tools/`, plus `ResolveAnimation` (the never-sweep-file-types rule as code, with no loop and no fallback), `AnimationRecordSane` and the frame walk. - **`EXTRACTOR_VERSION`**, **`overlay.toml` protocol 7 → 8**, `AssetsEnabled`. ## Hashing had to come off the request path §6's gate is (size, mtime) first, hash only when those differ. The first call has nothing cached, so that still means hashing 1.06 GB — inside the sidecar's 10 s reply timeout it does not fit. So hashes are computed on their own thread (deliberately not the single-slot worker, which would answer every status poll `bridge.busy` for the whole pass) and the reply carries `hashing`/`complete`. Measured on the real rig: first call instant with `sha256: null`, second call **44 ms** with every hash present. ## Verified on the wire, not just compiled Real ServUO 57.4 + the real sidecar + the real client. `GET /assets/sources` → 200, `X-UOLink-Version: 8`, `imaging: {ok: true}`, and §4.6's diagnostic firing on a live client: `artDataFile: artlegacymul.uop`, with `art.mul` and `artidx.mul` both carrying `shadowedBy`. Live events kept flowing through the new capped reader with no warnings. Not exercised live: the disabled-plane 403 and the busy 425 (both unit-tested on the sidecar side; the shard halves are a config read and a lock). - [x] AI-assisted — Claude Code (Opus 5) Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016wDDVXWMDz82WqE1i969r4
44 lines
2.4 KiB
TOML
44 lines
2.4 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: 8 — see docs/link/v8.md (the Asset Bridge: client assets over the loopback link
|
|
# instead of a converter on somebody's desktop).
|
|
protocol = 8
|
|
|
|
# ── 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"
|