CLILOCS.md and SPAWN_ATLAS.md each explain WHY the operator has to supply
something out of their own client, but neither says how. UOFIDDLER.md is the
missing procedure: where to get UOFiddler, which two files in the zip matter,
which runtime it needs, where Cliloc.enu actually lives, the conversion, how to
point the site at the result, and how to confirm it took.
Verified end to end on a stock Windows box: UOFiddler 4.22.2 (Ultima.dll is
net10.0), .NET SDK 9.0.312 building the net8.0 converter, RollForward carrying
it onto runtime 10.0.8, and the site's own parser reading the output back.
Corrects one claim while doing it. CLILOCS.md said a UOFiddler GUI export
"works equally well"; it does not. Its Cliloc tab writes `Number;Text;Flag` --
three columns, flag LAST -- and parseClilocText splits on the first separator
only, so the flag is absorbed into the name and every item renders as
`quarter staff;0`. The parser already handles `number,flag,text` with the flag
in the middle, but a trailing `;0` is indistinguishable from a name that
genuinely ends that way, so this stays a documented `sed` on the operator's
side rather than a heuristic that would corrupt real names.
Co-Authored-By: Claude <noreply@anthropic.com>
Shards edit items and add new ones, carrying cliloc ids no stock client table
has. The cliloc table now reads a SET of sources rather than one file — a base
plus every operator-maintained overlay under `custom/`, hash-gated together and
re-read on every boot, exactly as §6 reads the ServUO tree. Matching docs for
website #115.
website/CLILOCS.md gains a "Shard-added and shard-edited items" section: the
directory layout, merge precedence, the per-source breakdown an operator uses
to confirm an overlay took effect, and why `custom/` is a convention we chose
rather than one discovered from the shard — ServUO has no server-side notion of
a custom cliloc, they live in the patched client a shard distributes and
nothing in the tree declares them. Scale recorded: the live shard's script tree
references 16,434 cliloc ids and only 37 are absent from stock, which is why
this is an overlay and not a second table.
"Why there is no staged-approval flow" is replaced by "Two ways a refresh is
refused", because the set brings back the hazard a single file did not have. A
corrupt source fails the parse loudly; a source that has VANISHED parses
perfectly and imports a table quietly missing everything it contributed. That
is the same ambiguity §6 stages a facet removal for, so it is staged here too
(`needsReview`, `{approve:true}` to accept) — as a flag rather than §6's
approve/reject pair, because the atlas stores a pending decision SO THAT
approving re-parses, and here nothing is stored.
Two more traps recorded in §8.6 (now five), both found by running a shard-style
overlay rather than another stock-table fixture:
- Tidying punctuation unconditionally corrupts real names — a custom
"Runic Gateway Sigil (v2)" rendered as "(v2". Stripping leftover brackets is
right after a placeholder is removed and wrong otherwise, the same condition
the `%` rule already had.
- Source labels must be forward-slashed and root-relative or the same directory
fingerprints differently on Windows and Linux and every boot looks like a
change — the identical bug §6 records.
BACKEND_DESIGN.md: the source set, the two refusals, and the updated admin
route notes (`approve`, `missingSources`, overlays found beside a file path).
Documentation only. Every claim was written after the behaviour was observed:
the counts come from the live shard's script tree, and the refusal/approve flow
and per-source breakdown are copied from real runs in website #115.
PROJECT_TREE.md files are deliberately untouched — CI-generated by the
sync-project-tree workflow.
Co-Authored-By: Claude <noreply@anthropic.com>
The progress table and CLILOCS.md carried #TBD placeholders until the PRs
existed; they now point at website #115 and docs #70.
Also corrects "all four Cliloc.* files" to eight (chs, cht, deu, enu, esp,
fra, jpn, kor) in both v3.md §8.6 and CLILOCS.md — the compression marker was
checked against every one of them, and understating the sample weakens the
claim it supports.
Co-Authored-By: Claude <noreply@anthropic.com>
Protocol 3.0 §8.6 resolved as its own website-only change, landing ahead of
§8 so the marketplace ships with real item names. Matching documentation for
website #TBD.
NEW website/CLILOCS.md — operator-facing: why the conversion step exists, how
to convert, how to configure the path, the refresh contract, what gets stored
and how names are applied.
link/v3.md §8.6 rewritten. Two things in the original recommendation turned
out to be wrong, and both are recorded because the reasoning generalises:
1. The committed db/data/clilocs.json artifact predates the Part C
corrections (§6.1) and violates both — no committed snapshot of derived
content, and nothing EA-derived ever shipped. UO's strings are EA's,
exactly as the creature sprites are.
2. "scripts/buildClilocs.js reads the UO client's Cliloc.enu" is not
possible. EVERY current client ships its cliloc files compressed (first
DWORD's high byte 0x8E, the Mythic container); the plain layout is what
those files looked like before that change, and parsing one as the other
does not fail cleanly — it yields ~19k records with negative ids, 1,722
distinct keys out of 19,508, one 62 KB "string", and a truncation
somewhere in the middle. ServUO's own Ultima.StringList cannot read it
either, so VendorSearch.GetItemName is already inert on such a shard and
the work could not be pushed to the plugin.
That second point also retires an open question in §8.2: the warning never to
call GetItemName in the market sweep costs us nothing we could otherwise have
had, because the in-game Vendor Search gump has the same gap.
Three traps found by building it are recorded: StringList.SaveStringList
RE-COMPRESSES on save (its output is byte-identical to its compressed input,
because its purpose is round-tripping a file back into the client); trimming a
text line before splitting silently drops the ~half of a table that is empty
strings; and Number('') is 0, not NaN.
Also updated:
- Progress and §9 sequencing tables: order 5 split into 5a (this, website
only) and 5b (the four-repo wire change).
- website/BACKEND_DESIGN.md — shard_clilocs / shard_cliloc_meta, the three
admin routes, and why there is no staged-approval flow and no public route.
- link/INTEGRATION.md — the char.profile field note now says explicitly not to
expect the shard to resolve clilocs, and points at CLILOCS.md.
- §10 documentation obligations list CLILOCS.md.
Documentation only. Every claim was written after the corresponding behaviour
was observed running: the compressed-format finding and the parse failures
come from the real client files on this machine, and the counts (123,490
parsed → 67,496 stored) and timings from importing them into the live MariaDB.
PROJECT_TREE.md files are deliberately untouched — they are CI-generated by
the sync-project-tree workflow and say so in their header.
Co-Authored-By: Claude <noreply@anthropic.com>