Ansible meets CurseForge on Linux
If you want to play modern Minecraft ModPacks on CurseForge in Java on Linux, the Twitch Launcher for Windows is not very helpful.
But since the project artifacts are available for public download and the data format is pretty straightforward, it was not a big deal to script a download of all files. I have chosen an Ansible Playbook for this task.
Some experience with this method on different modpacks including upgrade
shows, it’s best to assemble the artifacts in a separate folder, which can be
copied to the .minecraft
game folder simply using rsync
.
Install Ansible
For this method you will first need an installation of the Python-based Automation Tool Ansible on your Linux box. But since we are doing this to play modpacks on Linux, the preparation of Ansible as valuable Add-On should be no big deal, see Installation Guide for details. Please prefer an up-to-date release 2.4+ and don’t rely on standard repositories of your distribution too strictly.
Lookup Project Details
Please begin with a visit on the Minecraft ModPack’s Files page at
CurseForge resp. Feed the
Beast. You will later need a
meaningful PROJECT_NAME
, the VERSION
, the MD5 CHECKSUM
and the
DOWNLOAD_URL
. The PROJECT_NAME
is used for a dedicated folder in the local
filesystem, so you can set this to something comfortable, even though I
recommend a lowercase name without blanks.
Create your Ansible Playbook
Here is a template for CurseForge-PROJECT_NAME.yml
in which you normally
just need to set 4 variables pack_*
on the top. You can also override the
values on command line or in host variables, but we will assume, that the
information from the previous step goes into the pack_*
values.
---
- hosts: localhost
vars:
# ModPack URL: https://minecraft.curseforge.com/projects/PROJECT_NAME
pack_name: 'PROJECT_NAME'
pack_url: 'DOWNLOAD_URL'
pack_version: 'VERSION'
pack_sum: 'md5:CHECKSUM'
base: "{{playbook_dir}}/{{pack_name}}/dist"
json: "{{playbook_dir}}/{{pack_name}}/manifest.json"
copy: "{{playbook_dir}}/{{pack_name}}/overrides"
manifest: "{{lookup('file', json)|from_json}}"
skip_files: no
skip_forge: no
tasks:
- block:
# Download ModPack.
- name: download pack
get_url:
url: "{{pack_url}}"
dest: "{{playbook_dir}}/{{pack_name|default('pack')}}-{{pack_version|default('00')}}.zip"
checksum: "{{pack_sum|default(omit)}}"
# Directory for pack
- name: directory pack
file:
path: "{{playbook_dir}}/{{pack_name|default('pack')}}-{{pack_version|default('00')}}"
state: directory
# Extract pack.
- name: extract pack
unarchive:
src: "{{playbook_dir}}/{{pack_name|default('pack')}}-{{pack_version|default('00')}}.zip"
dest: "{{playbook_dir}}/{{pack_name|default('pack')}}-{{pack_version|default('00')}}"
- name: link pack
file:
src: "{{pack_name|default('pack')}}-{{pack_version|default('00')}}"
path: "{{playbook_dir}}/{{pack_name|default('pack')}}"
state: link
when: pack_url is defined
# Download mods' files from CurseForge.
- name: create mods target
file:
path: "{{base}}/mods"
state: directory
- name: download file
get_url:
dest: "{{base}}/mods"
url: "http://minecraft.curseforge.com/projects/{{item.projectID}}/files/{{item.fileID}}/download"
force: no
loop: "{{manifest.files}}"
when: not skip_files
# Override with files from ModPack.
- name: check for files to copy
local_action:
module: stat
path: "{{copy}}"
register: stat_copy
- name: sync files
synchronize:
dest: "{{base}}"
src: "{{copy}}/"
when: stat_copy.stat.exists
# Download Forge Installer in the recommended release.
- name: version for forge
set_fact:
forge_version: "{{manifest.minecraft.modLoaders[0].id|regex_replace('^forge-', '')}}"
when: >-
manifest.minecraft is defined and
manifest.minecraft.modLoaders is defined and
(manifest.minecraft.modLoaders[0].id|regex_search('^forge-') != None)
- name: download forge
get_url:
dest: "{{base}}/"
url: "https://files.minecraftforge.net/maven/net/minecraftforge/forge/{{manifest.minecraft.version}}-{{forge_version}}/forge-{{manifest.minecraft.version}}-{{forge_version}}-installer.jar"
force: no
when: not skip_forge and forge_version is defined
Apply ansible-playbook CurseForge-PROJECT_NAME.yml
on this Ansible Playbook
to download the project file and extract it into a folder
PROJECT_NAME-VERSION
aside the playbook file. It reads files
list in the
manifest.json
and downloads every entry, synchronizing the additional files
in overrides
to the destination. It finishes with a download of the
recommended Forge Installer.
I have prepared the example to assemble the downloads in a sub-folder dist
of PROJECT_NAME
. The download of files
is disabled by the setting
skip_files
to false, as well as the download of the Forge Installer by
skip_forge
.
Minecraft Installation with Forge and ModPack
- The first time you prepare a new CurseForge ModPack I recommend to start
with an empty directory (e.g.
$HOME/Minecraft/PROJECT_NAME
, that is symlinked to$HOME/.minecraft
. - Place the official Minecraft Launcher on your disk and start Vanilla Minecraft with a proper login, passing over to Play. After some downloading the Game Menu will show up, in which you can directly Quit Game. Beware, you need the Minecraft Release matching the the project with all the assets, which are downloaded in this step.
- Apply the Forge Installer downloaded in
the previous step to
PROJECT_NAME/dist
in Client Mode:java -jar forge*-installer.jar
- Start Vanilla Minecraft with Forge and configure the new Forge Profile
(check Minecraft Version, tune memory settings for Java, e.g.
-Xmx6G
). You can pass over to play for the Game Menu again and this time you should already see the typical Forge Animation. You may directly terminate on success like before. - Now it’s time to synchronize the
PROJECT_NAME/dist
folder:cd PROJECT_NAME && rsync -av dist/ $HOME/.minecraft/
That’s it, you should now be ready to enjoy the new ModPack by starting your launcher and passing over to the Forge Profile.
Update ModPack
In case you want to update the ModPack I recommend the following workflow:
- Get new
VERSION
, MD5CHECKSUM
andDOWNLOAD_URL
from the well-known project page (I recommende a comment with the ModPack URL in the playbook). - Change
pack_*
variables in the Ansible Playbook accordingly and apply the playbook to download all artifacts of the ModPack:ansible-playbook CurseForge-PROJECT_NAME.yml
- The playbook creates a new project folder this
VERSION
and links it toPROJECT_NAME
. - Backup your Minecraft folder from the previous step and delete
$HOME/.minecraft/mods
, so you get no conflicts by leftovers. - Synchronize the new project
PROJECT_NAME/dist
:cd PROJECT_NAME && rsync -av dist/ $HOME/.minecraft/
Normally this procedure will update the ModPack, keep your settings and you can easily rollback to the previous version as long as you do not cleanup your backup.
Organizing multiple ModPacks
In my environment I use a shell script to set the link to $HOME/.minecraft
before starting the Minecraft Launcher. Usage of this script is often
delegated to Desktop Shortcuts in my family.
Keeping all the ModPacks in a folder $HOME/Minecraft
, starting with the
procedure above, keeping the previous version as backup in the same folder and
putting a shell script with the name of the folder extended by .sh
is
after all this command line stuff quite comfortable.
Here is the example of a shell script
$HOME/Minecraft/start_minecraft.sh
, that extrapolates the location of
the ModPack from it’s name:
#!/bin/bash
set -x
# Link project to $HOME/.minecraft.
ln -snf \
"$(readlink -f "$(dirname "$0")/$(basename "$0" .sh)")" \
"$HOME/.minecraft"
cd "$HOME/.minecraft" || exit
# Pass over to Minecraft Launcher.
if [ -s "minecraft-launcher.sh" ]; then
exec /bin/sh minecraft-launcher.sh "$@"
fi
if [ -s "launcher.jar" ]; then
exec java -jar launcher.jar "$@"
fi
echo "ERROR: Can't locate launcher in $HOME/.minecraft!" >&2
exit 1
Link or copy this script to $HOME/Minecraft/PROJECT_NAME.sh
and it will link
your ModPack before starting the game. This will also work on backups.
Troubleshooting
- The example script for linking before executing the launcher expects
references in the folder. So please place the installation files of the
launcher in the project folder. The old java launcher is happy with
launcher.jar
, the latest launcher provides an archive with several files including a scriptminecraft-launcher.sh
. - If the Start of the ModPack issues errors or warnings, you should first
check, if your Minecraft and Forge Release is (still) matching the
recommended version in
PROJECT_NAME/dist
. - Please also check the memory settings in the Minecraft Forge Profile, the
standard
-Xmx1G
is often not enough, try-Xmx4G
or better-Xmx6G
instead and watch out for recommended memory limits on the Project Page. - If the problems still exists after an update, please start over with an
empty folder linked to
.minecraft
like you never installed thePROJECT_NAME
before. - Sometimes the Download of a mod fails, because the
fileID
is no longer available. Instead of waiting for an update of the ModPack you can try the following solution:- In that case the playbook will continue the Download Section which is looping over all mods and stops before going over to the next step.
- Investigate the download problems with the URL that is visible in the error message.
- You can go the Project Page looking for newer versions of the
*.jar
: http://minecraft.curseforge.com/projects/{{item.projectID}} - If you are able to download the file manually, put it into the
PROJECT_NAME/dist
folder and retry the playbook while skipping the mod downloading:ansible-playbook -e skip_files=yes CurseForge-PROJECT_NAME.yml