docs(link): the catalogue is real, and UOFiddler's last job is gone (Phase 3)
Phase 3 is built and walked on a live shard. What the walk measured, and the
two places the design of record needed correcting:
§8.1, new: the catalogue is 787 exactly as §4.8 predicted, and the whole scan
of bodies 1-2047 takes 734 ms cold -- so the wall-clock paging §11 designed
never fires on this client. Every §4.8/§5.2 prediction held when the bytes were
rendered and LOOKED at: 320, 607, 608 and 666 come back absent rather than as
another creature's picture, and the direction split is 783 at index 1 against 4
at index 0 -- four player bodies, not six.
44 of the 787 hashes are shared by two or three bodies, which is the exact
signature of the wrong-picture bug, so it was chased rather than assumed. It is
the client's own Body.def aliasing (83 {1}, 84 {1}, 106 {12, 59}), and the check
that settles it is at the source: Translate(ref body, ref hue) rewrites `body`
only when bit 31 is set, unlike the one-argument overload -- and ResolveAnimation
calls that same two-argument overload, so validator and decoder resolve the
identical record.
§12.1, new: **§12 is right about the outcome and wrong about the mechanism.**
`shard_spawn_creatures` is emptied and refilled by every atlas refresh, and a
refresh runs on every boot -- so an imported filename written to that row is
destroyed by an ordinary re-parse of the ServUO tree, and the next Update finds
the client files unchanged and never restores it. Three tables outside that
blast radius, and the atlas import re-derives `art` on the way past.
§14: **§16 listed phase 3 as servuo-plugins + module-uo and that was wrong.**
web.rs routes every command explicitly, so `link` is in the phase. Corrected in
both places.
UOFIDDLER.md is DELETED, two phases earlier than §9.1 predicted -- creature art
was the only thing still on it. SPAWN_ATLAS.md §Artwork is rewritten around the
import, keeping the operator's own map as the thing that wins; the module's
SCHEMA.md gains the three tables and API.md the two admin routes.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016wDDVXWMDz82WqE1i969r4
This commit is contained in:
@@ -188,10 +188,52 @@ Four column choices worth stating, because each one is a trap:
|
||||
Deceit"). The live `champ.update` feed in `shard_champs` is the separate answer to "it is on level 3
|
||||
right now". Both exist; they are not the same data.
|
||||
|
||||
**`shard_spawn_creatures.art` is always NULL on a fresh import.** The project ships no creature
|
||||
artwork: sprites live in the operator's own client `.mul`/`.uop` files and are theirs, not ours to
|
||||
redistribute. An operator supplies art via a gitignored map plus images under the (already
|
||||
gitignored) `server/uploads/atlas/`. Text-only is the normal, supported state.
|
||||
**`shard_spawn_creatures.art` is DERIVED, never written by the atlas import itself** — see
|
||||
`shard_assets` below. The project still ships no creature artwork: sprites live in the operator's own
|
||||
client `.mul`/`.uop` files and are theirs, not ours to redistribute. What changed in Protocol 8 is
|
||||
who extracts them: the shard does, from its own client, over the bridge. An operator's hand-drawn map
|
||||
plus images under the (already gitignored) `server/uploads/atlas/` still wins over anything imported.
|
||||
Text-only is still the normal, supported state — an install with no shard link never imports one, and
|
||||
even a complete import leaves two thirds of the playable ghost and gargoyle bodies without art.
|
||||
|
||||
## shard_assets / shard_creature_bodies / shard_asset_meta — the Asset Bridge (Protocol 8)
|
||||
|
||||
Creature artwork read from the shard's own UO client ([`link/v8.md`](../../link/v8.md) §6, §8, §12).
|
||||
|
||||
| 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_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` |
|
||||
|
||||
**These are the one part of this schema that is deliberately NOT import-owned**, and the reason is
|
||||
the atlas tables sitting directly above them. `replaceAtlas` empties and refills
|
||||
`shard_spawn_creatures` on every refresh, and a refresh runs on every boot; an imported filename
|
||||
stored on that row would be destroyed by an ordinary re-parse of the ServUO tree, with the next asset
|
||||
Update finding the client files unchanged, reporting "nothing to do", and never restoring it. So the
|
||||
assets live out here, upserted per key, and `replaceAtlas` re-derives `art` from them on the way
|
||||
past — `{ ...derived, ...operatorMap }`, which is the one place "the operator's map wins" is
|
||||
enforced.
|
||||
|
||||
Four details that are load-bearing rather than incidental:
|
||||
|
||||
- **`file` is a filename under the uploads directory, never a path**, and it is content-addressed
|
||||
(`uo-body-34-a0-<sha8>.png`). A stable name overwritten in place would leave every browser and CDN
|
||||
serving the previous client's sprite from cache, with the row perfectly correct.
|
||||
- **The `art` derivation joins on the catalogue key**, `a.asset_key = CONCAT('body/', b.body, '/a0')`,
|
||||
not `a.body = b.body`. The simpler join is correct today and stops being correct the moment deeper
|
||||
animation keys (`body/400/a2/f0`) arrive, at which point one slug matches dozens of rows.
|
||||
- **`shard_creature_bodies` IS replaced whole**, unlike `shard_assets`: it is derived from the atlas's
|
||||
creature list, so a slug that has left the atlas has no meaning, and the pass that rebuilds it is a
|
||||
shard round trip rather than a file transfer.
|
||||
- **`status` keeps the negative answers** — `unknown` (the spawn files name a type this shard's
|
||||
scripts do not define, which is real drift), `notCreature` (a spawn entry for an item or
|
||||
decoration, a permanent answer), `failed`. Without them the next pass asks again, and each name
|
||||
costs a real constructor on the shard's Core thread.
|
||||
|
||||
`shard_spawn_creatures.name` already holds the ServUO **class name** — the atlas build picks the
|
||||
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.
|
||||
|
||||
## shard_clilocs / shard_cliloc_meta — UO's localization table (Protocol 3.0)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user