From 7001f2bcbaa18cbd2cda89f8e855938b1975a672 Mon Sep 17 00:00:00 2001 From: Geoff Bourne Date: Mon, 27 Jun 2022 09:08:21 -0500 Subject: [PATCH] Added support for downloading mods from Modrinth (#1577) --- Dockerfile | 2 +- README.md | 16 +- examples/docker-compose-modrinth.yml | 18 +++ scripts/start-setupModpack | 153 ++++++++++-------- scripts/start-utils | 6 +- .../generic-packs-prefix/docker-compose.yml | 1 + .../generic-packs/docker-compose.yml | 1 + .../modrinth/docker-compose.yml | 15 ++ tests/setuponlytests/modrinth/fake.jar | 0 tests/setuponlytests/modrinth/verify.sh | 1 + 10 files changed, 143 insertions(+), 70 deletions(-) create mode 100644 examples/docker-compose-modrinth.yml create mode 100644 tests/setuponlytests/modrinth/docker-compose.yml create mode 100644 tests/setuponlytests/modrinth/fake.jar create mode 100644 tests/setuponlytests/modrinth/verify.sh diff --git a/Dockerfile b/Dockerfile index 22e38e09..4c3d6b0a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -46,7 +46,7 @@ RUN easy-add --var os=${TARGETOS} --var arch=${TARGETARCH}${TARGETVARIANT} \ --var version=0.1.1 --var app=maven-metadata-release --file {{.app}} \ --from https://github.com/itzg/{{.app}}/releases/download/{{.version}}/{{.app}}_{{.version}}_{{.os}}_{{.arch}}.tar.gz -ARG MC_HELPER_VERSION=1.17.0 +ARG MC_HELPER_VERSION=1.18.3 ARG MC_HELPER_BASE_URL=https://github.com/itzg/mc-image-helper/releases/download/v${MC_HELPER_VERSION} RUN curl -fsSL ${MC_HELPER_BASE_URL}/mc-image-helper-${MC_HELPER_VERSION}.tgz \ | tar -C /usr/share -zxf - \ diff --git a/README.md b/README.md index 095afd5c..8af46bcc 100644 --- a/README.md +++ b/README.md @@ -684,6 +684,20 @@ For example, the following will auto-download the [EssentialsX](https://www.spig -e SPIGET_RESOURCES=9089,34315 +### Auto-download mods from Modrinth + +[Modrinth](https://modrinth.com/) is an open source modding platform with a clean, easy to use website for finding [Fabric and Forge mods](https://modrinth.com/mods). At startup, the container will automatically locate and download the newest versions of mod files that correspond to the `TYPE` and `VERSION` in use. Older file versions downloaded previously will automatically be cleaned up. + +- **MODRINTH_PROJECTS** : comma separated list of project slugs (short name) or IDs. The project ID can be located in the "Technical information" section. The slug is the part of the page URL that follows `/mod/`: + ``` + https://modrinth.com/mod/fabric-api + ---------- + | + +-- project slug + ``` +- **MODRINTH_DOWNLOAD_OPTIONAL_DEPENDENCIES**=true : required dependencies of the project will _always_ be downloaded and optional dependencies can also be downloaded by setting this to `true` +- **MODRINTH_ALLOWED_VERSION_TYPE**=release : the version type is used to determine the newest version to use from each project. The allowed values are `release`, `beta`, `alpha`. + ### Downloadable mod/plugin pack for Forge, Fabric, and Bukkit-like Servers Like the `WORLD` option above, you can specify the URL or path of a "mod pack" @@ -899,7 +913,7 @@ Datapacks Json: "packs": { "survival": [ "graves", - "multiplayer sleep", + "multiplayer sleep" ], "items": ["armored elytra"] } diff --git a/examples/docker-compose-modrinth.yml b/examples/docker-compose-modrinth.yml new file mode 100644 index 00000000..62dd7937 --- /dev/null +++ b/examples/docker-compose-modrinth.yml @@ -0,0 +1,18 @@ +version: "3.8" + +services: + mc: + image: itzg/minecraft-server + tty: true + stdin_open: true + ports: + - "25565:25565" + environment: + EULA: "TRUE" + TYPE: FABRIC + MODRINTH_PROJECTS: fallingtree + volumes: + - data:/data + +volumes: + data: {} \ No newline at end of file diff --git a/scripts/start-setupModpack b/scripts/start-setupModpack index 94010165..827de93d 100755 --- a/scripts/start-setupModpack +++ b/scripts/start-setupModpack @@ -195,75 +195,102 @@ case "X$EFFECTIVE_MANIFEST_FILE" in esac fi -: "${GENERIC_PACKS:=${GENERIC_PACK}}" -: "${GENERIC_PACKS_PREFIX:=}" -: "${GENERIC_PACKS_SUFFIX:=}" +function genericPacks() { + : "${GENERIC_PACKS:=${GENERIC_PACK}}" + : "${GENERIC_PACKS_PREFIX:=}" + : "${GENERIC_PACKS_SUFFIX:=}" -if [[ "${GENERIC_PACKS}" ]]; then - IFS=',' read -ra packs <<< "${GENERIC_PACKS}" + if [[ "${GENERIC_PACKS}" ]]; then + IFS=',' read -ra packs <<< "${GENERIC_PACKS}" - packFiles=() - for packEntry in "${packs[@]}"; do - pack="${GENERIC_PACKS_PREFIX}${packEntry}${GENERIC_PACKS_SUFFIX}" - if isURL "${pack}"; then - mkdir -p /data/packs - log "Downloading generic pack from $pack" - if ! outfile=$(get -o /data/packs --output-filename --skip-up-to-date "$pack"); then - log "ERROR: failed to download $pack" - exit 2 + packFiles=() + for packEntry in "${packs[@]}"; do + pack="${GENERIC_PACKS_PREFIX}${packEntry}${GENERIC_PACKS_SUFFIX}" + if isURL "${pack}"; then + mkdir -p /data/packs + log "Downloading generic pack from $pack" + if ! outfile=$(get -o /data/packs --output-filename --skip-up-to-date "$pack"); then + log "ERROR: failed to download $pack" + exit 2 + fi + packFiles+=("$outfile") + else + packFiles+=("$pack") fi - packFiles+=("$outfile") - else - packFiles+=("$pack") - fi - done - - isDebugging && [ -f "$sum_file}" ] && cat "$sum_file" - - log "Checking if generic packs are up to date" - if isTrue "${SKIP_GENERIC_PACK_UPDATE_CHECK:-false}" && [ -f "$sum_file" ]; then - log "Skipping generic pack update check" - elif isTrue "${FORCE_GENERIC_PACK_UPDATE}" || ! checkSum "${sum_file}"; then - log "Generic pack(s) are out of date. Re-applying..." - - original_base_dir=/data/.tmp/generic_pack_base - base_dir=$original_base_dir - rm -rf "${base_dir}" - mkdir -p "${base_dir}" - for pack in "${packFiles[@]}"; do - isDebugging && ls -l "${pack}" - extract "${pack}" "${base_dir}" done - # recalculate the actual base directory of content - base_dir=$(find "$base_dir" -maxdepth 3 -type d \( -name mods -o -name plugins -o -name config \) -printf '%h' -quit) - if [[ ! $base_dir ]]; then - log "ERROR: Unable to find content base of generic packs ${GENERIC_PACKS}. Directories:" - find $original_base_dir -maxdepth 3 -type d -printf ' - %P\n' - exit 1 + isDebugging && [ -f "$sum_file}" ] && cat "$sum_file" + + log "Checking if generic packs are up to date" + if isTrue "${SKIP_GENERIC_PACK_UPDATE_CHECK:-false}" && [ -f "$sum_file" ]; then + log "Skipping generic pack update check" + elif isTrue "${FORCE_GENERIC_PACK_UPDATE}" || ! checkSum "${sum_file}"; then + log "Generic pack(s) are out of date. Re-applying..." + + original_base_dir=/data/.tmp/generic_pack_base + base_dir=$original_base_dir + rm -rf "${base_dir}" + mkdir -p "${base_dir}" + for pack in "${packFiles[@]}"; do + isDebugging && ls -l "${pack}" + extract "${pack}" "${base_dir}" + done + + # recalculate the actual base directory of content + base_dir=$(find "$base_dir" -maxdepth 3 -type d \( -name mods -o -name plugins -o -name config \) -printf '%h' -quit) + if [[ ! $base_dir ]]; then + log "ERROR: Unable to find content base of generic packs ${GENERIC_PACKS}. Directories:" + find $original_base_dir -maxdepth 3 -type d -printf ' - %P\n' + exit 1 + fi + + if [ -f /data/manifest.txt ]; then + log "Manifest exists from older generic pack, cleaning up ..." + while read -r f; do + rm -rf "/data/${f}" + done < /data/manifest.txt + # prune empty dirs + find /data -mindepth 1 -depth -type d -empty -delete + rm -f /data/manifest.txt + fi + + log "Writing generic pack manifest ... " + find "${base_dir}" -type f -printf "%P\n" > /data/manifest.txt + + log "Applying generic pack ..." + cp -R -f "${base_dir}"/* /data + rm -rf $original_base_dir + + log "Saving generic pack(s) checksum" + sha1sum "${packFiles[@]}" > "${sum_file}" + isDebugging && cat "$sum_file" fi - - if [ -f /data/manifest.txt ]; then - log "Manifest exists from older generic pack, cleaning up ..." - while read -r f; do - rm -rf "/data/${f}" - done < /data/manifest.txt - # prune empty dirs - find /data -mindepth 1 -depth -type d -empty -delete - rm -f /data/manifest.txt - fi - - log "Writing generic pack manifest ... " - find "${base_dir}" -type f -printf "%P\n" > /data/manifest.txt - - log "Applying generic pack ..." - cp -R -f "${base_dir}"/* /data - rm -rf $original_base_dir - - log "Saving generic pack(s) checksum" - sha1sum "${packFiles[@]}" > "${sum_file}" - isDebugging && cat "$sum_file" fi -fi +} + +function modrinthProjects() { + : "${MODRINTH_PROJECTS:=}" + : "${MODRINTH_DOWNLOAD_OPTIONAL_DEPENDENCIES:=true}" + : "${MODRINTH_ALLOWED_VERSION_TYPE:=release}" + + if [[ $MODRINTH_PROJECTS ]] && isFamily HYBRID FABRIC; then + if [[ ${FAMILY^^} = HYBRID ]]; then + loader=forge + else + loader="${FAMILY,,}" + fi + mc-image-helper modrinth \ + --output-directory=/data \ + --projects="${MODRINTH_PROJECTS}" \ + --game-version="${VANILLA_VERSION}" \ + --loader="$loader" \ + --download-optional-dependencies="$MODRINTH_DOWNLOAD_OPTIONAL_DEPENDENCIES" \ + --allowed-version-type="$MODRINTH_ALLOWED_VERSION_TYPE" + fi +} + +genericPacks + +modrinthProjects exec "${SCRIPTS:-/}start-setupModconfig" "$@" diff --git a/scripts/start-utils b/scripts/start-utils index efc33aca..235347fe 100755 --- a/scripts/start-utils +++ b/scripts/start-utils @@ -212,11 +212,7 @@ function removeOldMods { } function get() { - local flags=() - if isTrue "${DEBUG_GET:-false}"; then - flags+=("--debug") - fi - mc-image-helper "${flags[@]}" get "$@" + mc-image-helper get "$@" } function get_silent() { diff --git a/tests/setuponlytests/generic-packs-prefix/docker-compose.yml b/tests/setuponlytests/generic-packs-prefix/docker-compose.yml index 4d84fa67..5519c89f 100644 --- a/tests/setuponlytests/generic-packs-prefix/docker-compose.yml +++ b/tests/setuponlytests/generic-packs-prefix/docker-compose.yml @@ -9,6 +9,7 @@ services: GENERIC_PACKS: testing GENERIC_PACKS_PREFIX: /packs/ GENERIC_PACKS_SUFFIX: .zip + DEBUG: "true" volumes: - ./packs:/packs - ./data:/data diff --git a/tests/setuponlytests/generic-packs/docker-compose.yml b/tests/setuponlytests/generic-packs/docker-compose.yml index a2b27c5d..0f269418 100644 --- a/tests/setuponlytests/generic-packs/docker-compose.yml +++ b/tests/setuponlytests/generic-packs/docker-compose.yml @@ -18,6 +18,7 @@ services: TYPE: CUSTOM CUSTOM_SERVER: /servers/fake.jar VERSION: 1.18.1 + DEBUG: "true" volumes: - ./packs:/packs - ./data:/data diff --git a/tests/setuponlytests/modrinth/docker-compose.yml b/tests/setuponlytests/modrinth/docker-compose.yml new file mode 100644 index 00000000..394538dd --- /dev/null +++ b/tests/setuponlytests/modrinth/docker-compose.yml @@ -0,0 +1,15 @@ +version: "3" + +services: + mc: + image: ${IMAGE_TO_TEST:-itzg/minecraft-server} + environment: + EULA: "true" + SETUP_ONLY: "true" + TYPE: FABRIC + FABRIC_LAUNCHER: /servers/fake.jar + CUSTOM_SERVER: /servers/fake.jar + MODRINTH_PROJECTS: fabric-api,cloth-config + volumes: + - ./data:/data + - ./fake.jar:/servers/fake.jar diff --git a/tests/setuponlytests/modrinth/fake.jar b/tests/setuponlytests/modrinth/fake.jar new file mode 100644 index 00000000..e69de29b diff --git a/tests/setuponlytests/modrinth/verify.sh b/tests/setuponlytests/modrinth/verify.sh new file mode 100644 index 00000000..1fd1fe61 --- /dev/null +++ b/tests/setuponlytests/modrinth/verify.sh @@ -0,0 +1 @@ +mc-image-helper assert fileExists "mods/cloth-config-*.jar" "mods/fabric-api-*.jar" \ No newline at end of file