1
0
Fork 0
mirror of https://github.com/aclist/dztui.git synced 2025-01-14 13:08:05 +01:00

Compare commits

...

8 commits

Author SHA1 Message Date
aclist
99d964bf44 chore: bump version 2024-12-18 18:22:41 +09:00
aclist
471cfec94b
Merge pull request #174 from jiriks74/testing
fix(checks): Check `vm.max_map_count` using `cat`
2024-12-18 18:19:48 +09:00
aclist
717070ec40
Merge pull request #177 from aclist/release/5.6.0-beta.18
feat: open workshop subscriptions
2024-12-18 17:29:29 +09:00
aclist
a18d68776f chore: add logging 2024-12-18 17:26:31 +09:00
c73120295a
fix(checks): Check vm.max_map_count using cat
This solves multiple issues:
- We don't need `sudo` to check the value anymore
- Some systems may not have `sysctl` available
  - IDK about desktops, but my Debian server doesn't have this command
  (for whatever reason)
2024-12-17 15:54:17 +01:00
aclist
6e3746e9b4 fix: abort path discovery 2024-12-16 15:21:57 +09:00
aclist
34b3d3bc8c chore: drop unused var 2024-12-16 14:49:55 +09:00
aclist
4d3d9bf0bb feat: open workshop subscriptions 2024-12-15 09:08:35 +09:00
4 changed files with 125 additions and 19 deletions

View file

@ -1,5 +1,16 @@
# Changelog
## [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

View file

@ -1,7 +1,7 @@
#!/usr/bin/env bash
set -o pipefail
version=5.6.0-beta.17
version=5.6.0-beta.18
#CONSTANTS
aid=221100
@ -406,13 +406,20 @@ check_architecture(){
}
check_map_count(){
[[ $is_steam_deck -gt 0 ]] && return 0
local count=1048576
local map_count_file="/proc/sys/vm/max_map_count"
local min_count=1048576
local conf_file="/etc/sysctl.d/dayz.conf"
if [[ -f $conf_file ]]; then
logger DEBUG "System map count is already $count or higher"
local current_count
if [[ ! -f ${map_count_file} ]]; then
logger WARN "File '${map_count_file}' doesn't exist!"
return 1
fi
current_count=$(cat ${map_count_file})
if [[ $current_count -ge $min_count ]]; then
logger DEBUG "System map count is set to ${current_count}"
return 0
fi
qdialog "sudo password required to check system vm map count." "OK" "Cancel"
qdialog "sudo password required to set system vm map count." "OK" "Cancel"
if [[ $? -eq 0 ]]; then
local pass
logger INFO "Prompting user for sudo escalation"
@ -421,13 +428,11 @@ check_map_count(){
logger WARN "User aborted password prompt"
return 1
fi
local ct=$(sudo -S <<< "$pass" sh -c "sysctl -q vm.max_map_count | awk -F'= ' '{print \$2}'")
logger DEBUG "Old map count is $ct"
local new_ct
[[ $ct -lt $count ]] && ct=$count
sudo -S <<< "$pass" sh -c "echo 'vm.max_map_count=$ct' > $conf_file"
logger DEBUG "Old map count is $current_count"
[[ $current_count -lt $min_count ]] && current_count=$min_count
sudo -S <<< "$pass" sh -c "echo 'vm.max_map_count=${current_count}' > $conf_file"
sudo sysctl -p "$conf_file"
logger DEBUG "Updated map count to $count"
logger DEBUG "Updated map count to $min_count"
else
logger WARN "User aborted map count prompt"
return 1
@ -578,10 +583,10 @@ fetch_helpers_by_sum(){
[[ -f "$config_file" ]] && source "$config_file"
declare -A sums
sums=(
["ui.py"]="be3da1e542d14105f4358dd38901e25a"
["ui.py"]="99544ccef6060125509c4b689a808a15"
["query_v2.py"]="55d339ba02512ac69de288eb3be41067"
["vdf2json.py"]="2f49f6f5d3af919bebaab2e9c220f397"
["funcs"]="37897aa36bc2fb6286cee02c8bb07258"
["funcs"]="98261fdba4323f77c6dd610c1efc4d11"
["lan"]="c62e84ddd1457b71a85ad21da662b9af"
)
local author="aclist"
@ -747,7 +752,7 @@ find_library_folder(){
local search_path="$1"
steam_path="$(python3 "$helpers_path/vdf2json.py" -i "$1/steamapps/libraryfolders.vdf" \
| jq -r '.libraryfolders[]|select(.apps|has("221100")).path')"
if [[ ! $? -eq 0 ]]; then
if [[ ! $? -eq 0 ]] || [[ -z $steam_path ]]; then
logger WARN "Failed to parse Steam path using '$search_path'"
return 1
fi
@ -800,7 +805,7 @@ create_config(){
find_library_folder "$default_steam_path"
if [[ -z $steam_path ]]; then
logger raise_error "Steam path was empty"
zenity --question --text="DayZ not found or not installed at the Steam library given." --ok-label="Choose path manually" --cancel-label="Exit"
zenity --question --text="DayZ not found or not installed at the Steam library given. NOTE: if you recently installed DayZ or moved its location, you MUST restart Steam first for these changes to synch." --ok-label="Choose path manually" --cancel-label="Exit"
if [[ $? -eq 0 ]]; then
logger INFO "User selected file picker"
file_picker

View file

@ -104,6 +104,7 @@ declare -A funcs=(
["Connect by IP"]="validate_and_connect"
["Connect by ID"]="validate_and_connect"
["Connect from table"]="connect_from_table"
["find_id"]="find_id"
["toggle"]="toggle"
["Open link"]="open_link"
["filter"]="dump_servers"
@ -121,6 +122,7 @@ declare -A funcs=(
["is_in_favs"]="is_in_favs"
["show_log"]="show_log"
["Output system info to log file"]="generate_log"
["open_user_workshop"]="open_user_workshop"
["open_workshop_page"]="open_workshop_page"
["Add to my servers"]="update_favs_from_table"
["Remove from my servers"]="update_favs_from_table"
@ -332,18 +334,32 @@ is_in_favs(){
done
return 1
}
find_id(){
local file="$default_steam_path/config/loginusers.vdf"
[[ ! -f $file ]] && return 1
local res=$(python3 $HOME/.local/share/dzgui/helpers/vdf2json.py \
-i "$file" | jq -r '.users
|to_entries[]
|select(.value.MostRecent=="1")
|.key'
)
[[ -z $res ]] && return 1
printf "%s" "$res"
return 0
}
list_mods(){
local symlink
local sep
local name
local base_dir
local size
local mods
if [[ -z $(installed_mods) ]] || [[ -z $(find $workshop_dir -maxdepth 2 -name "*.cpp" | grep .cpp) ]]; then
printf "No mods currently installed or incorrect path set."
logger WARN "Found no locally installed mods"
return 1
else
for dir in $(find $game_dir/* -maxdepth 1 -type l); do
mods=$(for dir in $(find $game_dir/* -maxdepth 1 -type l); do
symlink=$(basename $dir)
sep="␞"
name=$(awk -F\" '/name/ {print $2}' "${dir}/meta.cpp")
@ -351,7 +367,14 @@ list_mods(){
size=$(du -s "$(readlink -f "$game_dir/$symlink")" | awk '{print $1}')
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
done | sort -k1)
# user may have manually pruned mods out-of-band
# handle directory detritus but no actual mods
if [[ -z $mods ]]; then
printf "No mods currently installed or incorrect path set."
return 1
fi
echo "$mods"
fi
}
installed_mods(){
@ -1051,6 +1074,12 @@ update_config_val(){
show_log(){
< "$debug_log" sed 's/Keyword␞/Keyword/'
}
open_user_workshop(){
shift
local id="$1"
url="https://steamcommunity.com/profiles/$id/myworkshopfiles/?appid=$aid&browsefilter=mysubscriptions"
$steam_cmd steam://openurl/$url &
}
open_workshop_page(){
shift
local id="$1"
@ -1173,7 +1202,7 @@ legacy_symlinks(){
logger INFO "Removing legacy symlinks"
for d in "$game_dir"/*; do
if [[ $d =~ @[0-9]+-.+ ]]; then
logger INFO "Unlinking $d"
logger INFO "Unlinking '$d'"
unlink "$d"
fi
done
@ -1183,11 +1212,14 @@ legacy_symlinks(){
logger INFO "Removing legacy encoding format"
for d in "${mod_dirs[@]}"; do
# suppress errors if mods are downloading at boot
logger INFO "Testing directory '$d'"
[[ ! -f "$d/meta.cpp" ]] && continue
local id=$(awk -F"= " '/publishedid/ {print $2}' "$d"/meta.cpp | awk -F\; '{print $1}')
logger INFO "Given id is '$id'"
local encoded_id=$(echo "$id" | awk '{printf("%c",$1)}' | base64 | sed 's/\//_/g; s/=//g; s/+/]/g')
logger INFO "Resolved id is '$encoded_id'"
if [[ -h "$game_dir/@$encoded_id" ]]; then
logger INFO "Unlinking $game_dir/@$encoded_id"
logger INFO "Unlinking '$game_dir/@$encoded_id'"
unlink "$game_dir/@$encoded_id"
fi
done

View file

@ -215,6 +215,7 @@ class RowType(EnumWithAttrs):
"label": "Toggle mod install mode",
"tooltip": "Switch between manual and auto mod installation",
"default": "manual",
"link_label": "Open Steam Workshop",
"alt": "auto",
"val": "auto_install"
}
@ -756,6 +757,29 @@ def process_tree_option(input, treeview):
case RowType.TGL_BRANCH:
wait_msg = "Updating DZGUI branch"
call_on_thread(False, "toggle", wait_msg, cmd_string)
case RowType.TGL_INSTALL:
if query_config(None, "auto_install")[0] == "1":
proc = call_out(transient_parent, "toggle", cmd_string)
grid.update_right_statusbar()
tooltip = format_metadata(command.dict["label"])
transient_parent.grid.update_statusbar(tooltip)
return
# manual -> auto mode
proc = call_out(transient_parent, "find_id", "")
if proc.returncode == 1:
link=None
uid=None
else:
link=command.dict["link_label"]
uid=proc.stdout
manual_sub_msg = """\
When switching from MANUAL to AUTO mod install mode,
DZGUI will manage mod installation and deletion for you.
To prevent conflicts with Steam Workshop subscriptions and old mods from being downloaded
when Steam updates, you should unsubscribe from any existing Workshop mods you manually subscribed to.
Open your Profile > Workshop Items and select 'Unsubscribe from all'
on the right-hand side, then click OK below to enable AUTO mod install mode."""
LinkDialog(transient_parent, textwrap.dedent(manual_sub_msg), Popup.NOTIFY, link, command, uid)
case _:
proc = call_out(transient_parent, "toggle", cmd_string)
grid.update_right_statusbar()
@ -2205,6 +2229,40 @@ class ModDialog(GenericDialog):
subprocess.Popen(['/usr/bin/env', 'bash', funcs, "open_workshop_page", mod_id])
class LinkDialog(GenericDialog):
def __init__(self, parent, text, mode, link, command, uid=None):
super().__init__(parent, text, mode)
self.dialog = GenericDialog(parent, text, mode)
self.dialogBox = self.dialog.get_content_area()
self.dialog.set_default_response(Gtk.ResponseType.OK)
self.dialog.set_size_request(500, 0)
if link is not None:
button = Gtk.Button(label=link)
button.set_margin_start(60)
button.set_margin_end(60)
button.connect("clicked", self._on_button_clicked, uid)
self.dialogBox.pack_end(button, False, False, 0)
self.dialog.show_all()
self.dialog.connect("response", self._on_dialog_response, parent, command)
def _on_button_clicked(self, button, uid):
subprocess.Popen(['/usr/bin/env', 'bash', funcs, "open_user_workshop", uid])
def _on_dialog_response(self, dialog, resp, parent, command):
match resp:
case Gtk.ResponseType.DELETE_EVENT:
return
case Gtk.ResponseType.OK:
self.dialog.destroy()
proc = call_out(parent, "toggle", command.dict["label"])
parent.grid.update_right_statusbar()
tooltip = format_metadata(command.dict["label"])
parent.grid.update_statusbar(tooltip)
class EntryDialog(GenericDialog):
def __init__(self, parent, text, mode, link):
super().__init__(parent, text, mode)