Dwarf Fortress Lazy Newb Pack, on Docker
Setup for Tarn and Zach Adams’ Dwarf Fortress, using the Linux Lazy Newb Pack, running on top of Docker.
Current setup is for DF v0.40.24 (x64 LNP). As stated by the LNP Linux page:
If you are using a x64 bit system then you should download the x64 PyLNP interface, and 32 bit should download i686 PyLNP interface
This has been tested on Debian Jessie, but should work on any system with Docker for Linux installed. Let me know if this isn’t the case.
Rationale
As stated in the forum posting, this LNP has been tested only on Ubuntu 14.04, on a fresh install. I’m not using Ubuntu — while I am using Debian, I’ve noticed enough differences between both distros to realize that this sort of thing is a pain in the ass to deal with.
Then I discovered Docker, and I noticed other projects using Docker to run LNP. Some even managed to do it so that they end up running GUI apps with Docker (the original idea came from one of Docker’s software engineers, and they’ve got a repo full of Dockerfiles for reference).
Which is neat. I wanted to do that.
How to use
First, follow the instructions for installing Docker for Linux. Once you’re able to run both hello-world
and whalesay
, you should be able to install this.
Clone this repository, or even download the ZIP file, and then run the following command:
$ make
Once that’s done, at the directory, run and it should work.
$ ./start-df-lnp-docker
How this works
There are several files that are available here:
Makefile
, which downloads the required ZIP files and creates the Docker image.Dockerfile
, tells Docker how to create and setup the image.start-df-lnp-docker
, which either runs or restarts the Docker image containing the LNP.
Dockerfile
The Dockerfile’s basic structure is as follows:
<<metadata>>
<<download-prerequisites>>
<<prepare-environment>>
<<setup-defaults>>
Setting up the metadata
Firstly, begin by defining the docker image’s meta-data and it’s base image:
FROM ubuntu:14.04
MAINTAINER Tariq Kamal <github.t-boy@xoxy.net>
LABEL vendor="Tariq Kamal" \
net.bebudak.version="0.0.2-alpha" \
net.bebudak.release_date="2015-11-05" \
net.bebudak.project_name="df/lnp/docker"
Downloading prerequisites
Then, set up and download the pre-requisites for the program:
RUN dpkg --add-architecture i386 && \
apt-get update -y && \
apt-get install -y default-jre libsdl1.2debian:i386 libsdl-image1.2:i386 libsdl-ttf2.0-0:i386 libglu1-mesa:i386 libgtk2.0-0:i386 libopenal1:i386 libjpeg62:i386 coreutils g++ gcc patch xterm sed python bzip2 qtchooser qtbase5-dev qtbase5-dev-tools qtscript5-dev qt5-qmake libqt5script5 libqt5scripttools5 libqxt-core0 libqxt-gui0 wget unzip locales
The download for this, disappointingly, will take a long time, and will bloat the image to approximately around 800 MB.
Prepare Environment
Set up the locales. We can only bring in the installation environment during the run command, so we’ll only do it then.
Essentially, set up the staging area — in this case, /home/Urist/bin/df
, and ensure that the locales are set properly.
ENV LANG en_US.UTF-8
RUN locale-gen en_US.UTF-8
RUN mkdir -p /home/Urist/bin/df
WORKDIR /home/Urist/bin/df
Set up defaults
Export the values needed for this container.
Sections of this portion come from this blog post, as it covers the instructions that are needed to share your X11 socket with the docker container.
ENV uid=1000 gid=1000
RUN echo "Urist:x:${uid}:${gid}:Urist,,,:/home/Urist:/bin/bash" >> /etc/passwd && \
echo "Urist:x:${uid}:" >> /etc/group && \
echo "Urist ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/Urist && \
chmod 0440 /etc/sudoers.d/Urist && \
chown ${uid}:${gid} -R /home/Urist
USER Urist
ENV HOME /home/Urist
CMD /home/Urist/bin/df/startlnp
Makefile
The Makefile’s basic structure is as follows:
<<make-variables>>
<<build-everything>>
<<download-LNP>>
<<cleanup>>
Define variables
We’re using the latest version of LNP, as of [2015-10-22 Thu]. Also, we’re using the latest version of DF, as of [2015-10-22 Thu]. These will be downloaded every make
.
lnp-URL=http://lazynewbpack.com/linux/04024/download/x64/04024r3-x64.zip
lnp-zip=resources/install.zip
image-name=tariqk/dwarf-fortress-lnp
Download the Lazy New Pack from the official website
We’re using the -k
flag because I don’t want to be stopped by any iffiness with regards to SSL certs. After that, unzip it to the working directory and rename the directory accordingly.
resources/install.zip:
curl -kL -o $(lnp-zip) $(lnp-URL)
df:
unzip $(lnp-zip) -d . && \
mv 04024r3-x64 df
Finally, build everything
Once that’s done, we’ll just have a go and build it, eh?
all: | resources/install.zip resources/PyLNP.user start-df-lnp-docker df
docker build -t $(image-name) .
Clean everything up
.PHONY: clean
clean:
rm -rf resources/install.zip df
Other files
Setting files for PyLNP
This settings file, which is included in the resources directory, resolves the following issue.
Once this bug is closed, I’ll update this.
{
"terminal": "xterm -e",
"tkgui_height": 643,
"tkgui_width": 386
}
The final executable
This basically checks if an existing container of the current version exists, and if so, restart the container.
Right now, if the ./df
folder is missing, I do think this will choke out.
<<project-variables>>
<<i-can-haz-container>>
if [[ $? != 0 ]]; then
echo "docker ps failed with exit code $?."
elif [[ $container_id ]]; then
echo "Container $container_id found. Restarting..."
<<restart-container>>
else
echo "No container found. Attempting to find image..."
<<i-can-haz-image>>
if [[ $? != 0 ]]; then
echo "docker images failed with exit code $?."
elif [[ $image_id ]]; then
echo "Image $image_id found. Running..."
<<run-image>>
else
echo "Image not found. Container not found. Have you already run make yet?"
fi
fi
Set the project variables
PROJECT_NAME="df/lnp/docker"
PROJECT_NAME_LABEL="net.bebudak.project_name"
PROJECT_VERSION="0.0.2-alpha"
PROJECT_VERSION_LABEL="net.bebudak.version"
USER_ID=$(id -u)
GROUP_ID=$(id -g)
WORK_DIR=$(pwd)
Ask the question: is there a container?
We do this by running the docker ps
command, relying on the project name and version labels. We take the first entry, which, by rights, should be the newest container.
container_id=$(docker ps \
--all \
--format "{{.ID}}" \
--filter="label=$PROJECT_NAME_LABEL=$PROJECT_NAME" \
--filter="label=$PROJECT_VERSION_LABEL=$PROJECT_VERSION" | \
head -n1)
If there is, restart the docker container
docker restart $container_id
Ask the question: is there an image?
We do this by running the the docker images
command, relying on the project name and version labels. We take the first entry, again, which, by rights, should be the newest image.
image_id=$(docker images \
-q \
--filter="label=$PROJECT_NAME_LABEL=$PROJECT_NAME" \
--filter="label=$PROJECT_VERSION_LABEL=$PROJECT_VERSION" | \
head -n1)
If there is, run the docker image
I’m trying to figure out where I got the export uid
and gid
trick is from, and when I do I’ll add the link.
docker run -ti \
-e DISPLAY=$DISPLAY \
-e uid=$USER_ID \
-e gid=$GROUP_ID \
-v /tmp/.X11-unix:/tmp/.X11-unix \
-v $WORK_DIR/df:/home/Urist/bin/df \
-v $WORK_DIR/resources/PyLNP.user:/home/Urist/bin/df/PyLNP.user \
-l $PROJECT_NAME_LABEL=$PROJECT_NAME \
-l $PROJECT_VERSION_LABEL=$PROJECT_VERSION \
$image_id
Behind the scenes
Yep, this is the org-file that generates most of the other files necessary for this, using org-mode
on Emacs.
After making changes in this document, I run org-babel-tangle
and update all the other files.
This file also sets up local variables (using add-file-local-variable
) to ensure that org-src-preserve-indentation
is set to t
. This ensures that the Makefile is properly created, preserving the TAB
used to define actions to specific rules.