fix: threaded dialog

This commit is contained in:
aclist 2026-01-18 15:00:12 +09:00
parent 2d58bb491e
commit 62936fa7b7
4 changed files with 550 additions and 311 deletions

View File

@ -1,56 +1,110 @@
# Changelog
## [6.0.1] 2026-01-16
## [6.0.2-beta.1] 2026-01-18
## Fixed
- Do not spawn dialogs from inside of thread when fetching prereqs
## 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
## [6.0.1-beta.1] 2026-01-16
## Fixed
- Explicitly use Python 3.13 when calling subprocesses
## [6.0.0] 2026-01-14
## [6.0.0-beta.20] 2026-01-14
## Fixed
- Write cache file after wiping
## [6.0.0-beta.19] 2026-01-14
## Fixed
- Steam Deck compatible script path expansion
## [6.0.0-beta.18] 2026-01-14
## Fixed
- Update UI checksums
## [6.0.0-beta.17] 2026-01-14
## 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
## [6.0.0-beta.16] 2026-01-04
## Fixed
- Regression introduced in previous hotfix
## [6.0.0-beta.15] 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
## [6.0.0-beta.14] 2025-12-09
## Fixed
- Dialogs with newlines breaking output in log table
## [6.0.0-beta.13] 2025-11-29
## Fixed
- Server filter panel not being hidden when entering other page contexts
- Path to remote changelog being constructed incorrectly
## [6.0.0-beta.12] 2025-11-14
## Changed
- Require Python 3.13
## Fixed
- Normalize beta version
## [6.0.0-beta.11] 2025-11-13
## Added
- Support sandboxed flatpak
## Changed
- Preferred client from radio toggle to combobox
## Fixed
- Config file erroneously getting updated when populating settings menu
## [6.0.0-beta.10] 2025-11-10
## Fixed
- Python 3.14 error in finally block
- Require Python version between 3.11 and 3.12
## [6.0.0-beta.9] 2025-11-05
## Fixed
- UI not being constructed correctly if CHANGELOG.md was missing
## [6.0.0-beta.8] 2025-11-04
## Added
- Internal flag to allow distribution packaged releases to disable in-app updates
- Pre-boot check to test whether script was invoked directly
- Commandline usage help text
## Fixed
- ESC key destroying wait dialogs while a thread is pending
- Tooltip signals being erroneously drawn on main menu
- Leaky variable name in dialog titles
- Prevent extraneous signals from propagating when column width is adjusted
- 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
## Changed
- Optimize time complexity of pre-boot checks (GaryBlackbourne)
- Moved location of notes file
- Rewrote distance calculation module (GaryBlackbourne)
## [6.0.0-beta.7] 2025-09-20
## Added
- Users can save text notes to describe servers
## Changed
- State file serialization methods
## [6.0.0-beta.6] 2025-09-12
## Added
- Support DayZ Experimental
- Show additional client information in Options menu
- Warn user of client version mismatches
- Support clickable hyperlinks
## Fixed
- 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
@ -58,188 +112,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

176
dzgui.sh
View File

@ -2,7 +2,7 @@
set -o pipefail
src_path="$(readlink -e "$0")"
version=6.0.1
version=6.0.2-beta.1
#CONSTANTS
aid=221100
@ -142,7 +142,7 @@ test_gobject(){
python3.13 -c "import gi"
if [[ ! $? -eq 0 ]]; then
logger CRITICAL "Missing PyGObject"
quit_with_pdialog "Requires PyGObject (python-gobject)"
quit_with_help_dialog "Requires PyGObject (python-gobject)"
exit 1
fi
logger INFO "Found PyGObject in Python env"
@ -247,7 +247,7 @@ open_url(){
xdg-open "$url"
fi
}
quit_with_pdialog(){
quit_with_help_dialog(){
local sel
msg="$1"
help_button="Open help page"
@ -260,7 +260,7 @@ quit_with_pdialog(){
check_pyver(){
if [[ ! $(python3.13 --version) ]]; then
local msg="Requires Python 3.13"
quit_with_pdialog "$msg"
quit_with_help_dialog "$msg"
fi
}
watcher_deps(){
@ -335,6 +335,7 @@ 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}')
@ -414,6 +415,7 @@ 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
@ -430,6 +432,7 @@ 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
@ -479,6 +482,7 @@ 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)
@ -489,16 +493,8 @@ steam_deps(){
exit 1
fi
}
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
@ -512,7 +508,7 @@ check_availability() {
return 1
fi
local url=$1
local timeout_sec="3"
local timeout_sec="1"
if [[ $2 ]]; then
timeout_sec=$2
fi
@ -523,6 +519,7 @@ 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
@ -534,6 +531,9 @@ 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,6 +548,7 @@ 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
@ -625,10 +626,10 @@ fetch_helpers_by_sum(){
[[ -f "$config_file" ]] && source "$config_file"
declare -A sums
sums=(
["funcs"]="5e35a9812c03fc64d75843a23d024f0d"
["funcs"]="69e83db00cbc7674e241565c88aed83d"
["query_v2.py"]="55d339ba02512ac69de288eb3be41067"
["servers.py"]="ed442c3aecf33f777d59dcf53650d263"
["ui.py"]="3d67e5e8e85a23dde1fd0e85a9be62a9"
["ui.py"]="d09b9d8bed3854efd51377289786c5ac"
["vdf2json.py"]="2f49f6f5d3af919bebaab2e9c220f397"
["pefile.py"]="21531f2c0d9dfa5f110cf6779f9d22c0"
)
@ -690,12 +691,12 @@ fetch_km_helper(){
}
get_response_code(){
local url="$1"
curl -Ls -I -o /dev/null -w "%{http_code}" "$url"
curl --connect-timeout 3 -Ls -I -o /dev/null -w "%{http_code}" "$url"
}
fetch_ip_db(){
parse_dl_url(){
curl -Ls "$url" \
curl --connect-timeout 3 -Ls "$url" \
| grep "csv.gz" \
| awk -F"['']" '{print $2}'
}
@ -711,6 +712,9 @@ 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
@ -730,7 +734,7 @@ fetch_ip_db(){
logger WARN "Abnormal exit while parsing IPs"
return
fi
rm "${state_path}/${month}.csv"
rm "${state_path}/${this_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
@ -745,55 +749,57 @@ fetch_ip_db(){
rm "$ip_file"
fi
echo "$month" > "$month_file"
logger INFO "Wrote '$month' to stub '$month_file'"
echo "$this_month" > "$month_file"
logger INFO "Wrote '$this_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"
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"
month_file="${state_path}/.month"
this_month=$(date +%Y-%m)
# no stub file
if [[ ! -f $month_file ]]; then
logger WARN "No stub file '$month_file' present"
fetch "$dl_url"
return
fi
# local needs update
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"
check_remote "$url"
return
fi
# if stub is same date, abort
logger INFO "Local stub '$last_month' is identical to remote, skipping"
local last_month=$(< "$month_file")
if [[ $last_month == "$this_month" ]]; then
logger INFO "Local stub '$last_month' is identical to remote, skipping"
return
fi
# local needs update
logger WARN "Local stub '$last_month' does not match '$this_month'"
check_remote "$url"
return
}
fetch_helpers(){
echo "# Checking helper files"
fetch_a2s
fetch_dzq
fetch_km_helper
@ -981,6 +987,7 @@ 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
@ -1007,12 +1014,14 @@ varcheck(){
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"
@ -1025,6 +1034,7 @@ 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
@ -1058,6 +1068,7 @@ 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
@ -1071,18 +1082,48 @@ 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 > >(pdialog "Checking helper files")
#fetch_helpers
varcheck
source "$config_file"
lock
@ -1091,14 +1132,12 @@ 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(){
@ -1200,8 +1239,15 @@ main(){
set_im_module
printf "Initializing setup...\n"
initial_setup
printf "Checking dependencies...\n"
setup_dirs
setup_state_files
depcheck
check_pyver
test_gobject
watcher_deps
initial_setup > >(pdialog "Initializing setup")
printf "All OK. Kicking off UI...\n"
python3.13 "$ui_helper" "--init-ui" "$version" "$is_steam_deck"

View File

@ -1,6 +1,6 @@
#!/usr/bin/env bash
set -o pipefail
version="6.0.1"
version="6.0.2-beta.1"
#CONSTANTS
aid=221100

View File

@ -19,7 +19,7 @@ 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
from typing import Literal, Self, Any, TYPE_CHECKING
import servers as Servers # noqa E402
import pefile as PeFile # noqa E402
@ -32,10 +32,12 @@ 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
@ -1027,13 +1029,7 @@ def process_tree_option(choice: RowType) -> None:
return
record = str_to_record(record)
thread_new_with_dialog(
App.treeview.prepare_connection,
parse_shell_output,
"Querying server",
command,
[record],
)
prepare_connection(command, record)
return
match command.dict["type"]:
@ -1061,48 +1057,54 @@ def parse_shell_output(proc: subprocess.CompletedProcess, row: RowType):
process_shell_return_code(msg, proc.returncode, row)
def thread_new_with_dialog(
func: Callable,
callback: Callable | None,
msg: str,
row: RowType | None,
args: list,
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
) -> None:
"""
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 background(addr, appid, path):
def cleanup():
App.treeview.dialog_hide()
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)
parse_shell_output(proc, row)
exception = None
proc = None
try:
proc = func(*args)
proc = call_out("try_connect", addr, appid, path)
except Exception as e:
exception = e
logger.critical(e)
GLib.idle_add(cleanup)
return
GLib.idle_add(cleanup)
msg = "Querying server"
App.treeview.dialog_show(msg)
thread = threading.Thread(target=background, args=(args))
thread = threading.Thread(target=background, args=(addr, appid, path))
thread.start()
@ -1142,27 +1144,31 @@ def record_to_str(record: Record) -> str:
def connect_by_ip(enum: RowType, response: str) -> None:
def _prep(response: str) -> None:
try:
record = Servers.validate_ip(response)
proc = App.treeview.prepare_connection(record)
return proc
thread_new_with_dialog(
_prep, parse_shell_output, "Querying IP", enum, [response]
)
return
except Exception as e:
spawn_dialog(str(e), Popup.NOTIFY)
return
prepare_connection(enum, record)
def connect_by_id(enum: RowType, response: str, key: str) -> None:
def _prep(key: str, response: str) -> None:
record = Servers.query_bm_api(key, response)
proc = App.treeview.prepare_connection(record)
return proc
def cleanup() -> None:
App.treeview.dialog_hide()
prepare_connection(enum, record)
thread_new_with_dialog(
_prep, parse_shell_output, "Querying API", enum, [key, response]
)
return
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()
def process_user_input(enum: RowType) -> None:
@ -2493,6 +2499,8 @@ 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(
@ -2943,9 +2951,9 @@ class TreeView(Gtk.TreeView):
def get_view(self):
return self.view
def prepare_connection(
def get_prereqs(
self, record: Record
) -> subprocess.CompletedProcess | None:
) -> tuple[bool, str, str|None, "Prereqs"]:
"""
Always called on a thread with a dialog on the transient parent window
"""
@ -2953,8 +2961,7 @@ 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"
spawn_dialog(msg, Popup.NOTIFY)
return None
return (False, msg, None, prereqs)
build = "DayZ" if prereqs.appid == APPID_DAYZ else "DayZ Experimental"
steam_path = query_config("default_steam_path")[0]
@ -2964,8 +2971,7 @@ 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."
spawn_dialog(msg, Popup.NOTIFY)
return None
return (False, msg, None, prereqs)
try:
pefile_path = PeFile.get_pefile_path(steam_path, prereqs.appid)
@ -2979,8 +2985,7 @@ 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."
)
spawn_dialog(msg, Popup.NOTIFY)
return None
return (False, msg, None, prereqs)
except AppMovedError:
logger.critical(
f"Library folder synch error for '{prereqs.appid}'"
@ -2990,13 +2995,11 @@ 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."
)
spawn_dialog(msg, Popup.NOTIFY)
return None
return (False, msg, None, prereqs)
except (VDFLoadError, PeFileError, Exception) as e:
logger.critical(e)
msg = "Steam settings or DayZ installation may be corrupted. Try restarting Steam."
spawn_dialog(msg, Popup.NOTIFY)
return None
return (False, msg, None, prereqs)
try:
local_vers = PeFile.get_dayz_version(pefile_path)
@ -3008,7 +3011,7 @@ class TreeView(Gtk.TreeView):
local_vers = None
try:
remote_vers = PeFile.dayz_version_from_str(prereqs.version)
remote_vers = PeFile.dayz_version_from_str(prereqs)
except Exception:
remote_vers = None
@ -3021,18 +3024,15 @@ 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?"
)
res = spawn_dialog(msg, Popup.CONFIRM)
if res is True:
return None
return (True, msg, pefile_path, prereqs)
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?"
)
res = spawn_dialog(msg, Popup.CONFIRM)
if res is True:
return None
return (True, msg, pefile_path, prereqs)
case VersionMatch.SAME_VERSION:
return (True, "", pefile_path, prereqs)
pass
if prereqs.password is True:
@ -3040,19 +3040,10 @@ class TreeView(Gtk.TreeView):
"This server is password-protected and you will be "
"prompted when connecting. Do you want to proceed?"
)
res = spawn_dialog(msg, Popup.CONFIRM)
if res is True:
return None
return (True, msg, pefile_path, prereqs)
return (True, "", pefile_path, prereqs)
"""
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
@ -3122,13 +3113,7 @@ class TreeView(Gtk.TreeView):
record = self.get_record()
if record is None:
return
thread_new_with_dialog(
self.prepare_connection,
parse_shell_output,
"Querying server",
None,
[record],
)
prepare_connection(None, record)
case _: # any other non-server option from the main menu
process_tree_option(output)