2017-12-09

OpenTTD under systemd

Just got OpenTTD running satisfactorily on Ubuntu 17.10 Server using systemd, and thought I'd make a note for future reference. When the system is rebooted, OpenTTD shuts down gracefully, saving the game state. Then it comes back up resumed from the saved state.

I happen to have installed OpenTTD from source, just to ensure it has the right version to match current Android apps (1.7.1), and installed in /usr/local, borrowing data from apt-installed packages:

sudo apt install openttd-{data,opengfx,openmsx}
ln -s /usr/share/games/openttd/baseset ~/.openttd/baseset

(That's probably not critical, and some of those packages might be unnecessary for a headless server.)

I run the whole thing in an openttd account to isolate it from anything else. It includes a script, which I've called ~/.install/share/server-process.sh, but you can call it what you like. It's meant to be run under the openttd account:

#!/bin/bash

## List the target file and all autosaves.
files=(~/.openttd/save/esp-main.sav ~/.openttd/save/autosave/*.sav)

## Choose the most recent file.
best="${files[0]}"
bestdate="$(date +'%s%N' -r "$best")"
files=("${files[@]:1}")
while [ ${#files[@]} -gt 0 ]
do
    cand="${files[0]}"

    ## Skip an unmatched wildcard.
    if [ "$cand" = ~/.openttd/save/autosave/\*.sav ]
    then
        continue
    fi

    ## Choose this candidate if it is newer than the best so far.
    canddate="$(date +'%s%N' -r "$cand")"
    if [ "$canddate" -gt "$bestdate" ]
    then
        best="$cand"
        bestdate="$canddate"
    fi

    ## Move on to next file.
    files=("${files[@]:1}")
done

## Save the best file just in case.
printf 'Best file is %s\n' "$best"
cp --reflink=auto "$best" ~/.openttd/save/best.sav

## Run a dedicated server with the best file.
exec /usr/local/games/openttd -g "$best" -D

The intention is to use the latest .sav from among the original file and all autosaves. If the server dies suddenly, it ought to be the last periodic autosave; otherwise, it will take the exit.sav file saved automatically on exit. I'm assuming that the server doesn't save any inconsistent files.

As root, create /etc/systemd/system/openttd.service:

[Unit]
Description=Open Transport Tycoon Deluxe
After=network.target

[Service]
User=openttd
Type=simple
ExecStart=/home/openttd/.install/share/server-process.sh

[Install]
WantedBy=multi-user.target

You might initially need to run this, or after every edit of openttd.service:

sudo systemctl daemon-reload

Test it with:

sudo systemctl start openttd.service
sudo systemctl status openttd.service
sudo systemctl stop openttd.service

Enable it to start on boot with:

sudo systemctl enable openttd.service

I tried using openttd -f, and Type=forking or Type=oneshot, but I think it had trouble killing it. Maybe it needed an explicit ExecStop directive.

Probably a lot more could be done with this to make it more robust, but it's a start.