Merge pull request #151 from aclist/release/5.3.0-backports
Release/5.3.0 backports
16
CHANGELOG.md
|
@ -1,5 +1,21 @@
|
|||
# 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
|
||||
### Added
|
||||
- Uninstall routine: invoke via dzgui.sh -u or dzgui.sh --uninstall and choose from full or partial uninstall
|
||||
|
|
|
@ -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
|
||||
|
||||
Looking for the DZGUI Knowledge Base? Click https://aclist.github.io/dzgui/kb.html[here]
|
||||
|
||||
== What this is
|
||||
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
|
||||
|
@ -100,11 +102,14 @@ Enable a Proton version ≥ `6.8` (or use Proton Experimental) in the `Compatibi
|
|||
|
||||
=== API key & server IDs
|
||||
|
||||
==== Steam 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.
|
||||
==== Steam Web API key (required)
|
||||
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.
|
||||
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)
|
||||
|
||||
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
|
||||
|
||||
.Mods take a long time to synchronize when subscribing from Workshop
|
||||
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.
|
||||
|
||||
Please refer to the https://aclist.github.io/dzgui/kb.html[DZGUI Knowledge Base] for common issues.
|
||||
|
||||
== Reference
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
Looking for the DZGUI Knowledge Base? Click https://aclist.github.io/dzgui/kb_dark.html[here]
|
||||
|
||||
== What this is
|
||||
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
|
||||
|
@ -100,11 +102,14 @@ Enable a Proton version ≥ `6.8` (or use Proton Experimental) in the `Compatibi
|
|||
|
||||
=== API key & server IDs
|
||||
|
||||
==== Steam 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.
|
||||
==== Steam Web API key (required)
|
||||
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.
|
||||
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)
|
||||
|
||||
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
|
||||
|
||||
.Mods take a long time to synchronize when subscribing from Workshop
|
||||
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.
|
||||
|
||||
Please refer to the https://aclist.github.io/dzgui/kb.html[DZGUI Knowledge Base] for common issues.
|
||||
|
||||
== Reference
|
||||
|
||||
|
|
28
docs/kb.adoc
Normal 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
|
@ -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[]
|
11
docs/kb_sections/dzg001.adoc
Normal 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.
|
5
docs/kb_sections/dzg002.adoc
Normal 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>>.
|
7
docs/kb_sections/dzg003.adoc
Normal 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.
|
7
docs/kb_sections/dzg004.adoc
Normal 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.
|
7
docs/kb_sections/dzg005.adoc
Normal 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.
|
11
docs/kb_sections/dzg006.adoc
Normal 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.
|
17
docs/kb_sections/dzg007.adoc
Normal 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.
|
7
docs/kb_sections/dzg008.adoc
Normal 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.
|
5
docs/kb_sections/dzg009.adoc
Normal 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.
|
66
dzgui.sh
|
@ -1,7 +1,7 @@
|
|||
#!/usr/bin/env bash
|
||||
set -o pipefail
|
||||
|
||||
version=5.3.1
|
||||
version=5.3.0
|
||||
|
||||
#CONSTANTS
|
||||
aid=221100
|
||||
|
@ -13,7 +13,7 @@ sd_res="--width=1280 --height=800"
|
|||
steamsafe_zenity="/usr/bin/zenity"
|
||||
zenity_flags=("--width=500" "--title=DZGUI")
|
||||
declare -A deps
|
||||
deps=([awk]="5.1.1" [curl]="7.80.0" [jq]="1.6" [tr]="9.0" [$steamsafe_zenity]="3.42.1")
|
||||
deps=([awk]="5.1.1" [curl]="7.80.0" [jq]="1.6" [tr]="9.0" [$steamsafe_zenity]="3.44.1")
|
||||
|
||||
#CONFIG
|
||||
config_path="$HOME/.config/dztui"
|
||||
|
@ -65,6 +65,7 @@ km_helper_url="$releases_url/latlon"
|
|||
geo_file_url="$releases_url/ips.csv.gz"
|
||||
|
||||
set_im_module(){
|
||||
#TODO: drop pending SteamOS changes
|
||||
pgrep -a gamescope | grep -q "generate-drm-mode"
|
||||
if [[ $? -eq 0 ]]; then
|
||||
GTK_IM_MODULE=""
|
||||
|
@ -377,18 +378,20 @@ test_display_mode(){
|
|||
fi
|
||||
}
|
||||
check_architecture(){
|
||||
local cpu=$(< /proc/cpuinfo grep "AMD Custom APU 0405")
|
||||
if [[ -n "$cpu" ]]; then
|
||||
if [[ $(test_display_mode) == "gm" ]]; then
|
||||
is_steam_deck=2
|
||||
else
|
||||
is_steam_deck=1
|
||||
fi
|
||||
logger INFO "Setting architecture to 'Steam Deck'"
|
||||
else
|
||||
local cpu=$(< /proc/cpuinfo awk -F": " '/AMD Custom APU [0-9]{4}$/ {print $2; exit}')
|
||||
read -a APU_MODEL <<< "$cpu"
|
||||
if [[ ${APU_MODEL[3]} != "0932" ]] && [[ ${APU_MODEL[3]} != "0405" ]]; then
|
||||
is_steam_deck=0
|
||||
logger INFO "Setting architecture to 'desktop'"
|
||||
return
|
||||
fi
|
||||
|
||||
if [[ $(test_display_mode) == "gm" ]]; then
|
||||
is_steam_deck=2
|
||||
else
|
||||
is_steam_deck=1
|
||||
fi
|
||||
logger INFO "Setting architecture to 'Steam Deck'"
|
||||
}
|
||||
check_map_count(){
|
||||
[[ $is_steam_deck -gt 0 ]] && return 0
|
||||
|
@ -531,14 +534,39 @@ fetch_dzq(){
|
|||
curl -Ls "$url" > "$file"
|
||||
logger INFO "Updated DZQ to sha '$sha'"
|
||||
}
|
||||
fetch_icons(){
|
||||
res=(
|
||||
"16"
|
||||
"24"
|
||||
"32"
|
||||
"48"
|
||||
"64"
|
||||
"96"
|
||||
"128"
|
||||
"256"
|
||||
)
|
||||
url="$stable_url/images/icons"
|
||||
for i in "${res[@]}"; do
|
||||
size="${i}x${i}"
|
||||
dir="$HOME/.local/share/icons/hicolor/$size/apps"
|
||||
icon="$dir/$app_name.png"
|
||||
[[ -f $icon ]] && return
|
||||
if [[ ! -d $dir ]]; then
|
||||
mkdir -p "$dir"
|
||||
fi
|
||||
logger INFO "Updating $size Freedesktop icon"
|
||||
curl -Ls "${url}/${i}.png" > "$icon"
|
||||
done
|
||||
}
|
||||
fetch_helpers_by_sum(){
|
||||
[[ -f "$config_file" ]] && source "$config_file"
|
||||
declare -A sums
|
||||
sums=(
|
||||
["ui.py"]="f14772424461ec438579dec567db0634"
|
||||
["query_v2.py"]="1822bd1769ce7d7cb0d686a60f9fa197"
|
||||
["ui.py"]="819a30c43644817a4f4a009f3df52b77"
|
||||
["query_v2.py"]="55d339ba02512ac69de288eb3be41067"
|
||||
["vdf2json.py"]="2f49f6f5d3af919bebaab2e9c220f397"
|
||||
["funcs"]="37ae407ac397f6775f3a412e7adb7840"
|
||||
["funcs"]="e1998f02f17776ccf2108fe5e9396d75"
|
||||
["lan"]="c62e84ddd1457b71a85ad21da662b9af"
|
||||
)
|
||||
local author="aclist"
|
||||
local repo="dztui"
|
||||
|
@ -576,6 +604,7 @@ fetch_helpers_by_sum(){
|
|||
logger INFO "Updated '$full_path' to sum '$sum'"
|
||||
fi
|
||||
[[ $file == "funcs" ]] && chmod +x "$full_path"
|
||||
[[ $file == "lan" ]] && chmod +x "$full_path"
|
||||
done
|
||||
return 0
|
||||
}
|
||||
|
@ -600,6 +629,7 @@ fetch_helpers(){
|
|||
fetch_geo_file
|
||||
fetch_helpers_by_sum
|
||||
[[ ! -f $share_path/icon.png ]] && freedesktop_dirs
|
||||
fetch_icons
|
||||
}
|
||||
raise_error_and_quit(){
|
||||
local msg="$1"
|
||||
|
@ -655,7 +685,9 @@ find_default_path(){
|
|||
debian_path="$HOME/.steam/debian-installation"
|
||||
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
|
||||
default_steam_path="$i"
|
||||
return 0
|
||||
|
@ -776,7 +808,7 @@ varcheck(){
|
|||
source "$config_file"
|
||||
local workshop_dir="$steam_path/steamapps/workshop/content/$aid"
|
||||
local game_dir="$steam_path/steamapps/common/DayZ"
|
||||
if [[ ! -d $steam_path ]] || [[ ! -d $game_dir ]]; then
|
||||
if [[ ! -d $steam_path ]] || [[ ! -d $game_dir ]] || [[ ! $(find $game_dir -type f) ]]; then
|
||||
logger WARN "DayZ path resolved to '$game_dir'"
|
||||
logger WARN "Workshop path resolved to '$workshop_dir'"
|
||||
qdialog "$msg2" "Yes" "Exit"
|
||||
|
@ -892,7 +924,7 @@ uninstall(){
|
|||
}
|
||||
main(){
|
||||
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
|
||||
uninstall &&
|
||||
exit 0
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#!/usr/bin/env bash
|
||||
set -o pipefail
|
||||
version=5.2.3
|
||||
version=5.3.0
|
||||
|
||||
#CONSTANTS
|
||||
aid=221100
|
||||
|
@ -44,6 +44,7 @@ _cache_launch="$cache_dir/$prefix.launch_mods"
|
|||
_cache_address="$cache_dir/$prefix.launch_address"
|
||||
_cache_coords="$cache_path/$prefix.coords"
|
||||
_cache_cooldown="$cache_path/$prefix.cooldown"
|
||||
_cache_lan="$cache_path/$prefix.lan"
|
||||
|
||||
#XDG
|
||||
freedesktop_path="$HOME/.local/share/applications"
|
||||
|
@ -55,6 +56,7 @@ km_helper="$helpers_path/latlon"
|
|||
sums_path="$helpers_path/sums.md5"
|
||||
query_helper="$helpers_path/query_v2.py"
|
||||
func_helper="$helpers_path/funcs"
|
||||
lan_helper="$helpers_path/lan"
|
||||
|
||||
#STEAM PATHS
|
||||
workshop_path="$steam_path/steamapps/workshop"
|
||||
|
@ -125,8 +127,19 @@ declare -A funcs=(
|
|||
["force_update"]="force_update"
|
||||
["Handshake"]="final_handshake"
|
||||
["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(){
|
||||
shift
|
||||
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)␞" +
|
||||
"\(.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(":")[1])"
|
||||
' | sort -k1
|
||||
|
@ -589,6 +602,16 @@ dump_servers(){
|
|||
_iterate "$file" "${iters[@]}"
|
||||
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
|
||||
shift
|
||||
logger INFO "Server context is '$subcontext', reading from file '$file'"
|
||||
|
@ -955,6 +978,7 @@ generate_log(){
|
|||
cat <<-DOC > $system_log
|
||||
Distro: $(< /etc/os-release grep -w NAME | awk -F\" '{print $2}')
|
||||
Kernel: $(uname -mrs)
|
||||
CPU: $(< /proc/cpuinfo awk -F": " '/model name/ {print $2; exit}')
|
||||
Version: $version
|
||||
Branch: $branch
|
||||
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'
|
||||
}
|
||||
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}'
|
||||
}
|
||||
encode(){
|
||||
|
@ -1287,7 +1309,7 @@ launch(){
|
|||
|
||||
update_symlinks
|
||||
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"
|
||||
return 0
|
||||
fi
|
||||
|
@ -1307,11 +1329,19 @@ final_handshake(){
|
|||
return 1
|
||||
fi
|
||||
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
|
||||
sleep 0.1s
|
||||
done
|
||||
logger INFO "Caught DayZ process"
|
||||
printf "\n"
|
||||
return 6
|
||||
}
|
||||
manual_mod_install(){
|
||||
|
|
46
helpers/lan
Executable 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
|
|
@ -5,6 +5,14 @@ import json
|
|||
from a2s import dayzquery
|
||||
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):
|
||||
try:
|
||||
info = a2s.info((ip, int(qport)))
|
||||
|
@ -73,3 +81,5 @@ match mode:
|
|||
get_rules(ip, qport)
|
||||
case "names":
|
||||
get_names(ip, qport)
|
||||
case "test":
|
||||
test_local(ip, qport)
|
||||
|
|
175
helpers/ui.py
|
@ -17,8 +17,9 @@ import time
|
|||
locale.setlocale(locale.LC_ALL, '')
|
||||
gi.require_version("Gtk", "3.0")
|
||||
from gi.repository import Gtk, GLib, Gdk, GObject, Pango
|
||||
from enum import Enum
|
||||
|
||||
# 5.2.3
|
||||
# 5.3.0
|
||||
app_name = "DZGUI"
|
||||
|
||||
start_time = 0
|
||||
|
@ -91,7 +92,8 @@ connect = [
|
|||
("Quick-connect to favorite server",),
|
||||
("Recent servers",),
|
||||
("Connect by IP",),
|
||||
("Connect by ID",)
|
||||
("Connect by ID",),
|
||||
("Scan LAN servers",)
|
||||
]
|
||||
manage = [
|
||||
("Add server by IP",),
|
||||
|
@ -143,6 +145,7 @@ status_tooltip = {
|
|||
"Recent servers": "Shows the last 10 servers you connected to (includes attempts)",
|
||||
"Connect by IP": "Connect to a server by IP",
|
||||
"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 ID": "Add a server by Battlemetrics ID",
|
||||
"Change favorite server": "Update your quick-connect server",
|
||||
|
@ -570,10 +573,16 @@ class ButtonBox(Gtk.Box):
|
|||
renderer = Gtk.CellRendererText()
|
||||
column = Gtk.TreeViewColumn(column_title, renderer, text=i)
|
||||
treeview.append_column(column)
|
||||
self._populate(context)
|
||||
treeview.set_model(row_store)
|
||||
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()
|
||||
status = array_context[0][0]
|
||||
treeview = self.get_treeview()
|
||||
|
@ -593,6 +602,7 @@ class ButtonBox(Gtk.Box):
|
|||
if context == "Exit":
|
||||
logger.info("Normal user exit")
|
||||
Gtk.main_quit()
|
||||
return
|
||||
cols = treeview.get_columns()
|
||||
|
||||
if len(cols) > 1:
|
||||
|
@ -606,11 +616,7 @@ class ButtonBox(Gtk.Box):
|
|||
for col in cols:
|
||||
col.set_title(context)
|
||||
|
||||
match context:
|
||||
case 'Manage': self._populate(manage)
|
||||
case 'Main menu': self._populate(connect)
|
||||
case 'Options': self._populate(options)
|
||||
case 'Help': self._populate(help)
|
||||
self._populate(context)
|
||||
|
||||
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, 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.show_all()
|
||||
thread = threading.Thread(target=self._background, args=(wait_dialog, mode))
|
||||
|
@ -1170,7 +1187,7 @@ class TreeView(Gtk.TreeView):
|
|||
right_panel = outer.grid.right_panel
|
||||
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:
|
||||
# server contexts share the same model type
|
||||
for check in checks:
|
||||
|
@ -1304,6 +1321,10 @@ class AppHeaderBar(Gtk.HeaderBar):
|
|||
self.set_decoration_layout("menu:minimize,maximize,close")
|
||||
self.set_show_close_button(True)
|
||||
|
||||
class Port(Enum):
|
||||
# Contains enums for LanButtonDialog ports
|
||||
DEFAULT = 1
|
||||
CUSTOM = 2
|
||||
|
||||
class GenericDialog(Gtk.MessageDialog):
|
||||
def __init__(self, parent, text, mode):
|
||||
|
@ -1361,6 +1382,140 @@ class GenericDialog(Gtk.MessageDialog):
|
|||
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):
|
||||
|
||||
dialog = GenericDialog(parent, text, mode)
|
||||
|
@ -1657,7 +1812,9 @@ class App(Gtk.Application):
|
|||
is_steam_deck = False
|
||||
is_game_mode = False
|
||||
|
||||
GLib.set_prgname(app_name)
|
||||
self.win = OuterWindow(is_steam_deck, is_game_mode)
|
||||
self.win.set_icon_name("dzgui")
|
||||
|
||||
accel = Gtk.AccelGroup()
|
||||
accel.connect(Gdk.KEY_q, Gdk.ModifierType.CONTROL_MASK, Gtk.AccelFlags.VISIBLE, self._halt_window_subprocess)
|
||||
|
|
BIN
images/icon.png
Before Width: | Height: | Size: 497 KiB After Width: | Height: | Size: 459 KiB |
BIN
images/icons/128.png
Normal file
After Width: | Height: | Size: 32 KiB |
BIN
images/icons/16.png
Normal file
After Width: | Height: | Size: 1 KiB |
BIN
images/icons/24.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
images/icons/256.png
Normal file
After Width: | Height: | Size: 118 KiB |
BIN
images/icons/32.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
BIN
images/icons/48.png
Normal file
After Width: | Height: | Size: 5.5 KiB |
BIN
images/icons/64.png
Normal file
After Width: | Height: | Size: 9.2 KiB |
BIN
images/icons/96.png
Normal file
After Width: | Height: | Size: 19 KiB |