update_gi.sh 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. #!/usr/bin/env bash
  2. # Disable undeclared variables, exit immediately when exit code != 0
  3. set -eu -o pipefail
  4. ############# Const
  5. UPDATE_URL="https://sdk-os-static.mihoyo.com/hk4e_global/mdk/launcher/api/resource?key=gcStgarh&launcher_id=10"
  6. #UPDATE_URL=http://localhost:8000/resource.json
  7. #UPDATE_URL=http://127.0.0.1/resource.json
  8. CONFIG=config.ini
  9. ANCHOR=UnityPlayer.dll
  10. LOG_FILE=_error.txt
  11. declare -A LANG_MAP=(
  12. ["zh-cn"]="Chinese"
  13. ["en-us"]="English(US)"
  14. ["ja-jp"]="Japanese"
  15. ["ko-kr"]="Korean"
  16. )
  17. VOICE_PACK_PATH="GenshinImpact_Data/StreamingAssets/Audio/GeneratedSoundBanks/Windows"
  18. SCRIPT_PATH=`cd "\`dirname \"$0\"\`"; echo "$PWD"`
  19. # Dedicated download directory for aria2c: it stores the index file in the same directory as target file
  20. DOWNLOAD_DIR=$PWD/../_update_gi_download
  21. DOWNLOAD_APPS=("aria2c|aria2c -c" "wget|wget -c" "curl|curl -C")
  22. ############# Functions
  23. fatal() {
  24. echo
  25. for arg in "$@"; do
  26. echo " * $arg" >&2
  27. done
  28. echo
  29. exit 1
  30. }
  31. download_file() {
  32. url=$1; md5=$2
  33. test -n "$url" -a -n "$md5" || fatal "argument missing: download_file <url> <md5>"
  34. echo "Downloading $url ..."
  35. archive_file="$DOWNLOAD_DIR/${url##*/}"
  36. archive_file_completed="${archive_file}.completed"
  37. if [ -f "$archive_file_completed" ]; then
  38. # patch was already downloaded but something went wrong when applying it
  39. echo "-- Found existing archive: ${download_url##*/} is already downloaded"
  40. else
  41. mkdir -p "$DOWNLOAD_DIR"
  42. cd "$DOWNLOAD_DIR"
  43. $dl_app "$url"
  44. cd - >/dev/null # Return to previous dir
  45. touch "$archive_file_completed"
  46. fi
  47. echo "-- Verifying MD5 checksum..."
  48. md5sum -c <<< "$md5 $archive_file"
  49. }
  50. # Perform path sanity checks
  51. # There is a good reason for this check. Do not pollute the game directory.
  52. test \! -e "$SCRIPT_PATH/$ANCHOR" || fatal \
  53. "Please move this script outside the game directory prior executing." \
  54. " -> See README.md for proper installation instructions"
  55. test -e "$CONFIG" || fatal \
  56. "Game information file $CONFIG not found." \
  57. "Make sure 'Genshin Impact Game' is the current working directory."
  58. # IDEA: Check whether this is a git clone and check for updates
  59. # hidden option to download pre-release version
  60. if [ "x${1:-}" == "x-pre" ]; then
  61. game_element="pre_download_game"
  62. end_element="deprecated_packages"
  63. pre_release=1
  64. else
  65. game_element="game"
  66. end_element="plugin"
  67. pre_release=0
  68. fi
  69. ################ Find a supported download executable
  70. dl_app=""
  71. for appname in ${DOWNLOAD_APPS[@]}; do
  72. dl_app_try=${appname%%|*}
  73. if command -v $dl_app_try &>/dev/null; then
  74. dl_app=${appname#*|}
  75. break
  76. fi
  77. done
  78. test -n "$dl_app" || fatal \
  79. "No downloader application found." \
  80. "Please install 'aria2c' (recommended), 'wget' or 'curl'."
  81. installed_version=`sed -n '/game_version=/{s/^.*=//;s/\r//p}' $CONFIG`
  82. test -n "$installed_version" || fatal "Cannot read game_version from $CONFIG"
  83. echo "Installed version: $installed_version"
  84. ################ Download the version information JSON file
  85. # wget and curl can download to stdout, but aria2c can't.
  86. # so we just create temp dir for it and read any downloaded file whose name can differ too
  87. tmp_path=$(mktemp -d)
  88. trap "rm -rf '$tmp_path'" EXIT
  89. update_content_src=$(cd "$tmp_path" && "$dl_app" "$UPDATE_URL" >"$LOG_FILE" 2>&1 && cat resource*) || fatal \
  90. "Failed to download version info. Check your internet connection." \
  91. "$LOG_FILE may contain some useful information."
  92. # trying to cut out the game info data. Tricky and not 100% realiable
  93. update_content=$(sed "s/^.*\"$game_element\":{//;s/,\"$end_element\":.*$//;s/{/&\n/g;s/}/\n&/g" <<< "$update_content_src")
  94. # find latest version: extract from JSON format
  95. latest_version_content=$(sed -n '/"latest":/,/^}/{/"version":/!d;s/,/\n/g;s/"//g;p}' <<< "$update_content")
  96. declare -A version_info
  97. while read -r keyvalue; do
  98. version_info[${keyvalue%%:*}]=${keyvalue#*:}
  99. done <<< "$latest_version_content"
  100. echo "Latest version: ${version_info[version]}"
  101. if [ "${version_info[version]}" = "$installed_version" ]; then
  102. echo "==> Client is up to date."
  103. if [[ "$update_content_src" =~ 'pre_download_game' ]]; then
  104. echo "NOTE: Pre-release client available."
  105. fi
  106. exit 0
  107. fi
  108. # Patch script directory
  109. patcher_dir="${SCRIPT_PATH}/../${version_info[version]//./}"
  110. test -f "$patcher_dir/patch.sh" || fatal \
  111. "No suitable patch script found. Please check the bug tracker for details about the progress."
  112. # find suitable patch: extract version information
  113. diffs_content=$(sed -n '/"diffs":/,/^}]}]/{/"name":/!d;s/"//g;p}' <<< "$update_content")
  114. patch_strategy="full" # download full client
  115. patch_voicepacks=()
  116. while read -r diff; do
  117. # we're found the correct version, now reading voicepacks
  118. if [ "$patch_strategy" == "diff" ]; then
  119. # if line doesn't contain "language" it isn't the voicepack
  120. if [[ ! "$diff" =~ "language:" ]]; then
  121. break
  122. fi
  123. patch_voicepacks+=("$diff")
  124. continue
  125. fi
  126. diff_content=$(sed 's/,/\n/g' <<< "$diff")
  127. unset diff_info
  128. declare -A diff_info
  129. while read -r keyvalue; do
  130. diff_info[${keyvalue%%:*}]=${keyvalue#*:}
  131. done <<< "$diff_content"
  132. if [ "${diff_info[version]}" == "$installed_version" ]; then
  133. patch_strategy="diff"
  134. # continue reading voicepacks
  135. fi
  136. done <<< "$diffs_content"
  137. if [ "$patch_strategy" == "diff" ]; then
  138. download_url=${diff_info[path]}
  139. patch_size=${diff_info[size]}
  140. patch_md5=${diff_info[md5]}
  141. patch_type="incremental update"
  142. else
  143. download_url=${version_info[path]}
  144. patch_size=${version_info[size]}
  145. patch_md5=${version_info[md5]}
  146. patch_type="full client"
  147. patch_voicepacks=($(sed -n '/"latest":/,/"diffs":/{!d;/"language":/!d;s/"//g;p}' <<< "$update_content"))
  148. echo "[WARNING] Cannot find any suitable upgrade to ${version_info[version]}. Will download full client!"
  149. fi
  150. echo
  151. # Unknown origin of the factor 10 (blame the devs)
  152. patch_size_mib=$(($patch_size / 10 / 1024 / 1024))
  153. echo "Main URL: $download_url"
  154. echo "Download size: ${patch_size_mib} MiB (${patch_type})"
  155. # array of files to download "[url]=md5"
  156. unset download_files
  157. declare -A download_files
  158. # add main game file/patch
  159. download_files["$download_url"]="$patch_md5"
  160. # extract voicepacks versions
  161. for voicepack in "${patch_voicepacks[@]}"; do
  162. voicepack_content=$(sed 's/,/\n/g' <<< "$voicepack")
  163. unset voicepack_info
  164. declare -A voicepack_info
  165. while read -r keyvalue; do
  166. voicepack_info[${keyvalue%%:*}]=${keyvalue#*:}
  167. done <<< "$voicepack_content"
  168. # filter the installed languages ${voicepack_info[language]}
  169. # language:zh-cn,name:zh-cn_1.4.0_1.5.0_diff_hvg2F3QM.zip,path:https://..._hvg2F3QM.zip,size:876760040,md5:ED2649DC29C17B67A33883F6F29B1DDA
  170. language=${voicepack_info[language]}
  171. voice_path=$VOICE_PACK_PATH/${LANG_MAP[$language]}
  172. if [ -d "$voice_path" ]; then
  173. download_files[${voicepack_info[path]}]=${voicepack_info[md5]}
  174. patch_size_mib=$((${voicepack_info[size]} / 10 / 1024 / 1024))
  175. echo "$language voice pack URL: ${voicepack_info[path]}"
  176. echo "Download size: ${patch_size_mib} MiB (${patch_type})"
  177. fi
  178. done
  179. echo
  180. if [ $pre_release -eq 1 ]; then
  181. echo "ATTENTION: You're going to install pre-release version."
  182. echo "The wine patch may not be yet available for this version."
  183. echo "Use on your own risk."
  184. echo
  185. fi
  186. # confirm update
  187. while :; do
  188. read -r -p "Start/continue update? [Y/n]: " input
  189. case "$input" in
  190. Y|y|'')
  191. break
  192. ;;
  193. n|N)
  194. exit 0
  195. ;;
  196. esac
  197. done
  198. echo "Download queue:"
  199. for url in "${!download_files[@]}"; do
  200. echo ">> $url"
  201. done
  202. echo
  203. ######## Start/continue downloading patch or full client and voice packs
  204. downloaded_files=()
  205. for url in "${!download_files[@]}"; do
  206. download_file "$url" "${download_files[$url]}"
  207. downloaded_files+=("$archive_file")
  208. done
  209. ######## Apply clean client update
  210. # Run 'patch_revert.sh' of the newest directory
  211. if [ -e launcher.bat ]; then
  212. echo
  213. echo "============== Reverting previous Wine patch ==============="
  214. bash "$patcher_dir/patch_revert.sh"
  215. echo "============================================================"
  216. echo
  217. fi
  218. # Unpack the game files and remove old ones according to deletefiles.txt
  219. echo "-- Updating game files...."
  220. for archive_file in "${downloaded_files[@]}"; do
  221. # Prevent deleting of the possibly necessary files in case of full update
  222. rm -f deletefiles.txt
  223. echo "Unpacking $archive_file..."
  224. unzip -o "$archive_file" >>"$LOG_FILE"
  225. if [ -f deletefiles.txt ]; then
  226. while read -r delme; do
  227. rm -f "$delme"
  228. done < deletefiles.txt
  229. rm deletefiles.txt
  230. fi
  231. done
  232. sed -i "s/game_version=$installed_version/game_version=${version_info[version]}/" "$CONFIG"
  233. # If we got this far, this was a successful update. Clean up old files.
  234. rm -r "$DOWNLOAD_DIR"
  235. rm -f "$LOG_FILE"
  236. echo "==> Update to version ${version_info[version]} completed"
  237. ######## Run wine compatibility patch script
  238. echo
  239. echo "================= Applying new Wine patch =================="
  240. bash "$patcher_dir/patch.sh"
  241. if [ -f "$patcher_dir/patch_anti_logincrash.sh" ]; then
  242. bash "$patcher_dir/patch_anti_logincrash.sh"
  243. fi
  244. echo "============================================================"
  245. echo "==> Update script completed successfully"
  246. exit 0