1
0
Fork 0
mirror of https://github.com/aclist/dztui.git synced 2024-12-28 21:32:36 +01:00

Merge pull request #151 from aclist/release/5.3.0-backports

Release/5.3.0 backports
This commit is contained in:
aclist 2024-09-09 17:16:31 +09:00 committed by GitHub
commit c2c7b37b90
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
28 changed files with 472 additions and 84 deletions

View file

@ -1,5 +1,21 @@
# Changelog # Changelog
## [5.3.3] 2024-08-27
### Added
- Scan local area network for DayZ servers
- Freedesktop application icons for system taskbar, tray, and other dialogs
- Emit CPU model name when exporting system debug log
### Fixed
- Detect Steam Deck OLED APU variant during initial setup
- Errors being printed to the console when Exit button was explicitly clicked
- Test if DayZ library location was moved internally on Steam by user
- Encapsulate player names correctly to support whitespace
- Report WM_CLASS name to the window manager
## [5.3.2] 2024-07-02
### Fixed
- Server list would sometimes be missing some expected servers due to truncation being caused when a server erroneously set an incomplete gametype
## [5.3.1] 2024-06-15 ## [5.3.1] 2024-06-15
### Added ### Added
- Uninstall routine: invoke via dzgui.sh -u or dzgui.sh --uninstall and choose from full or partial uninstall - Uninstall routine: invoke via dzgui.sh -u or dzgui.sh --uninstall and choose from full or partial uninstall

View file

@ -7,6 +7,8 @@ DayZ server browser and mod manager for Linux | Last updated: {d}
Click https://aclist.github.io/dzgui/dzgui_dark.html[here] for dark mode Click https://aclist.github.io/dzgui/dzgui_dark.html[here] for dark mode
Looking for the DZGUI Knowledge Base? Click https://aclist.github.io/dzgui/kb.html[here]
== What this is == What this is
A GUI version of https://github.com/aclist/dztui[DZTUI] for Linux. A GUI version of https://github.com/aclist/dztui[DZTUI] for Linux.
Used to list official and community server details and quick connect to preferred servers Used to list official and community server details and quick connect to preferred servers
@ -100,11 +102,14 @@ Enable a Proton version ≥ `6.8` (or use Proton Experimental) in the `Compatibi
=== API key & server IDs === API key & server IDs
==== Steam API key (required) ==== Steam Web API key (required)
1. Register for a https://steamcommunity.com/dev/apikey[Steam API key] (free) using your Steam account. You will be asked for a unique URL for your app when registering. 1. Register for a https://steamcommunity.com/dev/apikey[Steam Web API key] (free) using your Steam account. You will be asked for a unique URL for your app when registering.
2. Since this key is for a personal use application and does not actually call back anywhere, set a generic local identifier here like "127.0.0.1" or some other name that is meaningful to you. 2. Since this key is for a personal use application and does not actually call back anywhere, set a generic local identifier here like "127.0.0.1" or some other name that is meaningful to you.
3. Once configured, you can insert this key in the app when launching it for the first time. 3. Once configured, you can insert this key in the app when launching it for the first time.
[NOTE]
If you are confused about this requirement, please refer to DZGUI Knowledge Base article https://aclist.github.io/dzgui/kb.html#DZG-007[DZG-007] for additional information.
==== BattleMetrics API key (optional) ==== BattleMetrics API key (optional)
This key is optional. Using this key in conjunction with the above allows you to also connect to and query servers by numerical ID instead of by IP. See <<Manage > Add server by ID, Add server by ID>>. This key is optional. Using this key in conjunction with the above allows you to also connect to and query servers by numerical ID instead of by IP. See <<Manage > Add server by ID, Add server by ID>>.
@ -539,30 +544,7 @@ This can be used to diagnose problems and test functionality without actually la
== Troubleshooting/FAQ == Troubleshooting/FAQ
.Mods take a long time to synchronize when subscribing from Workshop Please refer to the https://aclist.github.io/dzgui/kb.html[DZGUI Knowledge Base] for common issues.
Steam schedules the downloads in the background and processes them in the order they were subscribed to.
This process is not instantaneous and can take some time.
.The Steam Workshop shows a black screen when attempting to open/download a mod via DZGUI
This bug is being tracked at https://github.com/ValveSoftware/steam-for-linux/issues/9598. If the issue occurs, manually intervene in the Steam client
by clicking a different window context (e.g., navigate to the Store page from Workshop, then back again) until the Workshop page starts to load content.
.The game does not launch through Steam
Check the logs emitted by Steam in the terminal, or in `<Steam path>/error.log`.
.The game launches, but throws a "mod missing/check PBO file" error when connecting
In rare cases, the server may be using misconfigured, malformed, or obsolete mods.
This depends on server operators checking their mods for integrity.
.The game launches, but when joining the game world, an error occurs
A mod is corrupted or the issue lies with the server. Replace the mods in question and reconnect.
.The game is slow or prone to crashing
DZGUI does not manipulate the game itself and does not contribute to/degrade its performance.
If you are experiencing performance degradation, it can be caused by too many mods installed or
by a server-side problem (underpowered server, misconfiguration, etc.) Contact the server administrator
for assistance.
== Reference == Reference

View file

@ -7,6 +7,8 @@ DayZ server browser and mod manager for Linux | Last updated: {d}
Click https://aclist.github.io/dzgui/dzgui.html[here] for light mode Click https://aclist.github.io/dzgui/dzgui.html[here] for light mode
Looking for the DZGUI Knowledge Base? Click https://aclist.github.io/dzgui/kb_dark.html[here]
== What this is == What this is
A GUI version of https://github.com/aclist/dztui[DZTUI] for Linux. A GUI version of https://github.com/aclist/dztui[DZTUI] for Linux.
Used to list official and community server details and quick connect to preferred servers Used to list official and community server details and quick connect to preferred servers
@ -100,11 +102,14 @@ Enable a Proton version ≥ `6.8` (or use Proton Experimental) in the `Compatibi
=== API key & server IDs === API key & server IDs
==== Steam API key (required) ==== Steam Web API key (required)
1. Register for a https://steamcommunity.com/dev/apikey[Steam API key] (free) using your Steam account. You will be asked for a unique URL for your app when registering. 1. Register for a https://steamcommunity.com/dev/apikey[Steam Web API key] (free) using your Steam account. You will be asked for a unique URL for your app when registering.
2. Since this key is for a personal use application and does not actually call back anywhere, set a generic local identifier here like "127.0.0.1" or some other name that is meaningful to you. 2. Since this key is for a personal use application and does not actually call back anywhere, set a generic local identifier here like "127.0.0.1" or some other name that is meaningful to you.
3. Once configured, you can insert this key in the app when launching it for the first time. 3. Once configured, you can insert this key in the app when launching it for the first time.
[NOTE]
If you are confused about this requirement, please refer to DZGUI Knowledge Base article https://aclist.github.io/dzgui/kb.html#DZG-007[DZG-007] for additional information.
==== BattleMetrics API key (optional) ==== BattleMetrics API key (optional)
This key is optional. Using this key in conjunction with the above allows you to also connect to and query servers by numerical ID instead of by IP. See <<Manage > Add server by ID, Add server by ID>>. This key is optional. Using this key in conjunction with the above allows you to also connect to and query servers by numerical ID instead of by IP. See <<Manage > Add server by ID, Add server by ID>>.
@ -539,30 +544,7 @@ This can be used to diagnose problems and test functionality without actually la
== Troubleshooting/FAQ == Troubleshooting/FAQ
.Mods take a long time to synchronize when subscribing from Workshop Please refer to the https://aclist.github.io/dzgui/kb.html[DZGUI Knowledge Base] for common issues.
Steam schedules the downloads in the background and processes them in the order they were subscribed to.
This process is not instantaneous and can take some time.
.The Steam Workshop shows a black screen when attempting to open/download a mod via DZGUI
This bug is being tracked at https://github.com/ValveSoftware/steam-for-linux/issues/9598. If the issue occurs, manually intervene in the Steam client
by clicking a different window context (e.g., navigate to the Store page from Workshop, then back again) until the Workshop page starts to load content.
.The game does not launch through Steam
Check the logs emitted by Steam in the terminal, or in `<Steam path>/error.log`.
.The game launches, but throws a "mod missing/check PBO file" error when connecting
In rare cases, the server may be using misconfigured, malformed, or obsolete mods.
This depends on server operators checking their mods for integrity.
.The game launches, but when joining the game world, an error occurs
A mod is corrupted or the issue lies with the server. Replace the mods in question and reconnect.
.The game is slow or prone to crashing
DZGUI does not manipulate the game itself and does not contribute to/degrade its performance.
If you are experiencing performance degradation, it can be caused by too many mods installed or
by a server-side problem (underpowered server, misconfiguration, etc.) Contact the server administrator
for assistance.
== Reference == Reference

28
docs/kb.adoc Normal file
View file

@ -0,0 +1,28 @@
:nofooter:
:toc: left
:stylesheet: custom.css
= DZGUI Knowledge Base (v5.x.x)
FAQs for DZGUI
Click https://aclist.github.io/dzgui/kb_dark.html[here] for dark mode
Looking for the main DZGUI documentation? Click https://aclist.github.io/dzgui/dzgui.html[here]
include::kb_sections/dzg001.adoc[]
include::kb_sections/dzg002.adoc[]
include::kb_sections/dzg003.adoc[]
include::kb_sections/dzg004.adoc[]
include::kb_sections/dzg005.adoc[]
include::kb_sections/dzg006.adoc[]
include::kb_sections/dzg007.adoc[]
include::kb_sections/dzg008.adoc[]
include::kb_sections/dzg009.adoc[]

28
docs/kb_dark.adoc Normal file
View file

@ -0,0 +1,28 @@
:nofooter:
:toc: left
:stylesheet: dark.css
= DZGUI Knowledge Base (v5.x.x)
FAQs for DZGUI
Click https://aclist.github.io/dzgui/kb.html[here] for light mode
Looking for the main DZGUI documentation? Click https://aclist.github.io/dzgui/dzgui_dark.html[here]
include::kb_sections/dzg001.adoc[]
include::kb_sections/dzg002.adoc[]
include::kb_sections/dzg003.adoc[]
include::kb_sections/dzg004.adoc[]
include::kb_sections/dzg005.adoc[]
include::kb_sections/dzg006.adoc[]
include::kb_sections/dzg007.adoc[]
include::kb_sections/dzg008.adoc[]
include::kb_sections/dzg009.adoc[]

View file

@ -0,0 +1,11 @@
[[DZG-001, DZG-001]]
== DZG-001: Periodically getting dropped from servers, or servers appear unreachable
Last updated: {d}
It is a longstanding issue in DayZ that the game opens a large number of connections when querying servers and/or while connected to servers. This can result in excess traffic on the user's PC which, depending on how much headroom your network has, can lead to getting dropped, unresponsiveness, or a timeout.
If you are on Wi-Fi, try switching to a wired connection and see if the problem resolves itself. If it does, your wireless router settings do not have enough headroom for max simultaneous connections. Use a wired connection, or update your network settings to a more permissive setup.
Bohemia has acknowledged this issue going back 10+ years and stated that DayZ has a heavy impact on the network, but there is as yet no proposed solution on the DayZ side.
This issue is frequently seen on Steam Deck, due to the tendency for users to use it in an untethered Wi-Fi setup.

View file

@ -0,0 +1,5 @@
[[DZG-002,DZG-002]]
== DZG-002: Some servers appear locked in the official DayZ client, and are unreachable in DZGUI
Last updated: {d}
This is a variant of <<DZG-001>>.

View file

@ -0,0 +1,7 @@
[[DZG-003, DZG-003]]
== DZG-003: On Steam Deck, DayZ becomes unresponsive/sluggish over time
Last updated: {d}
When DayZ is open for 1+ hours, a gradual loss in performance and FPS may occur on the Steam Deck.
A solution that seems to work for most users is to install https://github.com/CryoByte33/steam-deck-utilities[Cryo Utilities], a third-party performance management application.

View file

@ -0,0 +1,7 @@
[[DZG-004, DZG-004]]
== DZG-004: On Steam Deck, some mods in the Workshop show a black screen when DZGUI attempts to open them
Last updated: {d}
This is a bug in the Steam client that is being tracked at Valve's Steam for Linux issue tracker https://github.com/ValveSoftware/steam-for-linux/issues/9598[here].
To resolve this issue, manually intervene in the Steam client by selecting a different context (e.g., Store, Library), waiting for it to load, then navigating back to the Workshop context. This should clear the blockage and allow the contents to render.

View file

@ -0,0 +1,7 @@
[[DZG-005,DZG-005]]
== DZG-005: Rendering problems with objects in the Winter Chernarus v2 mod
Last updated: {d}
This mod has LOD (level of detail) bugs that may cause objects near the player, such as leaves, to render incorrectly, or cause distant trees to pop in abruptly. This is an acknowledged issue with the mod itself, not with DayZ or DZGUI.
There is no user-side fix for this issue; it is a problem solely on the mod side.

View file

@ -0,0 +1,11 @@
[[DZG-006,DZG-006]]
== DZG-006: After moving DayZ to another drive, DZGUI fails to locate it on initial setup
Last updated: {d}
If you recently moved the location of DayZ using Steam's internal dialogs, it may take some time for this information to update internally on Steam's side.
Steam stores the location of installed games in a unified file, and DZGUI checks this file during initial setup to determine where Steam claims DayZ is installed.
If you recently moved DayZ to a different drive or partition but did not restart Steam, this information may be out of date, causing Steam to report the wrong location.
Try restarting the Steam client and starting the DZGUI initial setup again.

View file

@ -0,0 +1,17 @@
[[DZG-007,DZG-007]]
== DZG-007: Why do I need a Steam Web API key? Is it safe?
Last updated: {d}
In order to provide a server browser showing a searchable list of all available servers, DZGUI utilizes the Steam Web API.
Actual connections and queries to individual servers are performed directly between the computer and the DayZ server.
DZGUI gets its server information directly from the most authoritative source: Steam. It does this by letting the user be solely in control of their own API key and the application in an authenticated way. Users explicitly get permission to use a Web API key instead of scraping DayZ server info from third-party sites.
Everything that happens between DZGUI and the Steam Web API endpoint takes place solely on the user's computer, using a GET request (fetch server list), and no information gets sent back to the developer. DZGUI does not scrape third party DayZ APIs without permission.
There is some misconception that a Steam Web API key could be used to gain information about a user's account or control their account. Not only is this not possible, but the Web API key is used solely by the user on their own computer and is protected by Steam Guard.
A Steam Web API key is the most strict way of getting authentic, reliable, and consistent server information in a zero-trust model.
You are responsible for the creation, storage, management, and revocation of your Web API key.

View file

@ -0,0 +1,7 @@
[[DZG-008,DZG-008]]
== DZG-008: DZGUI server browser stops working, and Steam API key is seemingly malformed
Last updated: {d}
In order to use a Steam API key, you will have to enable Steam Guard (2FA) protection on your account. If you previously generated an API key and enabled Steam Guard, but then disabled Steam Guard for some other reason, this will also disable any prior API keys you had.
If, after setting up DZGUI, you inadvertently turned off Steam Guard for some reason, check to see if your API key has been disabled, and reapply Steam Guard accordingly.

View file

@ -0,0 +1,5 @@
[[DZG-009,DZG-009]]
== DZG-009: Livonia map is missing from maps dropdown in DZGUI
Last updated: {d}
The Livonia map was iterated off of a map used for the Arma 3 Contact DLC, and is internally called Enoch. Servers running the Livonia map thus use the internal name. Search for Enoch in the list.

View file

@ -1,7 +1,7 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -o pipefail set -o pipefail
version=5.3.1 version=5.3.0
#CONSTANTS #CONSTANTS
aid=221100 aid=221100
@ -13,7 +13,7 @@ sd_res="--width=1280 --height=800"
steamsafe_zenity="/usr/bin/zenity" steamsafe_zenity="/usr/bin/zenity"
zenity_flags=("--width=500" "--title=DZGUI") zenity_flags=("--width=500" "--title=DZGUI")
declare -A deps declare -A deps
deps=([awk]="5.1.1" [curl]="7.80.0" [jq]="1.6" [tr]="9.0" [$steamsafe_zenity]="3.42.1") deps=([awk]="5.1.1" [curl]="7.80.0" [jq]="1.6" [tr]="9.0" [$steamsafe_zenity]="3.44.1")
#CONFIG #CONFIG
config_path="$HOME/.config/dztui" config_path="$HOME/.config/dztui"
@ -65,6 +65,7 @@ km_helper_url="$releases_url/latlon"
geo_file_url="$releases_url/ips.csv.gz" geo_file_url="$releases_url/ips.csv.gz"
set_im_module(){ set_im_module(){
#TODO: drop pending SteamOS changes
pgrep -a gamescope | grep -q "generate-drm-mode" pgrep -a gamescope | grep -q "generate-drm-mode"
if [[ $? -eq 0 ]]; then if [[ $? -eq 0 ]]; then
GTK_IM_MODULE="" GTK_IM_MODULE=""
@ -377,18 +378,20 @@ test_display_mode(){
fi fi
} }
check_architecture(){ check_architecture(){
local cpu=$(< /proc/cpuinfo grep "AMD Custom APU 0405") local cpu=$(< /proc/cpuinfo awk -F": " '/AMD Custom APU [0-9]{4}$/ {print $2; exit}')
if [[ -n "$cpu" ]]; then read -a APU_MODEL <<< "$cpu"
if [[ $(test_display_mode) == "gm" ]]; then if [[ ${APU_MODEL[3]} != "0932" ]] && [[ ${APU_MODEL[3]} != "0405" ]]; then
is_steam_deck=2
else
is_steam_deck=1
fi
logger INFO "Setting architecture to 'Steam Deck'"
else
is_steam_deck=0 is_steam_deck=0
logger INFO "Setting architecture to 'desktop'" logger INFO "Setting architecture to 'desktop'"
return
fi 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(){ check_map_count(){
[[ $is_steam_deck -gt 0 ]] && return 0 [[ $is_steam_deck -gt 0 ]] && return 0
@ -531,14 +534,39 @@ fetch_dzq(){
curl -Ls "$url" > "$file" curl -Ls "$url" > "$file"
logger INFO "Updated DZQ to sha '$sha'" 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(){ fetch_helpers_by_sum(){
[[ -f "$config_file" ]] && source "$config_file" [[ -f "$config_file" ]] && source "$config_file"
declare -A sums declare -A sums
sums=( sums=(
["ui.py"]="f14772424461ec438579dec567db0634" ["ui.py"]="819a30c43644817a4f4a009f3df52b77"
["query_v2.py"]="1822bd1769ce7d7cb0d686a60f9fa197" ["query_v2.py"]="55d339ba02512ac69de288eb3be41067"
["vdf2json.py"]="2f49f6f5d3af919bebaab2e9c220f397" ["vdf2json.py"]="2f49f6f5d3af919bebaab2e9c220f397"
["funcs"]="37ae407ac397f6775f3a412e7adb7840" ["funcs"]="e1998f02f17776ccf2108fe5e9396d75"
["lan"]="c62e84ddd1457b71a85ad21da662b9af"
) )
local author="aclist" local author="aclist"
local repo="dztui" local repo="dztui"
@ -576,6 +604,7 @@ fetch_helpers_by_sum(){
logger INFO "Updated '$full_path' to sum '$sum'" logger INFO "Updated '$full_path' to sum '$sum'"
fi fi
[[ $file == "funcs" ]] && chmod +x "$full_path" [[ $file == "funcs" ]] && chmod +x "$full_path"
[[ $file == "lan" ]] && chmod +x "$full_path"
done done
return 0 return 0
} }
@ -600,6 +629,7 @@ fetch_helpers(){
fetch_geo_file fetch_geo_file
fetch_helpers_by_sum fetch_helpers_by_sum
[[ ! -f $share_path/icon.png ]] && freedesktop_dirs [[ ! -f $share_path/icon.png ]] && freedesktop_dirs
fetch_icons
} }
raise_error_and_quit(){ raise_error_and_quit(){
local msg="$1" local msg="$1"
@ -655,7 +685,9 @@ find_default_path(){
debian_path="$HOME/.steam/debian-installation" debian_path="$HOME/.steam/debian-installation"
flatpak_path="$HOME/.var/app/com.valvesoftware.Steam/data/Steam" flatpak_path="$HOME/.var/app/com.valvesoftware.Steam/data/Steam"
for i in "$def_path" "$ubuntu_path" "$debian_path" "$flatpak_path"; do #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 if [[ -d "$i" ]]; then
default_steam_path="$i" default_steam_path="$i"
return 0 return 0
@ -776,7 +808,7 @@ varcheck(){
source "$config_file" source "$config_file"
local workshop_dir="$steam_path/steamapps/workshop/content/$aid" local workshop_dir="$steam_path/steamapps/workshop/content/$aid"
local game_dir="$steam_path/steamapps/common/DayZ" local game_dir="$steam_path/steamapps/common/DayZ"
if [[ ! -d $steam_path ]] || [[ ! -d $game_dir ]]; then if [[ ! -d $steam_path ]] || [[ ! -d $game_dir ]] || [[ ! $(find $game_dir -type f) ]]; then
logger WARN "DayZ path resolved to '$game_dir'" logger WARN "DayZ path resolved to '$game_dir'"
logger WARN "Workshop path resolved to '$workshop_dir'" logger WARN "Workshop path resolved to '$workshop_dir'"
qdialog "$msg2" "Yes" "Exit" qdialog "$msg2" "Yes" "Exit"
@ -892,7 +924,7 @@ uninstall(){
} }
main(){ main(){
local zenv=$(zenity --version 2>/dev/null) local zenv=$(zenity --version 2>/dev/null)
[[ -z $zenv ]] && { echo "Requires zenity <= 3.44.1"; exit 1; } [[ -z $zenv ]] && { echo "Requires zenity >= ${deps[$steamsafe_zenity]}"; exit 1; }
if [[ $1 == "--uninstall" ]] || [[ $1 == "-u" ]]; then if [[ $1 == "--uninstall" ]] || [[ $1 == "-u" ]]; then
uninstall && uninstall &&
exit 0 exit 0

View file

@ -1,6 +1,6 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -o pipefail set -o pipefail
version=5.2.3 version=5.3.0
#CONSTANTS #CONSTANTS
aid=221100 aid=221100
@ -44,6 +44,7 @@ _cache_launch="$cache_dir/$prefix.launch_mods"
_cache_address="$cache_dir/$prefix.launch_address" _cache_address="$cache_dir/$prefix.launch_address"
_cache_coords="$cache_path/$prefix.coords" _cache_coords="$cache_path/$prefix.coords"
_cache_cooldown="$cache_path/$prefix.cooldown" _cache_cooldown="$cache_path/$prefix.cooldown"
_cache_lan="$cache_path/$prefix.lan"
#XDG #XDG
freedesktop_path="$HOME/.local/share/applications" freedesktop_path="$HOME/.local/share/applications"
@ -55,6 +56,7 @@ km_helper="$helpers_path/latlon"
sums_path="$helpers_path/sums.md5" sums_path="$helpers_path/sums.md5"
query_helper="$helpers_path/query_v2.py" query_helper="$helpers_path/query_v2.py"
func_helper="$helpers_path/funcs" func_helper="$helpers_path/funcs"
lan_helper="$helpers_path/lan"
#STEAM PATHS #STEAM PATHS
workshop_path="$steam_path/steamapps/workshop" workshop_path="$steam_path/steamapps/workshop"
@ -125,8 +127,19 @@ declare -A funcs=(
["force_update"]="force_update" ["force_update"]="force_update"
["Handshake"]="final_handshake" ["Handshake"]="final_handshake"
["get_player_count"]="get_player_count" ["get_player_count"]="get_player_count"
["lan_scan"]="lan_scan"
) )
lan_scan(){
local port="$1"
local res
res=$("$lan_helper" "$port")
if [[ -z $res ]]; then
printf "\n"
else
printf "%s\n" "$res"
fi
}
get_player_count(){ get_player_count(){
shift shift
local res local res
@ -521,7 +534,7 @@ parse_server_json(){
"\(if .gametype == null then "null" else (.gametype as $time|$time|test("[0-9]{2}:[0-9]{2}$") as $match|(if $match == true then ($time|scan("[0-9]{2}:[0-9]{2}$")) else "XXXX" end)) end)␞" + "\(if .gametype == null then "null" else (.gametype as $time|$time|test("[0-9]{2}:[0-9]{2}$") as $match|(if $match == true then ($time|scan("[0-9]{2}:[0-9]{2}$")) else "XXXX" end)) end)␞" +
"\(.players)␞" + "\(.players)␞" +
"\(.max_players)␞" + "\(.max_players)␞" +
"\(if .gametype == null then "0" else .gametype|split("lqs")[1]|split(",")[0] end)␞" + "\(if .gametype == null then "0" elif .gametype|split("lqs")[1] == null then "0" else .gametype|split("lqs")[1]|split(",")[0] end)␞" +
"\(.addr|split(":")[0]):\(if .gameport == null then "XXXX" else .gameport end)␞" + "\(.addr|split(":")[0]):\(if .gameport == null then "XXXX" else .gameport end)␞" +
"\(.addr|split(":")[1])" "\(.addr|split(":")[1])"
' | sort -k1 ' | sort -k1
@ -589,6 +602,16 @@ dump_servers(){
_iterate "$file" "${iters[@]}" _iterate "$file" "${iters[@]}"
fi fi
;; ;;
*Scan[[:space:]]LAN[[:space:]]servers*)
local port=$(<<< "$subcontext" awk -F: '{print $2}')
local file="$_cache_lan"
if [[ ! $subcontext =~ Name ]]; then
[[ -f $file ]] && rm $file
local lan=$(lan_scan $port)
readarray -t iters <<< "$lan"
_iterate "$file" "${iters[@]}"
fi
;;
esac esac
shift shift
logger INFO "Server context is '$subcontext', reading from file '$file'" logger INFO "Server context is '$subcontext', reading from file '$file'"
@ -955,6 +978,7 @@ generate_log(){
cat <<-DOC > $system_log cat <<-DOC > $system_log
Distro: $(< /etc/os-release grep -w NAME | awk -F\" '{print $2}') Distro: $(< /etc/os-release grep -w NAME | awk -F\" '{print $2}')
Kernel: $(uname -mrs) Kernel: $(uname -mrs)
CPU: $(< /proc/cpuinfo awk -F": " '/model name/ {print $2; exit}')
Version: $version Version: $version
Branch: $branch Branch: $branch
Mode: $(if [[ -z $debug ]]; then echo normal; else echo debug; fi) Mode: $(if [[ -z $debug ]]; then echo normal; else echo debug; fi)
@ -988,8 +1012,6 @@ query_defunct(){
-d "$(payload)" 'https://api.steampowered.com/ISteamRemoteStorage/GetPublishedFileDetails/v1/?format=json' -d "$(payload)" 'https://api.steampowered.com/ISteamRemoteStorage/GetPublishedFileDetails/v1/?format=json'
} }
local result=$(post | jq -r '.[].publishedfiledetails[] | select(.result==1) | "\(.file_size) \(.publishedfileid)"') local result=$(post | jq -r '.[].publishedfiledetails[] | select(.result==1) | "\(.file_size) \(.publishedfileid)"')
local result2=$(post | jq -r '')
echo "$result2" > $HOME/json
<<< "$result" awk '{print $2}' <<< "$result" awk '{print $2}'
} }
encode(){ encode(){
@ -1287,7 +1309,7 @@ launch(){
update_symlinks update_symlinks
if [[ $debug -eq 1 ]]; then if [[ $debug -eq 1 ]]; then
local launch_options="$steam_cmd -applaunch $aid -connect=$ip:$gameport -nolauncher -nosplash -name=$name -skipintro \"-mod=$concat\"" local launch_options="$steam_cmd -applaunch $aid -connect=$ip:$gameport -nolauncher -nosplash -name=$name -skipintro -mod=$concat"
printf "Debug mode: these options would have been used to launch the game: $launch_options" printf "Debug mode: these options would have been used to launch the game: $launch_options"
return 0 return 0
fi fi
@ -1307,11 +1329,19 @@ final_handshake(){
return 1 return 1
fi fi
logger INFO "Kicking off Steam launch" logger INFO "Kicking off Steam launch"
$steam_cmd -applaunch $aid -connect=$saved_address -nolauncher -nosplash -skipintro -name=$name \"-mod=$saved_mods\" & local params=()
params+=("-connect=$saved_address")
params+=("-nolauncher")
params+=("-nosplash")
params+=("-skipintro")
params+=("-name=$name")
params+=("-mod=$saved_mods")
$steam_cmd -applaunch $aid "${params[@]}" &
until [[ $(is_dayz_running) -eq 1 ]]; do until [[ $(is_dayz_running) -eq 1 ]]; do
sleep 0.1s sleep 0.1s
done done
logger INFO "Caught DayZ process" logger INFO "Caught DayZ process"
printf "\n"
return 6 return 6
} }
manual_mod_install(){ manual_mod_install(){

46
helpers/lan Executable file
View file

@ -0,0 +1,46 @@
#!/usr/bin/env bash
query_name(){
local ip="$1"
local port="$2"
local api="$HOME/.local/share/dzgui/helpers/query_v2.py"
python3 "$api" "$ip" "$port" test
}
scan(){
local ip="$1"
local port="$2"
local res=$(query_name "$ip" "$port")
[[ -z $res ]] && return 1
printf "%s\n" "${ip}:XXX:${port}"
}
get_netmask(){
ip r \
| awk '/default/ {print $3}' \
| uniq \
| awk -F. 'OFS="."{print $1,$2,$3}'
}
iter(){
_testping(){
ping -c1 -i 0.1 -w 1 "$1" 2>/dev/null 1>&2
[[ $? -eq 0 ]] && echo "$1"
}
export -f _testping
local mask=$(get_netmask)
# GNU parallel is not available OOTB on Steam Deck
for i in $(seq 1 255); do
echo "${mask}.${i}"
done | xargs -I {} -P 200 bash -c '_testping "{}"'
}
export -f scan
export -f query_name
DZG_LAN_PORT="$1"
readarray -t ips < <(iter)
for i in "${ips[@]}"; do
scan "$i" $DZG_LAN_PORT
done

View file

@ -5,6 +5,14 @@ import json
from a2s import dayzquery from a2s import dayzquery
sys.path.append('a2s') sys.path.append('a2s')
def test_local(ip, qport):
try:
info = a2s.info((ip, int(qport)), 0.5)
name = info.server_name
print(name)
except:
sys.exit(1)
def get_info(ip, qport): def get_info(ip, qport):
try: try:
info = a2s.info((ip, int(qport))) info = a2s.info((ip, int(qport)))
@ -73,3 +81,5 @@ match mode:
get_rules(ip, qport) get_rules(ip, qport)
case "names": case "names":
get_names(ip, qport) get_names(ip, qport)
case "test":
test_local(ip, qport)

View file

@ -17,8 +17,9 @@ import time
locale.setlocale(locale.LC_ALL, '') locale.setlocale(locale.LC_ALL, '')
gi.require_version("Gtk", "3.0") gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, GLib, Gdk, GObject, Pango from gi.repository import Gtk, GLib, Gdk, GObject, Pango
from enum import Enum
# 5.2.3 # 5.3.0
app_name = "DZGUI" app_name = "DZGUI"
start_time = 0 start_time = 0
@ -91,7 +92,8 @@ connect = [
("Quick-connect to favorite server",), ("Quick-connect to favorite server",),
("Recent servers",), ("Recent servers",),
("Connect by IP",), ("Connect by IP",),
("Connect by ID",) ("Connect by ID",),
("Scan LAN servers",)
] ]
manage = [ manage = [
("Add server by IP",), ("Add server by IP",),
@ -143,6 +145,7 @@ status_tooltip = {
"Recent servers": "Shows the last 10 servers you connected to (includes attempts)", "Recent servers": "Shows the last 10 servers you connected to (includes attempts)",
"Connect by IP": "Connect to a server by IP", "Connect by IP": "Connect to a server by IP",
"Connect by ID": "Connect to a server by Battlemetrics ID", "Connect by ID": "Connect to a server by Battlemetrics ID",
"Scan LAN servers": "Search for servers on your local network",
"Add server by IP": "Add a server by IP", "Add server by IP": "Add a server by IP",
"Add server by ID": "Add a server by Battlemetrics ID", "Add server by ID": "Add a server by Battlemetrics ID",
"Change favorite server": "Update your quick-connect server", "Change favorite server": "Update your quick-connect server",
@ -570,10 +573,16 @@ class ButtonBox(Gtk.Box):
renderer = Gtk.CellRendererText() renderer = Gtk.CellRendererText()
column = Gtk.TreeViewColumn(column_title, renderer, text=i) column = Gtk.TreeViewColumn(column_title, renderer, text=i)
treeview.append_column(column) treeview.append_column(column)
self._populate(context)
treeview.set_model(row_store) treeview.set_model(row_store)
treeview.grab_focus() treeview.grab_focus()
def _populate(self, array_context): def _populate(self, context):
match context:
case 'Manage': array_context = manage
case 'Main menu': array_context = connect
case 'Options': array_context = options
case 'Help': array_context = help
row_store.clear() row_store.clear()
status = array_context[0][0] status = array_context[0][0]
treeview = self.get_treeview() treeview = self.get_treeview()
@ -593,6 +602,7 @@ class ButtonBox(Gtk.Box):
if context == "Exit": if context == "Exit":
logger.info("Normal user exit") logger.info("Normal user exit")
Gtk.main_quit() Gtk.main_quit()
return
cols = treeview.get_columns() cols = treeview.get_columns()
if len(cols) > 1: if len(cols) > 1:
@ -606,11 +616,7 @@ class ButtonBox(Gtk.Box):
for col in cols: for col in cols:
col.set_title(context) col.set_title(context)
match context: self._populate(context)
case 'Manage': self._populate(manage)
case 'Main menu': self._populate(connect)
case 'Options': self._populate(options)
case 'Help': self._populate(help)
toggle_signal(treeview, treeview.selected_row, '_on_tree_selection_changed', True) toggle_signal(treeview, treeview.selected_row, '_on_tree_selection_changed', True)
@ -1069,6 +1075,17 @@ class TreeView(Gtk.TreeView):
toggle_signal(self.get_outer_grid().right_panel.filters_vbox, check, '_on_check_toggle', True) toggle_signal(self.get_outer_grid().right_panel.filters_vbox, check, '_on_check_toggle', True)
toggle_signal(self, self, '_on_keypress', True) toggle_signal(self, self, '_on_keypress', True)
if mode == "Scan LAN servers":
lan_dialog = LanButtonDialog(self.get_outer_window())
port = lan_dialog.get_selected_port()
if port is None:
grid = self.get_outer_grid()
right_panel = grid.right_panel
vbox = right_panel.button_vbox
vbox._update_single_column("Main menu")
return
mode = mode + ":" + port
wait_dialog = GenericDialog(transient_parent, "Fetching server metadata", "WAIT") wait_dialog = GenericDialog(transient_parent, "Fetching server metadata", "WAIT")
wait_dialog.show_all() wait_dialog.show_all()
thread = threading.Thread(target=self._background, args=(wait_dialog, mode)) thread = threading.Thread(target=self._background, args=(wait_dialog, mode))
@ -1170,7 +1187,7 @@ class TreeView(Gtk.TreeView):
right_panel = outer.grid.right_panel right_panel = outer.grid.right_panel
filters_vbox = right_panel.filters_vbox filters_vbox = right_panel.filters_vbox
valid_contexts = ["Server browser", "My saved servers", "Recent servers"] valid_contexts = ["Server browser", "My saved servers", "Recent servers", "Scan LAN servers"]
if chosen_row in valid_contexts: if chosen_row in valid_contexts:
# server contexts share the same model type # server contexts share the same model type
for check in checks: for check in checks:
@ -1304,6 +1321,10 @@ class AppHeaderBar(Gtk.HeaderBar):
self.set_decoration_layout("menu:minimize,maximize,close") self.set_decoration_layout("menu:minimize,maximize,close")
self.set_show_close_button(True) self.set_show_close_button(True)
class Port(Enum):
# Contains enums for LanButtonDialog ports
DEFAULT = 1
CUSTOM = 2
class GenericDialog(Gtk.MessageDialog): class GenericDialog(Gtk.MessageDialog):
def __init__(self, parent, text, mode): def __init__(self, parent, text, mode):
@ -1361,6 +1382,140 @@ class GenericDialog(Gtk.MessageDialog):
self.format_secondary_text(text) self.format_secondary_text(text)
class LanButtonDialog(Gtk.Window):
def __init__(self, parent):
super().__init__()
self.buttonBox = Gtk.Box()
header_label = "Scan LAN servers"
buttons = [
( "Use default query port (27016)", Port.DEFAULT ),
( "Enter custom query port", Port.CUSTOM ),
]
self.buttonBox.set_orientation(Gtk.Orientation.VERTICAL)
self.buttonBox.active_button = None
for i in enumerate(buttons):
string = i[1][0]
enum = i[1][1]
button = Gtk.RadioButton(label=string)
button.port = enum
button.connect("toggled", self._on_button_toggled)
if i[0] == 0:
self.buttonBox.active_button = button
else:
button.join_group(self.buttonBox.active_button)
self.buttonBox.add(button)
self.entry = Gtk.Entry()
self.buttonBox.add(self.entry)
self.entry.set_no_show_all(True)
self.label = Gtk.Label()
self.label.set_text("Invalid port")
self.label.set_no_show_all(True)
self.buttonBox.add(self.label)
self.dialog = LanDialog(parent, header_label, self.buttonBox, self.entry, self.label)
self.dialog.run()
self.dialog.destroy()
def get_selected_port(self):
return self.dialog.p
def _on_button_toggled(self, button):
if button.get_active():
self.buttonBox.active_button = button
match button.port:
case Port.DEFAULT:
self.entry.set_visible(False)
case Port.CUSTOM:
self.entry.set_visible(True)
self.entry.grab_focus()
def get_active_button():
return self.buttonBox.active_button
class LanDialog(Gtk.MessageDialog):
# Custom dialog class that performs integer validation and blocks input if invalid port
# Returns None if user cancels the dialog
def __init__(self, parent, text, child, entry, label):
super().__init__(transient_for=parent,
flags=0,
message_type=Gtk.MessageType.INFO,
buttons=Gtk.ButtonsType.OK_CANCEL,
text=text,
secondary_text="Select the query port",
title=app_name,
modal=True,
)
self.outer = self.get_content_area()
self.outer.pack_start(child, False, False, 0)
self.set_position(Gtk.WindowPosition.CENTER_ON_PARENT)
self.set_size_request(500, 0)
self.outer.set_margin_start(30)
self.outer.set_margin_end(30)
self.outer.show_all()
self.connect("response", self._on_dialog_response, child, entry)
self.connect("key-press-event", self._on_keypress, entry)
self.connect("key-release-event", self._on_key_release, entry, label)
self.child = child
self.p = None
def _on_key_release(self, dialog, event, entry, label):
label.set_visible(False)
if entry.is_visible() == False or entry.get_text() == "":
return
if self._is_invalid(entry.get_text()):
label.set_visible(True)
else:
label.set_visible(False)
def _on_keypress(self, a, event, entry):
if event.keyval == Gdk.KEY_Return:
self.response(Gtk.ResponseType.OK)
if event.keyval == Gdk.KEY_Up:
entry.set_text("")
self.child.get_children()[0].grab_focus()
def _on_dialog_response(self, dialog, resp, child, entry):
match resp:
case Gtk.ResponseType.CANCEL:
return
case Gtk.ResponseType.DELETE_EVENT:
return
string = entry.get_text()
port = child.active_button.port
match port:
case Port.DEFAULT:
self.p = "27016"
case Port.CUSTOM:
if self._is_invalid(string):
self.stop_emission_by_name("response")
else:
self.p = string
def _is_invalid(self, string):
if string.isdigit() == False \
or int(string) == 0 \
or int(string[0]) == 0 \
or int(string) > 65535:
return True
return False
def ChangelogDialog(parent, text, mode): def ChangelogDialog(parent, text, mode):
dialog = GenericDialog(parent, text, mode) dialog = GenericDialog(parent, text, mode)
@ -1657,7 +1812,9 @@ class App(Gtk.Application):
is_steam_deck = False is_steam_deck = False
is_game_mode = False is_game_mode = False
GLib.set_prgname(app_name)
self.win = OuterWindow(is_steam_deck, is_game_mode) self.win = OuterWindow(is_steam_deck, is_game_mode)
self.win.set_icon_name("dzgui")
accel = Gtk.AccelGroup() accel = Gtk.AccelGroup()
accel.connect(Gdk.KEY_q, Gdk.ModifierType.CONTROL_MASK, Gtk.AccelFlags.VISIBLE, self._halt_window_subprocess) accel.connect(Gdk.KEY_q, Gdk.ModifierType.CONTROL_MASK, Gtk.AccelFlags.VISIBLE, self._halt_window_subprocess)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 497 KiB

After

Width:  |  Height:  |  Size: 459 KiB

BIN
images/icons/128.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

BIN
images/icons/16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 KiB

BIN
images/icons/24.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
images/icons/256.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

BIN
images/icons/32.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

BIN
images/icons/48.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

BIN
images/icons/64.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

BIN
images/icons/96.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB