update_hyt.sh 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. #!/bin/bash
  2. # LinuxGSM update_hyt.sh module
  3. # Author: Andrew dos Santos
  4. # Contributors: https://linuxgsm.com/contrib
  5. # Website: https://linuxgsm.com
  6. # Description: Handles updating of Hytale servers.
  7. moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")"
  8. fn_update_hyt_downloader_arch() {
  9. case "${arch}" in
  10. x86_64 | amd64)
  11. hytaledownloaderfile="hytale-downloader-linux-amd64"
  12. ;;
  13. aarch64 | arm64)
  14. fn_print_failure "Hytale supports arm64 servers, but the official downloader archive currently used by LinuxGSM does not include a Linux arm64 downloader."
  15. fn_script_log_fail "Unsupported Hytale downloader architecture: ${arch}"
  16. core_exit.sh
  17. ;;
  18. *)
  19. fn_print_failure "Unknown or unsupported hytale-downloader architecture: ${arch}"
  20. fn_script_log_fail "Unknown or unsupported hytale-downloader architecture: ${arch}"
  21. core_exit.sh
  22. ;;
  23. esac
  24. hytaledownloader="${serverfiles}/${hytaledownloaderfile}"
  25. }
  26. fn_update_downloader() {
  27. fn_update_hyt_downloader_arch
  28. if [ ! -f "${hytaledownloader}" ] || [ "${forceupdate}" == "1" ]; then
  29. fn_fetch_file "https://downloader.hytale.com/hytale-downloader.zip" "" "" "" "${tmpdir}" "hytale-downloader.zip" "nochmodx" "norun" "forcedl" "nohash"
  30. echo -en "extracting hytale-downloader..."
  31. unzip -oq "${tmpdir}/hytale-downloader.zip" "${hytaledownloaderfile}" "QUICKSTART.md" -d "${serverfiles}"
  32. exitcode=$?
  33. if [ "${exitcode}" -ne 0 ]; then
  34. fn_print_fail_eol_nl
  35. fn_script_log_fail "Extracting hytale-downloader"
  36. core_exit.sh
  37. else
  38. chmod +x "${hytaledownloader}"
  39. fn_print_ok_eol_nl
  40. fn_script_log_pass "Extracting hytale-downloader"
  41. fi
  42. fi
  43. }
  44. fn_update_hyt_patchline_args() {
  45. hytalepatchline="${hytalepatchline:-release}"
  46. hytalepatchlineargs=()
  47. if [ "${hytalepatchline}" != "release" ]; then
  48. hytalepatchlineargs=(-patchline "${hytalepatchline}")
  49. fi
  50. }
  51. # The downloader needs a Hytale account login (OAuth device code) the first time it runs, and again
  52. # if the saved credentials stop working. It waits for the login with no time limit, so it must
  53. # never run unattended without credentials, otherwise cron jobs hang.
  54. # Install always shows the login and waits: someone is watching, either in a terminal or in the
  55. # container logs (e.g. docker logs) during the first install.
  56. fn_update_hyt_auth() {
  57. hytalecredentials="${serverfiles}/.hytale-downloader-credentials.json"
  58. if [ "${firstcommandname}" == "INSTALL" ] || { [ -t 0 ] && [ -t 1 ]; }; then
  59. hytaledownloadertimeout="900"
  60. if [ ! -f "${hytalecredentials}" ]; then
  61. echo -e ""
  62. echo -e "${bold}${lightyellow}Hytale account login required${default}"
  63. echo -e "The Hytale downloader needs you to log in with a Hytale account that owns the game."
  64. echo -e "Open the URL shown below in a browser and approve the code within 15 minutes. This is only needed once."
  65. echo -e "Running in Docker? The URL is also shown in the container logs (docker logs)."
  66. echo -e ""
  67. fn_script_log_info "Hytale downloader login required"
  68. fi
  69. else
  70. hytaledownloadertimeout="300"
  71. if [ ! -f "${hytalecredentials}" ]; then
  72. fn_print_failure_nl "Hytale downloader is not logged in"
  73. echo -e "* Run ./${selfname} update in a terminal and approve the Hytale account login once."
  74. fn_script_log_fail "Hytale downloader is not logged in: ${hytalecredentials} not found"
  75. core_exit.sh
  76. fi
  77. fi
  78. }
  79. # Report a downloader timeout, which usually means it was waiting for a login.
  80. fn_update_hyt_timeout_check() {
  81. if [ "${exitcode}" -eq 124 ]; then
  82. fn_print_failure_nl "Hytale downloader timed out, it is probably waiting for a Hytale account login"
  83. echo -e "* The saved credentials may have expired. Run ./${selfname} update in a terminal to log in again."
  84. fn_script_log_fail "Hytale downloader timed out after ${hytaledownloadertimeout}s"
  85. core_exit.sh
  86. fi
  87. }
  88. fn_update_extract() {
  89. extractdir="${tmpdir}/hytale-game"
  90. rm -rf "${extractdir:?}"
  91. mkdir -p "${extractdir}"
  92. echo -en "extracting ${remotebuildfilename}..."
  93. unzip -oq "${tmpdir}/${remotebuildfilename}" -d "${extractdir}"
  94. exitcode=$?
  95. if [ "${exitcode}" -ne 0 ]; then
  96. fn_print_fail_eol_nl
  97. fn_script_log_fail "Extracting ${remotebuildfilename}"
  98. core_exit.sh
  99. fi
  100. if [ -d "${extractdir}/game/Server" ]; then
  101. extractedroot="${extractdir}/game"
  102. else
  103. extractedroot="${extractdir}"
  104. fi
  105. mkdir -p "${serverfiles}"
  106. if [ "${firstcommandname}" == "INSTALL" ]; then
  107. cp -a "${extractedroot}/." "${serverfiles}/"
  108. else
  109. for item in "${extractedroot}"/*; do
  110. [ -e "${item}" ] || continue
  111. itemname="$(basename "${item}")"
  112. case "${itemname}" in
  113. Server | .hytale-downloader-credentials.json)
  114. continue
  115. ;;
  116. jvm.options)
  117. if [ -f "${serverfiles}/jvm.options" ]; then
  118. continue
  119. fi
  120. ;;
  121. esac
  122. cp -a "${item}" "${serverfiles}/"
  123. done
  124. mkdir -p "${serverfiles}/Server"
  125. for item in "${extractedroot}/Server"/*; do
  126. [ -e "${item}" ] || continue
  127. itemname="$(basename "${item}")"
  128. case "${itemname}" in
  129. backups | bans.json | config.json | logs | mods | permissions.json | universe | whitelist.json)
  130. continue
  131. ;;
  132. esac
  133. cp -a "${item}" "${serverfiles}/Server/"
  134. done
  135. fi
  136. [ -f "${serverfiles}/start.sh" ] && chmod +x "${serverfiles}/start.sh"
  137. fn_print_ok_eol_nl
  138. fn_script_log_pass "Extracting ${remotebuildfilename}"
  139. rm -rf "${extractdir:?}"
  140. }
  141. fn_update_dl() {
  142. fn_update_downloader
  143. fn_update_hyt_patchline_args
  144. remotebuildfilename="hytale-server-${remotebuild:-latest}.zip"
  145. echo -e "downloading file [ ${italic}${remotebuildfilename}${default} ]"
  146. fn_sleep_time
  147. cd "${serverfiles}" || exit
  148. fn_update_hyt_auth
  149. timeout --foreground "${hytaledownloadertimeout}" "${hytaledownloader}" -download-path "${tmpdir}/${remotebuildfilename}" "${hytalepatchlineargs[@]}" -skip-update-check
  150. exitcode=$?
  151. fn_update_hyt_timeout_check
  152. if [ "${exitcode}" -ne 0 ]; then
  153. fn_print_failure_nl "Downloading ${remotebuildfilename}"
  154. fn_script_log_fail "Downloading ${remotebuildfilename}"
  155. core_exit.sh
  156. fi
  157. fn_update_extract
  158. if [ -n "${remotebuild}" ]; then
  159. echo "${remotebuild}" > "${localbuildfile}"
  160. fi
  161. fn_clear_tmp
  162. }
  163. fn_update_hyt_check_localbuild_tracking() {
  164. if [ -f "${localbuildfile}" ] && [ -f "${serverfiles}/Server/HytaleServer.jar" ] && [ "${serverfiles}/Server/HytaleServer.jar" -nt "${localbuildfile}" ]; then
  165. fn_print_warn_nl "Hytale server files are newer than LinuxGSM build tracking"
  166. echo -e "* Hytale may have updated itself outside LinuxGSM."
  167. echo -e "* Run ./${selfname} update to refresh LinuxGSM version tracking."
  168. fn_script_log_warn "Hytale server files are newer than LinuxGSM build tracking"
  169. fi
  170. }
  171. fn_update_localbuild() {
  172. fn_print_dots "Checking local build: ${remotelocation}"
  173. if [ -f "${localbuildfile}" ]; then
  174. localbuild="$(cat "${localbuildfile}")"
  175. fi
  176. if [ -z "${localbuild}" ]; then
  177. fn_print_error "Checking local build: ${remotelocation}: missing local build info"
  178. fn_script_log_error "Missing local build info"
  179. fn_script_log_error "Set localbuild to 0"
  180. localbuild="0"
  181. else
  182. fn_print_ok "Checking local build: ${remotelocation}"
  183. fn_script_log_pass "Checking local build"
  184. fn_update_hyt_check_localbuild_tracking
  185. fi
  186. }
  187. fn_update_remotebuild() {
  188. fn_update_downloader
  189. fn_update_hyt_patchline_args
  190. cd "${serverfiles}" || exit
  191. remotebuildresponsefile="${tmpdir}/hytale-print-version-response.txt"
  192. rm -f "${remotebuildresponsefile}"
  193. fn_update_hyt_auth
  194. timeout --foreground "${hytaledownloadertimeout}" "${hytaledownloader}" -print-version "${hytalepatchlineargs[@]}" -skip-update-check 2>&1 | tee "${remotebuildresponsefile}"
  195. exitcode=${PIPESTATUS[0]}
  196. fn_update_hyt_timeout_check
  197. remotebuildresponse="$(cat "${remotebuildresponsefile}")"
  198. if [ -f "${lgsmlog}" ]; then
  199. cat "${remotebuildresponsefile}" >> "${lgsmlog}"
  200. fi
  201. remotebuild=$(echo "${remotebuildresponse}" | grep -Eo "[0-9]{4}\.[0-9]{2}\.[0-9]{2}-[A-Za-z0-9]+" | tail -1)
  202. if [ -z "${remotebuild}" ]; then
  203. remotebuild=$(echo "${remotebuildresponse}" | tail -1)
  204. fi
  205. if [ "${firstcommandname}" != "INSTALL" ]; then
  206. fn_print_dots "Checking remote build: ${remotelocation}"
  207. if [ "${exitcode}" -ne 0 ] || [ -z "${remotebuild}" ] || [ "${remotebuild}" == "null" ]; then
  208. fn_print_fail "Checking remote build: ${remotelocation}"
  209. fn_script_log_fail "Checking remote build"
  210. core_exit.sh
  211. else
  212. fn_print_ok "Checking remote build: ${remotelocation}"
  213. fn_script_log_pass "Checking remote build"
  214. fi
  215. else
  216. if [ "${exitcode}" -ne 0 ] || [ -z "${remotebuild}" ] || [ "${remotebuild}" == "null" ]; then
  217. fn_print_failure "Unable to get remote build"
  218. fn_script_log_fail "Unable to get remote build"
  219. core_exit.sh
  220. fi
  221. fi
  222. }
  223. fn_update_compare() {
  224. fn_print_dots "Checking for update: ${remotelocation}"
  225. if [ "${localbuild}" != "${remotebuild}" ] || [ "${forceupdate}" == "1" ]; then
  226. date '+%s' > "${lockdir:?}/update.lock"
  227. fn_print_ok_nl "Checking for update: ${remotelocation}"
  228. fn_print "\n"
  229. fn_print_nl "${bold}${underline}Update${default} available"
  230. fn_print_nl "* Local build: ${red}${localbuild}${default}"
  231. fn_print_nl "* Remote build: ${green}${remotebuild}${default}"
  232. fn_print_nl "* Patchline: ${hytalepatchline}"
  233. fn_print "\n"
  234. fn_script_log_info "Update available"
  235. fn_script_log_info "Local build: ${localbuild}"
  236. fn_script_log_info "Remote build: ${remotebuild}"
  237. fn_script_log_info "Patchline: ${hytalepatchline}"
  238. if [ "${commandname}" == "UPDATE" ]; then
  239. date +%s > "${lockdir:?}/last-updated.lock"
  240. unset updateonstart
  241. check_status.sh
  242. if [ "${status}" == "0" ]; then
  243. fn_update_dl
  244. else
  245. fn_print_restart_warning
  246. exitbypass=1
  247. command_stop.sh
  248. fn_firstcommand_reset
  249. exitbypass=1
  250. fn_update_dl
  251. exitbypass=1
  252. command_start.sh
  253. fn_firstcommand_reset
  254. fi
  255. unset exitbypass
  256. alert="update"
  257. elif [ "${commandname}" == "CHECK-UPDATE" ]; then
  258. alert="check-update"
  259. fi
  260. alert.sh
  261. else
  262. fn_print_ok_nl "Checking for update: ${remotelocation}"
  263. fn_print "\n"
  264. fn_print_nl "${bold}${underline}No update${default} available"
  265. fn_print_nl "* Local build: ${green}${localbuild}${default}"
  266. fn_print_nl "* Remote build: ${green}${remotebuild}${default}"
  267. fn_print_nl "* Patchline: ${hytalepatchline}"
  268. fn_print "\n"
  269. fn_script_log_info "No update available"
  270. fn_script_log_info "Local build: ${localbuild}"
  271. fn_script_log_info "Remote build: ${remotebuild}"
  272. fn_script_log_info "Patchline: ${hytalepatchline}"
  273. fi
  274. }
  275. info_distro.sh
  276. localbuildfile="${datadir}/${selfname}-hytale-version"
  277. remotelocation="hytale.com"
  278. if [ "${firstcommandname}" == "INSTALL" ]; then
  279. fn_update_remotebuild
  280. fn_update_dl
  281. else
  282. fn_print_dots "Checking for update"
  283. fn_print_dots "Checking for update: ${remotelocation}"
  284. fn_script_log_info "Checking for update: ${remotelocation}"
  285. fn_update_localbuild
  286. fn_update_remotebuild
  287. fn_update_compare
  288. fi