Classic Ultima Online on Godot 4 .NET
The Deck is an x86_64 Linux PC (SteamOS 3), so GUO runs on it as Godot’s own
Linux export of the .NET project. Nothing is compiled on the Deck: the PC
exports, copies the build over ssh and starts it. The decision and its
evidence are in ADR-0018 (Accepted); the full how-to, with every command and
the troubleshooting table, is docs/steamdeck.md. This page is the short
version.
launchers\steamdeck\doctor.bat REM what is missing here and on the Deck, with the fix
launchers\steamdeck\export.bat REM the Linux build -> build\steamdeck\GUO.x86_64 + GUO.pck + data_*\
launchers\steamdeck\push.bat REM copy it to the Deck over ssh, write guo.sh there
launchers\steamdeck\run.bat REM start it in the Deck's Desktop-mode session
launchers\steamdeck\screenshot.bat REM photograph the Deck's screen
launchers\steamdeck\smoke.bat REM export + push + run + wait for the login gump + screenshot
Underneath: python tools\steamdeck\run.py <command>, plus templates,
preset, stop, log, shortcut, awake (keep the Deck from sleeping for
a while) and release (end that hold), which have no launcher.
Prefer not to export it yourself? The release workflow builds the same thing on GitHub: see Download a build.
passwd, then
sudo systemctl enable --now sshd. Note the Deck’s address and give it a
DHCP reservation so it stays put.~/.ssh/authorized_keys
(ssh-keygen -t ed25519 -f ~/.ssh/guo_deck). The tools run ssh in batch
mode, so a key that still prompts fails fast instead of hanging.Your values in launchers\_shared\config.local.bat, never in
config.bat (they are your network):
if not defined UO_DECK_HOST set "UO_DECK_HOST=<deck-address>"
if not defined UO_DECK_SSH_KEY set "UO_DECK_SSH_KEY=~/.ssh/guo_deck"
if not defined UO_SHARD_HOST set "UO_SHARD_HOST=<this PC's LAN address>"
REM optional
REM if not defined UO_DECK_CLIENT_DATA set "UO_DECK_CLIENT_DATA=~/UO"
REM if not defined UO_DECK_ACCOUNT set "UO_DECK_ACCOUNT=<your account>"
UO_DECK_ACCOUNT, when set, is passed to the client as --account.
Every key is documented in config.bat; see Configuration.
launchers\steamdeck\doctor.bat checks both ends and names the fix for
each miss.The client reads your own Ultima Online install, the folder with the
.uop / .mul / .idx files. It is proprietary and 2 to 4 GB, so the
tools never copy it: you put it at UO_DECK_CLIENT_DATA yourself, once
(default ~/UO, that is /home/deck/UO):
scp -r "<your UO folder>" deck@<deck-address>:UO
(fine on a cable, slow on Wi-Fi);/run/media/deck/<card-name>/UO, with
UO_DECK_CLIENT_DATA set to that path. The card is mounted in both modes.doctor looks for tiledata.mul there.
launchers\steamdeck\export.bat
launchers\steamdeck\push.bat --host <the shard's address>
launchers\steamdeck\run.bat --wait 60
push writes guo.sh next to the build:
exec ./GUO.x86_64 -- --play --client-data "$HOME/UO" --host <shard> --port 2593 "$@"
Anything you pass guo.sh goes to the client (./guo.sh --sound). Never
leave the host at 127.0.0.1: on the Deck that is the Deck itself, not your
shard; doctor and push warn about it.
launchers\steamdeck\smoke.bat [--host <shard>] [--timeout 180] [--no-export] [--no-push]
Exports, pushes, starts the client with the login probe, waits for the login
gump, photographs the screen (build\steamdeck\smoke.png), keeps the log
(build\steamdeck\smoke_guo.log) and stops the client. Non-zero if the gump
never shows or the client dies. It needs Desktop mode and the client data on
the Deck. This is the record behind ADR-0018’s Accepted status.
Game mode runs gamescope, which an ssh session cannot draw into, so there the client has to be started by Steam. From Desktop mode:
python tools\steamdeck\run.py shortcut
puts GUO in the Plasma application menu and prints Steam’s usual steps:
Games > Add a Non-Steam Game, browse to /home/deck/GUO/guo.sh (file
type All Files), name it GUO, optionally add client flags as launch options,
and pick the Keyboard (WASD) and Mouse controller layout. Back in Gaming
Mode it is under Library > Non-Steam. The tool never edits Steam’s
shortcuts.vdf, and re-pushing a build does not touch the shortcut.
Notes for Game mode:
src/Input/Gamepad, checked by
--gamepad-probe): D-pad or left stick walks, A clicks at the pointer, B
cancels, the right stick moves the pointer. Steam’s keyboard-and-mouse
layout hands the client keys and a mouse instead, so the layer stays idle.
A gamepad layout has not been tried on the Deck yet; the Thor is the
only device it has been run on.run and screenshot only work in Desktop mode.The pre-game screens use upstream ClassicUO’s fixed 640x480 window, so on
the Deck’s 1280x800 panel the login gump sits in a small window at 1x (the
smoke log reports window 640x480), and the canvas background is not seen
behind it. The phone build centres these screens full-screen instead, but
doing the same on the Deck or the desktop would depart from upstream: it is
an open decision for the project owner, not a bug to fix in passing.