123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369 |
- #!/usr/bin/env bash
- # Disable undeclared variables, exit immediately when exit code != 0
- set -eu -o pipefail
- ############# Const
- UPDATE_URL="https://sdk-os-static.mihoyo.com/hk4e_global/mdk/launcher/api/resource?key=gcStgarh&launcher_id=10"
- #UPDATE_URL=http://localhost:8000/resource.json
- #UPDATE_URL=http://127.0.0.1/resource.json
- CONFIG=config.ini
- ANCHOR=UnityPlayer.dll
- LOG_FILE=_error.txt
- # Voice pack information
- declare -A LANG_MAP=(
- ["zh-cn"]="Chinese"
- ["en-us"]="English(US)"
- ["ja-jp"]="Japanese"
- ["ko-kr"]="Korean"
- )
- VOICE_PACK_PATH="GenshinImpact_Data/StreamingAssets/Audio/GeneratedSoundBanks/Windows"
- SCRIPT_PATH=`cd "\`dirname \"$0\"\`"; echo "$PWD"`
- # Dedicated download directory for aria2c: it stores the index file in the same directory as target file
- DOWNLOAD_DIR=$PWD/../_update_gi_download
- DOWNLOAD_APPS=("aria2c|aria2c -c" "wget|wget -c" "curl|curl -C")
- ############# Functions
- fatal() {
- echo
- for arg in "$@"; do
- echo " * $arg" >&2
- done
- echo
- exit 1
- }
- download_file() {
- url=$1; md5=$2
- test -n "$url" -a -n "$md5" || fatal "argument missing: download_file <url> <md5>"
- echo "Downloading $url ..."
- archive_file="$DOWNLOAD_DIR/${url##*/}"
- archive_file_completed="${archive_file}.completed"
- if [ -f "$archive_file_completed" ]; then
- # patch was already downloaded but something went wrong when applying it
- echo "-- Found existing archive: ${download_url##*/} is already downloaded"
- else
- mkdir -p "$DOWNLOAD_DIR"
- cd "$DOWNLOAD_DIR"
- $dl_app "$url"
- cd - >/dev/null # Return to previous dir
- touch "$archive_file_completed"
- fi
- echo "-- Verifying MD5 checksum..."
- md5sum -c <<< "$md5 $archive_file"
- }
- # Perform path sanity checks
- # There is a good reason for this check. Do not pollute the game directory.
- test \! -e "$SCRIPT_PATH/$ANCHOR" || fatal \
- "Please move this script outside the game directory prior executing." \
- " -> See README.md for proper installation instructions"
- # IDEA: Check whether this is a git clone and check for updates
- # some help
- if [ "${1:-}" == "-h" -o "${1:-}" == "help" ]; then
- cat << HELP
- $0 [-h|help] [install]
-
- This script will modify the current working directory.
- Specify "install" for a new installation, or nothing to perform an update.
- See README.md for details and examples.
- HELP
- exit 0
- fi
- # option to install
- if [ "${1:-}" == "install" ]; then
- if [ `ls | wc -l` -ne 0 ]; then
- fatal "The current directory contain some files/subdirectories." \
- "Please install to the empty directory." \
- "If you would like to update or continue the installation, remove the 'install' option:" \
- " bash '$0'"
- fi
- echo -e '[General]\r\nchannel=1\r\ncps=mihoyo\r\ngame_version=0.0.0\r\nsub_channel=0\r\n' > config.ini
- shift
- install_mode=y
- fi
- # hidden option to download pre-release version
- if [ "x${1:-}" == "x-pre" ]; then
- game_element="pre_download_game"
- end_element="deprecated_packages"
- pre_release=1
- else
- game_element="game"
- end_element="plugin"
- pre_release=0
- fi
- ################ Find a supported download executable
- dl_app=""
- for appname in ${DOWNLOAD_APPS[@]}; do
- dl_app_try=${appname%%|*}
- if command -v $dl_app_try &>/dev/null; then
- dl_app=${appname#*|}
- break
- fi
- done
- test -n "$dl_app" || fatal \
- "No downloader application found." \
- "Please install 'aria2c' (recommended), 'wget' or 'curl'."
- # Check and read out the configuration file
- test -e "$CONFIG" || fatal \
- "Game information file $CONFIG not found." \
- "Make sure 'Genshin Impact Game' is the current working directory." \
- "If you would like to install the game append the 'install' option:" \
- " bash '$0' install"
- # In case people accidentally want to install the game into the launcher directory
- if [ $(ls -b1q *.dll 2>/dev/null | wc -l) -gt 1 ]; then
- fatal "This script is likely run in the wrong directory." \
- "Found more than one DLL file. (expected: 1 or 0)" \
- "Please run this script in a proper/clean game directory."
- fi
- installed_version=`sed -n 's/^game_version=\(.*\)/\1/p' "$CONFIG" | tr -d "\r\n"`
- test -n "$installed_version" || fatal "Cannot read game_version from $CONFIG"
- echo "Installed version: $installed_version"
- ################ Download the version information JSON file
- # wget and curl can download to stdout, but aria2c can't.
- # so we just create temp dir for it and read any downloaded file whose name can differ too
- tmp_path=$(mktemp -d)
- trap "rm -rf '$tmp_path'" EXIT
- update_content_src=$(cd "$tmp_path" && "$dl_app" "$UPDATE_URL" >"$LOG_FILE" 2>&1 && cat resource*) || fatal \
- "Failed to download version info. Check your internet connection." \
- "$LOG_FILE may contain some useful information."
- # trying to cut out the game info data. Tricky and not 100% realiable
- update_content=$(sed "s/^.*\"$game_element\":{//;s/,\"$end_element\":.*$//;s/{/&\n/g;s/}/\n&/g" <<< "$update_content_src")
- # find latest version: extract from JSON format
- latest_version_content=$(sed -n '/"latest":/,/^}/{/"version":/!d;s/,/\n/g;s/"//g;p}' <<< "$update_content")
- declare -A version_info
- while read -r keyvalue; do
- version_info[${keyvalue%%:*}]=${keyvalue#*:}
- done <<< "$latest_version_content"
- echo "Latest version: ${version_info[version]}"
- if [ "${version_info[version]}" = "$installed_version" ]; then
- echo
- echo "==> Client is up to date."
- if [[ "$update_content_src" == *'"pre_download_game":{'* ]]; then
- echo "NOTE: Pre-release client is available."
- fi
- exit 0
- fi
- # Patch script directory
- patcher_dir="${SCRIPT_PATH}/../${version_info[version]//./}"
- test -f "$patcher_dir/patch.sh" || fatal \
- "No suitable patch script found. Please check the bug tracker for details about the progress."
- # find suitable patch: extract version information
- diffs_content=$(sed -n '/"diffs":/,/^}]}]/{/"name":/!d;s/"//g;p}' <<< "$update_content")
- patch_strategy="full" # download full client
- patch_voicepacks=()
- while read -r diff; do
- # we're found the correct version, now reading voicepacks
- if [ "$patch_strategy" == "diff" ]; then
- # if line doesn't contain "language" it isn't the voicepack
- if [[ ! "$diff" =~ "language:" ]]; then
- break
- fi
- patch_voicepacks+=("$diff")
- continue
- fi
- diff_content=$(sed 's/,/\n/g' <<< "$diff")
- unset diff_info
- declare -A diff_info
- while read -r keyvalue; do
- diff_info[${keyvalue%%:*}]=${keyvalue#*:}
- done <<< "$diff_content"
- if [ "${diff_info[version]:-}" == "$installed_version" ]; then
- patch_strategy="diff"
- # continue reading voicepacks
- fi
- done <<< "$diffs_content"
- if [ "$patch_strategy" == "diff" ]; then
- download_url=${diff_info[path]}
- patch_size=${diff_info[size]}
- patch_md5=${diff_info[md5]}
- patch_type="incremental update"
- else
- download_url=${version_info[path]}
- patch_size=${version_info[size]}
- patch_md5=${version_info[md5]}
- patch_type="full client"
- patch_voicepacks=($(sed -n '/"latest":/,/"diffs":/{!d;/"language":/!d;s/"//g;p}' <<< "$update_content"))
- echo
- if [ "${install_mode:-}" != "y" ]; then
- echo "[WARNING] Cannot find any suitable upgrade to ${version_info[version]}. Will download full client!"
- else
- echo "Will download and install the full client version."
- fi
- fi
- ################ Add links to the download queue "download_files"
- echo
- patch_size_mib=$(($patch_size / (1024 * 1024 * 2)))
- echo "Main URL: $download_url"
- echo "Installed size: ${patch_size_mib} MiB (${patch_type})"
- # array of files to download "[url]=md5"
- unset download_files
- declare -A download_files
- # add main game file/patch
- download_files["$download_url"]="$patch_md5"
- # extract voicepacks versions
- for voicepack in "${patch_voicepacks[@]}"; do
- voicepack_content=$(sed 's/,/\n/g' <<< "$voicepack")
- unset voicepack_info
- declare -A voicepack_info
- while read -r keyvalue; do
- voicepack_info[${keyvalue%%:*}]=${keyvalue#*:}
- done <<< "$voicepack_content"
- # filter the installed languages ${voicepack_info[language]}
- # language:LANGUAGE_NAME,name:ARCHIVE_NAME,path:LINK_TO_ZIP,size:NUMBER,md5:MD5SUM_CAPS
- language=${voicepack_info[language]}
- voice_path=$VOICE_PACK_PATH/${LANG_MAP[$language]}
- if [ -d "$voice_path" ]; then
- download_files[${voicepack_info[path]}]=${voicepack_info[md5]}
- patch_size_mib=$((${voicepack_info[size]} / (1024 * 1024 * 2)))
- echo "$language voice pack URL: ${voicepack_info[path]}"
- echo "Installed size: ${patch_size_mib} MiB (${patch_type})"
- fi
- done
- echo
- if [ $pre_release -eq 1 ]; then
- echo "ATTENTION: You're going to install pre-release version."
- echo "The wine patch may not be yet available for this version."
- echo "Use on your own risk."
- echo
- fi
- # confirm update
- while :; do
- read -r -p "Start/continue update? [Y/n]: " input
- case "$input" in
- Y|y|'')
- break
- ;;
- n|N)
- exit 0
- ;;
- esac
- done
- echo "Download queue:"
- for url in "${!download_files[@]}"; do
- echo ">> $url"
- done
- echo
- ######## Start/continue downloading patch or full client and voice packs
- downloaded_files=()
- for url in "${!download_files[@]}"; do
- download_file "$url" "${download_files[$url]}"
- downloaded_files+=("$archive_file")
- done
- ######## Apply clean client update
- # Run 'patch_revert.sh' of the newest directory
- if [ -e launcher.bat ]; then
- echo
- echo "============== Reverting previous Wine patch ==============="
- bash "$patcher_dir/patch_revert.sh"
- echo "============================================================"
- echo
- fi
- # Unpack the game files and remove old ones according to deletefiles.txt
- echo "-- Updating game files...."
- for archive_file in "${downloaded_files[@]}"; do
- # Prevent deleting of the possibly necessary files in case of full update
- rm -f deletefiles.txt
- echo "Unpacking $archive_file..."
- unzip -o "$archive_file" >>"$LOG_FILE"
- if [ -f deletefiles.txt ]; then
- while read -r delme; do
- rm -f "$delme"
- done < deletefiles.txt
- rm deletefiles.txt
- fi
- done
- sed -i "s/game_version=$installed_version/game_version=${version_info[version]}/" "$CONFIG"
- # If we got this far, this was a successful update. Clean up old files.
- rm -r "$DOWNLOAD_DIR"
- rm -f "$LOG_FILE"
- echo "==> Update to version ${version_info[version]} completed"
- ######## Run wine compatibility patch script
- echo
- echo "================= Applying new Wine patch =================="
- bash "$patcher_dir/patch.sh"
- if [ -f "$patcher_dir/patch_anti_logincrash.sh" ]; then
- bash "$patcher_dir/patch_anti_logincrash.sh"
- fi
- echo "============================================================"
- echo "==> Update script completed successfully"
- exit 0
|