# cliloc-export Converts a UO client's **compressed** `Cliloc.enu` into the plain format the website can read. This is a one-off operator utility, not part of the website build. Nothing in the Node application references it and CI never touches it. Full background — including why the conversion is necessary at all — is in [`docs/website/CLILOCS.md`](https://gitea.whitlocktech.com/RunicGateway/docs/src/branch/edge/website/CLILOCS.md). ## The short version Every current UO client ships its cliloc files in the compressed "Mythic" container (the first DWORD's high byte is `0x8E`). The website parses the plain layout those files used before that change. Decompressing is an inverse-BWT coder that the site has no business carrying at runtime — and ServUO's own bundled `Ultima.StringList` cannot read it either, so the shard cannot supply item names on our behalf. So: convert once, here, using a decompressor that already exists and is already maintained — [UOFiddler](https://github.com/polserver/UOFiddler)'s `Ultima.dll`. ## Usage ```bash dotnet build -c Release # plain binary (recommended — exact) dotnet run -- "/Ultima.dll" "/Cliloc.enu" /srv/uo-data/clilocs.plain # tab-delimited text (convenient; does not preserve leading/trailing whitespace) dotnet run -- "/Ultima.dll" "/Cliloc.enu" /srv/uo-data/clilocs.tsv --tsv ``` Then point the site at the output: **Admin → Shard → cliloc path**, or the `UO_CLIENT_PATH` environment variable. The setting wins over the environment. Expected output for a stock English client: ``` wrote 123490 entries to /srv/uo-data/clilocs.plain (maxTextBytes=12150, skippedOversize=0) ``` The site stores ~67,500 of those — roughly half a cliloc table is empty strings for ids the client reserves and never uses. ## Two implementation notes worth keeping **`Ultima.dll` is loaded reflectively, not referenced.** UOFiddler ships as net10.0; a project reference from an older SDK fails at *compile* time with CS1705. Reflection moves that to run time, where `RollForward: LatestMajor` answers it — so this builds on whatever SDK you have and runs on the newest runtime installed. **`StringList.SaveStringList` is not the export path**, despite looking exactly like it. It *re-compresses* on save, because its purpose is round-tripping a file back into the client — its output is byte-identical to its input. The plain records are written by hand for that reason. ## Output is never committed UO's strings are EA's. `.gitignore` covers this project's build output and the conventional in-repo output location, but the supported arrangement is a path **outside** the repository entirely.