GodotUO

Classic Ultima Online on Godot 4 .NET


Project maintained by DatMoshu Hosted on GitHub Pages — Theme by mattgraham

Editor

A Godot editor add-on for looking at, editing and shipping UO world data, built on the ported client rather than beside it. Sources of truth: docs\editor_plan.md, ADR-0010, ADR-0011, ADR-0012, ADR-0015, and the READMEs of tools\editor_smoke, tools\editor_live, tools\editor_shard, tools\world and tools\world_parity.

The add-on lives in godot\GUO\addons\guo_editor\. It is enabled in project.godot, so launchers\editor\open_project.bat opens with the UO tabs across the top (World, Assets, Store, Gumps, MapGen, Multis and Admin), the UO Inspector on the right and the UO Shard dock in the bottom panel.

Admin is a tab for a server you run on this computer: health, Save and Restart, accounts, settings, backups, commands, a god view of who is where, and an audit log. See Admin Tab. The add-on is an editor package (layer L3, see Feature Layers): it is compiled only for the editor and is never in an exported client.

The editor can also be driven by an automation (MCP) client. Editor Settings

GUO > MCP Access has one switch per group of tools: reading state, moving around and connecting start on; anything that changes your server starts off. Everything AI is behind Editor Settings > GUO > AI > Enabled. With it off, the AI and MCP surfaces are hidden and their work stops. Manual authoring is unaffected. See tools\editor_mcp\README.md.

New to the World tab? World Editing walks through selecting, placing and moving things on the map, step by step.

UO Gumps is the layout authoring tab for classic gump documents and native Godot forms. It includes a canvas, layers, properties, undo/redo, classic layout import/export and live-client capture/apply. See the Gump Studio guide for commands, runtime integration and the limits of custom-control captures.

Server and client profiles

The run bar has separate Server and Client lists. Choosing a server selects its default client; the Client list lets you override that choice. Use Manage servers → Clients to add a Godot project, an exported GUO build, or an external client executable, then choose that profile on the Servers page. A mismatch warning reports a different expected version or changed data files.

Profiles share a per-user workspace across checkouts. UO_WORKSPACE_DIR overrides its location. Each server/client pair has four separate run slots for settings, accounts and logs. Existing editor profiles migrate with a .migrated backup; UO installs remain in place. See the server manager guide for setup and the workspace decision for the layout and migration rules.

Asset fields

Every box that wants a UO id is an asset field, like Unity’s object field: Gump Studio’s art, pressed art and hue; the World tab’s static and hue; the Multi Editor’s multi id and hue; the Parity panel’s id. The code is in addons\guo_editor\Fields\.

Names come from the data: tiledata for art, hues.mul for hues, the sound index, the cliloc table, and, for gumps, the UI classes that name them. Recent picks are kept per kind in the project’s editor metadata.

Shape (ADR-0010)

Phases

Phase What it delivers State
0 The add-on skeleton, the docks, the smoke. Done
1 The Assets dock’s panels (addons\guo_editor\Panels\): art, gumps, animations, hues, sounds, clilocs, multis, map, plus a Parity panel that renders an asset through the port and through the reference reader side by side. Done
2 The World tab: the client’s own renderer embedded in the editor (ADR-0015), drawing any cell of the install at the client’s size, with a season. tools\world_parity proves it draws what a logged-in client draws. Done
3 The world project overlay (ADR-0011): edits are whole replaced 8x8 blocks stored as JSON under UO_WORLD_PROJECT, drawn over the install in the World tab. Tools, undo, and export to patched map files (tools\world). Done
4 The live tier (ADR-0012): a UO Shard dock that talks to a private ModernUO instance through a bridge assembly, so a block edit is pushed to the shard and to connected clients (UltimaLive) while they play. Done
5 Asset edits (ADR-0020; the number 0013 was retired): land art, static art, gumps and hues replaced from PNG in the world project’s assets\, shown at once in the Assets dock and the World tab, exported as a verdata.mul and a patched hues.mul that any ClassicUO-lineage client loads through files_override. Done
6 Shard world objects (ADR-0014): spawners and items kept in the project’s shard\objects.json, placed in the World tab and written into the export for the shard. Done (smoke-tested on the private instance)
H Bulk import/export (ADR-0022): the Assets dock’s Bulk tab unpacks art, land, gumps, animations or tiledata to PNG plus JSON sidecars and packs an edited folder into a staged data set, by running tools/uopack and showing its lines; Verify re-checks the stage and the untouched install. See Author UO Data. Done (unpack smoke-tested)

“Done” here means the phase’s check has been run and its README or ADR records the run; the details are in each validation section.

The world project (ADR-0011)

The ported MapLoader is not changed. A project replaces whole blocks, and the editor repoints the loader’s index entries for those blocks at the project’s data, so everything else reads the install untouched. The format is docs\data_formats.md section 9. docs\editor_plan.md section 4.3 had proposed one PORT DEVIATION in MapLoader.cs instead; the ADR chose the index repointing, and the plan was not updated.

Exporting it

launchers\pipeline\04_world_export.bat [--project DIR] [--out DIR] [--force]

tools\world export copies the install’s land, staidx and statics files for each facet the project touches and patches the copies in place; every block the project does not replace stays byte for byte the install’s. Beside them it writes files_override.txt (ClassicUO’s files_override format, so either client can read the export) and export.json (fingerprint, blocks, SHA-1 per file). verify reads the export back with an independent Python reader and checks every block. An --out inside UO_CLIENT_DATA is refused; a project made on a different install is refused without --force.

A server reads the export by listing the folder first in its data directories (ModernUO: dataDirectories), ahead of the install.

The live tier (ADR-0012)

A small bridge assembly is loaded into a ModernUO instance (the private one below, or the shared dev shard, whose launchers\shard\run.bat loads it too) and listens on UO_EDITOR_LIVE_HOST:UO_EDITOR_LIVE_PORT (127.0.0.1:2595) for JSON lines from editors. A block edit goes editor, bridge, shard, and the shard sends the changed block to its clients with UltimaLive packets, which the ported client already handles. GUO_BRIDGE_MAPS says which maps the bridge serves. The wire format is docs\data_formats.md section 10.

The private shard instance

python tools\editor_shard\run.py setup --from <built Distribution> [--port 2594]
python tools\editor_shard\run.py start [--data-first <export folder>]
python tools\editor_shard\run.py status
python tools\editor_shard\run.py bridge [--bridge-port 2595]
python tools\editor_shard\run.py stop

A copy of the built dev shard on port 2594 with its own saves, so live edits and export checks never touch the shard people play on. --data-first puts an export ahead of the install in its data directories.

The checks

Tool Proves
launchers\dev\editor_smoke.bat (tools\editor_smoke) The real editor opens headless, the add-on loads, the docks answer, an art id is found. --windowed for screenshots (takes the desktop’s focus); --reload also rebuilds and hot-reloads the assembly; --require-native fails if a check that needs a real external program was skipped; --header-only checks the toolbar at three widths; --out FOLDER sends the evidence to a central folder.
python tools\scenario_run\run.py editor.admin.offline --headless Plays a scripted editor scenario (tools\scenarios\editor\: tabs sweep, MCP access, Admin offline, header layout). launchers\dev\scenario_run.bat is the launcher.
tools\editor_live\run.py Two editors and a client, end to end: an edit in editor A appears in editor B and in the client’s UltimaLive log. Headless by default; --windowed for a client picture.
tools\world_parity\run.py --at X,Y --windowed The World tab’s frame of a cell against a logged-in client’s frame of the same cell, pixel by pixel, masking the player, the paperdoll and the chat line. Measured 2026-09-27: 99.98% identical in the wilderness, 99.29% in Britain with the residual being shard decoration, 99.84% for a project drawn over the install against the client on its export. Plays on the private instance by default; the shared dev shard’s port is refused without --allow-shared.
tools\editor_asset_roundtrip\run.py A project’s asset edits are exported, verified, and read back unchanged by a headless GUO client pointed at the export; a control run without the export must not match. editor_smoke runs it on its own fixtures.

Output of all of them goes under UO_BUILD_DIR (build\ unless you set it) and contains renders of client art, so it is never committed.

For a task-by-task walk-through (setup, world view, export, live tier) see Manage Your Shard From the Editor. For the Admin tab see Admin Tab. The Store tab installs packs: see Content Packs.