feat(asset-bridge): item and land art on demand, hued where the files are (Phase 5)
The body catalogue is a set; this is not. This client addresses 49,152 static ids and has art for 39,189 of them, plus 4,244 land tiles of 16,384 -- and hues multiply the statics by three thousand. So there is no manifest and no scan: `assets.fetch` grows two more families (`static`, `land`) and answers the keys the website's own data names. `assets.fetch` becomes shared plumbing. BridgeAssets now owns the command, does the reqId/consent/key-ceiling checks once, derives the family from the keys themselves (§5 made the key the address; a request that also named its family would have two places to be wrong and one of them silent) and dispatches to the reader that registered it. A batch must be of one family, because the reply carries one `catalog` id. `assets.sources` gains `families` -- additive, so the protocol stays 8, and EXTRACTOR_VERSION stays 2 because no existing key's bytes change. Two traps, both in §4.5's family -- a confident, plausible, wrong picture: - `Art.GetStatic` memoises into a static Bitmap[0xFFFF] and hands back the SAME instance, while `Hue.ApplyTo` repaints in place. Hue a static once and the plain key comes back hued from then on, and the next hue stacks on the last. Measured on this client before the fix. `Files.CacheData` is now off for the life of the process; `TryHue` re-checks it and refuses rather than risk it, and the same flag decides whether a bitmap is ours to dispose. - `PartialHue` decides whether a hue repaints every pixel or only the grey ones, per item id, out of `tiledata.mul` -- 13,259 of 65,536 ids on this client. Item 597 is a wooden screen with painted flowers: one mode reddens the flowers, the other the whole screen. Both decode. The first cut of this reader bound `TileData` to ServUO's OWN `Server.TileData` (the enclosing namespace beats `using Ultima;`, and it has a PartialHue flag too), which compiled and refused every hued key at runtime. Every such type is spelled `Ultima.` now. Land takes no hue segment: the mode that decides how is an item flag and land has no equivalent, so `land/3/h33` is refused rather than guessed. `h0` is not a key either -- hue 0 means "not hued", and the plain key already names it. Measured through the reader over the whole range: 39,189 statics and 4,244 land tiles served, and the only refusals are the 9,963 + 12,140 empty index slots §4.5 predicted. Nothing that carries art is refused. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016wDDVXWMDz82WqE1i969r4
This commit is contained in:
@@ -124,6 +124,13 @@ namespace Server.Custom.Bridge
|
||||
public static int AssetPlayerDirection { get; private set; }
|
||||
public static int AssetCreatureDirection { get; private set; }
|
||||
|
||||
// How many bytes of rendered item and land art the shard holds between requests (§11,
|
||||
// phase 5). This is a convenience, not a store: the website keeps every picture it fetches
|
||||
// and does not ask twice, so what this actually buys is the second page of a batch, a
|
||||
// retry after a 425, and the same item appearing in two rows of one page. Sized so a
|
||||
// full 512 KB batch and the one before it both fit with room over.
|
||||
public static int AssetArtCacheBytes { get; private set; }
|
||||
|
||||
public static int LeaseMaxDurationSec { get; private set; }
|
||||
public static int LeaseGraceSec { get; private set; }
|
||||
|
||||
@@ -222,6 +229,16 @@ namespace Server.Custom.Bridge
|
||||
AssetPlayerDirection = Clamp(Config.Get("Bridge.AssetPlayerDirection", 0), 0, 4);
|
||||
AssetCreatureDirection = Clamp(Config.Get("Bridge.AssetCreatureDirection", 1), 0, 4);
|
||||
|
||||
// The floor is one batch: a cache that cannot hold the page being built evicts rows
|
||||
// while they are still being written, which is a cache that costs and never pays. The
|
||||
// ceiling is a game server's memory, and 64 MB of PNG is already ~34,000 sprites --
|
||||
// most of this client's art, held for a working set that is measured in hundreds.
|
||||
AssetArtCacheBytes = Config.Get("Bridge.AssetArtCacheBytes", 16 * 1024 * 1024);
|
||||
if (AssetArtCacheBytes < AssetBatchBytes)
|
||||
AssetArtCacheBytes = AssetBatchBytes;
|
||||
if (AssetArtCacheBytes > 64 * 1024 * 1024)
|
||||
AssetArtCacheBytes = 64 * 1024 * 1024;
|
||||
|
||||
StatSweepSeconds = Config.Get("Bridge.StatSweepSeconds", 30);
|
||||
DecaySweepSeconds = Config.Get("Bridge.DecaySweepSeconds", 60);
|
||||
EconomySweepSeconds = Config.Get("Bridge.EconomySweepSeconds", 300);
|
||||
|
||||
Reference in New Issue
Block a user