Compare commits

..
1 Commits
Author SHA1 Message Date
Koloszár Gergely ac08239fd0 Merge e73617c2f4 into a94f8f0e32 2025-10-30 13:09:26 +09:00
10 changed files with 537 additions and 502 deletions

No files matched your search

-4
View File
@@ -5,10 +5,6 @@ labels: ["bug"]
assignees:
- aclist
body:
- type: markdown
attributes:
value: |
### WARNING: When posting log/config data, redact any sensitive information like API keys.
- type: checkboxes
id: kb
attributes:
-4
View File
@@ -5,10 +5,6 @@ labels: ["troubleshooting"]
assignees:
- aclist
body:
- type: markdown
attributes:
value: |
### WARNING: When posting log/config data, redact any sensitive information like API keys.
- type: dropdown
id: device
attributes:
-3
View File
@@ -1,4 +1 @@
tags
__pycache__
pre-commit
tests/
+286 -162
View File
@@ -1,67 +1,37 @@
# Changelog
## [6.0.2] 2026-01-26
## [6.0.0-beta.8] XXXX-XX-XX
## Added
- Flag to disable branch toggle for distro-packaged releases
- Test whether script was sourced inline
- Commandline usage help text
## Fixed
- Explicitly use Python 3.13 when calling subprocesses
- Raise error correctly from module
- Do not spawn dialogs from inside of thread when fetching prereqs
- ESC key destroying wait dialogs while thread is pending
- Tooltip signals being processed on main menu
- Leaky variable name in dialog title
- Prevent extraneous signals from propagating when column width is adjusted
- Script failing to start when remote endpoints are unavailable
## Changed
- Optimize time complexity of startup checks
- Optimize coordinate calculation by using local records first
- Rename some internal functions
- Wrap entire startup process in dialog
- Optimize time cost of setup checks
- Location of notes file
## [6.0.1] 2026-01-16
## Fixed
- Explicitly use Python 3.13 when calling subprocesses
## [6.0.0-beta.7] 2025-09-20
## Added
- Users can save text notes to describe servers
## [6.0.0] 2026-01-14
## Changed
- State file serialization methods
## [6.0.0-beta.6] 2025-09-12
## Added
- Support DayZ Experimental
- Ping display on server tables
- Save descriptive text notes on a per-server basis
- Speed up load time and navigation of server tables
- More robust threading and cache system when filtering servers
- Show additional DayZ client information in Options menu
- Warn user of DayZ client version mismatches
- Support clickable hyperlinks in dialogs
- Rich server metadata details dialog (right-click on server table)
- Filter by modded servers
- Breadcrumbs showing current menu context
- Dedicated changelog page
- Dedicated keybindings page
- Dedicated settings page ("Options")
- Support sandboxed version of Flatpak
- Vim-style navigation keybindings
- Added "Return to main menu" button to dialog windows when failing to load server table
- Dynamic context menus for modded servers
- Additional keybindings for new filter toggles
- If a server is locked, prompt user when connecting
- Internal flag to allow distro-packaged releases to disable in-app updates
- Pre-boot checks to test whether script was invoked directly
- Commandline usage help text (GaryBlackbourne)
- More descriptive help dialogs when initial dependencies are missing
- Show additional client information in Options menu
- Warn user of client version mismatches
- Support clickable hyperlinks
## Fixed
- Script failing to start when remote endpoints are unavailable (GaryBlackbourne)
- Key stickiness when quickly navigating through entries in tables
- Servers returning malformed A2S_INFO blocking server browser from loading
- Normalized buttons in dialogs and restored proper padding
- GTK errors being emitted to stdout when inserting debug table
- Entry dialog sensitivity when validating API keys
- Additional validation on entry dialogs to prevent submitting empty text
- Suppress errors during pre-boot checks when mods are not installed
- Centered filter checkboxes within panel
- Do not pop unhighlight/select stale buttons if no stale mods exist
- Improved keybinding interaction with side panels
- Suppress typeahead search in mod dialogs
- Do not trigger global API cooldown if no LAN/favorite servers are found
- Fix table column expansion in server mod dialogs
- Missing parameters when closing application via window decorations
- Statusbar contents not updating on certain pages
- Prevent debug button from activating when in certain input fields
- Window size not updating correctly when unmaximizing window after changing "fullscreen at boot" setting
- Branch toggle signal being emitted when entering Options menu from other contexts
- Mods rarely not appearing in local mod list if download completed too quickly
- Statusbar not updating when clicking a row after spamming keyboard input
- Extraneous logs being generated when subscribing to mods
@@ -69,188 +39,342 @@
- Newline terminators in history file
- Floating point number calculation
- Window resizing too small if no prior resolution was set
- ESC key destroying wait dialogs while a thread is pending
- Tooltip signals being erroneously emitted on main menu
- UI not being constructed correctly if CHANGELOG.md was missing
- Config file erroneously getting updated when populating settings menu
- Leaky variable name in dialog titles
- Prevent extraneous signals from propagating when column width is adjusted
- Server filter panel not being hidden when entering other page contexts
- Path to remote changelog being constructed incorrectly
- Dialogs with newlines breaking output in log table
- Path discovery during first-time setup when parsing filepaths with whitespaces
- First-time setup dialog continuously triggering when DayZ install path had whitespaces in it
## [6.0.0-beta.5] 2025-08-20
## Fixed
- Servers returning malformed A2S_INFO blocking server browser from loading
## [6.0.0-beta.4] 2025-08-13
## Fixed
- Branch toggle signal being emitted when entering Options menu from other contexts
## [6.0.0-beta.3] 2025-08-08
## Added
- Additional server metadata to details dialog
- Prompt user when connecting if a server is locked
- Dedicated settings page ("Options")
## Fixed
- Statusbar contents not updating on certain pages
- Breadcrumbs not updating when returning from keybindings page
- Wrap long descriptions in server details
- Prevent debug button from activating when in certain input fields
- Window size not updating correctly when unmaximizing window after changing "fullscreen at boot" setting
## Dropped
- Extraneous information from right statusbar
## [6.0.0-beta.2] 2025-07-29
## Fixed
- Missing parameters when closing application via window decorations
## [6.0.0-beta.1] 2025-07-29
## Added
- Ping column to server browsing contexts
- Server details dialog to server browsing contexts
- Filter by modded servers
- Breadcrumbs showing current menu context to top of window
- Speed up load time and navigation of server tables
- More robust threading and cache system when filtering servers
- Dedicated changelog page
- Dedicated keybindings page
- Vim-style navigation keybindings
- Additional validation on entry dialogs to prevent submitting empty text
- Added "Return to main menu" button to dialog windows when failing to load server table
- Dynamic context menus for modded servers
- Additional keybindings for filter toggles
## Fixed
- Entry dialog sensitivity when validating API keys
- Normalized buttons in dialogs and restored proper padding
- GTK errors being emitted to stdout when inserting debug table
- Suppress errors during pre-boot checks when mods are not installed
- Centered filter checkboxes within panel
- Do not pop unhighlight/select stale buttons if no stale mods exist
- Improved keybinding interaction with side panels
- Key stickiness when quickly navigating through entries in tables
- Suppress typeahead search in mod dialogs
- Do not trigger global API cooldown if no LAN/favorite servers are found
- Fix table column expansion in server mod dialogs
## Changed
- Require Python 3.13
- Reduced global API cooldown from 60s to 30s
- Clarify dialog messages when DayZ path could not be found
- Auto-focus first item when opening context menus
- Opacity setting on side buttons when in a different context
- Refactored BM API key validation to account for new key format
- State file serialization methods
- Optimize time complexity of pre-boot checks (GaryBlackbourne)
- Rewrote distance calculation module (GaryBlackbourne)
- Changed preferred client setting from radio toggle to combobox
## Dropped
- Ping readout in statusbar
- Extraneous information from right statusbar
## [5.8.3] 2026-01-04
## Fixed
- Normalize checksum numbers and dates
## [5.8.2] 2026-01-04
## Fixed
- Fix regression in symlink routine introduced by previous hotfix
## [5.8.1] 2025-12-27
## Fixed
- Path discovery during first-time setup when parsing filepaths with whitespaces
- First-time setup dialog continuously triggering when DayZ install path had whitespaces in it
## [5.8.0] 2025-07-06
## [5.8.0-beta.2] 2025-07-06
## Added
- Filter servers by official/unofficial status
- Automatically fetch geolocation records
## Changed
- Updated internal versioning of helper files
## [5.8.0-beta.1] 2025-06-05
## Added
- Automatically fetch geolocation records
## Fixed
- Corrected erroneous 2024 date in prior changelog entries
## [5.7.0] 2025-04-17
## Added
- Save application dimensions when quitting and restore on subsequent boot
## Fixed
- Issues with the window exceeding the bounds of the screen when displaying some table contexts
## [5.7.1-beta.1] 2025-04-17
## Changed
- More direct server ping query method that should return marginally more accurate times
- Updated geolocation records
## [5.6.7] 2025-04-04
## [5.7.0-beta.13] 2025-04-17
## Fixed
- Updated checksum for UI helper file
## [5.7.0-beta.12] 2025-04-04
## Dropped
- Removed extraneous pre-boot API checks that could cause error messages to be printed if the user had not set up an API key yet
## [5.6.6] 2025-03-16
## Changed
- Update IP database records for 2025-03
## [5.7.0-beta.11] 2025-03-20
## Fixed
- Reduce startup time when testing remote APIs
## [5.6.5] 2025-03-04
## [5.7.0-beta.10] 2025-03-15
## Added
- Restore application size on subsequent startup
## Fixed
- Grid scaling causes table to exceeds bounds of display viewport
- Window exceeds taskbar on Steam Deck
- Reduce possibility of timeouts when pinging servers
## Changed
- Packed filter checkbox buttons into a 3x3 grid
- Updated IP database to 2025-03 records
## [5.7.0-beta.9] 2025-03-04
## Fixed
- Livonia server results being dropped from batch queries
## [5.6.4] 2025-02-10
### Changed
## [5.7.0-beta.8] 2025-02-10
## Changed
- Drop launch flag and check for invocation through Steam automatically
## [5.6.3] 2025-02-09
### Changed
## [5.7.0-beta.7] 2025-02-09
## Changed
- Update IP database records for 2025-02
## [5.6.2] 2025-01-22
### Fixed
- Resolve regression introduced with IP resolution feature in 5.6.0 (restores functionality of right-click action: Add to My Servers)
## [5.7.0-beta.6] 2025-01-10
## Fixed
- Resolve regression introduced with IP resolution feature in 13c6813
## [5.6.1] 2025-01-10
### Fixed
- Add fallback support for jq 1.6
## [5.7.0-beta.5] 2025-01-10
## Changed
- Stricter redacting of usernames (again)
## [5.6.0] 2025-01-06
### Added
- Application header bar and controls
- Menu context subtitle in header bar
- Bulk delete mods (via 'List installed mods' list). Not compatible with Manual Mod install mode
- Highlight stale mods in mods list
- Added --steam launch parameter
- Open Steam workshop subscriptions dialog when switching from Manual to Auto mode
- Hover tooltips to most buttons
- Add in-app documentation link to Codeberg mirror
- Additional logging
### Fixed
- Avoid sudo escalation if system map count is sufficient (jiriks74)
- Duplicate dialog title on Steam Deck
- Resolve remote IP when saving records for game servers with multiple hosts
- More performant symlink traversal when checking for legacy links
- Only iterate on missing symlinks at boot (400% performance uplift)
- Fix for server list truncation causing some servers to not appear in results
- Empty dialog popups if user manually deletes local mods while application is running
- Update statusbar when removing servers from list/repopulating
- Abort DayZ path discovery if Steam files are not synched
- Race condition when checking for installed mods
- Favorite server message not updating correctly
- Improved handling for cases where there are no locally installed mods
- Set up mod symlinks at boot, rather than only on server connect
- Prevent context menus from opening when table is empty
- When reloading table in-place, prevent duplicate panel elements from being added if already present
- Clean up local mod signatures from versions file when deleting mods
- Focus first row when opening mods list
## [5.7.0-beta.4] 2025-01-10
## Fixed
- Clerical hotfix
## [5.7.0-beta.3] 2025-01-10
## Changed
- Support legacy jq syntax for Ubuntu variants
## [5.7.0-beta.2] 2025-01-07
## Fixed
- Stricter redacting of usernames
- Omit nested directories when traversing symlinks
## [5.7.0-beta.1] 2025-01-07
### Changed
- Redact usernames in log files
- Normalize version number
## [5.6.0-beta.21] 2025-01-06
### Added
- Add in-app documentation link to Codeberg mirror
- Hover tooltips to most buttons
### Fixed
- Prevent ArrowUp/ArrowDown input when inside keyword field
- Admonish user to restart Steam in error dialog if DayZ path could not be found
- Refactor control flow for more robust contextual parsing
- Stop sending modal dialog hints to outer window
- Clean up signal emission
- Clarify some error messages and normalize text formatting
### Changed
- Update forum URL
- Reword Help section links to include destination
- Update README.md
- Update IP database to 2025-01
- Reduce IP database size by 50%
- Update documentation to 5.6.x standard
### Dropped
- Hall of Fame section from button links, to be moved inside documentation
- Unused imports
- Removed temporary mod ID output in debug logs
- Removed Hall of Fame section from button links, moved inside documentation
- Remove unused imports
## [5.5.3] 2024-12-13
## [5.6.0-beta.20] 2024-12-23
### Added
- Output real and resolved mod ids to logs (temporary)
- Added -steam launch parameter
### Fixed
- Only iterate on missing symlinks
- Move logging up
## [5.6.0-beta.19] 2024-12-18
### Added
- Redact usernames in log files
### Fixed
- More performant symlink traversal when checking for legacy links
## [5.6.0-beta.18] 2024-12-14
### Added
- Open Steam workshop subscriptions dialog
- Additional logging
### Fixed
- Empty dialog popups if user manually deletes local mods while application is running
- Abort DayZ path discovery if VDF if Steam files are not synched
- Avoid sudo escalation if system map count is sufficient (jiriks74)
### Changed
- Admonish user to restart Steam in error dialog if DayZ path could not be found
## [5.6.0-beta.17] 2024-12-14
### Added
- Additional logging
## [5.6.0-beta.16] 2024-12-13
### Fixed
- Add remote resource health checks before downloading updates
### Added
- Add fallback repository
## [5.5.1] 2024-12-03
## [5.6.0-beta.11] 2024-12-07
### Fixed
- Support localized decimal separators when parsing installed mod sizes
- Add missing function definition
## [5.5.0] 2024-11-10
## [5.6.0-beta.10] 2024-12-04
### Fixed
- Untoggle highlight button when repopulating mod list
- Resolve remote IP when saving records for game servers with multiple hosts
- Update statusbar when removing servers from list/repopulating
### Added:
- "Select stale" button to bulk select mods marked as obsolete
## [5.6.0-beta.9] 2024-12-03
### Fixed
- Normalize user locale when parsing floats
## [5.6.0-beta.8] 2024-11-28
### Fixed
- Normalize user locale when parsing floats
## [5.6.0-beta.7] 2024-11-28
### Changed
- Add additional logging when fetching installed mods
## [5.6.0-beta.6] 2024-11-28
### Fixed
- Race condition when checking for installed mods
## [5.6.0-beta.5] 2024-11-21
### Added
- Support servers running DLC content (fixes Frostline servers)
- Expose a toggle setting for whether to launch the application in fullscreen
- Text autocompletion in maps search field (partial search)
- Add disk space warning to popup dialog when downloading mods
- Highlight stale mods in mods list
### Fixed
- Duplicate dialog title on Steam Deck
## [5.6.0-beta.4] 2024-11-20
### Added
- Application header bar and controls
- Menu context subtitle in header bar
### Changed
- Refactor control flow for more robust contextual parsing
- Stop sending modal dialog hints to outer window
### Fixed
- Favorite server message not updating correctly
## [5.6.0-beta.3] 2024-11-18
### Fixed
- Improved handling for cases where there are no locally installed mods
- Set up mod symlinks at boot, rather than only on server connect
- Prevent context menus from opening when table is empty
- When reloading table in-place, prevent duplicate panel elements from being added if already present
- Clean up signal emission
## [5.6.0-beta.2] 2024-11-15
### Fixed
- Clean up local mod signatures from versions file when deleting mods
## [5.6.0-beta.1] 2024-11-12
### Added
- Bulk delete mods (via 'List installed mods' list). Not compatible with Manual Mod install mode
### Fixed
- Fix for server list truncation causing some servers to not appear in results
- Suppress signal emission when switching menu contexts
- Focus first row when opening mods list
### Changed
- Clarify some error messages and normalize text formatting
## [5.5.0-beta.5] 2024-11-03
### Changed
- Use updated A2S_RULES logic
### Fixed
- Servers in saved servers list would populate context menu with same option when right-clicking in server browser
## [5.5.0-beta.4] 2024-10-31
### Added
- Expose a toggle setting for whether to launch the application in fullscreen
### Fixed
- Enable adding/removing servers to/from My Saved Servers when in Recent Servers context
## [5.5.0-beta.3] 2024-10-31
### Fixed
- Prevent maps combobox from duplicating contents
## [5.5.0-beta.2] 2024-10-31
### Fixed
- Restore keyboard input to keyword entry field
### Changed
## [5.5.0-beta.1] 2024-10-30
### Added
- Support servers running DLC content (fixes Frostline servers)
- Text autocompletion in maps search field
- Add disk space warning to popup dialog
### Fixed
- Abort fallback query method if DLC is required
## [5.4.2] 2024-10-05
## [5.4.2-beta.1] 2024-10-05
### Fixed
- Sanitize third-party API IDs to remove UGC collisions
## [5.4.1] 2024-09-25
## [5.4.1-beta.2] 2024-09-12
### Fixed
- Use fallback logic for modlist queries when user traverses networks
## [5.4.1-beta.2] 2024-09-10
### Fixed
- Fix signal handling control flow for checkbox toggles
## [5.4.1-beta.1] 2024-09-10
### Added
- Pre-boot validation check for users with self-compiled version of jq
### Fixed
- Use fallback logic for modlist queries when user traverses networks
- Fix signal handling control flow for checkbox toggles
- When reloading the server browser, the map combobox selection would revert to the last selected map instead of All Maps
- Server filter toggle signals were accessible from the main menu when switching between menu contexts
- Global cooldown dialog could sometimes block filter toggles after cooldown reset
- Normalized minor version number due to a previous clerical error
## [5.4.0] 2024-08-27
## [5.4.0-beta.5] 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
- Errors being printed to the console when Exit button was explicitly clicked
## [5.4.0-beta.4] 2024-08-21
### Added
- Emit CPU model name when exporting system debug log
### Fixed
- Detect Steam Deck OLED APU variant during initial setup
- Encapsulate player names correctly so that names with whitespace in them are supported
## [5.4.0-beta.3] 2024-08-04
### Added
- Scan local area network for DayZ servers
## [5.4.0-beta.2] 2024-08-03
### Fixed
- Clerical hotfix for previous player names fix
- Test if DayZ directory is empty at startup, implying that the game was moved to a new library collection
- Report WM_CLASS name to the window manager
## [5.4.0-beta.1] 2024-07-16
### Fixed
- Encapsulate player names correctly so that names with whitespace in them are supported
## [5.3.2] 2024-07-02
### Fixed
+1 -9
View File
@@ -11,15 +11,6 @@ This overcomes certain limitations in the Linux client and helps prepare the gam
- Concatenate launch options to pass to Steam
- Connect to mod-enabled LAN servers
## Design philosophy
DZGUI follows a specific set of guidelines, enumerated below:
- Provide a free and open-source tool under GPL
- Do not use undocumented, third-party servers to aggregate data; no central "DZGUI" server
- All connections go to Steam and DayZ servers directly; the tool should function in perpetuity without intermediary endpoints
- Target Linux desktop and Steam deck specifically; not a cross-platform tool
## Setup and usage
Refer to the documentation for installation and setup instructions:
@@ -27,6 +18,7 @@ Refer to the documentation for installation and setup instructions:
- [GitHub](https://aclist.github.io/dzgui/index.html)
- [Mirror (Codeberg)](https://aclist.codeberg.page)
![A screenshot of DZGUI](/images/example.png)
## Attribution
+103 -171
View File
@@ -1,8 +1,7 @@
#!/usr/bin/env bash
set -o pipefail
src_path="$(readlink -e "$0")"
version=6.0.2
version=6.0.0.beta-8
#CONSTANTS
aid=221100
@@ -40,7 +39,6 @@ cols_file="$state_path/$prefix.cols.json"
#CACHE FILES
coords_file="$cache_path/$prefix.coords"
src_path_file="$cache_path/$prefix.src"
#legacy paths
hist_file="$config_path/history"
@@ -117,7 +115,6 @@ setup_state_files(){
done
logger INFO "Wiped cache files"
fi
echo "$src_path" > "$src_path_file"
}
print_config_vals(){
local keys=(
@@ -139,10 +136,10 @@ print_config_vals(){
}
test_gobject(){
python3.13 -c "import gi"
python3 -c "import gi"
if [[ ! $? -eq 0 ]]; then
logger CRITICAL "Missing PyGObject"
quit_with_help_dialog "Requires PyGObject (python-gobject)"
fdialog "Requires PyGObject (python-gobject)"
exit 1
fi
logger INFO "Found PyGObject in Python env"
@@ -221,14 +218,16 @@ default_steam_path="$default_steam_path"
#Preferred Steam launch command (for Flatpak support)
preferred_client="$preferred_client"
#DZGUI source path
src_path="$src_path"
END
}
depcheck(){
for dep in "${!deps[@]}"; do
if ! command -v "$dep" &> /dev/null; then
local msg="Requires $dep >= ${deps[$dep]}"
echo "$msg"
exit 1
raise_error_and_quit "$msg"
fi
done
local jqmsg="jq must be compiled with support for oniguruma"
@@ -237,31 +236,14 @@ depcheck(){
[[ $? -ne 0 ]] && raise_error_and_quit "$jqmsg"
logger INFO "Initial dependencies satisfied"
}
open_url(){
url="$1"
if [[ -n "$BROWSER" ]]; then
logger INFO "Opening '$url' in '$BROWSER'"
"$BROWSER" "$url"
else
logger INFO "Opening '$url' with xdg-open"
xdg-open "$url"
fi
}
quit_with_help_dialog(){
local sel
msg="$1"
help_button="Open help page"
url="https://aclist.github.io/dzgui/installation.html"
logger CRITICAL "$msg"
sel=$(zenity --info --extra-button="$help_button" --text="$msg")
[[ $sel == "$help_button" ]] && open_url "$url" &
exit 1
}
check_pyver(){
if [[ ! $(python3.13 --version) ]]; then
local msg="Requires Python 3.13"
quit_with_help_dialog "$msg"
local pyver=$(python3 --version | awk '{print $2}')
local minor=$(<<< $pyver awk -F. '{print $2}')
if [[ -z $pyver ]] || [[ ${pyver:0:1} -lt 3 ]] || [[ $minor -lt 10 ]]; then
local msg="Requires Python >=3.10"
raise_error_and_quit "$msg"
fi
logger INFO "Found Python version: $pyver"
}
watcher_deps(){
if [[ ! $(command -v wmctrl) ]] && [[ ! $(command -v xdotool) ]]; then
@@ -335,8 +317,6 @@ check_unmerged(){
fi
}
check_version(){
echo "# Checking version"
[[ -n $reference_branch ]] && return
local version_url=$(format_version_url)
local upstream=$(curl -Ls "$version_url" | awk -F= '/^version=/ {print $2}')
local res=$(get_response_code "$version_url")
@@ -400,11 +380,10 @@ prompt_dl(){
dl_changelog(){
local mdbranch
local md
source "$config_file"
[[ $branch == "stable" ]] && mdbranch="dzgui"
[[ $branch == "testing" ]] && mdbranch="testing"
local changelog="$url_prefix/${mdbranch}/CHANGELOG.md"
curl -Ls "$changelog" > "$state_path/CHANGELOG.md"
local md="$url_prefix/${mdbranch}/$file"
curl -Ls "$md" > "$state_path/CHANGELOG.md"
}
test_display_mode(){
pgrep -a gamescope | grep -q "generate-drm-mode"
@@ -415,7 +394,6 @@ test_display_mode(){
fi
}
check_architecture(){
echo "# Checking system architecture"
local cpu=$(< /proc/cpuinfo awk -F": " '/AMD Custom APU [0-9]{4}$/ {print $2; exit}')
read -a APU_MODEL <<< "$cpu"
if [[ ${APU_MODEL[3]} != "0932" ]] && [[ ${APU_MODEL[3]} != "0405" ]]; then
@@ -432,7 +410,6 @@ check_architecture(){
logger INFO "Setting architecture to 'Steam Deck'"
}
check_map_count(){
echo "# Checking map count"
[[ $is_steam_deck -gt 0 ]] && return 0
local map_count_file="/proc/sys/vm/max_map_count"
local min_count=1048576
@@ -482,7 +459,6 @@ tdialog(){
$steamsafe_zenity --info --text="$1" "${zenity_flags[@]}"
}
steam_deps(){
echo "# Checking Steam"
local flatpak
local steam
[[ $(command -v flatpak) ]] && flatpak=$(flatpak list | grep valvesoftware.Steam)
@@ -491,15 +467,33 @@ steam_deps(){
local msg="Found neither Steam nor Flatpak Steam"
raise_error_and_quit "$msg"
exit 1
elif [[ -n "$steam" ]] && [[ -n "$flatpak" ]]; then
[[ -n $preferred_client ]] && return 0
if [[ -z $preferred_client ]]; then
preferred_client="steam"
fi
elif [[ -n "$steam" ]]; then
preferred_client="steam"
else
preferred_client="flatpak"
fi
update_config
logger INFO "Preferred client set to '$preferred_client'"
}
migrate_files(){
if [[ ! -f $config_path/dztuirc.oldapi ]]; then
cp $config_file $config_path/dztuirc.oldapi
logger INFO "Migrated old API file"
fi
[[ ! -f $hist_file ]] && return
rm $hist_file
logger INFO "Wiped old history file"
}
stale_symlinks(){
echo "# Cleaning stale symlinks"
local game_dir="$steam_path/steamapps/common/DayZ"
readarray -t links < <(find "$game_dir" -xtype l)
for link in "${links[@]}"; do
logger DEBUG "Updating stale symlink '$link'"
unlink "$link"
for l in $(find "$game_dir" -xtype l); do
logger DEBUG "Updating stale symlink '$l'"
unlink "$l"
done
}
@@ -508,7 +502,7 @@ check_availability() {
return 1
fi
local url=$1
local timeout_sec="2"
local timeout_sec="3"
if [[ $2 ]]; then
timeout_sec=$2
fi
@@ -519,7 +513,6 @@ check_availability() {
}
local_latlon(){
echo "# Checking coordinates"
if [[ -z $(command -v dig) ]]; then
local url_ipecho="https://ipecho.net/plain"
if ! check_availability "ipecho.net"; then
@@ -531,9 +524,6 @@ local_latlon(){
# TODO : implement checking remote
local local_ip=$(dig -4 +short myip.opendns.com @resolver1.opendns.com)
fi
if calc_local_coords "$local_ip"; then
return 0
fi
local url_ip_api="http://ip-api.com/json/$local_ip"
if ! check_availability "ip-api.com"; then
logger WARN "Failed to get local coordinates, ip-api.com service may be down."
@@ -548,7 +538,6 @@ local_latlon(){
}
lock(){
echo "# Setting up lock file"
[[ ! -f $lock_file ]] && touch $lock_file
local pid=$(cat $lock_file)
ps -p $pid -o pid= >/dev/null 2>&1
@@ -626,12 +615,12 @@ fetch_helpers_by_sum(){
[[ -f "$config_file" ]] && source "$config_file"
declare -A sums
sums=(
["funcs"]="5523d933e9f0668fc14b3faf0d4aafd8"
["funcs"]="6ae3ead7034dc8e7543472bddee75c63"
["query_v2.py"]="55d339ba02512ac69de288eb3be41067"
["servers.py"]="ed442c3aecf33f777d59dcf53650d263"
["ui.py"]="d09b9d8bed3854efd51377289786c5ac"
["ui.py"]="8d05bbd7b8e15a97fae568e9a3dbf4d6"
["vdf2json.py"]="2f49f6f5d3af919bebaab2e9c220f397"
["pefile.py"]="b452974a84bff1d821872fcebf59e380"
["pefile.py"]="21531f2c0d9dfa5f110cf6779f9d22c0"
)
local author="aclist"
local repo="dztui"
@@ -650,10 +639,6 @@ fetch_helpers_by_sum(){
realbranch="dzgui"
fi
if [[ -n $reference_branch ]]; then
realbranch="$reference_branch"
fi
for i in "${!sums[@]}"; do
file="$i"
sum="${sums[$i]}"
@@ -691,12 +676,15 @@ fetch_km_helper(){
}
get_response_code(){
local url="$1"
curl --connect-timeout 3 -Ls -I -o /dev/null -w "%{http_code}" "$url"
curl -Ls -I -o /dev/null -w "%{http_code}" "$url"
}
raise_error_and_quit(){
echo "$1"
exit 1
}
fetch_ip_db(){
parse_dl_url(){
curl --connect-timeout 3 -Ls "$url" \
curl -Ls "$url" \
| grep "csv.gz" \
| awk -F"['']" '{print $2}'
}
@@ -712,9 +700,6 @@ fetch_ip_db(){
fetch(){
logger INFO "Triggering fetch routine"
local url="$1"
local ip_file="${state_path}/ips.csv"
local base_file="${state_path}/${this_month}.csv.gz"
local extracted_file="${state_path}/${this_month}.csv"
curl -Ls "$url" > "$base_file"
if [[ $? -ne 0 ]]; then
@@ -734,7 +719,7 @@ fetch_ip_db(){
logger WARN "Abnormal exit while parsing IPs"
return
fi
rm "${state_path}/${this_month}.csv"
rm "${state_path}/${month}.csv"
readarray -t records < <(cat $ip_file | awk -F, 'NR==1 {print $1} END {print $1}')
if [[ ${records[0]} != "0.0.0.0" ]] && [[ ${records[1]} != "224.0.0.0" ]]; then
@@ -749,57 +734,55 @@ fetch_ip_db(){
rm "$ip_file"
fi
echo "$this_month" > "$month_file"
logger INFO "Wrote '$this_month' to stub '$month_file'"
echo "$month" > "$month_file"
logger INFO "Wrote '$month' to stub '$month_file'"
logger INFO "Updated '$ip_file'"
}
check_remote(){
local url="$1"
local res=$(get_response_code "$url")
if [[ $res -ne 200 ]]; then
logger WARN "Failed to retrieve remote resource: '$url' ($res)"
return
fi
logger INFO "Resolved remote URL: '$url'"
# test dl url
local dl_url="$(parse_dl_url)"
local res=$(get_response_code "$dl_url")
if [[ $res -ne 200 ]]; then
logger WARN "Remote resource unavailable: '$dl_url' ($res)"
return
fi
logger INFO "Resolved download URL: '$dl_url'"
fetch "$dl_url"
}
local url="https://db-ip.com/db/download/ip-to-city-lite"
month_file="${state_path}/.month"
this_month=$(date +%Y-%m)
local month_file="${state_path}/.month"
local ip_file="${state_path}/ips.csv"
# test main url
local res=$(get_response_code "$url")
if [[ $res -ne 200 ]]; then
logger WARN "Failed to retrieve remote resource: '$url' ($res)"
return
fi
logger INFO "Resolved remote URL: '$url'"
# test dl url
local dl_url="$(parse_dl_url)"
local res=$(get_response_code "$dl_url")
if [[ $res -ne 200 ]]; then
logger WARN "Remote resource unavailable: '$dl_url' ($res)"
return
fi
logger INFO "Resolved download URL: '$dl_url'"
local month=$(parse_dl_url_date "$dl_url")
local base_file="${state_path}/${month}.csv.gz"
local extracted_file="${state_path}/${month}.csv"
# no stub file
if [[ ! -f $month_file ]]; then
logger WARN "No stub file '$month_file' present"
check_remote "$url"
return
fi
# if stub is same date, abort
local last_month=$(< "$month_file")
if [[ $last_month == "$this_month" ]]; then
logger INFO "Local stub '$last_month' is identical to remote, skipping"
fetch "$dl_url"
return
fi
# local needs update
logger WARN "Local stub '$last_month' does not match '$this_month'"
check_remote "$url"
return
local last_month=$(< "$month_file")
if [[ $last_month != "$month" ]]; then
logger WARN "Local stub '$last_month' does not match remote stub '$month'"
fetch "$dl_url"
return
fi
# if stub is same date, abort
logger INFO "Local stub '$last_month' is identical to remote, skipping"
}
fetch_helpers(){
echo "# Checking helper files"
fetch_a2s
fetch_dzq
fetch_km_helper
@@ -898,26 +881,12 @@ file_picker(){
}
find_library_folder(){
local search_path="$1"
readarray -t paths < <(python3.13 "$helpers_path/vdf2json.py" -i "$1/steamapps/libraryfolders.vdf" \
| jq -r '.libraryfolders[]|select(.apps|has("221100")).path')
if [[ ! $? -eq 0 ]]; then
steam_path="$(python3 "$helpers_path/vdf2json.py" -i "$1/steamapps/libraryfolders.vdf" \
| jq -r '.libraryfolders[]|select(.apps|has("221100")).path')"
if [[ ! $? -eq 0 ]] || [[ -z $steam_path ]]; then
logger WARN "Failed to parse Steam path using '$search_path'"
return 1
fi
if [[ ${#paths[@]} -eq 0 ]]; then
logger WARN "No valid VDF paths in '$search_path'"
return 1
fi
if [[ ${#paths[@]} -gt 1 ]]; then
for path in "${paths[@]}"; do
if [[ -d "$path" ]]; then
steam_path="$path"
break
fi
done
else
steam_path="${paths[0]}"
fi
logger INFO "Steam path resolved to: $steam_path"
}
create_config(){
@@ -926,7 +895,6 @@ create_config(){
unset default_steam_path
unset steam_path
preferred_client="steam"
while true; do
local player_input="$($steamsafe_zenity \
--forms \
@@ -987,7 +955,6 @@ create_config(){
done
}
varcheck(){
echo "# Checking config file"
local msg="Config file '$config_file' missing. Start first-time setup now?"
local msg2="The Steam paths set in your config file appear to be invalid (DayZ was moved or uninstalled). Restart first-time setup now?"
if [[ ! -f $config_file ]]; then
@@ -1001,7 +968,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 ]] || [[ ! $(find "$game_dir" -type f) ]]; 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"
@@ -1012,16 +979,18 @@ varcheck(){
create_config
return 0
fi
if [[ $src_path != $(realpath "$0") ]]; then
src_path=$(realpath "$0")
update_config
fi
}
is_dzg_downloading(){
echo "# Checking DayZ"
if [[ -d $steam_path ]] && [[ -d $steam_path/downloading/$aid ]]; then
logger WARN "DayZ may be scheduling updates"
return 0
fi
}
is_steam_running(){
echo "# Checking Steam"
local res=$(ps aux | grep "steamwebhelper" | grep -v grep)
if [[ -z $res ]]; then
logger WARN "Steam may not be running"
@@ -1034,7 +1003,6 @@ get_response_code(){
curl -Ls -I -o /dev/null -w "%{http_code}" "$url"
}
test_connection(){
echo "# Testing connection"
declare -A hr
local res1
local res2
@@ -1068,7 +1036,6 @@ legacy_cols(){
mv $cols_file.new $cols_file
}
stale_mod_signatures(){
echo "# Checking stale mods"
[[ ! -f "$versions_file" ]] && return
local workshop_dir="$steam_path/steamapps/workshop/content/$aid"
if [[ -d $workshop_dir ]]; then
@@ -1082,48 +1049,18 @@ stale_mod_signatures(){
}
create_new_links(){
echo "# Setting up symlinks"
"$func_helper" "update_symlinks"
}
calc_local_coords(){
local ip="$1"
[[ ! -f "$geo_helper" ]] && return 1
IFS="." read -ra split <<< "$ip"
[[ ${#split[@]} -ne 4 ]] && return 1
prefix="^${split[0]}.${split[1]}."
readarray -t res < <(grep "$prefix" "$geo_helper")
for address in "${res[@]}"; do
IFS="," read -ra fields <<< "$address"
upper="${fields[1]}"
IFS="." read -ra upper_digits <<< "$upper"
if [[ ${split[2]} -gt ${upper_digits[2]} ]]; then
continue
fi
if [[ ${split[2]} -eq ${upper_digits[2]} ]]; then
if [[ ${split[3]} -gt ${upper_digits[3]} ]]; then
continue
fi
if [[ ${split[3]} -eq ${upper_digits[3]} ]]; then
echo "${fields[-2]}" >> "$coords_file"
echo "${fields[-1]}" >> "$coords_file"
return 0
fi
fi
if [[ ${split[2]} -lt ${upper_digits[2]} ]]; then
echo "${fields[-2]}" >> "$coords_file"
echo "${fields[-1]}" >> "$coords_file"
return 0
fi
done
return 1
}
initial_setup(){
setup_dirs
setup_state_files
depcheck
check_pyver
test_gobject
watcher_deps
check_architecture
test_connection
fetch_helpers
fetch_helpers > >(pdialog "Checking helper files")
varcheck
source "$config_file"
lock
@@ -1132,12 +1069,14 @@ initial_setup(){
check_version
check_map_count
steam_deps
migrate_files
stale_symlinks
stale_mod_signatures
create_new_links
local_latlon
is_steam_running
is_dzg_downloading
print_config_vals
}
uninstall(){
_full(){
@@ -1239,18 +1178,11 @@ main(){
set_im_module
printf "Checking dependencies...\n"
setup_dirs
setup_state_files
depcheck
check_pyver
test_gobject
watcher_deps
initial_setup > >(pdialog "Initializing setup")
printf "Initializing setup...\n"
initial_setup
printf "All OK. Kicking off UI...\n"
python3.13 "$ui_helper" "--init-ui" "$version" "$is_steam_deck"
python3 "$ui_helper" "--init-ui" "$version" "$is_steam_deck"
}
+20 -13
View File
@@ -1,6 +1,6 @@
#!/usr/bin/env bash
set -o pipefail
version="6.0.2"
version="6.0.0-beta.8"
#CONSTANTS
aid=221100
@@ -51,7 +51,6 @@ _cache_binary="$cache_dir/$prefix.binary"
_cache_coords="$cache_path/$prefix.coords"
_cache_cooldown="$cache_path/$prefix.cooldown"
_cache_lan="$cache_path/$prefix.lan"
_cache_src_path="$cache_path/$prefix.src"
#XDG
freedesktop_path="$HOME/.local/share/applications"
@@ -88,14 +87,17 @@ steam_api_url="https://steamcommunity.com/dev/apikey"
battlemetrics_api_url="https://www.battlemetrics.com/developers"
bm_api="https://api.battlemetrics.com/servers"
steam_cmd="$preferred_client"
if [[ $preferred_client == "steam" ]]; then
steam_cmd="steam"
else
steam_cmd="flatpak run com.valvesoftware.Steam"
fi
declare -A funcs=(
["Highlight stale"]="find_stale_mods"
["Change player name"]="update_config_val"
["Change Steam API key"]="update_config_val"
["Change Battlemetrics API key"]="update_config_val"
["Change client"]="update_config_val"
["Change favorite server"]="add_record"
["Add server by IP"]="add_record"
["Add server by ID"]="add_record"
@@ -286,7 +288,7 @@ a2s(){
local mode="$3"
logger INFO "Querying '$ip:$qport' with mode '$mode'"
local res
res=$(python3.13 "$query_helper" "$ip" "$qport" "$mode")
res=$(python3 "$query_helper" "$ip" "$qport" "$mode")
if [[ $? -eq 1 ]]; then
res=$(try_fallback "$ip" "$qport" "$mode")
if [[ $? -eq 1 ]]; then
@@ -309,7 +311,7 @@ is_in_favs(){
find_id(){
local file="$default_steam_path/config/loginusers.vdf"
[[ ! -f $file ]] && return 1
local res=$(python3.13 "$helpers_path/vdf2json.py" \
local res=$(python3 "$helpers_path/vdf2json.py" \
-i "$file" \
| jq -r '.users
|to_entries[]
@@ -338,7 +340,7 @@ list_mods(){
name=$(awk -F\" '/name/ {print $2}' "${dir}/meta.cpp")
base_dir=$(basename $(readlink -f $game_dir/$symlink))
size=$(du -s "$(readlink -f "$game_dir/$symlink")" | awk '{print $1}')
size=$(python3.13 -c "n=($size/1024) +.005; print(round(n,4))")
size=$(python3 -c "n=($size/1024) +.005; print(round(n,4))")
LC_NUMERIC=C printf "%s$sep%s$sep%s$sep%3.3f\n" "$name" "$symlink" "$base_dir" "$size"
done | sort -k1)
# user may have manually pruned mods out-of-band
@@ -397,7 +399,6 @@ get_dist(){
logger INFO "Distance: $dist km"
fi
}
query_config(){
[[ -n $2 ]] && local key=$2
keys=(
@@ -423,7 +424,6 @@ query_config(){
echo "${!i}"
done
}
align_versions_file(){
shift
local mod="$1"
@@ -589,6 +589,9 @@ default_steam_path="$default_steam_path"
#Preferred Steam launch command (for Flatpak support)
preferred_client="$preferred_client"
#DZGUI source path
src_path="$src_path"
END
}
format_version_url(){
@@ -642,7 +645,6 @@ download_new_version(){
return 1
fi
local version_url="$(format_version_url)"
local src_path="$(< "$_cache_src_path")"
mv "$src_path" "$src_path.old"
curl -Ls "$version_url" > "$src_path"
rc=$?
@@ -699,6 +701,13 @@ toggle(){
debug=""
fi
;;
Toggle[[:space:]]Steam/Flatpak)
if [[ $preferred_client == "steam" ]]; then
preferred_client="flatpak"
else
preferred_client="steam"
fi
;;
Toggle[[:space:]]DZGUI[[:space:]]fullscreen[[:space:]]boot)
if [[ $fullscreen == "true" ]]; then
fullscreen="false"
@@ -797,9 +806,6 @@ update_config_val(){
local context="$1"
local value="$2"
case $1 in
"Change client")
key="preferred_client"
;;
"Change player name")
key="name"
if [[ -z "${value// }" ]]; then
@@ -825,6 +831,7 @@ update_config_val(){
declare -n nr=$key
nr="$value"
update_config
echo "Updated the key '$key' to '$value'"
return 80
}
show_log(){
+1 -1
View File
@@ -295,7 +295,7 @@ def get_dayz_version(file: Path) -> DayZVersion | Exception:
try:
version = get_version(file)
except Exception as e:
raise e
return e
patch = str(version.build) + str(version.revision)
dz_vers = DayZVersion(version.major, version.minor, int(patch))
return dz_vers
+1 -4
View File
@@ -7,7 +7,7 @@
#include <stdlib.h>
#include <stdio.h>
// Earth's radius in meters.
// Earths radius in meters
#define RADIUS ((12756L / 2.0L) * 1000L)
// PI natural constant
@@ -68,9 +68,6 @@ int main(int argc, const char* argv[]) {
.longitude = radian_from(atof(argv[4])),
};
// Returns the distance in meters.
// To pretty-print the result in a consumer of this module, it is
// recommended to divide the result by 1,000 and round it.
printf("%.1f\n", great_circle_distance(a, b));
return 0;
+125 -131
View File
@@ -18,8 +18,7 @@ from enum import Enum
from collections.abc import Callable
from concurrent.futures import wait
from concurrent.futures import ThreadPoolExecutor
from pathlib import Path
from typing import Literal, Self, Any, TYPE_CHECKING
from typing import Literal, Self, Any
import servers as Servers # noqa E402
import pefile as PeFile # noqa E402
@@ -32,12 +31,10 @@ from pefile import (
)
from pefile import VersionMatch
if TYPE_CHECKING:
from servers import Prereqs
locale.setlocale(locale.LC_ALL, "")
import gi # noqa E402
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, GLib, Gdk, GObject, Pango # noqa E402
@@ -826,7 +823,8 @@ def query_history() -> list | None:
rows = [row.rstrip("\n") for row in f]
except OSError:
rows = None
return rows
finally:
return rows
def query_favorites() -> None | list:
@@ -868,14 +866,13 @@ def spawn_dialog(msg: str, mode: Popup) -> bool:
dialog = GenericDialog(msg, mode)
response = dialog.run()
dialog.destroy()
clean_msg = msg.replace("\n", " ")
match response:
case Gtk.ResponseType.OK:
logger.info(f"User confirmed dialog with message '{clean_msg}'")
logger.info(f"User confirmed dialog with message '{msg}'")
return False
case Gtk.ResponseType.CANCEL | Gtk.ResponseType.DELETE_EVENT:
logger.info(f"User aborted dialog with message '{clean_msg}'")
logger.info(f"User aborted dialog with message '{msg}'")
return True
return False
@@ -1019,7 +1016,7 @@ def process_tree_option(choice: RowType) -> None:
return
if command == RowType.CHANGELOG:
App.grid.notebook.open_changelog()
App.grid.notebook.set_page_by_enum(NotebookPage.CHANGELOG)
return
if command == RowType.QUICK_CONNECT:
@@ -1029,7 +1026,13 @@ def process_tree_option(choice: RowType) -> None:
return
record = str_to_record(record)
prepare_connection(command, record)
thread_new_with_dialog(
App.treeview.prepare_connection,
parse_shell_output,
"Querying server",
command,
[record],
)
return
match command.dict["type"]:
@@ -1057,54 +1060,48 @@ def parse_shell_output(proc: subprocess.CompletedProcess, row: RowType):
process_shell_return_code(msg, proc.returncode, row)
def prepare_connection(rowtype: RowType, record: Record) -> None:
def background(rowtype: RowType, record: Record) -> None:
def cleanup() -> None:
App.treeview.wait_dialog.destroy()
# NOTE: When using RowType.CONN_BY_IP, the gameport needs to be interpolated
record.gameport = prereqs.gameport
addr = record_to_str(record)
if proceed is False:
spawn_dialog(msg, Popup.NOTIFY)
return
if msg != "":
res = spawn_dialog(msg, Popup.CONFIRM)
if res is False:
try_connect(addr, str(prereqs.appid), str(pefile_path), rowtype)
else:
try_connect(addr, str(prereqs.appid), str(pefile_path), rowtype)
proceed, msg, pefile_path, prereqs = App.treeview.get_prereqs(record)
GLib.idle_add(cleanup)
msg = "Checking prerequisites"
App.treeview.dialog_show(msg)
thread = threading.Thread(target=background, args=(rowtype, record))
thread.start()
def try_connect(
addr: str,
appid: str,
path: str,
row: RowType
def thread_new_with_dialog(
func: Callable,
callback: Callable | None,
msg: str,
row: RowType | None,
args: list,
) -> None:
def background(addr, appid, path):
"""
Pop a GenericDialog transient to App.treeview and
call a function on a thread, with optional callback.
Chiefly used for connection-related subprocesses.
After completion, the dialog is destroyed in the main event loop
and additional exception handling occurs.
This is intended as a bridge between legacy shell methods and the UI.
A more abstracted version of call_on_thread() for when extra threaded
processing occurs before calls to shell subprocesses.
"""
def background(*args):
def cleanup():
App.treeview.dialog_hide()
parse_shell_output(proc, row)
if exception is not None:
spawn_dialog(str(exception), Popup.NOTIFY)
process_user_input(row)
return
if callback is not None and proc is not None:
callback(proc, row)
exception = None
proc = None
try:
proc = call_out("try_connect", addr, appid, path)
proc = func(*args)
except Exception as e:
logger.critical(e)
exception = e
GLib.idle_add(cleanup)
return
GLib.idle_add(cleanup)
msg = "Querying server"
App.treeview.dialog_show(msg)
thread = threading.Thread(target=background, args=(addr, appid, path))
thread = threading.Thread(target=background, args=(args))
thread.start()
@@ -1144,31 +1141,27 @@ def record_to_str(record: Record) -> str:
def connect_by_ip(enum: RowType, response: str) -> None:
try:
def _prep(response: str) -> None:
record = Servers.validate_ip(response)
except Exception as e:
spawn_dialog(str(e), Popup.NOTIFY)
return
prepare_connection(enum, record)
proc = App.treeview.prepare_connection(record)
return proc
thread_new_with_dialog(
_prep, parse_shell_output, "Querying IP", enum, [response]
)
return
def connect_by_id(enum: RowType, response: str, key: str) -> None:
def _prep(key: str, response: str) -> None:
def cleanup() -> None:
App.treeview.dialog_hide()
prepare_connection(enum, record)
record = Servers.query_bm_api(key, response)
proc = App.treeview.prepare_connection(record)
return proc
try:
record = Servers.query_bm_api(key, response)
except Exception as e:
spawn_dialog(str(e), Popup.NOTIFY)
App.treeview.dialog_hide()
return
GLib.idle_add(cleanup)
msg = "Validating ID"
App.treeview.dialog_show(msg)
thread = threading.Thread(target=_prep, args=(key, response))
thread.start()
thread_new_with_dialog(
_prep, parse_shell_output, "Querying API", enum, [key, response]
)
return
def process_user_input(enum: RowType) -> None:
@@ -1493,8 +1486,6 @@ class ButtonBox(Gtk.Box):
context = button.type
logger.info(f"User clicked '{context}'")
App.grid.right_panel.filters_vbox.set_visible(False)
if context == ButtonType.EXIT:
logger.info("Normal user exit")
save_res_and_quit()
@@ -2499,8 +2490,6 @@ class TreeView(Gtk.TreeView):
def _dump_servers(self, ips: list) -> list | None:
if len(ips) == 0:
return []
# NOTE: block malformed records
ips = [ip for ip in ips if len(ip.split(":")) == 3 and ip.split(":")[2] != "" ]
with ThreadPoolExecutor() as executor:
futures = [
executor.submit(
@@ -2951,9 +2940,9 @@ class TreeView(Gtk.TreeView):
def get_view(self):
return self.view
def get_prereqs(
def prepare_connection(
self, record: Record
) -> tuple[bool, str, str|None, "Prereqs"]:
) -> subprocess.CompletedProcess | None:
"""
Always called on a thread with a dialog on the transient parent window
"""
@@ -2961,7 +2950,8 @@ class TreeView(Gtk.TreeView):
if prereqs.appid is None:
logger.warning(f"Query to '{record.ip}:{record.qport}' timed out")
msg = "Timed out when querying server, check IP or try again later"
return (False, msg, None, prereqs)
spawn_dialog(msg, Popup.NOTIFY)
return None
build = "DayZ" if prereqs.appid == APPID_DAYZ else "DayZ Experimental"
steam_path = query_config("default_steam_path")[0]
@@ -2971,7 +2961,8 @@ class TreeView(Gtk.TreeView):
"Config file has no value set for 'default_steam_path'"
)
msg = "Local Steam installation is not set, possibly malformed config file."
return (False, msg, None, prereqs)
spawn_dialog(msg, Popup.NOTIFY)
return None
try:
pefile_path = PeFile.get_pefile_path(steam_path, prereqs.appid)
@@ -2985,7 +2976,8 @@ class TreeView(Gtk.TreeView):
f"If you recently installed {build} or moved it to a different drive, "
"restart Steam to allow these changes to synchronize, then try again."
)
return (False, msg, None, prereqs)
spawn_dialog(msg, Popup.NOTIFY)
return None
except AppMovedError:
logger.critical(
f"Library folder synch error for '{prereqs.appid}'"
@@ -2995,11 +2987,13 @@ class TreeView(Gtk.TreeView):
f"If you recently installed {build} or moved it to a different drive, "
"restart Steam to allow these changes to synchronize, then try again."
)
return (False, msg, None, prereqs)
spawn_dialog(msg, Popup.NOTIFY)
return None
except (VDFLoadError, PeFileError, Exception) as e:
logger.critical(e)
msg = "Steam settings or DayZ installation may be corrupted. Try restarting Steam."
return (False, msg, None, prereqs)
spawn_dialog(msg, Popup.NOTIFY)
return None
try:
local_vers = PeFile.get_dayz_version(pefile_path)
@@ -3011,7 +3005,7 @@ class TreeView(Gtk.TreeView):
local_vers = None
try:
remote_vers = PeFile.dayz_version_from_str(prereqs)
remote_vers = PeFile.dayz_version_from_str(prereqs.version)
except Exception:
remote_vers = None
@@ -3024,15 +3018,18 @@ class TreeView(Gtk.TreeView):
f"This server is running a newer build ({prereqs.version}) of {build} than "
f"your local version. You may be unable to connect. Proceed anyway?"
)
return (True, msg, pefile_path, prereqs)
res = spawn_dialog(msg, Popup.CONFIRM)
if res is True:
return None
case VersionMatch.LOCAL_NEWER:
msg = (
f"This server is running an out-of-date build ({prereqs.version}) of {build}. "
"You may be unable to connect. Proceed anyway?"
)
return (True, msg, pefile_path, prereqs)
res = spawn_dialog(msg, Popup.CONFIRM)
if res is True:
return None
case VersionMatch.SAME_VERSION:
return (True, "", pefile_path, prereqs)
pass
if prereqs.password is True:
@@ -3040,10 +3037,19 @@ class TreeView(Gtk.TreeView):
"This server is password-protected and you will be "
"prompted when connecting. Do you want to proceed?"
)
return (True, msg, pefile_path, prereqs)
return (True, "", pefile_path, prereqs)
res = spawn_dialog(msg, Popup.CONFIRM)
if res is True:
return None
"""
When using RowType.CONN_BY_IP, the gameport needs to be interpolated
"""
record.gameport = prereqs.gameport
addr = record_to_str(record)
proc = call_out(
"try_connect", addr, str(prereqs.appid), str(pefile_path)
)
return proc
@signal_emission
@update_window_labels
@@ -3113,7 +3119,13 @@ class TreeView(Gtk.TreeView):
record = self.get_record()
if record is None:
return
prepare_connection(None, record)
thread_new_with_dialog(
self.prepare_connection,
parse_shell_output,
"Querying server",
None,
[record],
)
case _: # any other non-server option from the main menu
process_tree_option(output)
@@ -3789,22 +3801,12 @@ class Options(Gtk.Box):
"Always fullscreen",
Preferences.WINDOW,
)
# TODO: gray out options if not available on system
client_store = Gtk.ListStore(str, str)
client_store.append(["steam", "steam"])
client_store.append(["flatpak", "flatpak run com.valvesoftware.Steam"])
client_store.append(["flatpak (container)", "flatpak-spawn --host flatpak run com.valvesoftware.Steam"])
renderer_text = Gtk.CellRendererText(ellipsize=Pango.EllipsizeMode.END)
self.client_combo = Gtk.ComboBox.new_with_model(client_store)
self.client_combo.set_halign(Gtk.Align.START)
self.client_combo.pack_start(renderer_text, True)
self.client_combo.connect("changed", self._on_client_changed)
self.client_combo.add_attribute(renderer_text, "text", 0)
self.steam_toggle = self.make_binary_radio(
"Steam", "Flatpak (experimental)", Preferences.CLIENT
)
pref_rows = [
[LeftLabel("Steam client"), self.client_combo],
[LeftLabel("Steam client"), self.steam_toggle],
[LeftLabel("Window size at boot"), self.fullscreen_toggle],
[LeftLabel("Player name"), self.player_box],
]
@@ -3989,15 +3991,6 @@ class Options(Gtk.Box):
show_wait_dialog = True
call_on_thread(show_wait_dialog, cmd, wait_msg, "")
def _on_client_changed(self, combo: Gtk.ComboBox) -> None:
# prevent triggering on initial init
if App.treeview.subpage is not RowType.OPTIONS:
return
ind = combo.get_active()
mod = combo.get_model()
client = mod[ind][1]
call_bash_func("Change client", client)
def _on_branch_changed(self, combo: Gtk.ComboBoxText) -> None:
# prevent triggering on initial init
if App.treeview.subpage is not RowType.OPTIONS:
@@ -4007,9 +4000,11 @@ class Options(Gtk.Box):
def _on_radio_toggled(
self, button: Gtk.RadioButton, context: Preferences
) -> None:
if App.treeview.subpage is not RowType.OPTIONS:
if App.treeview.subpage is None:
return
match context:
case Preferences.CLIENT:
toggle = RowType.TGL_STEAM
case Preferences.INSTALL:
toggle = RowType.TGL_INSTALL
state = button.get_group()[0].get_active()
@@ -4131,9 +4126,11 @@ class Options(Gtk.Box):
radio = 0
self.mod_install_toggle.get_children()[radio].set_active(True)
for ind, row in enumerate(self.client_combo.get_model()):
if row[1] == client:
self.client_combo.set_active(ind)
if client == "flatpak":
radio = 1
else:
radio = 0
self.steam_toggle.get_children()[radio].set_active(True)
if fullscreen == "true":
radio = 1
@@ -4328,20 +4325,22 @@ class KeybindingsDialog(Gtk.Box):
class Changelog(Gtk.Box):
def __init__(self):
super().__init__()
self.changelog_label = Gtk.Label()
self.add(self.changelog_label)
def open_changelog(self, path: Path) -> None:
try:
changelog = path.read_text()
with open(changelog_path, "r") as f:
changelog = f.read()
changelog_label = Gtk.Label()
changelog = self.format_pango(changelog)
changelog_label.set_markup(changelog)
self.add(changelog_label)
except FileNotFoundError:
msg = f"Failed to find CHANGELOG.md at {changelog_path}"
logger.critical(msg)
spawn_dialog(msg, Popup.WARN)
return
except OSError as e:
spawn_dialog(f"Something went wrong: {e}", Popup.NOTIFY)
spawn_dialog(f"Something went wrong: {e}", Popup.WARN)
logger.critical(e)
return Exception
formatted = self.format_pango(changelog)
self.changelog_label.set_markup(formatted)
App.grid.notebook.set_page_by_enum(NotebookPage.CHANGELOG)
return
def format_pango(self, text: str) -> str:
medium = '<span size="medium"><b>'
@@ -4358,8 +4357,7 @@ class Notebook(Gtk.Notebook):
def __init__(self):
super().__init__(show_tabs=False, show_border=False)
self.changelog = Changelog()
self.clog = ScrollableNote(self.changelog)
self.clog = ScrollableNote(Changelog())
self.clog.type = RowType.CHANGELOG
self.clog.show_all()
self.append_page(self.clog)
@@ -4378,10 +4376,6 @@ class Notebook(Gtk.Notebook):
self.connect("switch-page", self._on_page_changed)
self.connect("key-press-event", self._on_keypress)
def open_changelog(self) -> None:
path = Path(changelog_path)
self.changelog.open_changelog(path)
def _set_adjustment(self, adjustment: VAdjustment) -> None:
INCREMENT = 50
page = self.get_page()