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:
@@ -213,28 +213,59 @@ implicitly commit, defeating the all-or-nothing guarantee. Point ids are assigne
|
||||
explicitly rather than left to `AUTO_INCREMENT`, because the join rows need them
|
||||
and `conn.batch()` reports no usable `insertId`.
|
||||
|
||||
## Artwork — operator-supplied, never shipped
|
||||
## Artwork — the shard extracts it now (Protocol 8)
|
||||
|
||||
**This project ships no creature art and no extraction tooling, and never will.**
|
||||
UO sprites live in the operator's own client `.mul`/`.uop` files. They are the
|
||||
operator's, not ours to redistribute.
|
||||
|
||||
The atlas is fully functional as text. `shard_spawn_creatures.art` is nullable
|
||||
and is NULL on every fresh import; pages render without images, which is the
|
||||
normal and supported state, not a degraded one.
|
||||
What changed in protocol 8 is not that rule — it is who does the extracting. The
|
||||
shard already has those files (a ServUO server cannot boot without a UO client),
|
||||
so as of [`v8.md`](../link/v8.md) phase 3 it decodes them itself and hands the
|
||||
pictures to the website over the bridge. Nobody installs UOFiddler and nobody
|
||||
copies images to a web host.
|
||||
|
||||
An operator who wants art — step-by-step, with the UOFiddler side spelled out, in
|
||||
[`UOFIDDLER.md`](UOFIDDLER.md) §Part 2:
|
||||
**Admin → Shard → Import.** The import walks the shard's asset manifest, fetches
|
||||
only the sprites whose hash changed, writes them under `uploads/atlas/`, asks the
|
||||
shard for a body id per creature (§8 — the shard constructs the creature and
|
||||
reads `Body.BodyID`, which is the only thing that is right for a shard's own
|
||||
custom creatures) and points each `shard_spawn_creatures.art` at its picture.
|
||||
Boot never calls the shard for this: the files change when an operator patches
|
||||
their client, which is an event they know about and the site does not.
|
||||
|
||||
1. Extracts it from **their own** client files (UOFiddler, ClassicUO tooling, or
|
||||
any art extractor).
|
||||
2. Drops the images under `server/uploads/atlas/`.
|
||||
3. Copies `server/db/data/spawnAtlas.art.example.json` to `spawnAtlas.art.json`
|
||||
and maps creature slugs to file names.
|
||||
4. Restarts, or runs `npm run atlas:import -- --force`.
|
||||
On this machine's stock client that is **787 creature portraits**, about a
|
||||
megabyte in total.
|
||||
|
||||
Both `spawnAtlas.art.json` and `server/uploads/` are gitignored, so neither the
|
||||
map nor the images can be committed by accident.
|
||||
**NULL stays a first-class state, and always will be.** An install with no shard
|
||||
link has never imported one; a Linux shard host without `libgdiplus` cannot
|
||||
render a sprite at all (a named `NO_IMAGING` status, not an error); and even
|
||||
after a complete import, two thirds of the playable ghost and gargoyle bodies
|
||||
have no art in the client. Pages render without images, which is normal and
|
||||
supported, not degraded.
|
||||
|
||||
### The operator's own artwork still wins
|
||||
|
||||
An operator who has drawn their own portraits keeps them. The map is unchanged:
|
||||
|
||||
1. Drop the images under `server/uploads/atlas/`.
|
||||
2. Copy `server/db/data/spawnAtlas.art.example.json` to `spawnAtlas.art.json` and
|
||||
map creature slugs to file names.
|
||||
3. Restart, or run the import.
|
||||
|
||||
`spawnAtlas.art.json` is applied **over** anything imported, per slug, so a sprite
|
||||
rip never replaces a hand-drawn portrait on the next Update. Both it and
|
||||
`server/uploads/` are gitignored, so neither the map nor the images can be
|
||||
committed by accident.
|
||||
|
||||
### Why the imported art is not stored on the creature row
|
||||
|
||||
`shard_spawn_creatures` is emptied and refilled by every atlas refresh, and a
|
||||
refresh happens on every boot. So the body ids and the imported files live in
|
||||
`shard_creature_bodies` and `shard_assets`, outside that blast radius, and the
|
||||
atlas import re-derives `art` from them on the way past. Storing it on the row
|
||||
would mean an ordinary re-parse of the ServUO tree silently deleting every
|
||||
portrait — with the next asset Update finding the client files unchanged,
|
||||
reporting "nothing to do", and never putting them back.
|
||||
|
||||
## Code layout
|
||||
|
||||
|
||||
Reference in New Issue
Block a user