mirror of
https://github.com/factoriotools/factorio-docker.git
synced 2025-07-07 01:18:10 +02:00
This fixes issue #517 where the auto mod updater was downloading the wrong mod versions after updating to Space Age (Factorio 2.0). The problem was that the version checking logic was incorrectly rejecting compatible mod versions. Changes: - Fixed check_game_version() to properly handle major version differences - Game versions can now run mods designed for older major versions (backward compatibility) - Game versions correctly reject mods requiring newer versions - Fixed variable references in check_dependency_version() - Added clarifying comments about the version checking behavior This also addresses issue #468 by ensuring mods requiring newer Factorio versions than currently installed are properly skipped. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-authored-by: Claude <noreply@anthropic.com>
237 lines
6.6 KiB
Bash
Executable File
237 lines
6.6 KiB
Bash
Executable File
#!/bin/bash
|
|
set -eou pipefail
|
|
|
|
FACTORIO_VERSION=$1
|
|
MOD_DIR=$2
|
|
USERNAME=$3
|
|
TOKEN=$4
|
|
|
|
MOD_BASE_URL="https://mods.factorio.com"
|
|
|
|
print_step()
|
|
{
|
|
echo "$1"
|
|
}
|
|
|
|
print_success()
|
|
{
|
|
echo "$1"
|
|
}
|
|
|
|
print_failure()
|
|
{
|
|
echo "$1"
|
|
}
|
|
|
|
# Checks if the current game version satisfies the mod's minimum required version.
|
|
# Returns 1 if the game version is compatible with the mod, 0 if not
|
|
check_game_version() {
|
|
local mod_required_version="$1" # The minimum Factorio version required by the mod
|
|
local current_game_version="$2" # The current Factorio version
|
|
|
|
local mod_major mod_minor game_major game_minor
|
|
mod_major=$(echo "$mod_required_version" | cut -d '.' -f1)
|
|
mod_minor=$(echo "$mod_required_version" | cut -d '.' -f2)
|
|
game_major=$(echo "$current_game_version" | cut -d '.' -f1)
|
|
game_minor=$(echo "$current_game_version" | cut -d '.' -f2)
|
|
|
|
# If game major version is greater than mod's required major version, it's compatible
|
|
if [[ "$game_major" -gt "$mod_major" ]]; then
|
|
echo 1
|
|
return
|
|
fi
|
|
|
|
# If game major version is less than mod's required major version, it's not compatible
|
|
if [[ "$game_major" -lt "$mod_major" ]]; then
|
|
echo 0
|
|
return
|
|
fi
|
|
|
|
# Major versions are equal, check minor versions
|
|
# Game minor version must be >= mod's required minor version
|
|
if [[ "$game_minor" -ge "$mod_minor" ]]; then
|
|
echo 1
|
|
else
|
|
echo 0
|
|
fi
|
|
}
|
|
|
|
# Checks dependency string with provided version.
|
|
# Only checks for operator based string, ignoring everything else
|
|
# Returns 1 if check is ok, 0 if not
|
|
check_dependency_version()
|
|
{
|
|
local dependency="$1"
|
|
local mod_version="$2"
|
|
|
|
if [[ "$dependency" =~ ^(\?|!|~|\(~\)) ]]; then
|
|
echo 1
|
|
fi
|
|
|
|
local condition
|
|
condition=$(echo "$dependency" | grep -oE '(>=|<=|>|<|=) [0-9]+(\.[0-9]+)*')
|
|
|
|
if [[ -z "$condition" ]]; then
|
|
echo 1
|
|
fi
|
|
|
|
local operator required_version
|
|
operator=$(echo "$condition" | awk '{print $1}')
|
|
required_version=$(echo "$condition" | awk '{print $2}')
|
|
|
|
case "$operator" in
|
|
">=")
|
|
if [[ "$(printf '%s\n%s\n' "$required_version" "$mod_version" | sort -V | head -n1)" == "$required_version" ]]; then
|
|
echo 1
|
|
else
|
|
echo 0
|
|
fi
|
|
;;
|
|
">")
|
|
if [[ "$(printf '%s\n%s\n' "$required_version" "$mod_version" | sort -V | head -n1)" == "$required_version" && "$required_version" != "$mod_version" ]]; then
|
|
echo 1
|
|
else
|
|
echo 0
|
|
fi
|
|
;;
|
|
"<=")
|
|
if [[ "$(printf '%s\n%s\n' "$required_version" "$mod_version" | sort -V | tail -n1)" == "$required_version" ]]; then
|
|
echo 1
|
|
else
|
|
echo 0
|
|
fi
|
|
;;
|
|
"<")
|
|
if [[ "$(printf '%s\n%s\n' "$required_version" "$mod_version" | sort -V | tail -n1)" == "$required_version" && "$required_version" != "$mod_version" ]]; then
|
|
echo 1
|
|
else
|
|
echo 0
|
|
fi
|
|
;;
|
|
"=")
|
|
if [[ "$mod_version" == "$required_version" ]]; then
|
|
echo 1
|
|
else
|
|
echo 0
|
|
fi
|
|
;;
|
|
*)
|
|
echo 0
|
|
;;
|
|
esac
|
|
}
|
|
|
|
get_mod_info()
|
|
{
|
|
local mod_info_json="$1"
|
|
|
|
# Process mod releases from newest to oldest, looking for a compatible version
|
|
while IFS= read -r mod_release_info; do
|
|
local mod_version mod_factorio_version
|
|
mod_version=$(echo "$mod_release_info" | jq -r ".version")
|
|
mod_factorio_version=$(echo "$mod_release_info" | jq -r ".info_json.factorio_version")
|
|
|
|
# Check if this mod version is compatible with our Factorio version
|
|
# This prevents downloading mods that require a newer Factorio version (fixes #468)
|
|
# and ensures backward compatibility (e.g., Factorio 2.0 can use 1.x mods) (fixes #517)
|
|
if [[ $(check_game_version "$mod_factorio_version" "$FACTORIO_VERSION") == 0 ]]; then
|
|
echo " Skipping mod version $mod_version because of factorio version mismatch" >&2
|
|
continue
|
|
fi
|
|
|
|
# If we found 'dependencies' element, we also check versions there
|
|
if [[ $(echo "$mod_release_info" | jq -e '.info_json | has("dependencies") and (.dependencies | length > 0)') == true ]]; then
|
|
while IFS= read -r dependency; do
|
|
|
|
# We only check for 'base' dependency
|
|
if [[ "$dependency" == base* ]] && [[ $(check_dependency_version "$dependency" "$FACTORIO_VERSION") == 0 ]]; then
|
|
echo " Skipping mod version $mod_version, unsatisfied base dependency: $dependency" >&2
|
|
continue 2
|
|
fi
|
|
|
|
done < <(echo "$mod_release_info" | jq -r '.info_json.dependencies[]')
|
|
fi
|
|
|
|
echo "$mod_release_info" | jq -j ".file_name, \";\", .download_url, \";\", .sha1"
|
|
break
|
|
|
|
done < <(echo "$mod_info_json" | jq -c ".releases|sort_by(.released_at)|reverse|.[]")
|
|
}
|
|
|
|
update_mod()
|
|
{
|
|
MOD_NAME="$1"
|
|
MOD_NAME_ENCODED="${1// /%20}"
|
|
|
|
print_step "Checking for update of mod $MOD_NAME for factorio $FACTORIO_VERSION ..."
|
|
|
|
MOD_INFO_URL="$MOD_BASE_URL/api/mods/$MOD_NAME_ENCODED/full"
|
|
MOD_INFO_JSON=$(curl --silent "$MOD_INFO_URL")
|
|
|
|
if ! echo "$MOD_INFO_JSON" | jq -e .name >/dev/null; then
|
|
print_success " Custom mod not on $MOD_BASE_URL, skipped."
|
|
return 0
|
|
fi
|
|
|
|
MOD_INFO=$(get_mod_info "$MOD_INFO_JSON")
|
|
|
|
if [[ "$MOD_INFO" == "" ]]; then
|
|
print_failure " Not compatible with version"
|
|
return 0
|
|
fi
|
|
|
|
MOD_FILENAME=$(echo "$MOD_INFO" | cut -f1 -d";")
|
|
MOD_URL=$(echo "$MOD_INFO" | cut -f2 -d";")
|
|
MOD_SHA1=$(echo "$MOD_INFO" | cut -f3 -d";")
|
|
|
|
if [[ $MOD_FILENAME == null ]]; then
|
|
print_failure " Not compatible with version"
|
|
return 0
|
|
fi
|
|
|
|
if [[ -f $MOD_DIR/$MOD_FILENAME ]]; then
|
|
print_success " Already up-to-date."
|
|
return 0
|
|
fi
|
|
|
|
print_step " Downloading $MOD_FILENAME"
|
|
FULL_URL="$MOD_BASE_URL$MOD_URL?username=$USERNAME&token=$TOKEN"
|
|
HTTP_STATUS=$(curl --silent -L -w "%{http_code}" -o "$MOD_DIR/$MOD_FILENAME" "$FULL_URL")
|
|
|
|
if [[ $HTTP_STATUS != 200 ]]; then
|
|
print_failure " Download failed: Code $HTTP_STATUS."
|
|
rm -f "$MOD_DIR/$MOD_FILENAME"
|
|
return 1
|
|
fi
|
|
|
|
if [[ ! -f $MOD_DIR/$MOD_FILENAME ]]; then
|
|
print_failure " Downloaded file missing!"
|
|
return 1
|
|
fi
|
|
|
|
if ! [[ $(sha1sum "$MOD_DIR/$MOD_FILENAME") =~ $MOD_SHA1 ]]; then
|
|
print_failure " SHA1 mismatch!"
|
|
rm -f "$MOD_DIR/$MOD_FILENAME"
|
|
return 1
|
|
fi
|
|
|
|
print_success " Download complete."
|
|
|
|
for file in "$MOD_DIR/${MOD_NAME}_"*".zip"; do # wildcard does usually not work in quotes: https://unix.stackexchange.com/a/67761
|
|
if [[ $file != $MOD_DIR/$MOD_FILENAME ]]; then
|
|
print_success " Deleting old version: $file"
|
|
rm -f "$file"
|
|
fi
|
|
done
|
|
|
|
return 0
|
|
}
|
|
|
|
if [[ -f $MOD_DIR/mod-list.json ]]; then
|
|
jq -r ".mods|map(select(.enabled))|.[].name" "$MOD_DIR/mod-list.json" | while read -r mod; do
|
|
if [[ $mod != base ]]; then
|
|
update_mod "$mod" || true
|
|
fi
|
|
done
|
|
fi
|