Skip to content

Instantly share code, notes, and snippets.

@hsandt
Last active April 13, 2025 18:36
Show Gist options
  • Save hsandt/113d3c6698a54e378d44b5024140c2a0 to your computer and use it in GitHub Desktop.
Save hsandt/113d3c6698a54e378d44b5024140c2a0 to your computer and use it in GitHub Desktop.
Install Godot 3 stable or 4 beta, rc or stable and create desktop entry for Linux
[Desktop Entry]
Name=Godot Engine $VERSION $CHANNEL
GenericName=Libre game engine
Comment=Multi-platform 2D and 3D game engine with a feature-rich editor
Exec=godot$VERSION_$CHANNEL %f
Icon=$HOME/.local/share/applications/godot.png
Terminal=false
Type=Application
MimeType=application/x-godot-project;
Categories=Development;IDE;
Name[en_US]=Godot $VERSION $CHANNEL.desktop
#!/usr/bin/env bash
# Gist: https://gist.github.com/hsandt/113d3c6698a54e378d44b5024140c2a0
# CONFIG: customize to match your needs
base_install_folder="${HOME}/Applications/Game Engines/Godot"
usage() {
echo "Usage: install_godot_and_create_desktop_entry.sh <version> <channel>
Install a version of Godot for Linux in ${HOME}/Applications/Game Engines/Godot/ and
create a .desktop launcher for it.
Requirements:
- perl installed
- \"Godot template.desktop\" placed in the same directory as this script
- Godot icon placed at ~/.local/share/applications/godot.png
- jq installed (https://jqlang.org/) if using --latest option
ARGUMENTS
version Version of godot to download. Do not include channel like 'beta' here.
Ex: '4.0.1'.
channel Channel of godot to download, including number, excluding mono (see option -m instead).
Ex: 'beta14', 'rc1', 'stable'
-m, --mono Download mono build
-l, --latest Show latest version available on Godot repository and quit
-h, --help Show this help and quit
"
}
show_latest() {
# Use CLI to get latest release on GitHub: https://stackoverflow.com/questions/34899736/how-can-i-use-git-cli-to-get-the-latest-release
# Parsing JSON with Unix tools: https://stackoverflow.com/questions/1955505/parsing-json-with-unix-tools
# Requires jq (https://jqlang.org/)
latest_version_with_quotes=`curl -s https://api.github.com/repos/godotengine/godot/releases/latest | jq .name`
# Remove surrounding quotes: https://stackoverflow.com/questions/9733338/shell-script-remove-first-and-last-quote-from-a-variable
latest_version="${latest_version_with_quotes%\"}"
latest_version="${latest_version#\"}"
echo "$latest_version"
}
# Default arguments
mono=false
# Read arguments
positional_args=()
while [[ $# -gt 0 ]]; do
case $1 in
-h | --help )
usage
exit 0
;;
-l | --latest )
show_latest
exit 0
;;
-m | --mono )
mono=true
shift # past argument
;;
-* ) # unknown option
echo "Unknown option: '$1'"
usage
exit 1
;;
* ) # store positional argument for later
positional_args+=("$1")
shift # past argument
;;
esac
done
if ! [[ ${#positional_args[@]} -eq 2 ]]; then
echo "Wrong number of positional arguments: found $#, expected 2."
echo "Passed positional arguments: $@"
usage
exit 1
fi
version="${positional_args[0]}"
channel="${positional_args[1]}"
parent_dir_path="$(dirname "$0")"
if [[ "$version" == 3* ]]; then
# Godot 3 was naming "X11" the Linux build
binary_linux_suffix="x11.64"
if [[ "$mono" == true ]]; then
zip_linux_suffix="x11_64"
else
zip_linux_suffix="x11.64"
fi
else
binary_linux_suffix="linux.x86_64"
if [[ "$mono" == true ]]; then
zip_linux_suffix="linux_x86_64"
else
zip_linux_suffix="linux.x86_64"
fi
fi
if [[ "$mono" == true ]]; then
full_channel="${channel}_mono"
else
full_channel="${channel}"
fi
# Non-mono build example: "Godot_v4.2.2-stable_linux_x86_64"
# Mono build example: "Godot_v4.2.2-stable_mono_linux_x86_64"
godot_zip_basename="Godot_v${version}-${full_channel}_${zip_linux_suffix}"
godot_zip_name="${godot_zip_basename}.zip"
godot_bin_name="Godot_v${version}-${full_channel}_${binary_linux_suffix}"
# Remove existing archive if any (in case it was previously incorrectly downloaded)
rm -f "$godot_zip_name"
if [[ "$channel" == "stable"* ]]; then
# Stable releases are on GitHub
# Note that the directory never contains "mono", so we use channel instead of full_channel
# but we use full_channel for the actual zip
download_url="https://github.com/godotengine/godot/releases/download/${version}-${channel}/${godot_zip_name}"
elif [[ "$channel" == "dev"* ]]; then
# Dev releases are on GitHub with a slightly different directory name, godot-builds
download_url="https://github.com/godotengine/godot-builds/releases/download/${version}-${channel}/${godot_zip_name}"
else
# Release candidates are on Tux Family
# Note that the directory never contains "mono", so we use channel instead of full_channel
download_url="https://downloads.tuxfamily.org/godotengine/${version}/${channel}/${godot_zip_name}"
fi
# Download archive for passed version in current folder
wget "$download_url"
# Unzip it
unzip "$godot_zip_name"
# Remove archive to clean up current folder
rm "$godot_zip_name"
if [[ "$mono" == true ]]; then
# Move the whole directory (named like zip basename), which contains binary + GodotSharp directory, under the install folder
binary_install_folder="$base_install_folder/$godot_zip_basename"
mv "$godot_zip_basename" "$binary_install_folder"
else
# Non-mono build: we should have extracted a single file named "$godot_bin_name"
# Move it to the target folder (overwrites any existing file)
binary_install_folder="$base_install_folder"
mv "$godot_bin_name" "$binary_install_folder"
fi
echo "Installed in ${binary_install_folder}"
# Create symbolic link for terminal and future Desktop entry (overwrites any existing link)
install_path="${binary_install_folder}/${godot_bin_name}"
symlink_path="${HOME}/.local/bin/godot${version}_${full_channel}"
ln -sf "$install_path" "$symlink_path"
echo "Created symbolic link at '$symlink_path'"
# Create Desktop entry from template (overwrites any existing file)
desktop_entry_path="${HOME}/.local/share/applications/Godot ${version} ${full_channel}.desktop"
cp "${parent_dir_path}/Godot template.desktop" "$desktop_entry_path"
# https://stackoverflow.com/questions/6994947/how-to-replace-a-string-in-an-existing-file-in-perl
perl -pi -e "s/\\\$VERSION/${version}/g" "$desktop_entry_path"
perl -pi -e "s/\\\$CHANNEL/${full_channel}/g" "$desktop_entry_path"
# https://stackoverflow.com/questions/26080096/installed-desktop-file-to-have-users-home-directory-path-inserted
# mind the comma separator since we deal with paths containing slashes
# note that "~" doesn't work with Icon=, we need full path expansion
perl -pi -e "s,\\\$HOME,${HOME},g" "$desktop_entry_path"
echo "Created desktop entry at '$desktop_entry_path'"
#!/usr/bin/env bash
# The opposite operation of install_godot_and_create_desktop_entry.sh
# Gist: https://gist.github.com/hsandt/113d3c6698a54e378d44b5024140c2a0
# CONFIG: customize to match your needs
base_install_folder="${HOME}/Applications/Game Engines/Godot"
usage() {
echo "Usage: uninstall_godot_and_create_desktop_entry.sh version channel
Uninstall a version of Godot for Linux installed in ${HOME}/Applications/Game Engines/Godot/ and
remove the .desktop launcher for it.
Requirements:
- perl installed
- the Godot version to remove must have been installed with install_godot_and_create_desktop_entry.sh
(or using the same path conventions)
ARGUMENTS
version Version of godot to uninstall. Do not include channel like 'beta' here.
Ex: '4.0.1'.
channel Channel of godot to uninstall, including number, excluding mono (see option -m instead).
Ex: 'beta14', 'rc1', 'stable'
-m Uninstall mono build
"
}
# Default arguments
mono=false
# Read arguments
positional_args=()
while [[ $# -gt 0 ]]; do
case $1 in
-h | --help )
usage
exit 0
;;
-m | --mono )
mono=true
shift # past argument
;;
-* ) # unknown option
echo "Unknown option: '$1'"
usage
exit 1
;;
* ) # store positional argument for later
positional_args+=("$1")
shift # past argument
;;
esac
done
if ! [[ ${#positional_args[@]} -eq 2 ]]; then
echo "Wrong number of positional arguments: found $#, expected 2."
echo "Passed positional arguments: $@"
usage
exit 1
fi
version="${positional_args[0]}"
channel="${positional_args[1]}"
if [[ "$version" == 3* ]]; then
# Godot 3 was naming "X11" the Linux build
binary_linux_suffix="x11.64"
if [[ "$mono" == true ]]; then
zip_linux_suffix="x11_64"
else
zip_linux_suffix="x11.64"
fi
else
binary_linux_suffix="linux.x86_64"
if [[ "$mono" == true ]]; then
zip_linux_suffix="linux_x86_64"
else
zip_linux_suffix="linux.x86_64"
fi
fi
if [[ "$mono" == true ]]; then
full_channel="${channel}_mono"
else
full_channel="${channel}"
fi
# Non-mono build example: "Godot_v4.2.2-stable_linux_x86_64"
# Mono build example: "Godot_v4.2.2-stable_mono_linux_x86_64"
godot_zip_basename="Godot_v${version}-${full_channel}_${zip_linux_suffix}"
godot_bin_name="Godot_v${version}-${full_channel}_${binary_linux_suffix}"
if [[ "$mono" == true ]]; then
# Move the whole directory (named like zip basename), which contains binary + GodotSharp directory, under the install folder
binary_install_folder="$base_install_folder/$godot_zip_basename"
else
# Non-mono build: we should have extracted a single file named "$godot_bin_name"
# Move it to the target folder (overwrites any existing file)
binary_install_folder="$base_install_folder"
fi
install_path="${binary_install_folder}/${godot_bin_name}"
if [[ -f "$install_path" ]]; then
rm "$install_path"
echo "Removed Godot binary at $install_path"
else
echo "No file at '$install_path', so nothing to remove"
fi
symlink_path="${HOME}/.local/bin/godot${version}_${full_channel}"
if [[ -L "$symlink_path" ]]; then
rm "$symlink_path"
echo "Removed symlink at $symlink_path"
else
echo "No symlink at '$symlink_path', so nothing to remove"
fi
desktop_entry_path="${HOME}/.local/share/applications/Godot ${version} ${full_channel}.desktop"
if [[ -f "$desktop_entry_path" ]]; then
rm "$desktop_entry_path"
echo "Removed desktop entry at ${desktop_entry_path}"
else
echo "No file at '$desktop_entry_path', so nothing to remove"
fi
@hsandt
Copy link
Author

hsandt commented Jan 10, 2024

I also found another script that does a similar thing but is self-contained: https://gist.github.com/hieuns/ac4f117492771a690fa06cfa47b24714

It auto-downloads the icon svg from Wikimedia and embeds the .desktop template content in the same script.

However, it takes the Godot URL argument, making it more flexible but unable to retrieve the correct URL from version+channel automatically.

It may be worth merging both methods (download icon and deduce URL, possibly embed the template too) for a simple script the user can run without extra setup.

@hsandt
Copy link
Author

hsandt commented Aug 28, 2024

I added an uninstall script to revert the operations of the install script. Convenient to remove older versions of Godot, esp. dev and rc.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment