2022-05-09 13:42:24 +02:00
|
|
|
#!/bin/bash
|
|
|
|
|
|
|
|
set -eo pipefail
|
2022-05-29 08:33:14 +02:00
|
|
|
version=1.0.2
|
2022-05-09 13:42:24 +02:00
|
|
|
aid=221100
|
|
|
|
game="dayz"
|
|
|
|
workshop="https://steamcommunity.com/sharedfiles/filedetails/?id="
|
|
|
|
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-05-09 13:42:24 +02:00
|
|
|
|
|
|
|
|
|
|
|
declare -A deps
|
2022-05-22 21:20:34 +02:00
|
|
|
deps=([awk]="5.1.1" [curl]="7.80.0" [jq]="1.6" [tr]="9.0" [zenity]="3.42.1")
|
2022-05-09 13:42:24 +02:00
|
|
|
|
|
|
|
depcheck(){
|
|
|
|
for dep in "${!deps[@]}"; do
|
|
|
|
command -v $dep 2>&1>/dev/null || (printf "[ERROR] Requires %s >= %s\n" $dep ${deps[$dep]} ; exit 1)
|
|
|
|
done
|
|
|
|
}
|
|
|
|
|
2022-05-22 21:20:34 +02:00
|
|
|
items=(
|
|
|
|
"Launch server list"
|
|
|
|
"Connect to favorite server (not implemented)"
|
|
|
|
"Add server from ID (not implemented)"
|
|
|
|
"List mods (not implemented)"
|
|
|
|
"Open mod page (TEST)"
|
|
|
|
"List system browser (TEST)"
|
|
|
|
)
|
|
|
|
|
|
|
|
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(){
|
|
|
|
zenity --info --title="DZGUI" --text="$1" --icon-name="network-wireless" 2>/dev/null
|
|
|
|
}
|
2022-05-29 08:33:14 +02:00
|
|
|
#launch_in_bg(){
|
|
|
|
# info "$msg" &
|
|
|
|
# #TODO: use less brittle method
|
|
|
|
# msg_pid=$(pgrep zenity)
|
|
|
|
# ${1} &
|
|
|
|
# pid=$!
|
|
|
|
# while kill -0 $pid; do
|
|
|
|
# :
|
|
|
|
# done
|
|
|
|
# #TODO: suppress output
|
|
|
|
# #TODO: pid could be released to other process
|
|
|
|
# if [[ -n $msd_pid ]]; then
|
|
|
|
# kill -9 $msg_pid 1 >/dev/null 2>&1
|
|
|
|
# else
|
|
|
|
# :
|
|
|
|
# fi
|
|
|
|
#
|
|
|
|
#}
|
2022-05-09 13:42:24 +02:00
|
|
|
query_api(){
|
2022-05-22 21:20:34 +02:00
|
|
|
response=$(curl -s "$api" -H "Authorization: Bearer "$api_key"" -G -d "sort=-players" \
|
2022-05-09 13:42:24 +02:00
|
|
|
-d "filter[game]=$game" -d "filter[ids][whitelist]=$whitelist")
|
|
|
|
if [[ "$(jq -r 'keys[]' <<< "$response")" == "errors" ]]; then
|
|
|
|
code=$(jq -r '.errors[] .status' <<< $response)
|
|
|
|
#TODO: fix granular api codes
|
2022-05-22 21:20:34 +02:00
|
|
|
#TODO: put into copiable text info box
|
|
|
|
warn "Error $code: malformed API key"
|
2022-05-09 13:42:24 +02:00
|
|
|
fi
|
2022-05-22 21:20:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#TODO: find default SD path
|
|
|
|
write_config(){
|
|
|
|
cat <<-'END'
|
|
|
|
|
|
|
|
#Path to DayZ installation (change if using multiple SD cards)
|
2022-05-29 07:02:39 +02:00
|
|
|
steam_path="/home/deck/.local/share/Steam"
|
2022-05-22 21:20:34 +02:00
|
|
|
workshop_dir="$steam_path/steamapps/workshop/content/$aid"
|
|
|
|
game_dir="$steam_path/steamapps/common/DayZ"
|
|
|
|
|
|
|
|
#Your unique API key
|
|
|
|
api_key=""
|
|
|
|
|
|
|
|
#Comma-separated list of server IDs
|
|
|
|
whitelist=""
|
|
|
|
|
|
|
|
#Favorite server to fast-connect to (limit one)
|
|
|
|
fav=""
|
|
|
|
|
|
|
|
#Custom player name (optional, required by some servers)
|
|
|
|
name="player"
|
|
|
|
|
|
|
|
#Set to 1 to perform dry-run and print launch options
|
|
|
|
debug=0
|
|
|
|
|
|
|
|
#(Not implemented) Set to 0 to suppress ping attempt
|
|
|
|
ping=1
|
|
|
|
|
|
|
|
END
|
|
|
|
}
|
|
|
|
create_config(){
|
|
|
|
mkdir -p $config_path; write_config > $config_file
|
|
|
|
info "Config file created at $config_file.\nFill in values and relaunch."
|
|
|
|
exit
|
|
|
|
|
|
|
|
}
|
|
|
|
err(){
|
|
|
|
printf "[ERROR] %s\n" "$1"
|
|
|
|
}
|
|
|
|
varcheck(){
|
|
|
|
[[ -z $api_key ]] && (err "Error in key: 'api_key'")
|
|
|
|
[[ -z $whitelist ]] && (err "Error in key: 'whitelist'")
|
|
|
|
[[ ! -d $workshop_dir ]] && (err "Malformed workshop path")
|
|
|
|
[[ ! -d $game_dir ]] && (err "Malformed game path")
|
|
|
|
[[ $whitelist =~ [[:space:]] ]] && (err "Separate whitelist values with commas")
|
|
|
|
IFS=,
|
|
|
|
[[ ! "${whitelist[*]}" =~ ${fav} ]] && (err "Fav key value not in whitelist")
|
|
|
|
unset IFS
|
|
|
|
}
|
|
|
|
checks() {
|
|
|
|
if [[ -z $(depcheck) ]]; then
|
|
|
|
:
|
|
|
|
else
|
|
|
|
zenity $sd_res --text-info --cancel-label="Exit" <<< $(depcheck)
|
|
|
|
fi
|
|
|
|
if [[ -z $(varcheck) ]]; then
|
|
|
|
:
|
|
|
|
else
|
|
|
|
zenity $sd_res --text-info --cancel-label="Exit" <<< $(varcheck)
|
|
|
|
fi
|
|
|
|
}
|
|
|
|
config(){
|
|
|
|
if [[ ! -f $config_file ]]; then
|
|
|
|
zenity --question --cancel-label="Exit" --text="Config file not found. Should DZGUI create one for you?"
|
|
|
|
code=$?
|
|
|
|
if [[ $code -eq 1 ]]; then
|
|
|
|
exit
|
|
|
|
else
|
|
|
|
create_config
|
|
|
|
fi
|
|
|
|
else
|
|
|
|
source $config_file
|
|
|
|
fi
|
|
|
|
|
|
|
|
}
|
|
|
|
connect(){
|
|
|
|
#TODO: sanitize/validate input, return if failing
|
|
|
|
ip=$(echo "$1" | awk -F"$separator" '{print $1}')
|
|
|
|
bid=$(echo "$1" | awk -F"$separator" '{print $2}')
|
|
|
|
fetch_mods "$bid"
|
|
|
|
launch
|
|
|
|
|
|
|
|
#TODO: symlink validation, mod validation
|
|
|
|
}
|
|
|
|
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
|
|
|
}
|
|
|
|
concat_mods(){
|
|
|
|
readarray -t serv <<< "$remote_mods"
|
|
|
|
for i in "${serv[@]}"; do
|
|
|
|
id=$(awk -F"= " '/publishedid/ {print $2}' "$workshop_dir"/$i/meta.cpp | awk -F\; '{print $1}')
|
|
|
|
mod=$(awk -F\" '/name/ {print $2}' "$workshop_dir"/$i/meta.cpp | sed -E 's/[^[:alpha:]0-9]+/_/g; s/^_|_$//g')
|
|
|
|
link="@$id-$mod;"
|
|
|
|
echo -e "$link"
|
|
|
|
done | tr -d '\n' | perl -ple 'chop'
|
|
|
|
}
|
|
|
|
launch(){
|
|
|
|
mods=$(concat_mods)
|
|
|
|
if [[ $debug -eq 1 ]]; then
|
2022-05-22 21:20:34 +02:00
|
|
|
printf "[DEBUG] steam -applaunch $aid -connect=$ip -nolauncher -nosplash -skipintro \"-mod=$mods\"\n" | zenity --text-info $sd_res --title="DZGUI debug output"
|
2022-05-09 13:42:24 +02:00
|
|
|
else
|
|
|
|
steam -applaunch $aid -connect=$ip -nolauncher -nosplash -skipintro -name=$name \"-mod=$mods\"
|
|
|
|
exit
|
|
|
|
fi
|
|
|
|
}
|
2022-05-22 21:20:34 +02:00
|
|
|
test_mod_page(){
|
|
|
|
steam steam://url/CommunityFilePage/498101407
|
|
|
|
}
|
|
|
|
test_browser(){
|
2022-05-29 07:02:39 +02:00
|
|
|
#echo $BROWSER | zenity --text-info $sd_res
|
2022-05-29 07:32:26 +02:00
|
|
|
steam steam://openurl/https://github.com/aclist/dztui/issues/9
|
2022-05-22 21:20:34 +02:00
|
|
|
}
|
|
|
|
set_mode(){
|
|
|
|
if [[ $debug -eq 1 ]]; then
|
|
|
|
mode=DEBUG
|
|
|
|
else
|
|
|
|
mode=normal
|
|
|
|
fi
|
|
|
|
}
|
|
|
|
main_menu(){
|
|
|
|
while true; do
|
|
|
|
set_mode
|
2022-05-29 07:47:25 +02:00
|
|
|
sel=$(zenity --width=1280 --height=800 --list --title="DZGUI" --text="DZGUI $version | Mode: $mode | Fav: (not implemented)" --cancel-label="Exit" --ok-label="Select" --column="Select launch option" "${items[@]}" 2>/dev/null)
|
2022-05-22 21:20:34 +02:00
|
|
|
if [[ $? -eq 1 ]]; then
|
|
|
|
exit
|
|
|
|
elif [[ -z $sel ]]; then
|
|
|
|
warn "No item was selected."
|
|
|
|
elif [[ $sel == "Launch server list" ]]; then
|
|
|
|
query_api
|
|
|
|
parse_json <<< "$response"
|
|
|
|
msg="Retrieving server list. This may take some time.\nThis window will close automatically if left open."
|
2022-05-29 08:40:38 +02:00
|
|
|
create_array | zenity --progress --title="DZGUI" --auto-close
|
2022-05-22 21:20:34 +02:00
|
|
|
populate
|
|
|
|
return
|
|
|
|
elif [[ $sel == "Open mod page (TEST)" ]]; then
|
|
|
|
test_mod_page
|
|
|
|
elif [[ $sel == "List system browser (TEST)" ]]; then
|
|
|
|
test_browser
|
|
|
|
else
|
|
|
|
warn "This feature is not yet implemented."
|
|
|
|
fi
|
|
|
|
done
|
|
|
|
}
|
|
|
|
parse_json(){
|
|
|
|
list=$(jq -r '.data[] .attributes | "\(.name)\t\(.ip):\(.port)\t\(.players)/\(.maxPlayers)\t\(.status)\t\(.id)"')
|
|
|
|
echo -e "$list" > $tmp
|
2022-05-09 13:42:24 +02:00
|
|
|
}
|
|
|
|
check_ping(){
|
|
|
|
ping_ip=$(echo "$1" | awk -F'\t' '{print $2}' | awk -F: '{print $1}')
|
|
|
|
ms=$(ping -c 1 "$ping_ip" | awk -Ftime= '/time=/ {print $2}')
|
2022-05-22 21:20:34 +02:00
|
|
|
if [[ -z $ms ]]; then
|
|
|
|
echo "Timeout"
|
|
|
|
else
|
|
|
|
echo "$ms"
|
|
|
|
fi
|
|
|
|
}
|
|
|
|
populate(){
|
|
|
|
while true; do
|
|
|
|
#TODO: add boolean statement for ping flag; affects all column ordinal output
|
|
|
|
cols="--column="Server" --column="IP" --column="Players" --column="Status" --column="ID" --column="Ping""
|
2022-05-29 08:40:38 +02:00
|
|
|
sel=$(cat $tmp | zenity $sd_res --list $cols --title="DZGUI" --text="DZGUI $version | Mode: $mode | Fav: (not implemented)" --separator="$separator" --print-column=2,5 2>/dev/null)
|
2022-05-22 21:20:34 +02:00
|
|
|
if [[ $? -eq 1 ]]; then
|
|
|
|
echo "should return to main menu"
|
|
|
|
#TODO: drop back to main menu
|
|
|
|
:
|
|
|
|
elif [[ -z $sel ]]; then
|
|
|
|
warn "No item was selected."
|
|
|
|
else
|
|
|
|
connect $sel
|
|
|
|
return
|
|
|
|
fi
|
|
|
|
done
|
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-05-09 13:42:24 +02:00
|
|
|
if [[ $(echo "$name" | wc -m) -gt 30 ]]; then
|
|
|
|
name="$(echo $name | awk '{print substr($0,1,30) "..."}')"
|
|
|
|
else
|
|
|
|
:
|
|
|
|
fi
|
|
|
|
ip=$(echo "$line" | awk -F'\t' '{print $2}')
|
|
|
|
players=$(echo "$line" | awk -F'\t' '{print $3}')
|
|
|
|
stat=$(echo "$line" | awk -F'\t' '{print $4}')
|
2022-05-22 21:20:34 +02:00
|
|
|
#yad only
|
|
|
|
#[[ $stat == "online" ]] && stat="<span color='#77ff33'>online</span>" || :
|
2022-05-09 13:42:24 +02:00
|
|
|
#TODO: probe offline return codes
|
|
|
|
id=$(echo "$line" | awk -F'\t' '{print $5}')
|
2022-05-29 08:33:14 +02:00
|
|
|
tc=$(awk 'END{print NR}' $tmp)
|
|
|
|
echo "$lc/$tc"
|
|
|
|
echo "# Checking ping: $lc/$tc"
|
2022-05-09 13:42:24 +02:00
|
|
|
ping=$(check_ping "$line")
|
|
|
|
declare -g -a rows=("${rows[@]}" "$name" "$ip" "$players" "$stat" "$id" "$ping")
|
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
|
|
|
}
|
|
|
|
main(){
|
2022-05-22 21:20:34 +02:00
|
|
|
#TODO: check for upstream version and prompt to download
|
|
|
|
config
|
2022-05-09 13:42:24 +02:00
|
|
|
checks
|
2022-05-22 21:20:34 +02:00
|
|
|
main_menu
|
2022-05-09 13:42:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
main
|