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

fix: error handling for no local mods

This commit is contained in:
aclist 2024-11-19 21:49:59 +09:00
parent 32a43cd787
commit 8b9f751ff1
4 changed files with 108 additions and 50 deletions

View file

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

View file

@ -569,10 +569,10 @@ fetch_helpers_by_sum(){
[[ -f "$config_file" ]] && source "$config_file"
declare -A sums
sums=(
["ui.py"]="680ff0e4071681f26409fa3592a41e46"
["ui.py"]="4663cdda7bf91a0c594103d6f4382f15"
["query_v2.py"]="55d339ba02512ac69de288eb3be41067"
["vdf2json.py"]="2f49f6f5d3af919bebaab2e9c220f397"
["funcs"]="acd5d85b27141082b25e07138f8b5b54"
["funcs"]="5eae515ea2cac2ab38212a529415e86b"
["lan"]="c62e84ddd1457b71a85ad21da662b9af"
)
local author="aclist"
@ -874,6 +874,9 @@ stale_mod_signatures(){
fi
}
create_new_links(){
"$HOME/.local/share/$app_name/helpers/funcs" "update_symlinks"
}
initial_setup(){
setup_dirs
setup_state_files
@ -895,6 +898,7 @@ initial_setup(){
migrate_files
stale_symlinks
stale_mod_signatures
create_new_links
local_latlon
is_steam_running
is_dzg_downloading

View file

@ -116,7 +116,7 @@ declare -A funcs=(
["query_config"]="query_config"
["start_cooldown"]="start_cooldown"
["list_mods"]="list_mods"
["delete"]="delete_local_mod"
["Delete selected mods"]="delete_local_mod"
["align_local"]="align_versions_file"
["show_server_modlist"]="show_server_modlist"
["test_ping"]="test_ping"
@ -131,6 +131,7 @@ declare -A funcs=(
["Handshake"]="final_handshake"
["get_player_count"]="get_player_count"
["lan_scan"]="lan_scan"
["update_symlinks"]="update_symlinks"
)
lan_scan(){
@ -588,19 +589,34 @@ align_versions_file(){
mv $versions_file.new $versions_file
logger INFO "Removed local signatures for the mod '$mod'"
}
pluralize(){
local plural="$1"
local count="$2"
local mod
local suffix
local base
local ct
local s
if [[ "${plural: -2}" == "es" ]]; then
base="${plural::-2}"
suffix="${plural: -2}"
ct=$((count^2))
[[ $ct -ne 3 ]] && s="$suffix"
else
base="${plural::-1}"
suffix="${plural: -1}"
ct=$((count^1))
[[ $ct -gt 0 ]] && s="$suffix"
fi
printf "%s%s" "$base" "$s"
}
delete_local_mod(){
shift
if [[ -z $1 ]]; then
# use multi mode
readarray -t symlinks < <(awk '{print $1}' $_cache_mods_temp)
readarray -t ids < <(awk '{print $2}' $_cache_mods_temp)
rm "$_cache_mods_temp"
else
local symlink="$1"
local dir="$2"
readarray -t symlinks <<< "$symlink"
readarray -t ids <<< "$dir"
fi
readarray -t symlinks < <(awk '{print $1}' $_cache_mods_temp)
readarray -t ids < <(awk '{print $2}' $_cache_mods_temp)
rm "$_cache_mods_temp"
for ((i=0; i<${#symlinks[@]}; i++)); do
[[ ! -d $workshop_dir/${ids[$i]} ]] && return 1
[[ ! -L $game_dir/${symlinks[$i]} ]] && return 1
@ -608,16 +624,17 @@ delete_local_mod(){
rm -rf "${workshop_dir:?}/${ids[$i]}" && unlink "$game_dir/${symlinks[$i]}" || return 1
align_versions_file "align" "${ids[$i]}"
done
printf "Successfully deleted %s %s." "${#symlinks[@]}" "$(pluralize "mods" ${#symlinks[@]})"
return 95
}
test_cooldown(){
[[ ! -f $_cache_cooldown ]] && return 0
local old_time=$(< $_cache_cooldown)
local cur_time=$(date +%s)
local delta=$(($cur_time - $old_time))
local suffix="seconds"
if [[ $delta -lt 60 ]]; then
local remains=$((60 - $delta))
[[ $remains -eq 1 ]] && suffix="second"
local suffix=$(pluralize "seconds" $remains)
printf "Global API cooldown in effect. Please wait %s %s." "$remains" "$suffix"
exit 1
fi
@ -1104,7 +1121,11 @@ legacy_symlinks(){
unlink "$d"
fi
done
for d in "$workshop_dir"/*; do
readarray -t mod_dirs < <(find "$workshop_dir" -maxdepth 1 -mindepth 1 -type d)
[[ ${#mod_dirs[@]} -eq 0 ]] && return
for d in "${mod_dirs[@]}"; do
# suppress errors if mods are downloading at boot
[[ ! -f "$d/meta.cpp" ]] && continue
local id=$(awk -F"= " '/publishedid/ {print $2}' "$d"/meta.cpp | awk -F\; '{print $1}')
local encoded_id=$(echo "$id" | awk '{printf("%c",$1)}' | base64 | sed 's/\//_/g; s/=//g; s/+/]/g')
if [[ -h "$game_dir/@$encoded_id" ]]; then
@ -1113,7 +1134,11 @@ legacy_symlinks(){
done
}
symlinks(){
for d in "$workshop_dir"/*; do
readarray -t mod_dirs < <(find "$workshop_dir" -maxdepth 1 -mindepth 1 -type d)
[[ ${#mod_dirs[@]} -eq 0 ]] && return
for d in "${mod_dirs[@]}"; do
# suppress errors if mods are downloading at boot
[[ ! -f "$d/meta.cpp" ]] && continue
id=$(awk -F"= " '/publishedid/ {print $2}' "$d"/meta.cpp | awk -F\; '{print $1}')
encoded_id=$(encode "$id")
link="@$encoded_id"

View file

@ -330,8 +330,8 @@ def spawn_dialog(transient_parent, msg, mode):
def process_shell_return_code(transient_parent, msg, code, original_input):
logger.info("Processing return code '%s' for the input '%s', returned message '%s'" %(code, original_input, msg))
match code:
#TODO: add logger output to each
case 0:
# success with notice popup
spawn_dialog(transient_parent, msg, Popup.NOTIFY)
@ -369,6 +369,13 @@ def process_shell_return_code(transient_parent, msg, code, original_input):
transient_parent.grid.update_statusbar(tooltip)
spawn_dialog(transient_parent, msg, Popup.NOTIFY)
return
case 95:
# reload mods list
spawn_dialog(transient_parent, msg, Popup.NOTIFY)
treeview = transient_parent.grid.scrollable_treelist.treeview
# re-block this signal before redrawing table contents
toggle_signal(treeview, treeview, '_on_keypress', False)
treeview.update_quad_column("List installed mods")
case 100:
# final handoff before launch
final_conf = spawn_dialog(transient_parent, msg, Popup.CONFIRM)
@ -427,6 +434,8 @@ def process_tree_option(input, treeview):
else:
# non-blocking subprocess
subprocess.Popen(['/usr/bin/env', 'bash', funcs, "Open link", command])
case "Delete selected mods":
call_on_thread(True, context, "Deleting mods", command)
case "Handshake":
call_on_thread(True, context, "Waiting for DayZ", command)
case _:
@ -605,7 +614,9 @@ class ButtonBox(Gtk.Box):
# only applicable when returning from mod list
grid = widgets["grid"]
grid.right_panel.remove(grid.sel_panel)
grid_last_child = grid.right_panel.get_children()[-1]
if isinstance(grid_last_child, ModSelectionPanel):
grid.right_panel.remove(grid.sel_panel)
right_panel = self.get_parent()
right_panel.set_filter_visibility(False)
@ -780,15 +791,15 @@ class TreeView(Gtk.TreeView):
success_msg = "Successfully deleted the mod '%s'." %(value)
fail_msg = "An error occurred during deletion. Aborting."
res = spawn_dialog(parent, conf_msg, Popup.CONFIRM)
symlink = self.get_column_at_index(1)
dir = self.get_column_at_index(2)
if res == 0:
proc = call_out(parent, "delete", symlink, dir)
if proc.returncode == 0:
spawn_dialog(parent, success_msg, Popup.NOTIFY)
self.update_quad_column("List installed mods")
else:
spawn_dialog(parent, fail_msg, Popup.NOTIFY)
mods = []
symlink = self.get_column_at_index(1)
dir = self.get_column_at_index(2)
concat = symlink + " " + dir + "\n"
mods.append(concat)
with open(mods_temp_file, "w") as outfile:
outfile.writelines(mods)
process_tree_option(["Delete selected mods", ""], self)
case "Open in Steam Workshop":
record = self.get_column_at_index(2)
call_out(parent, "open_workshop_page", record)
@ -851,6 +862,11 @@ class TreeView(Gtk.TreeView):
self.menu.show_all()
if event.type is Gdk.EventType.KEY_PRESS and event.keyval is Gdk.KEY_l:
sel = self.get_selection()
sels = sel.get_selected_rows()
(model, pathlist) = sels
if len(pathlist) < 1:
return
self.menu.popup_at_widget(widget, Gdk.Gravity.CENTER, Gdk.Gravity.WEST)
else:
self.menu.popup_at_pointer(event)
@ -973,8 +989,11 @@ class TreeView(Gtk.TreeView):
def _focus_first_row(self):
path = Gtk.TreePath(0)
it = mod_store.get_iter(path)
self.get_selection().select_path(path)
try:
it = mod_store.get_iter(path)
self.get_selection().select_path(path)
except ValueError:
pass
def get_column_at_index(self, index):
select = self.get_selection()
@ -1056,31 +1075,42 @@ class TreeView(Gtk.TreeView):
def _background_quad(self, dialog, mode):
def load():
dialog.destroy()
# detach button panel if store is empty
if isinstance(panel_last_child, ModSelectionPanel):
if total_mods == 0:
right_panel.remove(grid.sel_panel)
grid.show_all()
right_panel.set_filter_visibility(False)
self.set_model(mod_store)
self.grab_focus()
if abort is False:
size = locale.format_string('%.3f', total_size, grouping=True)
pretty = pluralize("mods", total_mods)
grid.update_statusbar(f"Found {total_mods:n} {pretty} taking up {size} MiB")
size = locale.format_string('%.3f', total_size, grouping=True)
pretty = pluralize("mods", total_mods)
grid.update_statusbar(f"Found {total_mods:n} {pretty} taking up {size} MiB")
#2024-11-12
toggle_signal(self, self.selected_row, '_on_tree_selection_changed', True)
toggle_signal(self, self, '_on_keypress', True)
self._focus_first_row()
if total_mods == 0:
spawn_dialog(self.get_outer_window(), data.stdout, Popup.NOTIFY)
grid = self.get_outer_grid()
widgets = relative_widget(self)
grid = widgets["grid"]
right_panel = grid.right_panel
abort = False
right_panel.set_filter_visibility(False)
data = call_out(self, "list_mods", mode)
panel_last_child = right_panel.get_children()[-1]
# suppress errors if no mods available on system
if data.returncode == 1:
abort = True
total_mods = 0
total_size = 0
GLib.idle_add(load)
spawn_dialog(self.get_outer_window(), data.stdout, Popup.NOTIFY)
return 1
# attach button panel only if missing (prevents duplication when reloading in-place)
if not isinstance(panel_last_child, ModSelectionPanel):
right_panel.pack_start(grid.sel_panel, False, False, 0)
grid.show_all()
right_panel.set_filter_visibility(False)
result = parse_mod_rows(data)
total_size = result[0]
total_mods = result[1]
@ -1214,10 +1244,6 @@ class TreeView(Gtk.TreeView):
if mode == "List installed mods":
cols = mod_cols
self.set_model(mod_store)
# attach button panel
grid = self.get_parent().get_parent()
grid.right_panel.pack_start(grid.sel_panel, False, False, 0)
grid.show_all()
else:
cols = log_cols
self.set_model(log_store)
@ -1988,12 +2014,7 @@ class ModSelectionPanel(Gtk.Box):
mods.append(concat)
with open(mods_temp_file, "w") as outfile:
outfile.writelines(mods)
proc = call_out(parent, "delete")
if proc.returncode == 0:
spawn_dialog(parent, success_msg, Popup.NOTIFY)
treeview.update_quad_column("List installed mods")
else:
spawn_dialog(parent, fail_msg, Popup.NOTIFY)
process_tree_option(["Delete selected mods", ""], treeview)
class FilterPanel(Gtk.Box):
def __init__(self):