From 8aea4af68717d6e81f15cd73812bc8f376e195ba Mon Sep 17 00:00:00 2001 From: aclist <92275929+aclist@users.noreply.github.com> Date: Sun, 9 Feb 2025 18:55:33 +0900 Subject: [PATCH] chore: update IP db --- CHANGELOG.md | 4 + dzgui.sh | 4 +- dzgui.sh.old | 1024 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 1030 insertions(+), 2 deletions(-) create mode 100755 dzgui.sh.old diff --git a/CHANGELOG.md b/CHANGELOG.md index b3da467..676d7f1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## [5.6.6] 2024-02-09 +### Changed +- Update IP database records for 2025-02 + ## [5.6.2] 2024-01-22 ### Fixed - Resolve regression introduced with IP resolution feature in 5.6.0 (restores functionality of right-click action: Add to My Servers) diff --git a/dzgui.sh b/dzgui.sh index dcd64af..ae93854 100755 --- a/dzgui.sh +++ b/dzgui.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash set -o pipefail -version=5.6.2 +version=5.6.3 #CONSTANTS aid=221100 @@ -639,7 +639,7 @@ fetch_helpers_by_sum(){ } fetch_geo_file(){ # for binary releases - local geo_sum="28ccd75b3e03cf07a7011f22ef0cd69b" + local geo_sum="9824e9b9a75a4830a2423932cc188b06" local km_sum="b038fdb8f655798207bd28de3a004706" local gzip="$helpers_path/ips.csv.gz" if [[ ! -f $geo_file ]] || [[ $(get_hash $geo_file) != $geo_sum ]]; then diff --git a/dzgui.sh.old b/dzgui.sh.old new file mode 100755 index 0000000..65b151b --- /dev/null +++ b/dzgui.sh.old @@ -0,0 +1,1024 @@ +#!/usr/bin/env bash +set -o pipefail + +version=5.7.0-beta.5 + +#CONSTANTS +aid=221100 +game="dayz" +app_name="dzgui" +app_name_upper="DZGUI" +workshop="steam://url/CommunityFilePage/" +sd_res="--width=1280 --height=800" +steamsafe_zenity="/usr/bin/zenity" +zenity_flags=("--width=500" "--title=DZGUI") +declare -A deps +deps=([awk]="5.1.1" [curl]="7.80.0" [jq]="1.6" [tr]="9.0" [$steamsafe_zenity]="3.44.1") + +#CONFIG +config_path="$HOME/.config/dztui" +config_file="$config_path/dztuirc" + +#PATHS +state_path="$HOME/.local/state/$app_name" +cache_path="$HOME/.cache/$app_name" +share_path="$HOME/.local/share/$app_name" +script_path="$share_path/dzgui.sh" +helpers_path="$share_path/helpers" + +#LOGS +log_path="$state_path/logs" +debug_log="$log_path/DZGUI_DEBUG.log" + +#STATE FILES +prefix="dzg" +history_file="$state_path/$prefix.history" +versions_file="$state_path/$prefix.versions" +lock_file="$state_path/$prefix.lock" +cols_file="$state_path/$prefix.cols.json" + +#CACHE FILES +coords_file="$cache_path/$prefix.coords" + +#legacy paths +hist_file="$config_path/history" +version_file="$config_path/versions" + +#XDG +freedesktop_path="$HOME/.local/share/applications" + +#HELPERS +ui_helper="$helpers_path/ui.py" +geo_file="$helpers_path/ips.csv" +km_helper="$helpers_path/latlon" +sums_path="$helpers_path/sums.md5" +func_helper="$helpers_path/funcs" + +#REMOTE +remote_host=gh +author="aclist" +repo="dztui" +url_prefix="https://raw.githubusercontent.com/$author/$repo" +stable_url="$url_prefix/dzgui" +testing_url="$url_prefix/testing" +releases_url="https://github.com/$author/$repo/releases/download/browser" +km_helper_url="$releases_url/latlon" +geo_file_url="$releases_url/ips.csv.gz" + + +set_im_module(){ + #TODO: drop pending SteamOS changes + pgrep -a gamescope | grep -q "generate-drm-mode" + if [[ $? -eq 0 ]]; then + GTK_IM_MODULE="" + logger INFO "Detected Steam Deck (Game Mode), unsetting GTK_IM_MODULE" + else + return + fi +} +redact(){ + sed 's@\(/home/\)[^/]*@\1REDACTED@g' +} +logger(){ + local date="$(date "+%F %T,%3N")" + local tag="$1" + local string="$2" + local self="${BASH_SOURCE[0]}" + local caller="${FUNCNAME[1]}" + local line="${BASH_LINENO[0]}" + printf "%s␞%s␞%s::%s()::%s␞%s\n" "$date" "$tag" "$self" "$caller" "$line" "$string" \ + | redact >> "$debug_log" +} +setup_dirs(){ + for dir in "$state_path" "$cache_path" "$share_path" "$helpers_path" "$freedesktop_path" "$config_path" "$log_path"; do + if [[ ! -d $dir ]]; then + mkdir -p "$dir" + fi + done +} +setup_state_files(){ + if [[ -f "$debug_log" ]]; then + rm "$debug_log" && touch $debug_log + logger INFO "Initializing DZGUI version $version" + fi + if [[ -f "$version_file" ]]; then + mv "$version_file" "$versions_file" && + logger INFO "Migrating legacy version file" + fi + # wipe cache files + local path="$cache_path" + if find "$path" -mindepth 1 -maxdepth 1 | read; then + for file in $path/*; do + rm "$file" + done + logger INFO "Wiped cache files" + fi +} +print_config_vals(){ + local keys=( + "branch" + "name" + "fav_server" + "fav_label" + "auto_install" + "steam_path" + "default_steam_path" + "preferred_client" + ) + for i in "${keys[@]}"; do + logger INFO "Read key '$i': '${!i}'" + done + if [[ ${#ip_list[@]} -lt 1 ]]; then + logger WARN "No IPs in saved server list" + fi + +} +test_gobject(){ + python3 -c "import gi" + if [[ ! $? -eq 0 ]]; then + logger CRITICAL "Missing PyGObject" + fdialog "Requires PyGObject (python-gobject)" + exit 1 + fi + logger INFO "Found PyGObject in Python env" +} +update_config(){ + # handling for legacy files + [[ -z $branch ]] && branch="stable" + [[ -f $config_file ]] && mv $config_file ${config_file}.old + write_config > $config_file && return 90 || return 1 + logger INFO "Updated config file at '$config_file'" +} +setup_steam_client(){ + local flatpak + local steam + local steam_cmd + [[ -n $preferred_client ]] && return 0 + [[ $(command -v flatpak) ]] && flatpak=$(flatpak list | grep valvesoftware.Steam) + steam=$(command -v steam) + if [[ -z "$steam" ]] && [[ -z "$flatpak" ]]; then + raise_error_and_quit "Requires Steam or Flatpak Steam" + elif [[ -n "$steam" ]] && [[ -n "$flatpak" ]]; then + preferred_client="steam" + elif [[ -n "$steam" ]]; then + preferred_client="steam" + else + steam_cmd="flatpak run com.valvesoftware.Steam" + fi + update_config && logger INFO "Preferred client set to '$steam_cmd'" || return 1 +} +print_ip_list(){ + [[ ${#ip_list[@]} -eq 0 ]] && return 1 + printf "\t\"%s\"\n" "${ip_list[@]}" +} +write_config(){ +cat <<-END +#Path to DayZ installation +steam_path="$steam_path" + +#Battlemetrics API key +api_key="$api_key" + +#Favorited server IP:PORT array +ip_list=( +$(print_ip_list) +) + +#Favorite server to fast-connect to (limit one) +fav_server="$fav_server" + +#Favorite server label (human readable) +fav_label="$fav_label" + +#Custom player name (optional, required by some servers) +name="$name" + +#Set to 1 to perform dry-run and print launch options +debug="$debug" + +#Toggle stable/testing branch +branch="$branch" + +#Start in fullscreen +fullscreen="$fullscreen" + +#Steam API key +steam_api="$steam_api" + +#Auto-install mods +auto_install="$auto_install" + +#Automod staging directory +staging_dir="$staging_dir" + +#Path to default Steam client +default_steam_path="$default_steam_path" + +#Preferred Steam launch command (for Flatpak support) +preferred_client="$preferred_client" + +#DZGUI source path +src_path="$src_path" +END +} +depcheck(){ + for dep in "${!deps[@]}"; do + command -v "$dep" 2>&1>/dev/null + if [[ $? -eq 1 ]]; then + local msg="Requires $dep >= ${deps[$dep]}" + raise_error_and_quit "$msg" + fi + done + local jqmsg="jq must be compiled with support for oniguruma" + local jqtest + jqtest=$(echo '{"test": "foo"}' | jq '.test | test("^foo$")') + [[ $? -ne 0 ]] && raise_error_and_quit "$jqmsg" + logger INFO "Initial dependencies satisfied" +} +check_pyver(){ + local pyver=$(python3 --version | awk '{print $2}') + local minor=$(<<< $pyver awk -F. '{print $2}') + if [[ -z $pyver ]] || [[ ${pyver:0:1} -lt 3 ]] || [[ $minor -lt 10 ]]; then + local msg="Requires Python >=3.10" + raise_error_and_quit "$msg" + fi + logger INFO "Found Python version: $pyver" +} +watcher_deps(){ + if [[ ! $(command -v wmctrl) ]] && [[ ! $(command -v xdotool) ]]; then + raise_error_and_quit "Missing dependency: requires 'wmctrl' or 'xdotool'" + exit 1 + fi + logger INFO "Found DZG Watcher dependencies" +} +format_version_url(){ + [[ -z "$branch" ]] && branch="stable" + case "$branch" in + "stable") + version_url="$stable_url/dzgui.sh" + ;; + "testing") + version_url="$testing_url/dzgui.sh" + ;; + esac + echo "$version_url" +} +write_desktop_file(){ +cat <<-END +[Desktop Entry] +Version=1.0 +Type=Application +Terminal=false +Exec=$share_path/dzgui.sh +Name=$app_name_upper +Comment=$app_name +Icon=$share_path/$app_name +Categories=Game +END +} +freedesktop_dirs(){ + local version_url=$(format_version_url) + local img_url="$stable_url/images" + curl -s "$version_url" > "$script_path" + chmod +x "$script_path" + for i in dzgui grid.png hero.png logo.png icon.png; do + curl -s "$img_url/$i" > "$share_path/$i" + done + write_desktop_file > "$freedesktop_path/$app_name.desktop" + [[ $is_steam_deck -eq 0 ]] && return + write_desktop_file > "$HOME/Desktop/$app_name.desktop" +} +legacy_vars(){ + local suffix="fav" + local hr_msg="Config file contains values based on old API. Please update and re-run setup." + local msg="Config file contains legacy API value: '$suffix'" + if [[ -n $fav ]]; then + logger WARN "$msg" + fdialog "$hr_msg" + exit 1 + fi + if [[ -n $whitelist ]]; then + suffix="whitelist" + logger WARN "$msg" + fdialog "$hr_msg" + exit 1 + fi +} +merge_config(){ + [[ -z $staging_dir ]] && staging_dir="/tmp" + update_config + tdialog "Wrote new config format to \n${config_file}\nIf errors occur, you can restore the file:\n${config_file}.old" +} +check_unmerged(){ + if [[ -f ${config_path}.unmerged ]]; then + merge_config + rm ${config_path}.unmerged + fi +} +check_version(){ + local version_url=$(format_version_url) + local upstream=$(curl -Ls "$version_url" | awk -F= '/^version=/ {print $2}') + local res=$(get_response_code "$version_url") + [[ $res -ne 200 ]] && raise_error_and_quit "Remote resource unavailable: '$version_url'" + logger INFO "Local branch: '$branch', local version: $version" + if [[ $branch == "stable" ]]; then + version_url="$stable_url/dzgui.sh" + elif [[ $branch == "testing" ]]; then + version_url="$testing_url/dzgui.sh" + fi + [[ ! -f "$freedesktop_path/$app_name.desktop" ]] && freedesktop_dirs + if [[ $version == $upstream ]]; then + logger INFO "Local version is same as upstream" + check_unmerged + else + logger WARN "Local and remote version mismatch: $version != $upstream" + prompt_dl + fi +} +download_new_version(){ + local version_url="$(format_version_url)" + logger INFO "Version URL is '$version_url'" + logger INFO "$src_path" + mv "$src_path" "$src_path.old" + curl -L "$version_url" > "$src_path" 2>$debug_log + rc=$? + if [[ $rc -eq 0 ]]; then + dl_changelog + logger INFO "Wrote new version to $src_path" + chmod +x "$src_path" + touch "${config_path}.unmerged" + fdialog "DZGUI $upstream successfully downloaded. To use the new version, select Exit and restart." + logger INFO "User exited after version upgrade" + exit 0 + else + mv "$src_path.old" "$src_path" + logger WARN "curl failed to fetch new version. Rolling back" + fdialog "Failed to download the new version. Restoring old version" + return 1 + fi +} +prompt_dl(){ + _text(){ + cat <<-EOF + Version conflict. + + Your branch: $branch + Your version: $version + Upstream version: $upstream + + Version updates introduce important bug fixes and are encouraged. Attempt to download the latest version? + EOF + } + qdialog "$(_text)" "Yes" "No" + if [[ $? -eq 1 ]]; then + return 0 + else + download_new_version + fi +} +dl_changelog(){ + local mdbranch + local md + [[ $branch == "stable" ]] && mdbranch="dzgui" + [[ $branch == "testing" ]] && mdbranch="testing" + local md="$url_prefix/${mdbranch}/$file" + curl -Ls "$md" > "$state_path/CHANGELOG.md" +} +test_display_mode(){ + pgrep -a gamescope | grep -q "generate-drm-mode" + if [[ $? -eq 0 ]]; then + echo gm + else + echo dm + fi +} +check_architecture(){ + local cpu=$(< /proc/cpuinfo awk -F": " '/AMD Custom APU [0-9]{4}$/ {print $2; exit}') + read -a APU_MODEL <<< "$cpu" + if [[ ${APU_MODEL[3]} != "0932" ]] && [[ ${APU_MODEL[3]} != "0405" ]]; then + is_steam_deck=0 + logger INFO "Setting architecture to 'desktop'" + return + fi + + if [[ $(test_display_mode) == "gm" ]]; then + is_steam_deck=2 + else + is_steam_deck=1 + fi + logger INFO "Setting architecture to 'Steam Deck'" +} +check_map_count(){ + [[ $is_steam_deck -gt 0 ]] && return 0 + local map_count_file="/proc/sys/vm/max_map_count" + local min_count=1048576 + local conf_file="/etc/sysctl.d/dayz.conf" + local current_count + if [[ ! -f ${map_count_file} ]]; then + logger WARN "File '${map_count_file}' doesn't exist!" + return 1 + fi + current_count=$(cat ${map_count_file}) + if [[ $current_count -ge $min_count ]]; then + logger DEBUG "System map count is set to ${current_count}" + return 0 + fi + qdialog "sudo password required to set system vm map count." "OK" "Cancel" + if [[ $? -eq 0 ]]; then + local pass + logger INFO "Prompting user for sudo escalation" + pass=$($steamsafe_zenity --password) + if [[ $? -eq 1 ]]; then + logger WARN "User aborted password prompt" + return 1 + fi + logger DEBUG "Old map count is $current_count" + [[ $current_count -lt $min_count ]] && current_count=$min_count + sudo -S <<< "$pass" sh -c "echo 'vm.max_map_count=${current_count}' > $conf_file" + sudo sysctl -p "$conf_file" + logger DEBUG "Updated map count to $min_count" + else + logger WARN "User aborted map count prompt" + return 1 + fi +} +qdialog(){ + local text="$1" + local ok="$2" + local cancel="$3" + $steamsafe_zenity --question --text="$1" --ok-label="$ok" --cancel-label="$cancel" "${zenity_flags[@]}" +} +pdialog(){ + $steamsafe_zenity --progress --pulsate --auto-close "${zenity_flags[@]}" --text="$1" +} +fdialog(){ + $steamsafe_zenity --warning --ok-label="Exit" --text="$1" "${zenity_flags[@]}" +} +tdialog(){ + $steamsafe_zenity --info --text="$1" "${zenity_flags[@]}" +} +steam_deps(){ + local flatpak + local steam + [[ $(command -v flatpak) ]] && flatpak=$(flatpak list | grep valvesoftware.Steam) + steam=$(command -v steam) + if [[ -z "$steam" ]] && [[ -z "$flatpak" ]]; then + local msg="Found neither Steam nor Flatpak Steam" + raise_error_and_quit "$msg" + exit 1 + elif [[ -n "$steam" ]] && [[ -n "$flatpak" ]]; then + [[ -n $preferred_client ]] && return 0 + if [[ -z $preferred_client ]]; then + preferred_client="steam" + fi + elif [[ -n "$steam" ]]; then + preferred_client="steam" + else + preferred_client="flatpak" + fi + update_config + logger INFO "Preferred client set to '$preferred_client'" +} +migrate_files(){ + if [[ ! -f $config_path/dztuirc.oldapi ]]; then + cp $config_file $config_path/dztuirc.oldapi + logger INFO "Migrated old API file" + fi + [[ ! -f $hist_file ]] && return + rm $hist_file + logger INFO "Wiped old history file" +} +stale_symlinks(){ + local game_dir="$steam_path/steamapps/common/DayZ" + for l in $(find "$game_dir" -xtype l); do + logger DEBUG "Updating stale symlink '$l'" + unlink "$l" + done +} +local_latlon(){ + if [[ -z $(command -v dig) ]]; then + local local_ip=$(curl -Ls "https://ipecho.net/plain") + else + local local_ip=$(dig -4 +short myip.opendns.com @resolver1.opendns.com) + fi + local url="http://ip-api.com/json/$local_ip" + local res=$(curl -Ls "$url" | jq -r '"\(.lat)\n\(.lon)"') + if [[ -z "$res" ]]; then + logger WARN "Failed to get local coordinates" + return 1 + fi + echo "$res" > "$coords_file" +} +lock(){ + [[ ! -f $lock_file ]] && touch $lock_file + local pid=$(cat $lock_file) + ps -p $pid -o pid= >/dev/null 2>&1 + res=$? + if [[ $res -eq 0 ]]; then + local msg="DZGUI already running ($pid)" + raise_error_and_quit "$msg" + elif [[ $pid == $$ ]]; then + : + else + echo $$ > $lock_file + fi +} +get_hash(){ + local file="$1" + md5sum "$1" | awk '{print $1}' +} +fetch_a2s(){ + # this file is currently monolithic + [[ -d $helpers_path/a2s ]] && { logger INFO "A2S helper is current"; return 0; } + local sha=c7590ffa9a6d0c6912e17ceeab15b832a1090640 + local author="yepoleb" + local repo="python-a2s" + local url="https://github.com/$author/$repo/tarball/$sha" + local prefix="${author^}-$repo-${sha:0:7}" + local file="$prefix.tar.gz" + local res=$(get_response_code "$url") + [[ $res -ne 200 ]] && raise_error_and_quit "Remote resource unavailable: '$file'" + curl -Ls "$url" > "$helpers_path/$file" + tar xf "$helpers_path/$file" -C "$helpers_path" "$prefix/a2s" --strip=1 + rm "$helpers_path/$file" + logger INFO "Updated A2S helper to sha '$sha'" +} +fetch_dzq(){ + local sum="9caed1445c45832f4af87736ba3f9637" + local file="$helpers_path/a2s/dayzquery.py" + if [[ -f $file ]] && [[ $(get_hash "$file") == $sum ]]; then + logger INFO "DZQ is current" + return 0 + fi + local sha=3088bbfb147b77bc7b6a9425581b439889ff3f7f + local author="yepoleb" + local repo="dayzquery" + local url="https://raw.githubusercontent.com/$author/$repo/$sha/dayzquery.py" + local res=$(get_response_code "$url") + [[ $res -ne 200 ]] && raise_error_and_quit "Remote resource unavailable: 'dayzquery.py'" + curl -Ls "$url" > "$file" + logger INFO "Updated DZQ to sha '$sha'" +} +fetch_icons(){ + res=( + "16" + "24" + "32" + "48" + "64" + "96" + "128" + "256" + ) + url="$stable_url/images/icons" + for i in "${res[@]}"; do + size="${i}x${i}" + dir="$HOME/.local/share/icons/hicolor/$size/apps" + icon="$dir/$app_name.png" + [[ -f $icon ]] && return + if [[ ! -d $dir ]]; then + mkdir -p "$dir" + fi + logger INFO "Updating $size Freedesktop icon" + curl -Ls "${url}/${i}.png" > "$icon" + done +} +fetch_helpers_by_sum(){ + [[ -f "$config_file" ]] && source "$config_file" + declare -A sums + sums=( + ["ui.py"]="d3ad9153d8599bea0eede9fd3121ee8e" + ["query_v2.py"]="55d339ba02512ac69de288eb3be41067" + ["vdf2json.py"]="2f49f6f5d3af919bebaab2e9c220f397" + ["funcs"]="6a1c7ce585d9b76e2e75dba9d4295f8d" + ["lan"]="c62e84ddd1457b71a85ad21da662b9af" + ) + local author="aclist" + local repo="dztui" + local realbranch + local file + local sum + local full_path + + # first time setup + if [[ -z $branch ]]; then + realbranch="dzgui" + else + realbranch="$branch" + fi + if [[ $realbranch == "stable" ]]; then + realbranch="dzgui" + fi + + for i in "${!sums[@]}"; do + file="$i" + sum="${sums[$i]}" + full_path="$helpers_path/$file" + + url="${url_prefix}/$realbranch/helpers/$file" + + if [[ -f "$full_path" ]] && [[ $(get_hash "$full_path") == $sum ]]; then + logger INFO "$file is current" + else + logger WARN "File '$full_path' checksum != '$sum'" + local res=$(get_response_code "$url") + [[ $res -ne 200 ]] && raise_error_and_quit "Remote resource unavailable: '$url'" + curl -Ls "$url" > "$full_path" + if [[ ! $? -eq 0 ]]; then + raise_error_and_quit "Failed to fetch the file '$file'. Possible timeout?" + fi + if [[ $(get_hash $full_path) != $sum ]]; then + logger WARN "Downloaded new '$file', but checksum != '$sum'" + fi + logger INFO "Updated '$full_path' to sum '$sum'" + fi + [[ $file == "funcs" ]] && chmod +x "$full_path" + [[ $file == "lan" ]] && chmod +x "$full_path" + done + return 0 +} +fetch_geo_file(){ + # for binary releases + local geo_sum="28ccd75b3e03cf07a7011f22ef0cd69b" + local km_sum="b038fdb8f655798207bd28de3a004706" + local gzip="$helpers_path/ips.csv.gz" + if [[ ! -f $geo_file ]] || [[ $(get_hash $geo_file) != $geo_sum ]]; then + local res=$(get_response_code "$geo_file_url") + [[ $res -ne 200 ]] && raise_error_and_quit "Remote resource unavailable: '$geo_file_url'" + curl -Ls "$geo_file_url" > "$gzip" + #force overwrite + gunzip -f "$gzip" + fi + if [[ ! -f $km_helper ]] || [[ $(get_hash $km_helper) != $km_sum ]]; then + local res=$(get_response_code "$km_helper_url") + [[ $res -ne 200 ]] && raise_error_and_quit "Remote resource unavailable: '$km_helper_url'" + curl -Ls "$km_helper_url" > "$km_helper" + chmod +x "$km_helper" + fi +} +fetch_helpers(){ + fetch_a2s + fetch_dzq + fetch_geo_file + fetch_helpers_by_sum + [[ ! -f $share_path/icon.png ]] && freedesktop_dirs + fetch_icons +} +raise_error_and_quit(){ + local msg="$1" + logger CRITICAL "$msg" + fdialog "$msg" + exit 1 +} +test_steam_api(){ + local key="$1" + [[ -z $key ]] && return 1 + local url="https://api.steampowered.com/IGameServersService/GetServerList/v1/?filter=\appid\221100&limit=10&key=$key" + local code=$(curl -ILs "$url" | grep -E "^HTTP") + [[ ! $code =~ 200 ]] && echo 1 + [[ $code =~ 200 ]] && echo 0 +} +test_bm_api(){ + local bm_api="https://api.battlemetrics.com/servers" + local key="$1" + [[ -z $key ]] && return 1 + local code=$(curl -ILs "$bm_api" \ + -H "Authorization: Bearer "$key"" -G \ + -d "filter[game]=$game" \ + | grep -E "^HTTP") + [[ $code =~ 401 ]] && echo 1 + [[ $code =~ 200 ]] && echo 0 +} +find_default_path(){ + _discover(){ + readarray -t paths < <(find / -type d \( -path "/proc" -o -path "*/timeshift" -o -path \ + "/tmp" -o -path "/usr" -o -path "/boot" -o -path "/proc" -o -path "/root" \ + -o -path "/sys" -o -path "/etc" -o -path "/var" -o -path "/lost+found" \) -prune \ + -o -regex ".*Steam/config/libraryfolders.vdf$" -print 2>/dev/null | sed 's@/config/libraryfolders.vdf@@') + + if [[ "${#paths[@]}" -gt 1 ]]; then + echo "100" + default_steam_path=$(printf "%s\n" "${paths[@]}" | $steamsafe_zenity --list --column="paths" --hide-header --text="Found multiple valid Steam paths. Select your default Steam installation." --title="DZGUI") + [[ -z "$default_steam_path" ]] && exit 1 + else + default_steam_path="${paths[0]}" + fi + } + if [[ $is_steam_deck -gt 0 ]]; then + default_steam_path="$HOME/.local/share/Steam" + logger INFO "Set default Steam path to $default_steam_path" + return 0 + fi + local def_path + local ubuntu_path + local flatpak_path + local debian_path + def_path="$HOME/.local/share/Steam" + ubuntu_path="$HOME/.steam/steam" + debian_path="$HOME/.steam/debian-installation" + flatpak_path="$HOME/.var/app/com.valvesoftware.Steam/data/Steam" + + #ubuntu path must precede default path because + #both exist on ubuntu systems, but only ubuntu path contains library data + for i in "$ubuntu_path" "$def_path" "$debian_path" "$flatpak_path"; do + if [[ -d "$i" ]]; then + default_steam_path="$i" + return 0 + fi + done + + local msg="Let DZGUI auto-discover Steam path (accurate, slower)\nSelect the Steam path manually (less accurate, faster)" + local res=$(echo -e "$msg" | $steamsafe_zenity --list \ + --column="Choice" \ + --title="DZGUI" \ + --hide-header \ + --text="Steam is not installed in a standard location." \ + $sd_res) + + case "$res" in + *auto*) _discover > >(pdialog "Scanning paths") ;; + *manual*) + zenity --info --text="\nSelect the top-level entry point to the location where Steam (not DayZ)\nis installed and before entering the \"steamapps\" path.\n\nE.g., if Steam is installed at:\n\"/media/mydrive/Steam\"\n\nCorrect:\n- \"/media/mydrive/Steam\"\n\nIncorrect:\n- \"/media/mydrive/Steam/steamapps/common/DayZ\"\n- \"/media/mydrive/\"" --width=500 && + file_picker ;; + esac +} +file_picker(){ + local path=$($steamsafe_zenity --file-selection --directory) + logger INFO "File picker path resolved to: $path" + if [[ -z "$path" ]]; then + logger WARN "Steam path selection was empty" + return + else + default_steam_path="$path" + fi +} +find_library_folder(){ + local search_path="$1" + steam_path="$(python3 "$helpers_path/vdf2json.py" -i "$1/steamapps/libraryfolders.vdf" \ + | jq -r '.libraryfolders[]|select(.apps|has("221100")).path')" + if [[ ! $? -eq 0 ]] || [[ -z $steam_path ]]; then + logger WARN "Failed to parse Steam path using '$search_path'" + return 1 + fi + logger INFO "Steam path resolved to: $steam_path" +} +create_config(){ + #if old path is malformed and this function is forcibly called, + #wipe paths from memory before entering the loop to force path rediscovery + unset default_steam_path + unset steam_path + + while true; do + local player_input="$($steamsafe_zenity \ + --forms \ + --add-entry="Player name (required for some servers)" \ + --add-entry="Steam API key" \ + --add-entry="BattleMetrics API key (optional)" \ + --title="DZGUI" \ + --text="DZGUI" $sd_res \ + --separator="@")" + #explicitly setting IFS crashes $steamsafe_zenity in loop + #and mapfile does not support high ascii delimiters, so split fields with newline + readarray -t args < <(<<< "$player_input" sed 's/@/\n/g') + name="${args[0]}" + steam_api="${args[1]}" + api_key="${args[2]}" + + if [[ -z $player_input ]]; then + logger WARN "User aborted setup process" + exit 1 + fi + if [[ -z $steam_api ]]; then + tdialog "Steam API key canot be empty" + continue + elif [[ "${#steam_api}" -lt 32 ]] || [[ $(test_steam_api "$steam_api") -eq 1 ]]; then + tdialog "Invalid Steam API key" + continue + fi + if [[ -n $api_key ]] && [[ $(test_bm_api $api_key) -eq 1 ]]; then + tdialog "Invalid BM API key" + continue + fi + while true; do + if [[ -n $steam_path ]]; then + write_config + [[ $? -eq 0 ]] && logger INFO "Successfully created config file" + return 0 + fi + find_default_path + find_library_folder "$default_steam_path" + if [[ -z $steam_path ]]; then + logger raise_error "Steam path was empty" + zenity --question --text="DayZ not found or not installed at the Steam library given. NOTE: if you recently installed DayZ or moved its location, you MUST restart Steam first for these changes to synch." --ok-label="Choose path manually" --cancel-label="Exit" + if [[ $? -eq 0 ]]; then + logger INFO "User selected file picker" + file_picker + find_library_folder "$default_steam_path" + else + fdialog "Failed to find Steam at the provided location" + exit 1 + fi + else + branch="stable" + update_config + logger INFO "Wrote config to '$config_file'" + return 0 + fi + done + done +} +varcheck(){ + local msg="Config file '$config_file' missing. Start first-time setup now?" + local msg2="The Steam paths set in your config file appear to be invalid. Restart first-time setup now?" + if [[ ! -f $config_file ]]; then + qdialog "$msg" "Yes" "Exit" + if [[ $? -eq 1 ]]; then + logger CRITICAL "Config file missing, but user aborted setup" + exit 1 + fi + create_config + fi + source "$config_file" + local workshop_dir="$steam_path/steamapps/workshop/content/$aid" + local game_dir="$steam_path/steamapps/common/DayZ" + if [[ ! -d $steam_path ]] || [[ ! -d $game_dir ]] || [[ ! $(find $game_dir -type f) ]]; then + logger WARN "DayZ path resolved to '$game_dir'" + logger WARN "Workshop path resolved to '$workshop_dir'" + qdialog "$msg2" "Yes" "Exit" + if [[ $? -eq 1 ]]; then + logger CRITICAL "Malformed Steam path, but user aborted setup" + exit 1 + fi + create_config + return 0 + fi + if [[ $src_path != $(realpath "$0") ]]; then + src_path=$(realpath "$0") + update_config + fi +} +is_dzg_downloading(){ + if [[ -d $steam_path ]] && [[ -d $steam_path/downloading/$aid ]]; then + logger WARN "DayZ may be scheduling updates" + return 0 + fi +} +is_steam_running(){ + local res=$(ps aux | grep "steamwebhelper" | grep -v grep) + if [[ -z $res ]]; then + logger WARN "Steam may not be running" + tdialog "Is Steam running? For best results, make sure Steam is open in the background." + return 0 + fi +} +get_response_code(){ + local url="$1" + curl -Ls -I -o /dev/null -w "%{http_code}" "$url" +} +test_connection(){ + source "$config_file" + declare -A hr + local res1 + local res2 + local str="No connection could be established to the remote server" + hr=( + ["steampowered.com"]="https://api.steampowered.com/IGameServersService/GetServerList/v1/?key=$steam_api" + ["github.com"]="https://github.com/$author" + ["codeberg.org"]="https://codeberg.org/$author" + ) + # steam API is mandatory, except on initial setup + if [[ -n $steam_api ]]; then + res=$(get_response_code "${hr["steampowered.com"]}") + [[ $res -ne 200 ]] && raise_error_and_quit "$str ("steampowered.com")" + fi + + res=$(get_response_code "${hr["github.com"]}") + if [[ $res -ne 200 ]]; then + logger WARN "Remote host '${hr["github.com"]}' unreachable', trying fallback" + remote_host=cb + logger INFO "Set remote host to '${hr["codeberg.org"]}'" + res=$(get_response_code "${hr["codeberg.org"]}") + [[ $res -ne 200 ]] && raise_error_and_quit "$str (${hr["codeberg.org"]})" + fi + if [[ $remote_host == "cb" ]]; then + url_prefix="https://codeberg.org/$author/$repo/raw/branch" + releases_url="https://codeberg.org/$author/$repo/releases/download/browser" + stable_url="$url_prefix/dzgui" + testing_url="$url_prefix/testing" + km_helper_url="$releases_url/latlon" + geo_file_url="$releases_url/ips.csv.gz" + fi +} +legacy_cols(){ + [[ ! -f $cols_file ]] && return + local has=$(< "$cols_file" jq '.cols|has("Queue")') + [[ $has == "true" ]] && return + < $cols_file jq '.cols += { "Queue": 120 }' > $cols_file.new && + mv $cols_file.new $cols_file +} +stale_mod_signatures(){ + local workshop_dir="$steam_path/steamapps/workshop/content/$aid" + if [[ -d $workshop_dir ]]; then + readarray -t old_mod_ids < <(awk -F, '{print $1}' $versions_file) + for ((i=0; i<${#old_mod_ids[@]}; ++i)); do + if [[ ! -d $workshop_dir/${old_mod_ids[$i]} ]]; then + "$HOME/.local/share/$app_name/helpers/funcs" "align_local" "${old_mod_ids[$i]}" + fi + done + fi + +} +create_new_links(){ + "$HOME/.local/share/$app_name/helpers/funcs" "update_symlinks" +} +initial_setup(){ + setup_dirs + setup_state_files + depcheck + check_pyver + test_gobject + watcher_deps + check_architecture + test_connection +# fetch_helpers > >(pdialog "Checking helper files") + varcheck + source "$config_file" + lock + legacy_vars + legacy_cols + check_version + check_map_count + steam_deps + migrate_files + stale_symlinks + stale_mod_signatures + create_new_links + local_latlon + is_steam_running + is_dzg_downloading + print_config_vals +} +uninstall(){ + _full(){ + for i in "$config_path" "$state_path" "$cache_path" "$share_path"; do + echo "Deleting the path '$i'" + rm -rf "$i" + done + } + _partial(){ + for i in "$cache_path" "$share_path"; do + echo "Deleting the path '$i'" + rm -rf "$i" + done + } + local choice=$($steamsafe_zenity \ + --list \ + --radiolist \ + --column="a" \ + --column="b" \ + --hide-header \ + --text="Choose an uninstall routine below." \ + TRUE "Keep user config files" \ + FALSE "Delete all DZGUI files" \ + --title="DZGUI" + ) + + case "$choice" in + "Keep user config files") + _partial + ;; + "Delete all DZGUI files") + _full + ;; + "") + echo "User aborted uninstall process" + exit 1 + ;; + esac + local self="$(realpath "$0")" + echo "Deleting '$self'" + rm "$self" + echo "Uninstall routine complete" +} +main(){ + local zenv=$(zenity --version 2>/dev/null) + [[ -z $zenv ]] && { echo "Requires zenity >= ${deps[$steamsafe_zenity]}"; exit 1; } + if [[ $1 == "--uninstall" ]] || [[ $1 == "-u" ]]; then + uninstall && + exit 0 + fi + if [[ $1 == "--steam" ]] || [[ $1 == "-s" ]]; then + export STEAM_LAUNCH=1 + fi + + set_im_module + + printf "Initializing setup...\n" + initial_setup + + printf "All OK. Kicking off UI...\n" + python3 "$ui_helper" "--init-ui" "$version" "$is_steam_deck" +} +main "$@" +#TODO: tech debt: cruddy handling for steam forking +[[ $? -eq 1 ]] && pkill -f dzgui.sh