Using mise-en-place for Godot projects

by Rosa Richter

I’ve adopted mise-en-place for every single one of my projects. Mise is a software version manager, tool manager, script runner, and environment manager with a simple configuration that builds on great projects like asdf to become a “front-end for your dev env” as the homepage calls it. If you’ve used asdf before, mise is a straight upgrade.

That said, Godot projects are slightly off the beaten path for a tool like mise. Godot does have a command-line interface but it’s more than just an interpreter for a programming language. Fortunately, mise can handle Godot just fine.

mise can also install butler, Itch’s command-line utility for uploading game files, for you, managing its version and allowing you to install it and Godot with a simple mise install, on both your local machine and in CI. It took some trial and error, but Galactic Trading Tycoon’s build process feels very comfortable to me now, and I’d like to show you how it works.

If you know how mise works already and just want to see how I’ve done it, check out Galactic Trading Tycoon on my Codeberg profile.

Installing Godot and Butler

Godot and Butler are not “core” plugins to mise, but that’s no problem. Marko Kungla has already done the great work of creating mkungla/asdf-godot, which allows asdf—and by extension, mise—to manage Godot executables. In your mise.toml file, you simply need to point mise to that plugin with an [alias], and then specify your Godot version in the [tools] section:

mise.toml
[alias]
godot = "asdf:mkungla/asdf-godot"
[tools]
godot = "4.5.1-stable"

Pulling in butler to be managed by mise took more effort, but it was effort that everyone can now benefit from: butler was not in any of mise’s tool repositories, but I submitted a pull request to the aqua repository to add it (see aquaproj/aqua-registry#38467). Now anyone can install and run it with mise:

mise.toml
[alias]
godot = "asdf:mkungla/asdf-godot"
butler = "aqua:itchio/butler"
[tools]
godot = "4.5.1-stable"
butler = "15.24.0"

To install godot and butler is now a single command, and your mise.toml is the source of truth for your godot and butler version. mise will add the correct executables to your $PATH whenever you enter your project directory.

Terminal window
cd ~/gtt
mise install
godot --headless --export-release Windows build/windows/gtt.exe
butler push ./build/windows ladycantido/galactic-trading-tycoon:windows-nightly

Tasks and Environments

I streamlined my process even more by writing tasks in my mise.toml for exporting the project and uploading the project to itch.io. To do this, I used two features supported by mise: configuration environments to define separate nightly and stable update channels, and task dependencies to break the tasks up so I can run them individually or all together.

First, I created my configuration environments for nightly and stable releases under a mise/ folder in my project. I have both a Windows build and a Linux build which each require a seperate update channel on Itch. Here are the nightly channels:

mise/config.nightly.toml
[vars]
windows_channel = "ladycantido/galactic-trading-tycoon:windows-nightly"
linux_channel = "ladycantido/galactic-trading-tycoon:linux-nightly"

And the stable channels:

mise/config.stable.toml
[vars]
windows_channel = "ladycantido/galactic-trading-tycoon:windows-stable"
linux_channel = "ladycantido/galactic-trading-tycoon:linux-stable"

Then I wrote export and deploy tasks in mise.toml:

mise.toml
7 collapsed lines
[alias]
godot = "asdf:mkungla/asdf-godot"
butler = "aqua:itchio/butler"
[tools]
godot = "4.5.1-stable"
butler = "15.24.0"
[tasks."deploy"]
description = "Builds and deploys all for all operating systems"
depends = "deploy:*"
[tasks."deploy:windows"]
description = "Deploy a Windows build to Itch using Butler"
depends = ["export:windows"]
run = "butler push ./build/windows {{ vars.windows_channel }} --userversion-file version.txt"
[tasks."deploy:linux"]
description = "Deploy a Linux build to Itch using Butler"
depends = ["export:linux"]
run = "butler push ./build/linux {{ vars.linux_channel }} --userversion-file version.txt"
[tasks."export:windows"]
description = "Export the Godot project for Windows"
run = [
"mkdir -p build/windows",
"godot --headless --export-release Windows build/windows/gtt.exe",
]
[tasks."export:linux"]
description = "Export the Godot project for Linux"
run = [
"mkdir -p build/linux",
"godot --headless --export-release Linux build/linux/gtt.x86_64",
]

When running this on my CI server, I realized I missed a dependency: Godot’s export templates, which are a separate download. They were installed on my PC, but the CI server needs to pull them down since it always starts from scratch. I chose to put this mise task in its own script file so I could use an if statement without a multi-line TOML string, but it would work just as fine that way too. That task goes in mise/tasks/install-export-templates, and the file must be executable. This script takes the Godot version as an argument defined by mise’s task arguments feature.

mise/tasks/install-export-templates
#!/usr/bin/env bash
#MISE description="Install Godot export templates"
#USAGE arg "<godot_version>" help="The Godot version"
if [ ! -d ~/.local/share/godot/export_templates/${usage_godot_version?}.stable ]; then
tmp=$(mktemp -d)
trap "rm -rf $tmp" EXIT
curl -sLO --output-dir $tmp https://github.com/godotengine/godot/releases/download/${usage_godot_version?}-stable/Godot_v${usage_godot_version?}-stable_export_templates.tpz
mkdir -p ~/.local/share/godot/export_templates
unzip $tmp/Godot_v${usage_godot_version?}-stable_export_templates.tpz -d ~/.local/share/godot/export_templates
trap "rm -rf ~/.local/share/godot/export_templates/templates" EXIT
mv ~/.local/share/godot/export_templates/templates ~/.local/share/godot/export_templates/${usage_godot_version?}.stable
fi

Since the export jobs depend on the export templates, we can make both export tasks dependent on this one. mise is smart enough to only run this installation task once when multiple tasks depend on it.

mise.toml
21 collapsed lines
[alias]
godot = "asdf:mkungla/asdf-godot"
butler = "aqua:itchio/butler"
[tools]
godot = "4.5.1-stable"
butler = "15.24.0"
[tasks."deploy"]
description = "Builds and deploys all for all operating systems"
depends = "deploy:*"
[tasks."deploy:windows"]
description = "Deploy a Windows build to Itch using Butler"
depends = ["export:windows"]
run = "butler push ./build/windows {{ vars.windows_channel }} --userversion-file version.txt"
[tasks."deploy:linux"]
description = "Deploy a Linux build to Itch using Butler"
depends = ["export:linux"]
run = "butler push ./build/linux {{ vars.linux_channel }} --userversion-file version.txt"
[tasks."export:windows"]
description = "Export the Godot project for Windows"
depends = ["install-export-templates 4.5.1"]
run = [
"mkdir -p build/windows",
"godot --headless --export-release Windows build/windows/gtt.exe",
]
[tasks."export:linux"]
description = "Export the Godot project for Linux"
depends = ["install-export-templates 4.5.1"]
run = [
"mkdir -p build/linux",
"godot --headless --export-release Linux build/linux/gtt.x86_64",
]

Results

With these tasks defined, I can build and deploy my project to itch.io from scratch with a single command.

Terminal window
mise -E nightly deploy

Deploying a stable release just means replacing nightly with stable; mise handles the rest.

Terminal window
mise -E stable deploy

With this distraction concluded, I guess I actually have to work on the game itself now.

Galactic Trading Tycoon is pay-what-you-want on itch.io. It is currently a prototype, so manage your expectations, but it’s a decent little nugget of a game that I hope to work on for a while more.

Syndicated to:

Comments

Have you responded to this on your own site? Enter the URL of your post to add it to the comments. This site supports Webmentions.