1
0
Fork 0
mirror of https://github.com/aclist/dztui.git synced 2024-12-29 13:52:03 +01:00
dztui/dzgui.sh

1347 lines
42 KiB
Bash
Raw Normal View History

2022-05-09 13:42:24 +02:00
#!/bin/bash
2022-06-04 22:29:30 +02:00
set -o pipefail
2022-09-14 07:00:22 +02:00
version=2.7.0-rc.7
2022-08-14 04:03:27 +02:00
2022-05-09 13:42:24 +02:00
aid=221100
game="dayz"
workshop="steam://url/CommunityFilePage/"
2022-05-09 13:42:24 +02:00
api="https://api.battlemetrics.com/servers"
2022-05-22 21:20:34 +02:00
sd_res="--width=1280 --height=800"
config_path="$HOME/.config/dztui/"
config_file="${config_path}dztuirc"
tmp=/tmp/dztui.tmp
2022-05-29 07:41:56 +02:00
separator="%%"
2022-06-15 12:32:10 +02:00
check_config_msg="Check config values and restart."
2022-09-14 06:56:13 +02:00
issues_url="https://github.com/aclist/dztui/issues"
url_prefix="https://raw.githubusercontent.com/aclist/dztui"
stable_url="$url_prefix/dzgui"
testing_url="$url_prefix/testing"
releases_url="https://github.com/aclist/dztui/releases/download/browser"
help_url="https://aclist.github.io/dzgui/dzgui"
news_url="$testing_url/news"
2022-08-05 20:35:17 +02:00
freedesktop_path="$HOME/.local/share/applications"
2022-08-06 00:42:35 +02:00
sd_install_path="$HOME/.local/share/dzgui"
2022-09-12 16:55:30 +02:00
helpers_path="$sd_install_path/helpers"
2022-09-14 06:56:13 +02:00
geo_file="$helpers_path/ips.csv"
km_helper="$helpers_path/latlon"
sums_path="$helpers_path/sums.md5"
km_helper_url="$releases_url/latlon"
db_file="$releases_url/ips.csv.gz"
sums_url="$testing_url/helpers/sums.md5"
2022-05-09 13:42:24 +02:00
2022-07-24 15:20:06 +02:00
update_last_seen(){
mv $config_file ${config_path}dztuirc.old
nr=$(awk '/seen_news=/ {print NR}' ${config_path}dztuirc.old)
seen_news="seen_news=\"$sum\""
awk -v "var=$seen_news" -v "nr=$nr" 'NR==nr {$0=var}{print}' ${config_path}dztuirc.old > $config_file
printf "[DZGUI] Updated last seen news item to '$sum'\n"
source $config_file
}
check_news(){
result=$(curl -Ls "$news_url")
sum=$(echo -n "$result" | md5sum | awk '{print $1}')
}
print_news(){
check_news
if [[ $sum == $seen_news || -z $result ]]; then
hchar=""
news=""
else
hchar="─"
news="$result\n$(awk -v var="$hchar" 'BEGIN{for(c=0;c<90;c++) printf var;}')\n"
update_last_seen
fi
}
#TODO: prevent connecting to offline servers
2022-08-14 11:10:00 +02:00
#TODO: abstract zenity title params and dimensions
2022-05-09 13:42:24 +02:00
declare -A deps
2022-07-24 15:20:06 +02:00
deps=([awk]="5.1.1" [curl]="7.80.0" [jq]="1.6" [tr]="9.0" [zenity]="3.42.1" [steam]="1.0.0")
2022-06-12 06:44:30 +02:00
changelog(){
2022-07-24 15:20:06 +02:00
if [[ $branch == "stable" ]]; then
md="https://raw.githubusercontent.com/aclist/dztui/dzgui/changelog.md"
else
md="https://raw.githubusercontent.com/aclist/dztui/testing/changelog.md"
fi
2022-06-12 06:44:30 +02:00
prefix="This window can be scrolled."
echo $prefix
echo ""
curl -Ls "$md" | awk '/Unreleased/ {flag=1}flag'
2022-06-12 06:44:30 +02:00
}
2022-05-09 13:42:24 +02:00
depcheck(){
for dep in "${!deps[@]}"; do
2022-07-24 15:20:06 +02:00
command -v $dep 2>&1>/dev/null || (printf "Requires %s >=%s\n" $dep ${deps[$dep]}; exit 1)
2022-05-09 13:42:24 +02:00
done
}
2022-06-22 15:33:52 +02:00
init_items(){
#array order determines menu selector; this is destructive
2022-05-22 21:20:34 +02:00
items=(
"Launch server list"
2022-06-04 22:29:30 +02:00
"Quick connect to favorite server"
2022-08-16 17:49:51 +02:00
"Connect by IP"
2022-06-04 22:29:30 +02:00
"Add server by ID"
2022-06-15 12:32:10 +02:00
"Add favorite server"
2022-07-24 15:20:06 +02:00
"Delete server"
2022-09-12 16:55:30 +02:00
"[NEW] Server browser"
2022-06-15 12:32:10 +02:00
"List installed mods"
2022-06-22 15:33:52 +02:00
"Toggle debug mode"
2022-06-15 12:32:10 +02:00
"Report bug (opens in browser)"
"Help file (opens in browser)"
"View changelog"
2022-05-22 21:20:34 +02:00
)
2022-06-22 15:33:52 +02:00
}
2022-06-04 22:29:30 +02:00
warn_and_exit(){
zenity --info --title="DZGUI" --text="$1" --icon-name="dialog-warning" 2>/dev/null
2022-06-15 12:32:10 +02:00
printf "[DZGUI] %s\n" "$check_config_msg"
2022-06-04 22:29:30 +02:00
exit
}
2022-05-22 21:20:34 +02:00
warn(){
zenity --info --title="DZGUI" --text="$1" --icon-name="dialog-warning" 2>/dev/null
2022-05-09 13:42:24 +02:00
}
2022-05-22 21:20:34 +02:00
info(){
2022-06-15 12:32:10 +02:00
zenity --info --title="DZGUI" --text="$1" 2>/dev/null
2022-05-22 21:20:34 +02:00
}
2022-08-11 00:59:29 +02:00
set_api_params(){
response=$(curl -s "$api" -H "Authorization: Bearer "$api_key"" -G -d "sort=-players" \
-d "filter[game]=$game" -d "filter[ids][whitelist]=$list_of_ids")
2022-08-12 02:52:07 +02:00
list_response=$response
2022-08-14 18:22:21 +02:00
first_entry=1
2022-08-11 00:59:29 +02:00
}
2022-05-09 13:42:24 +02:00
query_api(){
2022-06-15 12:32:10 +02:00
#TODO: prevent drawing list if null values returned without API error
if [[ $one_shot_launch -eq 1 ]]; then
list_of_ids="$fav"
else
if [[ -n $fav ]]; then
list_of_ids="$whitelist,$fav"
else
list_of_ids="$whitelist"
fi
fi
2022-08-11 00:59:29 +02:00
set_api_params
2022-05-09 13:42:24 +02:00
if [[ "$(jq -r 'keys[]' <<< "$response")" == "errors" ]]; then
code=$(jq -r '.errors[] .status' <<< $response)
#TODO: fix granular api codes
2022-06-15 12:32:10 +02:00
if [[ $code -eq 401 ]]; then
warn_and_exit "Error $code: malformed API key"
elif [[ $code -eq 500 ]]; then
warn_and_exit "Error $code: malformed server list"
fi
fi
if [[ -z $(echo $response | jq '.data[]') ]]; then
warn_and_exit "API returned empty response. Check config file."
2022-05-09 13:42:24 +02:00
fi
2022-05-22 21:20:34 +02:00
}
write_config(){
2022-06-15 12:32:10 +02:00
cat <<-END
#Path to DayZ installation
steam_path="$steam_path"
2022-05-22 21:20:34 +02:00
#Your unique API key
2022-06-15 12:32:10 +02:00
api_key="$api_key"
2022-05-22 21:20:34 +02:00
#Comma-separated list of server IDs
2022-06-15 12:32:10 +02:00
whitelist="$whitelist"
2022-05-22 21:20:34 +02:00
#Favorite server to fast-connect to (limit one)
2022-06-15 12:32:10 +02:00
fav="$fav"
2022-05-22 21:20:34 +02:00
#Custom player name (optional, required by some servers)
2022-06-15 12:32:10 +02:00
name="$name"
2022-05-22 21:20:34 +02:00
#Set to 1 to perform dry-run and print launch options
2022-07-31 20:01:58 +02:00
debug="$debug"
2022-07-18 10:58:38 +02:00
#Toggle stable/testing branch
2022-07-31 19:52:59 +02:00
branch="$branch"
2022-07-24 15:20:06 +02:00
#Last seen news item
2022-07-31 20:01:58 +02:00
seen_news="$seen_news"
2022-08-16 17:49:51 +02:00
#Steam API key
2022-08-31 10:22:07 +02:00
steam_api="$steam_api"
2022-05-22 21:20:34 +02:00
END
}
2022-08-04 21:14:56 +02:00
write_desktop_file(){
cat <<-END
[Desktop Entry]
Version=1.0
Type=Application
Terminal=false
2022-08-06 00:42:35 +02:00
Exec=$sd_install_path/dzgui.sh
2022-08-04 21:14:56 +02:00
Name=DZGUI
Comment=dzgui
2022-08-06 00:42:35 +02:00
Icon=$sd_install_path/dzgui
2022-08-05 20:03:24 +02:00
Categories=Game
2022-08-04 21:14:56 +02:00
END
}
2022-08-05 21:58:59 +02:00
freedesktop_dirs(){
2022-08-06 00:42:35 +02:00
mkdir -p "$sd_install_path"
2022-08-05 21:58:59 +02:00
mkdir -p "$freedesktop_path"
#TODO: update url
2022-08-06 00:42:35 +02:00
curl -s "$version_url" > "$sd_install_path/dzgui.sh"
chmod +x "$sd_install_path/dzgui.sh"
2022-08-05 21:58:59 +02:00
img_url="https://raw.githubusercontent.com/aclist/dztui/testing/images"
for i in dzgui grid.png hero.png logo.png; do
2022-08-06 00:42:35 +02:00
curl -s "$img_url/$i" > "$sd_install_path/$i"
2022-08-05 21:58:59 +02:00
done
write_desktop_file > "$freedesktop_path/dzgui.desktop"
2022-08-06 02:42:41 +02:00
if [[ $is_steam_deck -eq 1 ]]; then
write_desktop_file > "$HOME/Desktop/dzgui.desktop"
fi
2022-08-05 21:58:59 +02:00
}
2022-08-14 11:10:00 +02:00
file_picker(){
#TODO: unimplemented
while true; do
local path=$(zenity --file-selection --directory 2>/dev/null)
if [[ -z "$path" ]] || [[ ! -d "$path" ]] || [[ ! "$path" =~ steamapps/common/DayZ ]]; then
continue
else
echo "[DZGUI]" Set path to $path
clean_path=$(echo -e "$path" | awk -F"/steamapps" '{print $1}')
steam_path="$clean_path"
return
fi
done
}
2022-08-05 21:58:59 +02:00
guess_path(){
echo "# Checking for default DayZ path"
2022-08-14 11:10:00 +02:00
path=$(find $HOME -type d -regex ".*/steamapps/common/DayZ$" -print -quit)
2022-08-31 10:22:07 +02:00
if [[ -n "$path" ]]; then
clean_path=$(echo -e "$path" | awk -F"/steamapps" '{print $1}')
steam_path="$clean_path"
2022-06-15 12:32:10 +02:00
else
2022-08-14 11:10:00 +02:00
echo "# Searching for alternate DayZ path. This may take some time."
path=$(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 "/run" -o -path "/sys" -o -path "/etc" -o -path "/var" -o -path "/run" -o -path "/lost+found" \) -prune -o -regex ".*/steamapps/common/DayZ$" -print -quit 2>/dev/null)
2022-08-05 21:58:59 +02:00
clean_path=$(echo -e "$path" | awk -F"/steamapps" '{print $1}')
steam_path="$clean_path"
2022-06-15 12:32:10 +02:00
fi
}
2022-05-22 21:20:34 +02:00
create_config(){
2022-08-04 21:14:56 +02:00
while true; do
2022-08-14 11:10:00 +02:00
player_input="$(zenity --forms --add-entry="Player name (required for some servers)" --add-entry="API key" --add-entry="Server 1 (you can add more later)" --title=DZGUI --text=DZGUI --add-entry="Server 2" --add-entry="Server 3" --add-entry="Server 4" $sd_res --separator="│" 2>/dev/null)"
2022-08-04 21:14:56 +02:00
#explicitly setting IFS crashes zenity in loop
#and mapfile does not support high ascii delimiters
#so split fields with newline
readarray -t args < <(echo "$player_input" | sed 's/│/\n/g')
name="${args[0]}"
api_key="${args[1]}"
server_1="${args[2]}"
server_2="${args[3]}"
server_3="${args[4]}"
server_4="${args[5]}"
[[ -z $player_input ]] && exit
if [[ -z $api_key ]]; then
warn "API key: invalid value"
elif [[ -z $server_1 ]]; then
warn "Server 1: cannot be empty"
2022-08-04 21:14:56 +02:00
elif [[ ! $server_1 =~ ^[0-9]+$ ]]; then
warn "Server 1: only numeric IDs"
2022-08-04 21:14:56 +02:00
elif [[ -n $server_2 ]] && [[ ! $server_2 =~ ^[0-9]+$ ]]; then
warn "Server 2: only numeric IDs"
2022-08-04 21:14:56 +02:00
elif [[ -n $server_3 ]] && [[ ! $server_3 =~ ^[0-9]+$ ]]; then
warn "Server 3: only numeric IDs"
2022-08-04 21:14:56 +02:00
elif [[ -n $server_4 ]] && [[ ! $server_3 =~ ^[0-9]+$ ]]; then
warn "Server 4: only numeric IDs"
2022-08-04 21:14:56 +02:00
else
whitelist=$(echo "$player_input" | awk -F"│" '{OFS=","}{print $3,$4,$5,$6}' | sed 's/,*$//g' | sed 's/^,*//g')
2022-08-14 11:10:00 +02:00
guess_path > >(zenity --width 500 --progress --auto-close --pulsate 2>/dev/null) &&
echo "[DZGUI] Set path to $steam_path"
#FIXME: tech debt: gracefully exit if user cancels search process
2022-05-22 21:20:34 +02:00
mkdir -p $config_path; write_config > $config_file
2022-06-15 12:32:10 +02:00
info "Config file created at $config_file."
2022-08-04 21:14:56 +02:00
return
fi
done
2022-05-22 21:20:34 +02:00
}
err(){
printf "[ERROR] %s\n" "$1"
}
varcheck(){
[[ -z $api_key ]] && (err "Error in key: 'api_key'")
[[ -z $whitelist ]] && (err "Error in key: 'whitelist'")
2022-08-31 10:22:07 +02:00
[[ ! -d "$game_dir" ]] && (err "Malformed game path")
2022-05-22 21:20:34 +02:00
[[ $whitelist =~ [[:space:]] ]] && (err "Separate whitelist values with commas")
}
2022-06-15 12:32:10 +02:00
run_depcheck() {
2022-05-22 21:20:34 +02:00
if [[ -z $(depcheck) ]]; then
:
else
2022-07-24 15:20:06 +02:00
zenity --warning --ok-label="Exit" --title="DZGUI" --text="$(depcheck)"
2022-06-04 22:29:30 +02:00
exit
2022-05-22 21:20:34 +02:00
fi
2022-06-15 12:32:10 +02:00
}
run_varcheck(){
source $config_file
workshop_dir="$steam_path/steamapps/workshop/content/$aid"
game_dir="$steam_path/steamapps/common/DayZ"
2022-05-22 21:20:34 +02:00
if [[ -z $(varcheck) ]]; then
:
else
zenity --warning --width 500 --text="$(varcheck)" 2>/dev/null
2022-06-15 12:32:10 +02:00
printf "[DZGUI] %s\n" "$check_config_msg"
zenity --question --cancel-label="Exit" --text="Malformed config file. This is probably user error.\nStart first-time setup process again?" 2>/dev/null
code=$?
if [[ $code -eq 1 ]]; then
exit
else
create_config
fi
2022-05-22 21:20:34 +02:00
fi
}
config(){
if [[ ! -f $config_file ]]; then
2022-08-05 22:26:00 +02:00
zenity --width 500 --info --text="Config file not found. Click OK to proceed to first-time setup." 2>/dev/null
2022-05-22 21:20:34 +02:00
code=$?
2022-08-05 21:58:59 +02:00
#prevent progress if user hits ESC
2022-05-22 21:20:34 +02:00
if [[ $code -eq 1 ]]; then
exit
else
create_config
fi
else
source $config_file
fi
2022-06-15 12:32:10 +02:00
}
open_mod_links(){
link_file=$(mktemp)
echo "<html>" > $link_file
echo "<title>DZGUI</title>" >> $link_file
echo "<h1>DZGUI</h1>" >> $link_file
echo "<p>Open these links and subscribe to them on the Steam Workshop, then continue with the application prompts.<br><b>Note:</b> it may take some time for mods to synchronize before DZGUI can see them.<br>It can help to have Steam in an adjacent window so that you can see the downloads completing.</p>" >> $link_file
2022-07-18 10:58:38 +02:00
n=1
for i in $diff; do
echo "$n. <a href=\"${workshop}$i\">${workshop}$i</a><br>"
let n++
2022-06-15 12:32:10 +02:00
done >> $link_file
echo "</html>" >> $link_file
2022-09-14 06:56:13 +02:00
browser "$link_file" 2>/dev/null &
2022-06-15 12:32:10 +02:00
2022-05-22 21:20:34 +02:00
}
2022-07-24 15:20:06 +02:00
steam_deck_mods(){
until [[ -z $diff ]]; do
next=$(echo -e "$diff" | head -n1)
zenity --question --ok-label="Open" --cancel-label="Cancel" --title="DZGUI" --text="Missing mods. Click [Open] to open mod $next in Steam Workshop and subscribe to it by clicking the green Subscribe button. After the mod is downloaded, return to this menu to continue validation." 2>/dev/null
rc=$?
if [[ $rc -eq 0 ]]; then
echo "[DZGUI] Opening ${workshop}$next"
steam steam://url/CommunityFilePage/$next 2>/dev/null &
zenity --info --title="DZGUI" --ok-label="Next" --text="Click [Next] to continue mod check." 2>/dev/null
else
return
fi
compare
done
}
2022-06-04 22:29:30 +02:00
manual_mod_install(){
l=0
2022-06-15 12:32:10 +02:00
if [[ $is_steam_deck -eq 0 ]]; then
open_mod_links
until [[ -z $diff ]]; do
zenity --question --title="DZGUI" --ok-label="Next" --cancel-label="Cancel" --text="Opened mod links in browser. Click [Next] when all mods have been subscribed to. This dialog may reappear if clicking [Next] too soon before mods are synchronized in the background." 2>/dev/null
rc=$?
if [[ $rc -eq 0 ]]; then
compare
open_mod_links
2022-06-15 12:32:10 +02:00
else
return
fi
done
else
2022-07-24 15:20:06 +02:00
steam_deck_mods
2022-06-15 12:32:10 +02:00
fi
2022-06-04 22:29:30 +02:00
passed_mod_check
}
2022-07-24 15:20:06 +02:00
encode(){
2022-08-13 15:00:35 +02:00
echo "$1" | md5sum | cut -c -8
2022-07-24 15:20:06 +02:00
}
stale_symlinks(){
for l in $(find "$game_dir" -xtype l); do
unlink $l
done
}
legacy_symlinks(){
for d in "$game_dir"/*; do
if [[ $d =~ @[0-9]+-.+ ]]; then
unlink "$d"
fi
done
2022-08-14 02:38:08 +02:00
for d in "$workshop_dir"/*; do
local id=$(awk -F"= " '/publishedid/ {print $2}' "$d"/meta.cpp | awk -F\; '{print $1}')
local encoded_id=$(echo "$id" | awk '{printf("%c",$1)}' | base64 | sed 's/\//_/g; s/=//g; s/+/]/g')
if [[ -h "$game_dir/@$encoded_id" ]]; then
unlink "$game_dir/@$encoded_id"
fi
done
2022-07-24 15:20:06 +02:00
}
2022-06-04 22:29:30 +02:00
symlinks(){
for d in "$workshop_dir"/*; do
id=$(awk -F"= " '/publishedid/ {print $2}' "$d"/meta.cpp | awk -F\; '{print $1}')
2022-07-24 15:20:06 +02:00
encoded_id=$(encode "$id")
2022-06-04 22:29:30 +02:00
mod=$(awk -F\" '/name/ {print $2}' "$d"/meta.cpp | sed -E 's/[^[:alpha:]0-9]+/_/g; s/^_|_$//g')
2022-07-24 15:20:06 +02:00
link="@$encoded_id"
2022-06-04 22:29:30 +02:00
if [[ -h "$game_dir/$link" ]]; then
2022-07-24 15:20:06 +02:00
:
else
printf "[DZGUI] Creating symlink for $mod\n"
2022-06-04 22:29:30 +02:00
ln -fs "$d" "$game_dir/$link"
2022-07-24 15:20:06 +02:00
fi
done
2022-06-04 22:29:30 +02:00
}
passed_mod_check(){
echo "[DZGUI] Passed mod check"
2022-07-24 15:20:06 +02:00
stale_symlinks
legacy_symlinks
2022-06-04 22:29:30 +02:00
symlinks
launch
2022-05-22 21:20:34 +02:00
}
2022-06-04 22:29:30 +02:00
connect(){
#TODO: sanitize/validate input
2022-07-18 10:58:38 +02:00
readarray -t qport_arr <<< "$qport_list"
if [[ -z ${qport_arr[@]} ]]; then
2022-08-12 02:52:07 +02:00
err "Failed to obtain query ports"
2022-07-18 10:58:38 +02:00
return
fi
2022-06-04 22:29:30 +02:00
ip=$(echo "$1" | awk -F"$separator" '{print $1}')
bid=$(echo "$1" | awk -F"$separator" '{print $2}')
2022-09-03 21:40:21 +02:00
if [[ $2 == "ip" ]]; then
fetch_mods_sa "$ip"
else
fetch_mods "$bid"
fi
2022-09-14 06:56:13 +02:00
if [[ $ret -eq 96 ]]; then
unset ret
return
fi
2022-06-04 22:29:30 +02:00
validate_mods
rc=$?
[[ $rc -eq 1 ]] && return
compare
if [[ -n $diff ]]; then
manual_mod_install
else
passed_mod_check
fi
}
2022-09-03 06:46:21 +02:00
fetch_mods(){
remote_mods=$(curl -s "$api" -H "Authorization: Bearer "$api_key"" -G -d filter[ids][whitelist]="$1" -d "sort=-players" \
| jq -r '.data[] .attributes .details .modIds[]')
}
fetch_mods_sa(){
2022-08-16 17:49:51 +02:00
sa_ip=$(echo "$1" | awk -F: '{print $1}')
for i in ${qport_arr[@]}; do
2022-07-18 10:58:38 +02:00
if [[ -n $(echo "$i" | awk -v ip=$ip '$0 ~ ip') ]]; then
sa_port=$(echo $i | awk -v ip=$ip -F$separator '$0 ~ ip {print $2}')
fi
done
echo "[DZGUI] Querying modlist on ${sa_ip}:${sa_port}"
2022-09-14 06:56:13 +02:00
local response=$(curl -Ls "https://dayzsalauncher.com/api/v1/query/$sa_ip/$sa_port")
local status=$(echo "$response" | jq '.status')
if [[ $status -eq 1 ]]; then
2022-07-18 10:58:38 +02:00
err "Failed to fetch modlist"
2022-09-14 06:56:13 +02:00
zenity --error --title=DZGUI --width=500 --text="Failed to fetch modlist" 2>/dev/null &&
ret=96
2022-07-18 10:58:38 +02:00
return
fi
2022-09-14 06:56:13 +02:00
remote_mods=$(echo "$response" | jq -r '.result.mods[].steamWorkshopId')
2022-08-16 17:49:51 +02:00
qport_arr=()
}
prepare_ip_list(){
ct=$(< "$1" jq '[.response.servers[]]|length')
for((i=0;i<$ct;i++));do
name=$(< $json jq --arg i $i -r '[.servers[]][($i|tonumber)].name')
addr=$(< $json jq --arg i $i -r '[.servers[]][($i|tonumber)].addr')
ip=$(echo "$addr" | awk -F: '{print $1}')
players=$(< $json jq --arg i $i -r '[.servers[]][($i|tonumber)].players')
max_players=$(< $json jq --arg i $i -r '[.servers[]][($i|tonumber)].max_players')
gameport=$(< $json jq --arg i $i -r '[.servers[]][($i|tonumber)].gameport')
ip_port=$(echo "$ip:$gameport")
time=$(< $json jq --arg i $i -r '[.servers[]][($i|tonumber)].gametype' | grep -oP '(?<!\d)\d{2}:\d{2}(?!\d)')
echo "$name"
echo "$ip_port"
echo "$players/$max_players"
echo "$time"
done
}
ip_table(){
while true; do
sel=$(prepare_ip_list "$meta_file" | zenity --width 1200 --height 800 --list --column=Name --column=IP --column=Players --column=Gametime --print-column=2 --separator=%% 2>/dev/null)
if [[ $? -eq 1 ]]; then
return_from_table=1
return
fi
if [[ -z $sel ]]; then
echo "No selection"
else
local gameport="$(echo "$sel" | awk -F: '{print $2}')"
2022-09-03 21:55:22 +02:00
local ip="$(echo "$sel" | awk -F: '{print $1}')"
2022-08-16 17:49:51 +02:00
local addr=$(< $json jq -r --arg gameport $gameport '.servers[]|select(.gameport == ($gameport|tonumber)).addr')
local qport=$(echo "$addr" | awk -F: '{print $2}')
local sa_ip=$(echo "$ip:$gameport%%$qport")
qport_list="$sa_ip"
2022-09-03 21:40:21 +02:00
connect "$sel" "ip"
2022-08-16 17:49:51 +02:00
fi
done
}
fetch_ip_metadata(){
local meta_file=$(mktemp)
source $config_file
url="https://api.steampowered.com/IGameServersService/GetServerList/v1/?filter=\appid\221100\gameaddr\\$ip&key=$steam_api"
curl -Ls "$url" > $meta_file
json=$(mktemp)
< $meta_file jq '.response' > $json
res=$(< $meta_file jq -er '.response.servers[]' 2>/dev/null)
if [[ ! $? -eq 0 ]]; then
warn "Failed to retrieve IP metadata. Check IP or API key and try again."
echo "[DZGUI] Failed to retrieve IP metadata"
else
ip_table
fi
}
#TODO: local servers
#local_ip(){
#(^127\.)|(^10\.)|(^172\.1[6-9]\.)|(^172\.2[0-9]\.)|(^172\.3[0-1]\.)|(^192\.168\.)
#}
add_steam_api(){
mv $config_file ${config_path}dztuirc.old
nr=$(awk '/steam_api=/ {print NR}' ${config_path}dztuirc.old)
steam_api="steam_api=\"$steam_api\""
awk -v "var=$steam_api" -v "nr=$nr" 'NR==nr {$0=var}{print}' ${config_path}dztuirc.old > ${config_path}dztuirc
echo "[DZGUI] Added Steam API key"
zenity --info --title="DZGUI" --text="Added Steam API key to:\n\n${config_path}dztuirc\nIf errors occur, you can restore the file:\n${config_path}dztuirc.old" 2>/dev/null
source $config_file
}
2022-09-13 06:41:26 +02:00
check_steam_api(){
2022-08-16 17:49:51 +02:00
if [[ -z $steam_api ]]; then
steam_api=$(zenity --entry --text="Key 'steam_api' not present in config file. Enter Steam API key:" --title="DZGUI" 2>/dev/null)
2022-08-31 10:22:07 +02:00
if [[ $? -eq 1 ]] ; then
return
elif [[ $steam_api -lt 32 ]]; then
2022-09-13 06:41:26 +02:00
zenity --warning --title="DZGUI" --text="Check API key and try again." 2>/dev/null
2022-08-16 17:49:51 +02:00
return
else
add_steam_api
fi
fi
2022-09-13 06:41:26 +02:00
}
validate_ip(){
echo "$1" | grep -qP '^((25[0-5]|(2[0-4]|1\d|[1-9]|)\d)\.?\b){4}$'
}
connect_by_ip(){
source $config_file
check_steam_api
2022-08-16 17:49:51 +02:00
while true; do
2022-08-31 10:22:07 +02:00
if [[ $return_from_table -eq 1 ]]; then
return_from_table=0
return
fi
ip=$(zenity --entry --text="Enter server IP" --title="DZGUI" 2>/dev/null)
[[ $? -eq 1 ]] && return
if validate_ip "$ip"; then
fetch_ip_metadata
else
continue
fi
2022-08-16 17:49:51 +02:00
done
}
2022-05-22 21:20:34 +02:00
fetch_mods(){
remote_mods=$(curl -s "$api" -H "Authorization: Bearer "$api_key"" -G -d filter[ids][whitelist]="$1" -d "sort=-players" \
| jq -r '.data[] .attributes .details .modIds[]')
2022-05-09 13:42:24 +02:00
}
2022-06-12 06:44:30 +02:00
query_defunct(){
max=${#modlist[@]}
concat(){
for ((i=0;i<$max;i++)); do
echo "publishedfileids[$i]=${modlist[$i]}&"
done | awk '{print}' ORS=''
}
payload(){
echo -e "itemcount=${max}&$(concat)"
}
post(){
curl -s -X POST -H "Content-Type:application/x-www-form-urlencoded" -d "$(payload)" 'https://api.steampowered.com/ISteamRemoteStorage/GetPublishedFileDetails/v1/?format=json'
}
readarray -t newlist <<< $(post | jq -r '.[].publishedfiledetails[] | select(.result==1) .publishedfileid')
}
2022-06-04 22:29:30 +02:00
validate_mods(){
url="https://steamcommunity.com/sharedfiles/filedetails/?id="
newlist=()
readarray -t modlist <<< $remote_mods
2022-06-12 06:44:30 +02:00
query_defunct
2022-06-04 22:29:30 +02:00
}
server_modlist(){
for i in "${newlist[@]}"; do
printf "$i\n"
done
}
compare(){
diff=$(comm -23 <(server_modlist | sort) <(installed_mods | sort))
}
installed_mods(){
ls -1 "$workshop_dir"
}
2022-05-09 13:42:24 +02:00
concat_mods(){
if [[ -z ${remote_mods[@]} ]]; then
return 1
else
readarray -t serv <<< "$(server_modlist)"
for i in "${serv[@]}"; do
id=$(awk -F"= " '/publishedid/ {print $2}' "$workshop_dir"/$i/meta.cpp | awk -F\; '{print $1}')
2022-07-24 15:20:06 +02:00
encoded_id=$(encode $id)
link="@$encoded_id;"
echo -e "$link"
done | tr -d '\n' | perl -ple 'chop'
fi
2022-05-09 13:42:24 +02:00
}
launch(){
mods=$(concat_mods)
if [[ $debug -eq 1 ]]; then
2022-07-24 15:20:06 +02:00
launch_options="steam -applaunch $aid -connect=$ip -nolauncher -nosplash -skipintro \"-mod=$mods\""
print_launch_options="$(printf "[DEBUG] This is a dry run. These options would have been used to launch the game:\n\n$launch_options\n" | fold -w 60)"
zenity --question --title="DZGUI" --ok-label="Write to file" --cancel-label="Back"\
--text="$print_launch_options" 2>/dev/null
if [[ $? -eq 0 ]]; then
source_script=$(realpath "$0")
source_dir=$(dirname "$source_script")
echo "$launch_options" > "$source_dir"/options.log
2022-08-15 12:39:05 +02:00
echo "[DZGUI] Wrote launch options to $source_dir/options.log"
2022-08-14 04:20:35 +02:00
zenity --info --width 500 --title="DZGUI" --text="Wrote launch options to \n$source_dir/options.log" 2>/dev/null
2022-07-24 15:20:06 +02:00
fi
2022-05-09 13:42:24 +02:00
else
2022-06-13 03:16:03 +02:00
echo "[DZGUI] All OK. Launching DayZ"
2022-08-14 11:10:00 +02:00
zenity --width 500 --title="DZGUI" --info --text="Launch conditions satisfied.\nDayZ will now launch after clicking [OK]." 2>/dev/null
2022-05-09 13:42:24 +02:00
steam -applaunch $aid -connect=$ip -nolauncher -nosplash -skipintro -name=$name \"-mod=$mods\"
exit
fi
2022-06-15 12:32:10 +02:00
one_shot_launch=0
}
browser(){
if [[ -n "$BROWSER" ]]; then
"$BROWSER" "$1" 2>/dev/null
else
xdg-open "$1" 2>/dev/null
fi
2022-05-09 13:42:24 +02:00
}
2022-06-04 22:29:30 +02:00
report_bug(){
2022-06-15 12:32:10 +02:00
echo "[DZGUI] Opening issues page in browser"
if [[ $is_steam_deck -eq 1 ]]; then
2022-09-14 06:56:13 +02:00
steam steam://openurl/"$issues_url" 2>/dev/null
2022-06-15 12:32:10 +02:00
elif [[ $is_steam_deck -eq 0 ]]; then
2022-09-14 06:56:13 +02:00
browser "$issues_url" 2>/dev/null &
2022-06-15 12:32:10 +02:00
fi
}
help_file(){
echo "[DZGUI] Opening help file in browser"
if [[ $is_steam_deck -eq 1 ]]; then
steam steam://openurl/"$help_url" 2>/dev/null
elif [[ $is_steam_deck -eq 0 ]]; then
2022-07-24 15:20:06 +02:00
browser "$help_url" 2>/dev/null &
2022-06-15 12:32:10 +02:00
fi
2022-05-22 21:20:34 +02:00
}
set_mode(){
if [[ $debug -eq 1 ]]; then
2022-06-04 22:29:30 +02:00
mode=debug
2022-05-22 21:20:34 +02:00
else
mode=normal
fi
}
2022-07-24 15:20:06 +02:00
delete_by_id(){
new_whitelist="whitelist=\"$(echo "$whitelist" | sed "s/,$server_id$//;s/^$server_id,//;s/,$server_id,/,/")\""
mv $config_file ${config_path}dztuirc.old
nr=$(awk '/whitelist=/ {print NR}' ${config_path}dztuirc.old)
awk -v "var=$new_whitelist" -v "nr=$nr" 'NR==nr {$0=var}{print}' ${config_path}dztuirc.old > ${config_path}dztuirc
echo "[DZGUI] Removed $server_id from key 'whitelist'"
zenity --info --title="DZGUI" --text="Removed "$server_id" from:\n${config_path}dztuirc\nIf errors occur, you can restore the file:\n${config_path}dztuirc.old" 2>/dev/null
source $config_file
}
delete_or_connect(){
if [[ $delete -eq 1 ]]; then
server_name=$(echo "$sel" | awk -F"%%" '{print $1}')
server_id=$(echo "$sel" | awk -F"%%" '{print $2}')
zenity --question --text="Delete this server? \n$server_name"
if [[ $? -eq 0 ]]; then
delete_by_id $server_id
fi
else
connect $sel
fi
}
2022-06-04 22:29:30 +02:00
populate(){
2022-05-22 21:20:34 +02:00
while true; do
2022-07-24 15:20:06 +02:00
if [[ $delete -eq 1 ]]; then
cols="--column="Server" --column="ID""
set_header "delete"
else
cols="--column="Server" --column="IP" --column="Players" --column="Gametime" --column="Status" --column="ID" --column="Ping""
set_header ${FUNCNAME[0]}
fi
2022-06-04 22:29:30 +02:00
rc=$?
2022-07-18 10:58:38 +02:00
if [[ $rc -eq 0 ]]; then
if [[ -z $sel ]]; then
2022-06-04 22:29:30 +02:00
warn "No item was selected."
else
2022-07-24 15:20:06 +02:00
delete_or_connect
return
2022-06-04 22:29:30 +02:00
fi
else
2022-07-24 15:20:06 +02:00
delete=0
2022-06-04 22:29:30 +02:00
return
fi
done
}
list_mods(){
2022-06-15 12:32:10 +02:00
if [[ -z $(installed_mods) || -z $(find $workshop_dir -maxdepth 2 -name "*.cpp" | grep .cpp) ]]; then
zenity --info --text="No mods currently installed or incorrect path given" $sd_res 2>/dev/null
else
2022-07-24 15:20:06 +02:00
for d in $(find $game_dir/* -maxdepth 1 -type l); do
dir=$(basename $d)
awk -v d=$dir -F\" '/name/ {printf "%s\t%s\n", $2,d}' "$gamedir"/$d/meta.cpp
2022-08-04 21:14:56 +02:00
done | sort
2022-06-15 12:32:10 +02:00
fi
2022-06-04 22:29:30 +02:00
}
2022-07-24 15:20:06 +02:00
fetch_query_ports(){
qport_list=$(echo "$response" | jq -r '.data[] .attributes | "\(.ip):\(.port)%%\(.portQuery)"')
}
2022-06-04 22:29:30 +02:00
connect_to_fav(){
2022-06-15 12:32:10 +02:00
if [[ -n $fav ]]; then
one_shot_launch=1
query_api
2022-07-24 15:20:06 +02:00
fetch_query_ports
2022-06-15 12:32:10 +02:00
echo "[DZGUI] Attempting connection to $fav_label"
2022-07-18 10:58:38 +02:00
connect "$qport_list"
one_shot_launch=0
2022-06-15 12:32:10 +02:00
else
warn "No fav server configured"
fi
2022-06-04 22:29:30 +02:00
}
2022-07-18 10:58:38 +02:00
set_header(){
2022-07-24 15:20:06 +02:00
if [[ $1 == "delete" ]]; then
sel=$(cat $tmp | zenity $sd_res --list $cols --title="DZGUI" --text="DZGUI $version | Mode: $mode | Branch: $branch | Fav: $fav_label" \
--separator="$separator" --print-column=1,2 --ok-label="Delete" 2>/dev/null)
elif [[ $1 == "populate" ]]; then
sel=$(cat $tmp | zenity $sd_res --list $cols --title="DZGUI" --text="DZGUI $version | Mode: $mode | Branch: $branch | Fav: $fav_label" \
2022-07-18 10:58:38 +02:00
--separator="$separator" --print-column=2,6 2>/dev/null)
elif [[ $1 == "main_menu" ]]; then
2022-07-24 15:20:06 +02:00
sel=$(zenity $sd_res --list --title="DZGUI" --text="${news}DZGUI $version | Mode: $mode | Branch: $branch | Fav: $fav_label" \
--cancel-label="Exit" --ok-label="Select" --column="Select launch option" --hide-header "${items[@]}" 2>/dev/null)
2022-07-18 10:58:38 +02:00
fi
}
toggle_branch(){
mv $config_file ${config_path}dztuirc.old
nr=$(awk '/branch=/ {print NR}' ${config_path}dztuirc.old)
if [[ $branch == "stable" ]]; then
branch="testing"
else
branch="stable"
fi
flip_branch="branch=\"$branch\""
awk -v "var=$flip_branch" -v "nr=$nr" 'NR==nr {$0=var}{print}' ${config_path}dztuirc.old > $config_file
printf "[DZGUI] Toggled branch to '$branch'\n"
source $config_file
}
2022-08-04 21:14:56 +02:00
generate_log(){
cat <<-DOC
Version: $version
Branch: $branch
Whitelist: $whitelist
Path: $steam_path
Linux: $(uname -mrs)
Mods:
$(list_mods)
DOC
}
2022-07-18 10:58:38 +02:00
debug_menu(){
debug_list=(
"Toggle branch"
2022-08-04 21:14:56 +02:00
"Generate debug log"
2022-07-18 10:58:38 +02:00
)
2022-07-24 15:20:06 +02:00
debug_sel=$(zenity --list --width=1280 --height=800 --column="Options" --title="DZGUI" --hide-header "${debug_list[@]}" 2>/dev/null)
2022-07-18 10:58:38 +02:00
if [[ $debug_sel == "${debug_list[0]}" ]]; then
enforce_dl=1
2022-07-31 20:01:58 +02:00
toggle_branch &&
2022-07-18 10:58:38 +02:00
check_version
2022-08-04 21:14:56 +02:00
elif [[ $debug_sel == "${debug_list[1]}" ]]; then
source_script=$(realpath "$0")
source_dir=$(dirname "$source_script")
2022-08-05 21:32:29 +02:00
generate_log > "$source_dir/log"
2022-08-06 02:42:41 +02:00
printf "[DZGUI] Wrote log file to %s/log\n" "$source_dir"
zenity --info --width 500 --title="DZGUI" --text="Wrote log file to \n$source_dir/log" 2>/dev/null
2022-07-18 10:58:38 +02:00
fi
}
2022-07-24 15:20:06 +02:00
query_and_connect(){
query_api
2022-08-11 00:59:29 +02:00
parse_json
2022-07-24 15:20:06 +02:00
#TODO: create logger function
echo "[DZGUI] Checking response time of servers"
2022-08-10 03:08:27 +02:00
create_array | zenity --width 500 --progress --pulsate --title="DZGUI" --auto-close 2>/dev/null
2022-07-24 15:20:06 +02:00
rc=$?
if [[ $rc -eq 1 ]]; then
:
else
populate
fi
}
2022-09-12 16:55:30 +02:00
exclude_full(){
response=$(echo "$response" | jq '[.[]|select(.players!=.max_players)]')
}
exclude_empty(){
response=$(echo "$response" | jq '[.[]|select(.players!=0)]')
}
filter_maps(){
echo "# Filtering maps"
[[ $ret -eq 98 ]] && return
local maps=$(echo "$response" | jq -r '.[].map//empty|ascii_downcase' | sort -u)
2022-09-13 15:45:28 +02:00
local map_ct=$(echo "$maps" | wc -l)
local map_sel=$(echo "$maps" | zenity --list --column="Check" --width=1200 --height=800 2>/dev/null --title=DZGUI --text="Found $map_ct map types")
2022-09-12 16:55:30 +02:00
echo "[DZGUI] Selected '$map_sel'"
if [[ -z $map_sel ]]; then
ret=97
return
fi
echo "100"
response=$(echo "$response" | jq --arg map "$map_sel" '[.[]|select(.map)//empty|select(.map|ascii_downcase == $map)]')
}
exclude_daytime(){
response=$(echo "$response" | jq '[.[]|select(.gametype|test(",[0][6-9]:|,[1][0-6]:")|not)]')
}
exclude_nighttime(){
response=$(echo "$response" | jq '[.[]|select(.gametype|test(",[1][7-9]:|,[2][0-4]:|[0][0-5]:")|not)]')
}
keyword_filter(){
response=$(echo "$response" | jq --arg search "$search" '[.[]|select(.name|ascii_downcase | contains($search))]')
}
exclude_lowpop(){
response=$(echo "$response" | jq '[.[]|select(.players > 9)]')
}
exclude_nonascii(){
response=$(echo "$response" | jq -r '[.[]|select(.name|test("^([[:ascii:]])*$"))]')
}
strip_null(){
response=$(echo "$response" | jq -r '[.[]|select(.map//empty)]')
}
local_latlon(){
local local_ip=$(dig +short myip.opendns.com @resolver1.opendns.com)
local url="http://ip-api.com/json/$local_ip"
local res=$(curl -Ls "$url" | jq -r '"\(.lat),\(.lon)"')
local_lat=$(echo "$res" | awk -F, '{print $1}')
local_lon=$(echo "$res" | awk -F, '{print $2}')
}
disabled(){
if [[ -z ${disabled[@]} ]]; then
printf "%s" "-"
else
for((i=0;i<${#disabled[@]};i++)); do
if [[ $i < $((${#disabled[@]}-1)) ]]; then
printf "%s, " "${disabled[$i]}"
else
printf "%s" "${disabled[$i]}"
fi
done
fi
}
pagination(){
if [[ ${#qport[@]} -eq 1 ]]; then
entry=server
else
entry=servers
fi
2022-09-12 17:33:29 +02:00
printf "DZGUI $version"
printf "Mode: $mode"
2022-09-13 06:41:26 +02:00
printf "Fav: $fav_label "
printf "\nIncluded: %s │ " "$filters"
printf "Excluded: %s " "$(disabled)"
2022-09-12 16:55:30 +02:00
if [[ -n $search ]]; then
2022-09-13 06:41:26 +02:00
printf "│ Keyword: %s " "$search"
2022-09-12 16:55:30 +02:00
fi
2022-09-13 06:41:26 +02:00
printf "\nReturned: %s %s of %s │ " "${#qport[@]}" "$entry" "$total_servers"
printf "Players online: %s" "$players_online"
2022-09-12 16:55:30 +02:00
}
check_geo_file(){
local gzip="$helpers_path/ips.csv.gz"
2022-09-14 06:22:14 +02:00
curl -Ls "$sums_url" > "$sums_path"
2022-09-14 06:56:13 +02:00
cd "$helpers_path"
md5sum -c "$sums_path" 2>/dev/null 1>&2
2022-09-14 06:22:14 +02:00
local res=$?
if [[ $res -eq 1 ]]; then
2022-09-12 16:55:30 +02:00
run(){
mkdir -p "$helpers_path"
2022-09-14 06:22:14 +02:00
echo "# Fetching new geolocation DB"
2022-09-12 16:55:30 +02:00
curl -Ls "$db_file" > "$gzip"
echo "# Extracting coordinates"
2022-09-14 06:56:13 +02:00
#force overwrite
gunzip -f "$gzip"
2022-09-12 16:55:30 +02:00
echo "# Preparing helper file"
curl -Ls "$km_helper_url" > "$km_helper"
2022-09-14 06:22:14 +02:00
chmod +x $km_helper
2022-09-12 16:55:30 +02:00
echo "100"
}
run > >(zenity --pulsate --progress --auto-close --width=500 2>/dev/null)
fi
}
choose_filters(){
sels=$(zenity --title=DZGUI --text="Server search" --list --checklist --column "Check" --column "Option" --hide-header TRUE "All maps" TRUE "Daytime" TRUE "Nighttime" False "Empty" False "Full" False "Low population" FALSE "Non-ASCII titles" FALSE "Keyword search" --width 1200 --height 800 2>/dev/null)
if [[ $sels =~ Keyword ]]; then
search=$(zenity --entry --text="Search (case insensitive)" --width=500 --title=DZGUI 2>/dev/null | awk '{print tolower($0)}')
[[ -z $search ]] && { ret=97; return; }
fi
[[ -z $sels ]] && return
filters=$(echo "$sels" | sed 's/|/, /g')
echo "[DZGUI] Filters: $filters"
}
get_dist(){
local given_ip="$1"
2022-09-13 15:35:13 +02:00
local network="$(echo "$given_ip" | awk -F. '{OFS="."}{print $1"."$2}')"
local binary=$(grep -E "^$network\." $geo_file)
local three=$(echo $given_ip | awk -F. '{print $3}')
local host=$(echo $given_ip | awk -F. '{print $4}')
local res=$(echo "$binary" | awk -F[.,] -v three=$three -v host=$host '$3 <=three && $7 >= three{if($3>three || ($3==three && $4 > host) || $7 < three || ($7==three && $8 < host)){next}{print}}' | awk -F, '{print $7,$8}')
local remote_lat=$(echo "$res" | awk '{print $1}')
local remote_lon=$(echo "$res" | awk '{print $2}')
2022-09-12 16:55:30 +02:00
if [[ -z $remote_lat ]]; then
local dist="Unknown"
echo "$dist"
else
2022-09-14 06:22:14 +02:00
local dist=$($km_helper "$local_lat" "$local_lon" "$remote_lat" "$remote_lon")
printf "%05.0f %s" "$dist" "km"
2022-09-12 16:55:30 +02:00
fi
}
prepare_filters(){
2022-09-14 06:22:14 +02:00
echo "# Filtering list"
2022-09-12 16:55:30 +02:00
[[ ! "$sels" =~ "Full" ]] && { exclude_full; disabled+=("Full") ; }
[[ ! "$sels" =~ "Empty" ]] && { exclude_empty; disabled+=("Empty") ; }
[[ ! "$sels" =~ "Daytime" ]] && { exclude_daytime; disabled+=("Daytime") ; }
[[ ! "$sels" =~ "Nighttime" ]] && { exclude_nighttime; disabled+=("Nighttime") ; }
[[ ! "$sels" =~ "Low population" ]] && { exclude_lowpop; disabled+=("Low-pop") ; }
[[ ! "$sels" =~ "Non-ASCII titles" ]] && { exclude_nonascii; disabled+=("Non-ASCII") ; }
[[ -n "$search" ]] && keyword_filter
strip_null
echo "100"
}
munge_servers(){
if [[ ! "$sels" =~ "All maps" ]]; then
filter_maps > >(zenity --pulsate --progress --auto-close --width=500 2>/dev/null)
disabled+=("All maps")
fi
[[ $ret -eq 97 ]] && return
2022-09-13 06:41:26 +02:00
total_servers=$(echo "$response" | jq 'length')
players_online=$(echo "$response" | jq '.[].players' | awk '{s+=$1}END{print s}')
2022-09-12 16:55:30 +02:00
prepare_filters > >(zenity --pulsate --progress --auto-close --width=500 2>/dev/null)
if [[ $(echo "$response" | jq 'length') -eq 0 ]]; then
zenity --error --text="No matching servers" 2>/dev/null
return
fi
local addr=$(echo "$response" | jq -r '.[].addr' | awk -F: '{print $1}')
local gameport=$(echo "$response" | jq -r '.[].gameport')
local qport=$(echo "$response" | jq -r '.[].addr' | awk -F: '{print $2}')
2022-09-13 15:35:13 +02:00
#jq bug #1788, raw output cannot be used with ASCII
2022-09-14 15:10:27 +02:00
local name=$(echo "$response" | jq -a '.[].name' | sed 's/\\u[0-9a-z]\{4\}//g;s/^"//;s/"$//')
2022-09-12 16:55:30 +02:00
local players=$(echo "$response" | jq -r '.[].players')
local max=$(echo "$response" | jq -r '.[].max_players')
local map=$(echo "$response" | jq -r '.[].map|ascii_downcase')
local gametime=$(echo "$response" | jq -r '.[].gametype' | grep -oE '[0-9]{2}:[0-9]{2}$')
readarray -t qport <<< $qport
readarray -t gameport <<< $gameport
readarray -t addr <<< $addr
readarray -t name <<< $name
readarray -t players <<< $players
readarray -t map <<< $map
readarray -t max <<< $max
readarray -t gametime <<< $gametime
if [[ $is_steam_deck -eq 0 ]]; then
sd_res="--width=1920 --height=1080"
fi
for((i=0;i<${#qport[@]};i++)); do
printf "%s\n%s\n%s\n%03d\n%03d\n%s\n%s:%s\n%s\n" "${map[$i]}" "${name[$i]}" "${gametime[$i]}" \
"${players[$i]}" "${max[$i]}" "$(get_dist ${addr[$i]})" "${addr[$i]}" "${gameport[$i]}" "${qport[$i]}"
done | zenity --text="$(pagination)" --title=DZGUI --list --column=Map --column=Name --column=Gametime --column=Players --column=Max --column=Distance --column=IP --column=Qport $sd_res --print-column=7,8 --separator=%% 2>/dev/null
}
server_browser(){
2022-09-13 06:41:26 +02:00
check_steam_api
2022-09-12 16:55:30 +02:00
unset ret
file=$(mktemp)
local limit=20000
local url="https://api.steampowered.com/IGameServersService/GetServerList/v1/?filter=\appid\221100&limit=$limit&key=$steam_api"
check_geo_file #> >(zenity --pulsate --progress --auto-close 2>/dev/null)
2022-09-12 17:33:29 +02:00
command -v python 2>&1>/dev/null || { zenity --error --width=500 --text="Requires python" 2>/dev/null ; return ; }
2022-09-12 16:55:30 +02:00
local_latlon
choose_filters
[[ -z $sels ]] && return
[[ $ret -eq 97 ]] && return
#TODO: some error handling here
2022-09-14 06:22:14 +02:00
fetch(){
echo "# Getting server list"
curl -Ls "$url" > $file
}
fetch > >(zenity --pulsate --progress --auto-close --width=500 2>/dev/null)
2022-09-12 16:55:30 +02:00
response=$(< $file jq -r '.response.servers')
local sel=$(munge_servers)
if [[ -z $sel ]]; then
unset filters
unset search
ret=98
return
fi
local sel_ip=$(echo "$sel" | awk -F%% '{print $1}')
local sel_port=$(echo "$sel" | awk -F%% '{print $2}')
qport_list="$sel_ip%%$sel_port"
if [[ -n "$sel_ip" ]]; then
connect "$sel_ip" "ip"
else
return
fi
}
2022-07-24 15:20:06 +02:00
2022-06-04 22:29:30 +02:00
main_menu(){
2022-07-24 15:20:06 +02:00
print_news
set_mode
2022-06-22 15:33:52 +02:00
if [[ $debug -eq 1 ]]; then
items+=("Debug options")
fi
2022-06-15 12:32:10 +02:00
if [[ -n $fav ]]; then
2022-08-16 17:49:51 +02:00
items[4]="Change favorite server"
2022-06-15 12:32:10 +02:00
fi
2022-06-04 22:29:30 +02:00
while true; do
2022-07-18 10:58:38 +02:00
set_header ${FUNCNAME[0]}
2022-06-04 22:29:30 +02:00
rc=$?
if [[ $rc -eq 0 ]]; then
if [[ -z $sel ]]; then
warn "No item was selected."
2022-06-15 12:32:10 +02:00
elif [[ $sel == "${items[0]}" ]]; then
2022-07-24 15:20:06 +02:00
query_and_connect
2022-06-15 12:32:10 +02:00
elif [[ $sel == "${items[1]}" ]]; then
2022-06-04 22:29:30 +02:00
connect_to_fav
2022-06-15 12:32:10 +02:00
elif [[ $sel == "${items[2]}" ]]; then
2022-08-16 17:49:51 +02:00
connect_by_ip
2022-06-15 12:32:10 +02:00
elif [[ $sel == "${items[3]}" ]]; then
2022-08-16 17:49:51 +02:00
add_by_id
2022-06-15 12:32:10 +02:00
elif [[ $sel == "${items[4]}" ]]; then
2022-08-16 17:49:51 +02:00
add_by_fav
elif [[ $sel == "${items[5]}" ]]; then
2022-07-24 15:20:06 +02:00
delete=1
query_and_connect
elif [[ $sel == "${items[6]}" ]]; then
2022-09-12 16:55:30 +02:00
server_browser
2022-08-16 17:49:51 +02:00
elif [[ $sel == "${items[7]}" ]]; then
2022-09-12 16:55:30 +02:00
list_mods | sed 's/\t/\n/g' | zenity --list --column="Mod" --column="Symlink" --title="DZGUI" $sd_res --print-column="" 2>/dev/null
elif [[ $sel == "${items[8]}" ]]; then
2022-06-22 15:33:52 +02:00
toggle_debug
main_menu
return
2022-07-18 10:58:38 +02:00
elif [[ $sel == "${items[9]}" ]]; then
2022-09-12 16:55:30 +02:00
report_bug
2022-07-24 15:20:06 +02:00
elif [[ $sel == "${items[10]}" ]]; then
2022-09-12 16:55:30 +02:00
help_file
2022-08-16 17:49:51 +02:00
elif [[ $sel == "${items[11]}" ]]; then
2022-09-12 16:55:30 +02:00
changelog | zenity --text-info $sd_res --title="DZGUI" 2>/dev/null
elif [[ $sel == "${items[12]}" ]]; then
2022-07-18 10:58:38 +02:00
debug_menu
2022-06-04 22:29:30 +02:00
else
warn "This feature is not yet implemented."
fi
2022-05-22 21:20:34 +02:00
else
2022-06-04 22:29:30 +02:00
return
2022-05-22 21:20:34 +02:00
fi
done
}
2022-08-11 00:59:29 +02:00
page_through(){
2022-08-12 02:52:07 +02:00
list_response=$(curl -s "$page")
list=$(echo "$list_response" | jq -r '.data[] .attributes | "\(.name)\t\(.ip):\(.port)\t\(.players)/\(.maxPlayers)\t\(.details.time)\t\(.status)\t\(.id)"')
2022-08-11 00:59:29 +02:00
idarr+=("$list")
parse_json
}
2022-05-22 21:20:34 +02:00
parse_json(){
2022-08-12 02:52:07 +02:00
page=$(echo "$list_response" | jq -r '.links.next?')
2022-08-14 18:22:21 +02:00
if [[ $first_entry -eq 1 ]]; then
list=$(echo "$list_response" | jq -r '.data[] .attributes | "\(.name)\t\(.ip):\(.port)\t\(.players)/\(.maxPlayers)\t\(.details.time)\t\(.status)\t\(.id)"')
idarr+=("$list")
first_entry=0
fi
2022-08-11 00:59:29 +02:00
if [[ "$page" != "null" ]]; then
2022-08-12 02:52:07 +02:00
list=$(echo "$list_response" | jq -r '.data[] .attributes | "\(.name)\t\(.ip):\(.port)\t\(.players)/\(.maxPlayers)\t\(.details.time)\t\(.status)\t\(.id)"')
2022-08-11 00:59:29 +02:00
idarr+=("$list")
page_through
else
printf "%s\n" "${idarr[@]}" > $tmp
idarr=()
fetch_query_ports
fi
2022-05-09 13:42:24 +02:00
}
check_ping(){
2022-07-24 15:20:06 +02:00
ping_ip=$(echo "$1" | awk -F'\t' '{print $2}' | awk -F: '{print $1}')
ms=$(ping -c 1 -W 1 "$ping_ip" | awk -Ftime= '/time=/ {print $2}')
if [[ -z $ms ]]; then
echo "Timeout"
else
echo "$ms"
fi
2022-05-22 21:20:34 +02:00
}
2022-05-09 13:42:24 +02:00
create_array(){
list=$(cat $tmp)
#TODO: improve error handling for null values
2022-05-29 08:33:14 +02:00
lc=1
2022-05-09 13:42:24 +02:00
while read line; do
name=$(echo "$line" | awk -F'\t' '{print $1}')
2022-05-22 21:20:34 +02:00
#truncate names
2022-06-15 12:32:10 +02:00
if [[ $(echo "$name" | wc -m) -gt 50 ]]; then
2022-08-10 03:08:27 +02:00
name="$(echo "$name" | awk '{print substr($0,1,50) "..."}')"
2022-05-09 13:42:24 +02:00
else
:
fi
ip=$(echo "$line" | awk -F'\t' '{print $2}')
players=$(echo "$line" | awk -F'\t' '{print $3}')
2022-06-15 12:32:10 +02:00
time=$(echo "$line" | awk -F'\t' '{print $4}')
stat=$(echo "$line" | awk -F'\t' '{print $5}')
2022-06-04 22:29:30 +02:00
2022-05-22 21:20:34 +02:00
#yad only
#[[ $stat == "online" ]] && stat="<span color='#77ff33'>online</span>" || :
2022-06-04 22:29:30 +02:00
2022-05-09 13:42:24 +02:00
#TODO: probe offline return codes
2022-06-15 12:32:10 +02:00
id=$(echo "$line" | awk -F'\t' '{print $6}')
2022-05-29 08:33:14 +02:00
tc=$(awk 'END{print NR}' $tmp)
2022-07-24 15:20:06 +02:00
if [[ $delete -eq 1 ]]; then
declare -g -a rows=("${rows[@]}" "$name" "$id")
else
echo "# Checking ping: $lc/$tc"
ping=$(check_ping "$line")
declare -g -a rows=("${rows[@]}" "$name" "$ip" "$players" "$time" "$stat" "$id" "$ping")
fi
2022-05-29 08:33:14 +02:00
let lc++
done <<< "$list"
for i in "${rows[@]}"; do echo -e "$i"; done > $tmp
2022-05-09 13:42:24 +02:00
}
2022-06-04 22:29:30 +02:00
set_fav(){
#TODO: test API key here and return errors
2022-08-12 02:52:07 +02:00
echo "[DZGUI] Querying favorite server"
2022-06-12 06:44:30 +02:00
query_api
2022-06-04 22:29:30 +02:00
fav_label=$(curl -s "$api" -H "Authorization: Bearer "$api_key"" -G -d "filter[game]=$game" -d "filter[ids][whitelist]=$fav" \
| jq -r '.data[] .attributes .name')
2022-06-15 12:32:10 +02:00
if [[ -z $fav_label ]]; then
fav_label=null
2022-06-12 06:44:30 +02:00
fi
echo "[DZGUI] Setting favorite server to '$fav_label'"
2022-06-04 22:29:30 +02:00
}
2022-06-15 12:32:10 +02:00
check_unmerged(){
if [[ -f ${config_path}.unmerged ]]; then
printf "[DZGUI] Found new config format, merging changes\n"
merge_config
rm ${config_path}.unmerged
fi
}
merge_config(){
source $config_file
mv $config_file ${config_path}dztuirc.old
write_config > $config_file
printf "[DZGUI] Wrote new config file to %sdztuirc\n" $config_path
2022-08-05 22:26:00 +02:00
zenity --info --width 500 --title="DZGUI" --text="Wrote new config format to \n${config_path}dztuirc\nIf errors occur, you can restore the file:\n${config_path}dztuirc.old" 2>/dev/null
2022-06-15 12:32:10 +02:00
}
2022-06-04 22:29:30 +02:00
download_new_version(){
2022-08-05 22:26:00 +02:00
if [[ $is_steam_deck -eq 1 ]]; then
freedesktop_dirs
fi
source_script=$(realpath "$0")
source_dir=$(dirname "$source_script")
mv $source_script $source_script.old
curl -Ls "$version_url" > $source_script
2022-06-04 22:29:30 +02:00
rc=$?
if [[ $rc -eq 0 ]]; then
echo "[DZGUI] Wrote $upstream to $source_script"
chmod +x $source_script
2022-06-15 12:32:10 +02:00
touch ${config_path}.unmerged
2022-08-05 22:26:00 +02:00
zenity --question --width 500 --title="DZGUI" --text "DZGUI $upstream successfully downloaded.\nTo view the changelog, select Changelog.\nTo use the new version, select Exit and restart." --ok-label="Changelog" --cancel-label="Exit" 2>/dev/null
2022-06-12 06:44:30 +02:00
code=$?
if [[ $code -eq 0 ]]; then
changelog | zenity --text-info $sd_res --title="DZGUI" 2>/dev/null
exit
elif [[ $code -eq 1 ]]; then
exit
fi
2022-06-04 22:29:30 +02:00
else
mv $source_script.old $source_script
2022-06-04 22:29:30 +02:00
zenity --info --title="DZGUI" --text "Failed to download new version." 2>/dev/null
return
fi
}
2022-07-18 10:58:38 +02:00
check_branch(){
if [[ $branch == "stable" ]]; then
2022-09-14 06:56:13 +02:00
version_url="$stable_url/dzgui.sh"
2022-07-18 10:58:38 +02:00
elif [[ $branch == "testing" ]]; then
2022-09-14 06:56:13 +02:00
version_url="$testing_url/dzgui.sh"
2022-07-18 10:58:38 +02:00
fi
upstream=$(curl -Ls "$version_url" | awk -F= '/^version=/ {print $2}')
}
enforce_dl(){
2022-07-31 20:01:58 +02:00
download_new_version
}
prompt_dl(){
2022-08-05 20:03:24 +02:00
zenity --question --title="DZGUI" --text "Version conflict.\n\nYour branch:\t\t$branch\nYour version\t\t$version\nUpstream version:\t\t$upstream\n\nVersion updates introduce important bug fixes and are encouraged.\n\nAttempt to download latest version?" --width=500 --ok-label="Yes" --cancel-label="No" 2>/dev/null
rc=$?
if [[ $rc -eq 1 ]]; then
return
else
download_new_version
fi
}
2022-06-04 22:29:30 +02:00
check_version(){
2022-08-04 21:14:56 +02:00
if [[ ! -f $config_file ]]; then : ; else source $config_file; fi
if [[ -z $branch ]]; then
branch="stable"
fi
2022-07-18 10:58:38 +02:00
check_branch
2022-08-06 00:38:46 +02:00
[[ ! -d "$HOME/dzgui" ]] && freedesktop_dirs
2022-06-04 22:29:30 +02:00
if [[ $version == $upstream ]]; then
2022-06-15 12:32:10 +02:00
check_unmerged
2022-06-04 22:29:30 +02:00
else
echo "[DZGUI] Upstream ($upstream) != local ($version)"
if [[ $enforce_dl -eq 1 ]]; then
enforce_dl
2022-06-04 22:29:30 +02:00
else
prompt_dl
2022-06-04 22:29:30 +02:00
fi
fi
}
2022-06-15 12:32:10 +02:00
check_architecture(){
2022-07-24 15:20:06 +02:00
cpu=$(cat /proc/cpuinfo | grep "AMD Custom APU 0405")
2022-08-04 21:41:25 +02:00
if [[ -n "$cpu" ]]; then
2022-06-15 12:32:10 +02:00
is_steam_deck=1
echo "[DZGUI] Setting architecture to 'Steam Deck'"
else
is_steam_deck=0
echo "[DZGUI] Setting architecture to 'desktop'"
fi
}
2022-06-04 22:29:30 +02:00
add_by_id(){
2022-08-04 21:14:56 +02:00
#FIXME: prevent redundant creation of existent IDs (for neatness)
2022-06-15 12:32:10 +02:00
while true; do
id=$(zenity --entry --text="Enter server ID" --title="DZGUI" 2>/dev/null)
rc=$?
if [[ $rc -eq 1 ]]; then
return
else
if [[ ! $id =~ ^[0-9]+$ ]]; then
zenity --warning --title="DZGUI" --text="Invalid ID" 2>/dev/null
else
new_whitelist="whitelist=\"$whitelist,$id\""
mv $config_file ${config_path}dztuirc.old
nr=$(awk '/whitelist=/ {print NR}' ${config_path}dztuirc.old)
awk -v "var=$new_whitelist" -v "nr=$nr" 'NR==nr {$0=var}{print}' ${config_path}dztuirc.old > ${config_path}dztuirc
echo "[DZGUI] Added $id to key 'whitelist'"
zenity --info --title="DZGUI" --text="Added "$id" to:\n${config_path}dztuirc\nIf errors occur, you can restore the file:\n${config_path}dztuirc.old" 2>/dev/null
source $config_file
return
fi
fi
done
}
2022-06-22 15:33:52 +02:00
toggle_debug(){
mv $config_file ${config_path}dztuirc.old
nr=$(awk '/debug=/ {print NR}' ${config_path}dztuirc.old)
if [[ $debug -eq 1 ]]; then
debug=0
items=()
init_items
else
debug=1
fi
flip_debug="debug=\"$debug\""
awk -v "var=$flip_debug" -v "nr=$nr" 'NR==nr {$0=var}{print}' ${config_path}dztuirc.old > $config_file
printf "[DZGUI] Toggled debug flag to '$debug'\n"
source $config_file
}
setup(){
if [[ -n $fav ]]; then
set_fav
2022-08-16 17:49:51 +02:00
items[4]="Change favorite server"
2022-06-22 15:33:52 +02:00
fi
}
2022-07-24 15:20:06 +02:00
check_map_count(){
count=1048576
2022-08-16 17:49:51 +02:00
echo "[DZGUI] Checking system map count"
2022-08-06 03:22:12 +02:00
if [[ $(sysctl -q vm.max_map_count | awk -F"= " '{print $2}') -lt $count ]]; then
2022-08-05 21:58:59 +02:00
map_warning=$(zenity --question --width 500 --title="DZGUI" --text "System map count must be $count or higher to run DayZ with Wine. Increase map count and make this change permanent? (will prompt for sudo password)" 2>/dev/null)
2022-07-24 15:20:06 +02:00
if [[ $? -eq 0 ]]; then
pass=$(zenity --password)
sudo -S <<< "$pass" sh -c "echo 'vm.max_map_count=1048576' > /etc/sysctl.d/dayz.conf"
echo ""
fi
fi
}
2022-06-15 12:32:10 +02:00
add_by_fav(){
2022-06-04 22:29:30 +02:00
while true; do
2022-06-15 12:32:10 +02:00
fav_id=$(zenity --entry --text="Enter server ID" --title="DZGUI" 2>/dev/null)
2022-06-04 22:29:30 +02:00
rc=$?
if [[ $rc -eq 1 ]]; then
return
else
2022-06-15 12:32:10 +02:00
if [[ ! $fav_id =~ ^[0-9]+$ ]]; then
2022-06-04 22:29:30 +02:00
zenity --warning --title="DZGUI" --text="Invalid ID"
else
2022-06-15 12:32:10 +02:00
new_fav="fav=\"$fav_id\""
2022-06-04 22:29:30 +02:00
mv $config_file ${config_path}dztuirc.old
2022-06-15 12:32:10 +02:00
nr=$(awk '/fav=/ {print NR}' ${config_path}dztuirc.old)
awk -v "var=$new_fav" -v "nr=$nr" 'NR==nr {$0=var}{print}' ${config_path}dztuirc.old > ${config_path}dztuirc
echo "[DZGUI] Added $fav_id to key 'fav'"
zenity --info --title="DZGUI" --text="Added "$fav_id" to:\n${config_path}dztuirc\nIf errors occurred, you can restore the file:\n${config_path}dztuirc.old" 2>/dev/null
2022-06-04 22:29:30 +02:00
source $config_file
2022-06-15 12:32:10 +02:00
set_fav
2022-08-16 17:49:51 +02:00
items[4]="Change favorite server"
2022-06-04 22:29:30 +02:00
return
fi
fi
done
}
2022-08-13 15:00:35 +02:00
#cleanup(){
# rm $config_path/.lockfile
#}
lock(){
if [[ ! -f $config_path/.lockfile ]]; then
touch $config_path/.lockfile
fi
pid=$(cat $config_path/.lockfile)
ps -p $pid -o pid= >/dev/null 2>&1
res=$?
if [[ $res -eq 0 ]]; then
echo "[DZGUI] Already running ($pid)"
exit
elif [[ $pid == $$ ]]; then
:
else
echo $$ > $config_path/.lockfile
fi
}
2022-05-09 13:42:24 +02:00
main(){
2022-08-13 15:00:35 +02:00
lock
2022-06-15 12:32:10 +02:00
run_depcheck
check_architecture
2022-08-05 22:28:52 +02:00
check_version
2022-07-24 15:20:06 +02:00
check_map_count
2022-05-22 21:20:34 +02:00
config
2022-06-15 12:32:10 +02:00
run_varcheck
2022-06-22 15:33:52 +02:00
init_items
setup
2022-05-22 21:20:34 +02:00
main_menu
2022-05-09 13:42:24 +02:00
}
main
2022-08-12 02:52:07 +02:00
#trap cleanup EXIT