docs(link): the hue belongs where the files are, and the cache poisons it (Phase 5)
§11.1 is new and carries what phase 5 measured: 49,152 addressable static ids (not the 81,884 `artidx.mul` declares -- `FileIndex` sizes its table from its length ARGUMENT), 39,189 with art, 4,244 land tiles, 9,963 + 12,140 empty index slots, and the whole set at 81 MB decoding in 34 s. That last number reopens the bulk question and the answer is still no: 108 MB of base64 through a 512 KB single-slot channel to store 43,433 pictures a shard displays a few hundred of. Two traps, both §4.5's failure mode -- a confident, plausible, wrong picture: - `Art.GetStatic` hands back the SAME cached Bitmap and `Hue.ApplyTo` repaints in place, so hueing edits the library's own copy: the plain key comes back hued from then on, and the next hue stacks. `Files.CacheData` off process-wide fixes it and also stops a game server retaining 74 MB of Bitmap. Copying instead does not solve the retention, and `new Bitmap(src)` throws on ARGB1555 anyway. - `PartialHue` (13,259 of 65,536 ids) decides whether a hue repaints every pixel or only the grey ones, from a file only the shard has. Item 597 is a wooden screen with painted flowers; one mode reddens the flowers, the other the whole screen, and both decode. Hence land takes no hue segment and `h0` is not a key. Plus the namespace trap that compiled: unqualified `TileData` binds to ServUO's own `Server.TileData`, because the enclosing namespace beats `using Ultima;`. §14 records what the wire gained -- the `static` and `land` families, `families` on `assets.sources`, and `assets.fetch` becoming shared plumbing whose family is DERIVED from the keys (§5 made the key the address; a request naming its family too would have two places to be wrong and one of them silent). Additive, so the protocol stays 8 and EXTRACTOR_VERSION stays 2. §15 records that `link` needed nothing in phases 4 or 5: it forwards verbatim in both directions. §17.10 is the four org-lead decisions. §12 and modules/uo/SCHEMA.md carry the website side: `uploads/items/`, per-row `catalog` staleness, and why a key with no art writes no row at all. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016wDDVXWMDz82WqE1i969r4
This commit is contained in:
@@ -202,7 +202,7 @@ Creature artwork read from the shard's own UO client ([`link/v8.md`](../../link/
|
||||
|
||||
| Table | Shape |
|
||||
|---|---|
|
||||
| `shard_assets` | `asset_key` VARCHAR PK (§5's key, e.g. `body/34/a0`), `family`, `sha256`, `bytes`, `width`, `height`, `body`, `direction`, `file`, `imported_at` |
|
||||
| `shard_assets` | `asset_key` VARCHAR PK (§5's key, e.g. `body/34/a0`, `static/3922/h33`, `land/3`), `family`, `sha256`, `bytes`, `width`, `height`, `body`, `direction`, `file`, `catalog`, `imported_at` |
|
||||
| `shard_creature_bodies` | `slug` PK, `type_name` (the ServUO class name asked), `body` nullable, `status`, `resolved_at` |
|
||||
| `shard_asset_meta` | Singleton (`id = 1`), `payload` JSON (catalogue id, extractor version, source fingerprint, counts), `imported_at` |
|
||||
|
||||
@@ -235,6 +235,34 @@ Four details that are load-bearing rather than incidental:
|
||||
winning spelling of the spawn type token rather than inventing a display label — which is why the
|
||||
body pass needs no extra column to ask its question.
|
||||
|
||||
### Item and land art: the same table, a different shape of use (phase 5)
|
||||
|
||||
The creature catalogue is a **set**: one manifest walk covers every key, so one stored fingerprint in
|
||||
`shard_asset_meta` describes all of them and an Update is a hash diff. Item art has no set — the
|
||||
client addresses 49,152 item graphics times 3,000 hues — so those rows arrive one at a time, because
|
||||
something on this site named the key.
|
||||
|
||||
Three consequences in this schema:
|
||||
|
||||
- **`catalog` is per row**, and it is what phase 5 added. It records the shard's art catalogue id (a
|
||||
hash of `artLegacyMUL.uop`/`art.mul`, `hues.mul`, `tiledata.mul`, `verdata.mul` and its extractor
|
||||
version), so staleness is a column comparison rather than a manifest diff. A client patch changes
|
||||
it; a restart does not. NULL means "written before the column existed", which is stale by the same
|
||||
test and costs one re-fetch. The body import fills it too, so one column answers the question
|
||||
everywhere.
|
||||
- **`shard_asset_meta` stays the body catalogue's alone.** A warm pass writing there would tell the
|
||||
body import that a client it never looked at is unchanged, and the creature catalogue would quietly
|
||||
stop updating.
|
||||
- **`family` is now load-bearing**, not decoration: `body`, `static` and `land` rows share the table
|
||||
and have different lifetimes. The admin status counts them separately for the same reason — there
|
||||
is no "how many are there" to compare `static` against, so the only honest number is how many the
|
||||
site has been asked for and holds.
|
||||
|
||||
Pictures land in `server/uploads/items/` (gitignored like `uploads/atlas/`), content-addressed the
|
||||
same way — `uo-static-3922-h33-<sha8>.png`. A key the shard has no art for writes **no row at all**:
|
||||
an empty row would make it "held" and it would never be asked again, including after the operator
|
||||
patches in the graphic that was missing.
|
||||
|
||||
## shard_clilocs / shard_cliloc_meta — UO's localization table (Protocol 3.0)
|
||||
|
||||
Items on the wire carry a `LabelNumber`, not a name. The bridge has always sent it —
|
||||
|
||||
Reference in New Issue
Block a user