diff --git a/README.md b/README.md index 7e1f2e9..6ae1b4b 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ The following requirements should be available out-of-the-box in most systems: - _bash_ - either _curl_ or _wget_ -- _zenity_ +- either _zenity_ or _kdialog_ - _protontricks-launcher_: should be available after installing `protontricks` already, if not see [this](https://github.com/Matoking/protontricks#desktop) #### Installation steps diff --git a/gamesinfo/enderal.sh b/gamesinfo/enderal.sh index 56279c1..f47d871 100644 --- a/gamesinfo/enderal.sh +++ b/gamesinfo/enderal.sh @@ -1,3 +1,4 @@ +game_full_name="Enderal: Forgotten Stories" game_steam_subdirectory="Enderal" game_nexusid="enderal" game_appid=933480 diff --git a/gamesinfo/enderal_se.sh b/gamesinfo/enderal_se.sh index 700b030..55a9d04 100644 --- a/gamesinfo/enderal_se.sh +++ b/gamesinfo/enderal_se.sh @@ -1,3 +1,4 @@ +game_full_name="Enderal: Forgotten Stories (Special Edition)" game_steam_subdirectory="Enderal Special Edition" game_nexusid="enderalspecialedition" game_appid=976620 diff --git a/gamesinfo/fallout3.sh b/gamesinfo/fallout3.sh index b2729ed..adc2596 100644 --- a/gamesinfo/fallout3.sh +++ b/gamesinfo/fallout3.sh @@ -1,7 +1,7 @@ +game_steam_subdirectory="Fallout 3" game_appid=22300 game_executable="FalloutLauncherSteam.exe" game_nexusid="fallout3" -game_steam_subdirectory="Fallout 3" game_protontricks=("d3dcompiler_43" "d3dx9") game_scriptextender_url="https://www.fose.silverlock.org/download/fose_v1_2_beta2.7z" game_scriptextender_files="*" diff --git a/gamesinfo/fallout3_goty.sh b/gamesinfo/fallout3_goty.sh index fb5df10..13c592e 100644 --- a/gamesinfo/fallout3_goty.sh +++ b/gamesinfo/fallout3_goty.sh @@ -1,7 +1,8 @@ +game_full_name="Fallout 3 - Game of the Year Edition" +game_steam_subdirectory="Fallout 3 goty" game_appid=22370 game_executable="FalloutLauncherSteam.exe" game_nexusid="fallout3" -game_steam_subdirectory="Fallout 3 goty" game_protontricks=("d3dcompiler_43" "d3dx9") game_scriptextender_url="https://www.fose.silverlock.org/download/fose_v1_2_beta2.7z" game_scriptextender_files="*" diff --git a/gamesinfo/newvegas.sh b/gamesinfo/newvegas.sh index 02fc482..3902aba 100644 --- a/gamesinfo/newvegas.sh +++ b/gamesinfo/newvegas.sh @@ -1,3 +1,4 @@ +game_full_name="Fallout: New Vegas" game_steam_subdirectory="Fallout New Vegas" game_nexusid="newvegas" game_appid=22380 diff --git a/gamesinfo/newvegas_ru.sh b/gamesinfo/newvegas_ru.sh index b773cfc..9a304d4 100644 --- a/gamesinfo/newvegas_ru.sh +++ b/gamesinfo/newvegas_ru.sh @@ -1,3 +1,4 @@ +game_full_name="Fallout: New Vegas RU" game_steam_subdirectory="Fallout New Vegas enplczru" game_nexusid="newvegas" game_appid=22490 diff --git a/gamesinfo/skyrimvr.sh b/gamesinfo/skyrimvr.sh index 47afa9a..a933089 100644 --- a/gamesinfo/skyrimvr.sh +++ b/gamesinfo/skyrimvr.sh @@ -1,3 +1,4 @@ +game_pretty_name="Skyrim VR" game_steam_subdirectory="SkyrimVR" game_nexusid="skyrimspecialedition" game_appid=611670 diff --git a/handlers/modorganizer2-nxm-broker.sh b/handlers/modorganizer2-nxm-broker.sh index 89de091..a80cfdf 100755 --- a/handlers/modorganizer2-nxm-broker.sh +++ b/handlers/modorganizer2-nxm-broker.sh @@ -8,6 +8,15 @@ if [ -z "$nxm_link" ]; then exit 1 fi +if [ -n "$(command -v zenity)" ]; then + ui_bin="zenity" +elif [ -z "$(command -v kdialog)" ]; then + ui_bin="kdialog" +else + echo "Error zenity or kdialog required, install one" >&2 + exit 1 +fi + nexus_game_id=${nxm_link#nxm://} nexus_game_id=${nexus_game_id%%/*} ### PARSE POSITIONAL ARGS ### @@ -17,8 +26,16 @@ instance_dir=$(readlink -f "$instance_link") if [ ! -d "$instance_dir" ]; then [ -L "$instance_link"] && rm "$instance_link" - zenity --ok-label=Exit --error --text \ - "Could not download file because there is no Mod Organizer 2 instance for '$nexus_game_id'" + error_text="Could not download file because there is no Mod Organizer 2 instance for '$nexus_game_id'" + case "$ui_bin" in + zenity) + zenity --ok-label=Exit --error --text "$error_text" + ;; + kdialog) + kdialog --ok-label=Exit --error "$error_text" + ;; + esac + exit 1 fi @@ -39,8 +56,15 @@ else fi if [ "$download_start_status" != "0" ]; then - zenity --ok-label=Exit --error --text \ - "Failed to start download:\n\n$download_start_output" + error_text="Failed to start download:\n\n$download_start_output" + case "$ui_bin" in + zenity) + zenity --ok-label=Exit --error --text "$error_text" + ;; + kdialog) + kdialog --ok-label=Exit --error "$error_text" + ;; + esac exit 1 fi diff --git a/install.sh b/install.sh index 49f613e..aab0d10 100755 --- a/install.sh +++ b/install.sh @@ -82,5 +82,5 @@ source "$step/apply_workarounds.sh" log_info "installation completed successfully" expect_exit=1 -"$dialog" infobox "Installation successful!\n\Launch the game on Steam to use Mod Organizer 2" +"$dialog" infobox "Installation successful!\n\nLaunch the game on Steam to use Mod Organizer 2" diff --git a/steam-redirector/README.md b/steam-redirector/README.md index 32f20e0..d986f55 100644 --- a/steam-redirector/README.md +++ b/steam-redirector/README.md @@ -32,6 +32,11 @@ sudo dnf install gcc make mingw64-gcc mingw64-winpthreads-static sudo pacman -S gcc make mingw-w64-gcc mingw-w64-winpthreads ``` +#### Debian/Ubuntu +``` +sudo apt install -y gcc make mingw-w64 +``` + Check MinGW's [downloads page](https://www.mingw-w64.org/downloads/) for a more complete list of available packages. ### Compile Commands diff --git a/step/check_dependencies.sh b/step/check_dependencies.sh index ae5bb06..0425bfc 100644 --- a/step/check_dependencies.sh +++ b/step/check_dependencies.sh @@ -14,8 +14,8 @@ if [ ! $("$utils/protontricks.sh" get-release) ]; then missing_deps+=(protontricks) fi -if [ -z "$(command -v zenity)" ]; then - missing_deps+=(zenity) +if [ -z "$(command -v zenity)" ] && [ -z "$(command -v kdialog)" ]; then + missing_deps+=("zenity or kdialog") fi if [ -n "${missing_deps[*]}" ]; then diff --git a/step/select_game.sh b/step/select_game.sh index 5fa7ba5..d4e424f 100644 --- a/step/select_game.sh +++ b/step/select_game.sh @@ -11,23 +11,23 @@ Which game would you like to manage with this installation? EOF ) +game_list=() +for game in $(ls -1 $gamesinfo); do + source "$gamesinfo/$game" + [[ -n "${game_full_name:-}" ]] && game_name="$game_full_name" \ + || game_name="$game_steam_subdirectory" + game_list+=("$(basename "$game" '.sh')" "$game_name") + unset game_full_name game_steam_subdirectory game_protontricks \ + game_nexusid game_appid game_executable \ + game_scriptextender_url game_scriptextender_files +done + + selected_game=$( \ "$dialog" \ radio \ 450 "$screen_text" \ - "enderal" "Enderal: Forgotten Stories" \ - "enderal_se" "Enderal: Forgotten Stories (Special Edition)" \ - "fallout3" "Fallout 3" \ - "fallout3_goty" "Fallout 3 - Game of the Year Edition" \ - "fallout4" "Fallout 4" \ - "newvegas" "Fallout: New Vegas" \ - "newvegas_ru" "Fallout: New Vegas RU" \ - "morrowind" "Morrowind" \ - "oblivion" "Oblivion" \ - "skyrim" "Skyrim" \ - "skyrimspecialedition" "Skyrim Special Edition" \ - "skyrimvr" "Skyrim VR" \ - "starfield" "Starfield"\ + "${game_list[@]}" ) if [ -z "$selected_game" ]; then diff --git a/utils/dialog.sh b/utils/dialog.sh index e27b32a..bf58cf2 100755 --- a/utils/dialog.sh +++ b/utils/dialog.sh @@ -2,80 +2,181 @@ dialogtype=$1; shift -if [ -z "$(command -v zenity)" ]; then +if [ -z "$(command -v zenity)" ] && [ -z "$(command -v kdialog)" ] ; then echo "ERROR: no interface available, make sure zenity is installed on your system" >&2 exit 1 +elif [ -n "$(command -v zenity)" ]; then + ui_bin="zenity" +elif [ -n "$(command -v kdialog)" ]; then + ui_bin="kdialog" fi +debug(){ + [[ -n "$DEBUG" ]] && echo "$@" >&2 +} + errorbox() { - zenity --ok-label=Exit --error --text "$1" + debug "error box: $ui_bin, $1" + # display an error with an exit button + case $ui_bin in + zenity) + zenity --ok-label=Exit --error --text "$1" + ;; + kdialog) + kdialog --ok-label=Exit --error "$1" + ;; + *) + echo "ERROR: $ui_bin not supported" >&2 + return 1 + ;; + esac return 0 } infobox() { - zenity --ok-label=Continue --info --text "$1" + # Display info with a continue button + case $ui_bin in + zenity) + zenity --ok-label=Continue --info --text "$1" + ;; + kdialog) + kdialog --ok-label=Contnue --msgbox "$1" + ;; + *) + echo "ERROR: $ui_bin not supported" >&2 + return 1 + ;; + esac return 0 } warnbox() { - zenity --ok-label=Continue --warning --text "$1" + # display a warning with a Continue button + case $ui_bin in + zenity) + zenity --ok-label=Continue --warning --text "$1" + ;; + kdialog) + kdialog --warningcontinuecancel "$1" + ;; + *) + echo "ERROR: $ui_bin not supported" >&2 + return 1 + ;; + esac return 0 } question() { - zenity --question --text="$1" >/dev/null - echo "$?" + # get yes = 0 or no = 1 from user + debug "question: $ui_bin, $1" + case $ui_bin in + zenity) + zenity --question --text="$1" >/dev/null + answer="$?" + ;; + kdialog) + kdialog --yesno "$1" + answer="$?" + ;; + *) + echo "ERROR: $ui_bin not supported" >&2 + return 1 + ;; + esac + echo "$answer" return 0 } dangerquestion() { - zenity --extra-button=No --ok-label=Yes --warning --text="$1" >/dev/null + # get yes = 0 or no = 1 from user, while displaying a warning + case $ui_bin in + zenity) + zenity --extra-button=No --ok-label=Yes --warning --text="$1" >/dev/null + ;; + kdialog) + kdialog --warningyesno "$1" + ;; + *) + echo "ERROR: $ui_bin not supported" >&2 + return 1 + ;; + esac echo "$?" return 0 } directorypicker() { + # enter a path or select a directory local message=$1; shift local default_directory=$1; shift local finish_selection="false" local selection_entry="$default_directory" while [ "$finish_selection" != "true" ]; do - raw_entry=$(zenity --entry --entry-text="$selection_entry" --extra-button="Browse" --text "$message"); confirm=$? + case $ui_bin in + zenity) + raw_entry=$(zenity --entry --entry-text="$selection_entry" --extra-button="Browse" --text "$message"); + confirm=$? + ;; + kdialog) + # no extra button in kdialog, using cancel label and second dialog + raw_entry=$(kdialog --inputbox "$message" "$selection_entry" --cancel-label "Browse or Cancel" ); + confirm=$? + if [ "$confirm" -eq 1 ]; then + kdialog --yesno "Browse or cancel?" --yes-label "Browse" --no-label "cancel" \ + && raw_entry="Browse" + fi + ;; + *) + echo "ERROR: $ui_bin not supported" >&2 + return 1 + ;; + esac + eval selection_entry="$raw_entry" case "$confirm" in - 0) - if [ ! -e "$selection_entry" ]; then - local confirm_create_dir=$( \ - question \ - "Directory '$selection_entry' does not exist. Would you like to create it?" \ - ) - - if [ "$confirm_create_dir" == "0" ]; then - mkdir -p "$selection_entry" - finish_selection=true - fi - elif [ -n "$(ls -A "$selection_entry/")" ]; then - local confirm_overwrite=$( \ - dangerquestion \ - "Directory '$selection_entry' is not empty. Would you like to continue anyway?" \ - ) - - if [ "$confirm_overwrite" == "0" ]; then - finish_selection=true - fi - else + 0) + if [ ! -e "$selection_entry" ]; then + local confirm_create_dir=$( \ + question \ + "Directory '$selection_entry' does not exist. Would you like to create it?" \ + ) + + if [ "$confirm_create_dir" == "0" ]; then + mkdir -p "$selection_entry" finish_selection=true fi - ;; - 1) - if [ "$selection_entry" == "Browse" ]; then - selection_entry=$(zenity --file-selection --directory) - else + elif [ -n "$(ls -A "$selection_entry/")" ]; then + local confirm_overwrite=$( \ + dangerquestion \ + "Directory '$selection_entry' is not empty. Would you like to continue anyway?" \ + ) + + if [ "$confirm_overwrite" == "0" ]; then finish_selection=true fi - ;; + else + finish_selection=true + fi + ;; + 1) + if [ "$selection_entry" == "Browse" ]; then + case $ui_bin in + zenity) + selection_entry=$(zenity --file-selection --directory) + ;; + kdialog) + selection_entry=$(kdialog --getexistingdirectory) + ;; + *) + ;; + esac + else + finish_selection=true + fi + ;; esac done @@ -87,39 +188,92 @@ directorypicker() { } textentry() { + # enter some text and return it message=$1; shift default_value=$1; shift - entry_value=$(zenity --entry --entry-text="$default_value" --text "$message"); confirm=$? + case $ui_bin in + zenity) + entry_value=$(zenity --entry --entry-text="$default_value" --text "$message"); + confirm=$? + ;; + kdialog) + entry_value=$(kdialog --inputbox "$message" "$default_value"); + confirm=$? + ;; + *) + echo "ERROR: $ui_bin not supported" >&2 + return 1 + ;; + esac if [ "$confirm" == "0" ]; then echo "$entry_value" fi - return $confirm + return "$confirm" } radio() { + debug "radio: $radio" + # debug "$(echo "$@" | tr ' ' '\n')" + # allow user to select one of a few options height=$1 title=$2 shift 2 local rows=() while [ "$#" -gt "0" ]; do - rows+=('' "$1" "$2") + debug "new row: $1 $2" + case $ui_bin in + zenity) + rows+=('' "$1" "$2") + ;; + kdialog) + rows+=("$1" "$2" "off") + + ;; + *) + echo "ERROR: $ui_bin not supported" >&2 + return 1 + ;; + esac shift 2 done - selected_option=$( \ - zenity --height="$height" --list --radiolist \ - --text="$title" \ - --hide-header \ - --column="checkbox" --column="option_value" --column="option_text" \ - --hide-column=2 \ - "${rows[@]}" \ - ) + case $ui_bin in + zenity) + selected_option=$( \ + zenity --height="$height" --list --radiolist \ + --text="$title" \ + --hide-header \ + --column="checkbox" --column="option_value" --column="option_text" \ + --hide-column=2 \ + "${rows[@]}" \ + ) + ;; + kdialog) + tmpstderr="$(mktemp)" + # --geometry "x${height}" \ + + selected_option=$( \ + kdialog --radiolist "$title" \ + "${rows[@]}" \ + 2> "$tmpstderr" \ + ) + if grep -q -e "error: Bad file descriptor" "$tmpstderr"; then + debug "bfd: |$title|\n\n|$height|\n\n|${rows[@]}|" + fi + ;; + *) + echo "ERROR: $ui_bin not supported" >&2 + return 1 + ;; + esac + if [ -z "$selected_option" ]; then + # debug "Cancelled at $title\n\n$height\n\n${rows[@]}" return 1 fi @@ -129,8 +283,36 @@ radio() { } loading() { - tee /dev/tty <&0 \ - | zenity --progress --auto-close --pulsate --no-cancel --text "$1" + # display loading bar + case $ui_bin in + zenity) + tee /dev/tty <&0 \ + | zenity --progress --auto-close --pulsate --no-cancel --text "$1" + ;; + kdialog) + IFS=" " read -r -a bus_ref <<< "$(kdialog --progressbar "$1")" + while read -u 5 input; do + echo "$input" > /dev/tty + if [[ "$input" =~ ^[0-9]+ ]]; then + num=$(echo $input | tr -d '%' ) + qdbus "${bus_ref[@]}" Set "" value "$num" + if [ "$num" -ge 100 ]; then + qdbus "${bus_ref[@]}" close + fi + elif [[ "$input" =~ ^\#.* ]]; then + # new text to use for progress bar + new_text=$(echo "$input" | tr -d '#' | xargs) + qdbus "${bus_ref[@]}" setLabelText "$new_text" + fi + done 5<&0 + qdbus "${bus_ref[@]}" close + ;; + *) + echo "ERROR: $ui_bin not supported" >&2 + return 1 + ;; + esac + return 0 } diff --git a/utils/download.sh b/utils/download.sh index ec3dc79..abe99a3 100755 --- a/utils/download.sh +++ b/utils/download.sh @@ -22,10 +22,43 @@ elif [ -z "$out_file" ]; then exit 1 fi +if [ -n "$(command -v zenity)" ]; then + ui_bin="zenity" +elif [ -n "$(command -v kdialog)" ]; then + ui_bin="kdialog" +else + echo "$0: Error zenity or kdialog required, install one" >&2 + exit 1 +fi + +display_download_progress() { + case "$ui_bin" in + zenity) + zenity --progress --auto-kill --auto-close --text "$1" <&0 + ;; + kdialog) + IFS=" " read -r -a bus_ref <<< "$(kdialog --progressbar "$1")" + while read -u 5 input; do + if [[ "$input" =~ ^[0-9]+ ]]; then + num=$(echo $input | tr -d '%' ) + qdbus "${bus_ref[@]}" Set "" value "$num" + if [ "$num" -ge 100 ]; then + qdbus "${bus_ref[@]}" close + fi + elif [[ "$input" =~ ^\#.* ]]; then + # new text to use for progress bar + new_text=$(echo "$input" | tr -d '#' | xargs) + qdbus "${bus_ref[@]}" setLabelText "$new_text" + fi + done 5<&0 + ;; + esac +} + progress_bar() { stdbuf -o0 tr '[:cntrl:]' '\n' \ | grep --color=never --line-buffered -oE '[0-9\.]+%' \ - | zenity --progress --auto-kill --auto-close --text "$1" + | display_download_progress "$1" } # We default to wget because it seems like a better choice for this sort of work - diff --git a/utils/extract.sh b/utils/extract.sh index d3db622..d688091 100755 --- a/utils/extract.sh +++ b/utils/extract.sh @@ -13,6 +13,8 @@ log_error() { compressed_file=$1 destination_dir=$2 + + # Preliminary checks if ! [ -f "$compressed_file" ]; then log_error "'$compressed_file' does not exist, aborting" @@ -24,6 +26,40 @@ if [ -n "$(ls -A "$destination_dir/")" ]; then exit 1 fi +if [ -n "$(command -v zenity)" ]; then + ui_bin="zenity" +elif [ -n "$(command -v kdialog)" ]; then + ui_bin="kdialog" +else + echo "$0: Error zenity or kdialog required, install one" >&2 + exit 1 +fi + +display_extract_progress() { + case "$ui_bin" in + zenity) + zenity --progress --auto-kill --auto-close --text="$1" <&0 + ;; + kdialog) + IFS=" " read -r -a bus_ref <<< "$(kdialog --progressbar "$1")" + while read -u 5 input; do + if [[ "$input" =~ ^[0-9]+ ]]; then + num=$(echo $input | tr -d '%' ) + qdbus "${bus_ref[@]}" Set "" value "$num" + if [ "$num" -ge 100 ]; then + qdbus "${bus_ref[@]}" close + fi + elif [[ "$input" =~ ^\#.* ]]; then + # new text to use for progress bar + new_text=$(echo "$input" | tr -d '#' | xargs) + qdbus "${bus_ref[@]}" setLabelText "$new_text" + fi + done 5<&0 + qdbus "${bus_ref[@]}" close + ;; + esac +} + base_filename=$(basename "$compressed_file") extension="${base_filename##*.}" @@ -58,7 +94,7 @@ echo "INFO: extracting '$compressed_file' to '$destination_dir'" | stdbuf -o128 tr -d '\b' \ | stdbuf -oL tr -s ' ' '\n' \ | grep --line-buffered --color=never -oE '[0-9]+%' \ - | zenity --progress --auto-kill --auto-close --text="$progress_text" + | display_extract_progress "$progress_text" if [ "$?" != "0" ]; then cleanup