docs(link): clilocs come over the bridge now, and UOFiddler's first job is gone
Phase 2 of the Asset Bridge is built, so the documentation stops telling an operator to install a GUI tool. `v8.md` gains §9.1 and §9.2 — what the port cost, what it measured, and where the base table comes from now. The measurement worth keeping: **67,496 rows in 290 ms**, which is exactly what UOFiddler's own `Ultima.dll` produced from this same client through the converter this phase deletes. An independent implementation agreeing to the row is the strongest check available that a format decoder is correct, and it is not something a subtly-wrong one produces. §17 records the four shapes the org lead settled before any of it was written. Two departed from the recommendation: **the bridge always wins** (no source setting — there is no version of that question an operator benefits from answering) and **import is admin-triggered** (boot does not call the shard at all). `CLILOCS.md` is rewritten around that: where the table comes from, what arrives and in how many pieces, the refusals — including the two the file pipeline had no equivalent of (a client patched mid-import, and the base's exemption from the vanished-source rule, which exists so an upgraded install is not asked to approve a change the upgrade itself made). `UOFIDDLER.md` loses Part 1 entirely rather than having it rewritten. What is left is creature art, which phase 5 takes, after which the page goes away. `v3.md` §8.6 keeps its reasoning with a note saying what superseded it, because the argument for why the manual step existed is still the argument for why this was worth building. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016wDDVXWMDz82WqE1i969r4
This commit is contained in:
@@ -1,34 +1,45 @@
|
||||
# Extracting from your own UO client (UOFiddler)
|
||||
|
||||
**Audience:** the shard operator, once, at setup time.
|
||||
**Related:** [`CLILOCS.md`](CLILOCS.md) (why the cliloc conversion is unavoidable),
|
||||
[`SPAWN_ATLAS.md`](SPAWN_ATLAS.md) (where creature art fits).
|
||||
**Related:** [`SPAWN_ATLAS.md`](SPAWN_ATLAS.md) (where creature art fits),
|
||||
[`../link/v8.md`](../link/v8.md) (the Asset Bridge, which is replacing this page).
|
||||
|
||||
Two features read data that **only exists inside a UO client**, and a UO client's
|
||||
files are EA's, not ours to redistribute. So neither this repo nor any image we
|
||||
publish can ship them — the operator extracts from **their own** client, once,
|
||||
> ### The cliloc conversion is gone — you no longer do this by hand
|
||||
>
|
||||
> **Protocol 8, phase 2.** The shard reads its own client's `Cliloc.enu` and
|
||||
> serves the table over the bridge, so there is nothing to install, convert or
|
||||
> copy. Press **Admin → Shard → Import** after you patch your client and that is
|
||||
> the whole procedure; see [`CLILOCS.md`](CLILOCS.md).
|
||||
>
|
||||
> Part 1 of this guide has been deleted rather than rewritten. If you already
|
||||
> have a converted file it keeps working on an install with no uo-link
|
||||
> configured, but nobody should make a new one.
|
||||
>
|
||||
> **Creature art is next** (phase 5), after which this page goes away entirely.
|
||||
|
||||
What remains here reads data that **only exists inside a UO client**, and a UO
|
||||
client's files are EA's, not ours to redistribute. So neither this repo nor any
|
||||
image we publish can ship them — the operator extracts from **their own** client
|
||||
and points the site at the result.
|
||||
|
||||
| Feature | What it needs | Required? | Without it |
|
||||
|---|---|---|---|
|
||||
| **Item / title names** ([`CLILOCS.md`](CLILOCS.md)) | `Cliloc.enu`, converted | No | Names render as raw ids — `id 1023721` instead of *quarter staff* |
|
||||
| **Creature art** ([`SPAWN_ATLAS.md`](SPAWN_ATLAS.md)) | Sprites from `.mul`/`.uop` | No | Atlas pages render as text, which is the normal state |
|
||||
|
||||
**Both are optional and neither is load-bearing.** A shard that never does any of
|
||||
this is fully supported. Do part one and skip part two if art is not worth your
|
||||
time — they share only the tool.
|
||||
**It is optional and it is not load-bearing.** A shard that never does any of this
|
||||
is fully supported.
|
||||
|
||||
Everything you extract stays **outside the repository**: the converted cliloc
|
||||
file lives at a path you choose, and `spawnAtlas.art.json` plus `server/uploads/`
|
||||
are gitignored, so none of it can be committed by accident.
|
||||
Everything you extract stays **outside the repository**: `spawnAtlas.art.json` and
|
||||
`server/uploads/` are gitignored, so none of it can be committed by accident.
|
||||
|
||||
---
|
||||
|
||||
## Part 0 — Get UOFiddler
|
||||
|
||||
[UOFiddler](https://github.com/polserver/UOFiddler) is the community client-file
|
||||
editor. We use it because its `Ultima.dll` already contains the cliloc
|
||||
decompressor, maintained by people who do this for a living.
|
||||
editor. What is left here uses its GUI to export sprites; the `Ultima.dll` this
|
||||
guide used to reach for was the cliloc decompressor, and the shard has its own
|
||||
now.
|
||||
|
||||
1. Download the latest release zip from
|
||||
<https://github.com/polserver/UOFiddler/releases/latest> — one asset, named
|
||||
@@ -38,204 +49,30 @@ decompressor, maintained by people who do this for a living.
|
||||
|
||||
```
|
||||
UOFiddler-4.22.2/
|
||||
Ultima.dll ← the decompressor (Part 1 needs this path)
|
||||
UoFiddler.exe ← the GUI (Part 2 needs this)
|
||||
Ultima.dll
|
||||
plugins/
|
||||
…
|
||||
```
|
||||
|
||||
3. **Runtime:** UOFiddler 4.22.2 is built for **.NET 10**. Running `UoFiddler.exe`
|
||||
needs the .NET 10 **Desktop** Runtime (Windows only); loading `Ultima.dll` from
|
||||
the converter in Part 1 needs the .NET 10 runtime. Install from
|
||||
<https://dotnet.microsoft.com/download/dotnet/10.0>.
|
||||
3. **Runtime:** UOFiddler 4.22.2 is built for **.NET 10**, so running
|
||||
`UoFiddler.exe` needs the .NET 10 **Desktop** Runtime (Windows only). Install
|
||||
from <https://dotnet.microsoft.com/download/dotnet/10.0>.
|
||||
|
||||
### Finding your client files
|
||||
|
||||
The cliloc file is in your **UO client installation directory**, not in your
|
||||
ServUO tree — the shard server has no copy of it. Look for `Cliloc.enu` (English;
|
||||
the other seven are `chs`, `cht`, `deu`, `esp`, `fra`, `jpn`, `kor`) beside
|
||||
`art.mul` / `artLegacyMUL.uop`. The EA Classic Client's default location is:
|
||||
The art files are in your **UO client installation directory**. Look for
|
||||
`art.mul` / `artLegacyMUL.uop` and the `anim*.mul` set. The EA Classic Client's
|
||||
default location is:
|
||||
|
||||
```
|
||||
C:\Program Files (x86)\Electronic Arts\Ultima Online Classic\
|
||||
```
|
||||
|
||||
**If your shard distributes its own patched client to players, use that copy.**
|
||||
Any cliloc edits you shipped to players are then already in the base table and
|
||||
you need no overlay for them (see [`CLILOCS.md`](CLILOCS.md) §Shard-added and
|
||||
shard-edited items).
|
||||
|
||||
---
|
||||
|
||||
## Part 1 — Convert the cliloc table
|
||||
|
||||
**Goal:** turn the client's compressed `Cliloc.enu` into a file the site can
|
||||
read, and point the site at it.
|
||||
|
||||
The site cannot read `Cliloc.enu` directly. Every modern client compresses it
|
||||
(the "Mythic" container), and so does ServUO's own bundled `Ultima.StringList` —
|
||||
which is why the shard cannot supply names on our behalf either. The full
|
||||
reasoning is in [`CLILOCS.md`](CLILOCS.md) §Why the operator has to convert the
|
||||
file; this section is just the procedure.
|
||||
|
||||
Two routes. **The bundled tool is the recommended one** — the GUI export needs a
|
||||
fixup step, described below.
|
||||
|
||||
### Route A — the bundled converter (recommended)
|
||||
|
||||
Needs a .NET SDK (any version 8 or newer — the project targets `net8.0` and rolls
|
||||
forward, so whatever you have works) **plus** the .NET 10 runtime from Part 0,
|
||||
which is what actually loads `Ultima.dll`.
|
||||
|
||||
```bash
|
||||
cd website/server/tools/cliloc-export
|
||||
dotnet build -c Release
|
||||
|
||||
# plain binary — recommended, exact
|
||||
dotnet run -c Release -- \
|
||||
"/path/to/UOFiddler-4.22.2/Ultima.dll" \
|
||||
"/path/to/UO client/Cliloc.enu" \
|
||||
/srv/uo-data/clilocs.plain
|
||||
|
||||
# or tab-delimited text, if you want to eyeball or hand-edit it
|
||||
dotnet run -c Release -- \
|
||||
"/path/to/UOFiddler-4.22.2/Ultima.dll" \
|
||||
"/path/to/UO client/Cliloc.enu" \
|
||||
/srv/uo-data/clilocs.tsv --tsv
|
||||
```
|
||||
|
||||
Expected output for a stock English client:
|
||||
|
||||
```
|
||||
wrote 123490 entries to /srv/uo-data/clilocs.plain (maxTextBytes=12150, skippedOversize=0)
|
||||
```
|
||||
|
||||
**Sanity-check that number.** A stock `Cliloc.enu` is ~123,000 entries. A few
|
||||
hundred means it read something else and you should not ship the result. The
|
||||
tool exits non-zero and says `no entries were written — is that a cliloc file?`
|
||||
when it gets nothing at all.
|
||||
|
||||
The conversion runs on whatever machine has the client (usually Windows), and the
|
||||
site reads the output wherever it runs — so **copy the output file to the server**
|
||||
if those are different machines. It is a single self-contained file (~5 MB); the
|
||||
`--tsv` form is larger but diff-able.
|
||||
|
||||
<details>
|
||||
<summary>Errors you may hit</summary>
|
||||
|
||||
| Message | Cause |
|
||||
|---|---|
|
||||
| `Ultima.StringList not found — is that really UOFiddler's Ultima.dll?` | First argument points at some other `Ultima.dll` (ServUO ships one too — it is **not** the same assembly and cannot do this) |
|
||||
| `You must install .NET to run this application` | Missing the .NET 10 runtime from Part 0 step 3 |
|
||||
| `Unexpected Ultima.StringList API` | UOFiddler older than 4.21 |
|
||||
| `usage: clilocexport …` | Fewer than three arguments |
|
||||
|
||||
</details>
|
||||
|
||||
### Route B — the UOFiddler GUI
|
||||
|
||||
Use this if you would rather not install a .NET SDK. **It needs one extra step**,
|
||||
so do not skip the fixup.
|
||||
|
||||
1. Launch `UoFiddler.exe` and point it at your client directory when it asks
|
||||
(or **Options → Path Settings**).
|
||||
2. Open the **Cliloc** tab and use its **export to CSV** action.
|
||||
3. It writes `CliLoc.csv` to UOFiddler's configured output path, in **three**
|
||||
columns with a header row:
|
||||
|
||||
```
|
||||
Number;Text;Flag
|
||||
1023721;quarter staff;0
|
||||
```
|
||||
|
||||
4. **Strip the trailing flag column.** The site's text parser reads
|
||||
`number<TAB|,|;>text`, so that third field is otherwise absorbed into the name
|
||||
and every item on the site renders as `quarter staff;0`.
|
||||
|
||||
```bash
|
||||
sed -E 's/;[0-9]+$//' CliLoc.csv > clilocs.csv
|
||||
```
|
||||
|
||||
```powershell
|
||||
Get-Content CliLoc.csv |
|
||||
ForEach-Object { $_ -replace ';\d+$','' } |
|
||||
Set-Content -Encoding utf8 clilocs.csv
|
||||
```
|
||||
|
||||
The header row needs no removal — a line whose first field is not an integer
|
||||
is skipped. Blank entries (`1005008;`) survive the fixup correctly and are
|
||||
dropped at import, as intended.
|
||||
|
||||
5. Copy `clilocs.csv` to the server.
|
||||
|
||||
**Why the fixup is not just done for us:** the parser already handles
|
||||
`number,flag,text` — the flag in the *middle*, which is what several exports
|
||||
emit. UOFiddler puts it at the *end*, where it is indistinguishable from a name
|
||||
that genuinely ends in `;0`. One `sed` on the operator's side beats a parser
|
||||
heuristic that would corrupt real names.
|
||||
|
||||
### Point the site at it
|
||||
|
||||
Two ways, the setting winning over the environment:
|
||||
|
||||
| Where | How |
|
||||
|---|---|
|
||||
| **Admin → Shard → cliloc path** | Takes effect on the next refresh, no redeploy |
|
||||
| `UO_CLIENT_PATH` env var | The deploy-time default |
|
||||
|
||||
The value may be **the file itself or a directory to search** — both are natural
|
||||
answers to "where is it", and overlays are picked up either way.
|
||||
|
||||
Setting the path deliberately does **not** import as a side effect. Click
|
||||
**Import** (or `POST /api/v1/admin/shard/clilocs/import`) to load it.
|
||||
|
||||
### Verify
|
||||
|
||||
`GET /api/v1/admin/shard/clilocs`, or the Admin → Shard panel, reports what each
|
||||
source contributed:
|
||||
|
||||
```json
|
||||
"sources": [
|
||||
{ "label": "clilocs.plain", "kind": "base", "entries": 123490, "added": 123490, "overrode": 0 }
|
||||
]
|
||||
```
|
||||
|
||||
Roughly **67,500 rows stored** from a stock table is correct — about half a
|
||||
cliloc table is empty strings for ids the client reserves and never uses.
|
||||
|
||||
Then load any character sheet with equipment: items should show names rather than
|
||||
`id 1023721`.
|
||||
|
||||
<details>
|
||||
<summary>What a refusal means</summary>
|
||||
|
||||
A bad file answers `200` with a `status` and a named reason, not a `500` — you
|
||||
need to be told *which file* to fix.
|
||||
|
||||
| `code` | Meaning |
|
||||
|---|---|
|
||||
| `COMPRESSED` | You pointed at the raw client `Cliloc.enu`. Convert it — this whole page. |
|
||||
| `TRUNCATED` | Half-copied file. Re-copy; the loaded table is untouched. |
|
||||
| `EMPTY` | A text source with no parseable rows — the file is named in the reason. |
|
||||
| `status: needsReview` + `missingSources` | A previously-loaded source has vanished (unmounted volume? deliberate deletion?). Nothing changes until you re-import with `{ "approve": true }`. |
|
||||
|
||||
</details>
|
||||
|
||||
### Custom items — do *not* re-export for these
|
||||
|
||||
Shard-added items carry ids no client table has. Drop a small delimited file in a
|
||||
`custom/` directory beside the base file and re-import:
|
||||
|
||||
```
|
||||
/srv/uo-data/
|
||||
clilocs.plain ← base, from this guide
|
||||
custom/
|
||||
01-uomysticmoon.tsv ← your additions and overrides
|
||||
```
|
||||
|
||||
Files are read in sorted order and **later sources win**, so an overlay both adds
|
||||
new ids and overrides stock ones you have re-purposed. **Adding one item never
|
||||
means re-exporting a 5 MB client file.** Details in [`CLILOCS.md`](CLILOCS.md).
|
||||
**If your shard distributes its own patched client to players, use that copy** —
|
||||
it is what your players actually see. (It is also the copy the shard itself reads
|
||||
from, since a ServUO server resolves `Config/DataPath.cfg` into its own client
|
||||
path at boot, which is the premise the Asset Bridge is built on.)
|
||||
|
||||
---
|
||||
|
||||
@@ -246,7 +83,8 @@ functional as text, and `art` is NULL on every fresh import.
|
||||
|
||||
**This project ships no art and no art-extraction tooling, and never will.**
|
||||
|
||||
1. In `UoFiddler.exe` (paths configured as in Route B step 1), open the
|
||||
1. Open `UoFiddler.exe` and point it at your client directory
|
||||
(**Settings → Paths**), then open the
|
||||
**Animations** tab for creature sprites — or **Items** for object art — find
|
||||
the creature, and export as PNG. Right-click an entry for its export options,
|
||||
or use the tab's *Export All* action for a batch. (4.22.2 added an export
|
||||
|
||||
Reference in New Issue
Block a user