diff --git a/link/v8.md b/link/v8.md index eaeb095..ee34cfa 100644 --- a/link/v8.md +++ b/link/v8.md @@ -169,10 +169,12 @@ application, and a minimal PNG writer over `System.IO.Compression.DeflateStream` into a `Bitmap` via `LockBits`, so System.Drawing is in the *decode*, not just the encode — a Linux/Mono shard needs libgdiplus even to read a sprite. Writing our own pixels and our own PNG makes the feature portable by construction. -3. **It removes the UOP gap.** ServUO's vendored `Animations` reads legacy `anim*.mul` only. This - client has a full 195 MB `anim.mul` so most bodies resolve — but **gargoyle bodies 666/667 - returned nothing**, because gargoyles live in `AnimationFrame*.uop`. A player race missing from - an asset store built for "player models and everything" is not a caveat, it is a defect. +3. **It removes the UOP gap, which lands squarely on the player bodies.** ServUO's vendored + `Animations` reads legacy `anim*.mul` only, never `AnimationFrame*.uop`. This client has a full + 195 MB `anim.mul` so most creatures resolve — but **six of the twelve stock player-character + bodies return nothing**, including every gargoyle and both human ghosts (§5.2). A missing + playable race in an asset store built for "player models and everything" is not a caveat, it is + a defect, and it is in the highest-attention part of the scope. 4. **We are already in this business.** §9 writes a cliloc decompressor from scratch regardless. A2 also ends the dependency on whatever version of `Ultima` a given ServUO happens to vendor, @@ -210,13 +212,20 @@ Three properties this shape buys: ### 5.1 There is no direction segment, because only one direction is wanted Bodies are stored in **five** directions and the client mirrors three of them to reach eight. Only -one is needed here — the one facing the viewer — so **direction is fixed by the extractor and is -not part of the key**. Leaving it in would advertise a choice nobody is going to make and would -five-fold every count in §11 for nothing. +one is needed here, so **direction is fixed by the extractor and is not part of the key**. Leaving +it in would advertise a choice nobody is going to vary and would five-fold every count in §11 for +nothing. -**The front-facing index is 0.** This was determined by rendering all five for a human, a wolf and -a dragon rather than from a table, because the answer is not obvious and the small-thumbnail version -of the same test suggested the opposite: +**Which one depends on whether the body is a player character:** + +| Body | Direction | Why | +|---|---|---| +| A player character body | **0** — head-on, facing the viewer | A character is a portrait; it should look at you | +| Everything else | **1** — front three-quarter | The view that actually reads as a creature (see the caveat below) | + +Which index is which was determined by **rendering all five** for a human, a wolf and a dragon +rather than from a table, because the answer is not obvious and the small-thumbnail version of the +same test suggested the exact opposite: | Index | View | |---|---| @@ -226,12 +235,45 @@ of the same test suggested the opposite: | 3 | Rear three-quarter | | 4 | Directly away — back of the head, and a quadruped's tail toward the camera | -One caveat the render made obvious, and it is the reason this is written down rather than assumed: -**index 0 is the least legible view for four-legged and long-bodied creatures.** A wolf seen head-on -is a dark blob; the same wolf at index 2 is unmistakably a wolf, and at index 1 is the view -UOFiddler's own thumbnail list picks. For a bestiary tile that matters. The extractor therefore -takes the index as a **configuration value defaulting to 0**, so changing the catalogue's mind later -is a setting and a re-import, not a protocol change. +The caveat the render made obvious is what produced the split: **index 0 is the least legible view +for four-legged and long-bodied creatures.** A wolf seen head-on is a dark blob; the same wolf at +index 1 is unmistakably a wolf, which is also why UOFiddler's own thumbnail list picks that view. A +humanoid has no such problem — it reads fine head-on, and head-on is what a character portrait +wants. + +Both indices stay **configuration values** (defaulting to 0 and 1), so changing the catalogue's mind +later is a setting and a re-import, not a protocol change. + +### 5.2 "Player character body" is asked of the shard, never hardcoded + +`Server.Race.AllRaces` gives every registered race, and each carries `MaleBody`, `FemaleBody`, +`MaleGhostBody` and `FemaleGhostBody`. The plugin enumerates those four ids per race and that set — +nothing else — takes index 0. On stock ServUO 57.4 that is twelve ids: + +| Race | Male | Female | Male ghost | Female ghost | +|---|---|---|---|---| +| Human | 400 | 401 | 402 | 403 | +| Elf | 605 | 606 | 607 | 608 | +| Gargoyle | 666 | 667 | **695** | **694** | + +This is the §8 argument again in miniature: only code inside ServUO can answer it, and asking is +the only thing that works on a shard with a custom race. Two details make the case that a +hardcoded list would have been wrong — `RaceDefinitions.cs` passes the gargoyle's ghost bodies in +the **opposite order** to the other two races (695 male, 694 female), and a shard that calls +`RegisterRace` adds ids no table of ours would contain. + +**Half of that set does not decode with ServUO's vendored library.** Measured: + +| Decodes | Does not | +|---|---| +| Human male/female (400, 401) | **Human ghosts (402, 403)** | +| Elf male/female (605, 606) | **Every gargoyle body (666, 667, 694, 695)** | +| Elf ghosts (607, 608) | | + +Six of twelve, including a whole playable race. So the one part of the asset scope with the most +attention on it — the player character, head-on — is precisely the part the vendored `Animations` +serves worst, and §4's recommendation to own the decoders is what fixes it. This is the single +strongest piece of evidence for that choice. --- @@ -505,8 +547,9 @@ prove byte-identical output *before* building six phases on top of it. libgdiplus dependency, the UOP gap and the vendor-drift risk all going away at once. 2. **§11: gump art deferred.** Confirm that paperdoll and equipment gump art is genuinely out of scope for 8, given it is the one kind whose existing decoder crashes. -3. **§5.1: direction is fixed at index 0** (head-on) and is not in the key — settled 2026-09-10. - What is *not* settled is whether the catalogue should default to index 1 or 2 instead, since a - head-on wolf is a dark blob and a side-on wolf is a wolf. It is a setting either way. +3. **§5.1/§5.2: direction — settled 2026-09-10.** Player character bodies use index 0, everything + else index 1, direction is not in the key, and the player-body set is enumerated from + `Race.AllRaces` rather than hardcoded. Nothing outstanding; recorded here because it changes + every count in §11. 4. **§13: the default audience** for asset serving — inheriting the using page's audience is proposed; the operator sets the policy either way.