#!/usr/bin/env bash
# Author: Castro-Fidel (linux-gaming.ru)
# shellcheck disable=SC2034
########################################################################
$PW_DEBUG

print_error () { printf "\E[31m%s Error: $@ %s\e[0m\n" ;}
export -f print_error

print_warning () { printf "\E[33m%s Warning: $@ %s\e[0m\n" ;}
export -f print_warning

print_info () { printf "\E[36m%s Info: $@ %s\e[0m\n" ;}
export -f print_info

print_ok () { printf "\E[35m%s OK: $@ %s\e[0m\n" ;}
export -f print_ok

python_module () {
    local python3_module="$1"
    shift
    print_info "Running python3 module: $python3_module $@" >&2
    python3 -m portprotonqt.scripts_utils.$python3_module "$@"
}

python_term () {
    print_info "Running: easyterm $@"
    python_module easyterm -e "$@"
    [[ "$?" == "0" ]] && return 0 || return 1
}

print_wrapped () {
    local text="$1"
    local a="0"
    local b="$2"

    if [[ -n "$3" ]] ; then
        if (( ${#text} > b )); then
            echo "${text:a:b}${3}"
        else
            echo "$text"
        fi
    else
        while (( a < ${#text} )) ; do
            echo "${text:a:b}"
            ((a+=b))
        done
    fi
}
export -f print_wrapped

make_acronym () {
    local words acronym i
    read -r -a words <<< "$1"
    acronym="${words[0]:0:1}"
    for ((i=1 ; i<${#words[@]} ; i++)) ; do
        acronym+="${words[$i]:0:1}"
    done
    echo "$acronym"
}
export -f make_acronym

make_abbreviation () {
    local word abbreviation i
    word=$1
    for (( i=0 ; i<${#word} ; i++ )) ; do
        if [[ ${word:$i:1} =~ ^[A-Z]$ ]] ; then
            abbreviation+="${word:$i:1}"
        fi
    done
    echo "$abbreviation"
}
export -f make_abbreviation

check_variables () { [[ -z ${!1} ]] && export "$1"="$2" ;}

# Экспортирует несколько переменных за один раз (одной командой)
# и создаёт список этих переменных в $keys_all
# К примеру set_several_variables PW_MANGOHUD=1 PW_VKBASALT=0
set_several_variables () {
    local key value
    unset keys_all
    while (( $# > 0 )) ; do
        key="${1%%=*}"
        value="${1#*=}"
        keys_all+="$key "
        export "$key"="$value"
        shift
    done
}

add_to_var () {
    if ! echo "${!1}" | grep "$2" &>/dev/null
    then export "$1"="${!1} $2"
    fi
}

rm_from_var () {
    if echo "${!1}" | grep "$2" &>/dev/null
    then export "$1"="$(echo "${!1//$2/}" | tr -s " ")"
    fi
}

add_to_array () {
    local array_name=$1
    local add_names=${*:2}

    if [[ -v "$array_name" ]] ; then
        for element in $add_names ; do
            eval "$array_name+=($element)"
        done
    else
        print_error "$array_name not found for array"
    fi
}

rm_from_array () {
    local array_name=$1
    local rm_names=${*:2}

    if [[ -v "$array_name" ]] ; then
        local count=0
        eval \
        "for element in \${$array_name[@]} ; do
            if [[ \$rm_names =~ \$element ]] ; then
                unset $array_name[\$count]
                $array_name=(\${$array_name[@]})
                ((count--))
            fi
            ((count++))
        done"
    else
        print_error "$array_name not found for array"
    fi
}

fatal () {
    #TODO
    pw_notify_send -i error "$@"
    print_error "$@"
    stop_portproton
    exit 1
}

pw_enable_idle_inhibit() {
    PW_INHIBIT_SLR=""

    if [[ "$GAMEMODERUN" == "1" ]] \
    || [[ "$PW_USE_INHIBIT_SLEEP" != "1" ]] \
    || [[ -z "${DBUS_SESSION_BUS_ADDRESS:-}" ]]
    then
        return
    fi

    PW_INHIBIT_SLR="python3 -m portprotonqt.scripts_utils.idle_inhibit"
    print_info "Screensaver will be inhibited using D-Bus"
}

pw_is_process_active() {
    local process_name
    for process_name in "$@" ; do
        if command -v pgrep &>/dev/null && pgrep -x "$process_name" &>/dev/null ; then
            return 0
        fi
        if command -v pidof &>/dev/null && pidof "$process_name" &>/dev/null ; then
            return 0
        fi
    done
    return 1
}

pw_power_profile_state_file() {
    echo "${PW_TMPFS_PATH}/power_profile"
}

pw_save_power_profile() {
    [[ -n "$1" ]] || return 1
    printf "%s\n" "$1" > "$(pw_power_profile_state_file)"
}

pw_restore_power_profile() {
    local current_power_profile saved_power_profile state_file
    state_file="$(pw_power_profile_state_file)"
    saved_power_profile="$PW_POWERPROFILECTL_PROFILE"

    if [[ -z "$saved_power_profile" && -f "$state_file" ]] ; then
        saved_power_profile="$(head -n 1 "$state_file")"
    fi

    [[ -n "$saved_power_profile" ]] || return 0
    current_power_profile=$(python_module power_profiles get)
    if [[ "$current_power_profile" != "$saved_power_profile" ]] ; then
        python_module power_profiles set "$saved_power_profile" &>/dev/null
    fi
    rm -f "$state_file"
}

try_copy_file () {
    if [[ ! -f "$1" ]] ; then print_info "file $1 not found for copy" && return 1
    elif [[ -z "$2" ]] ; then print_error "no way to copy file $1" && return 1
    elif [[ -L "$2" ]] ; then print_warning "$2 is a file with a symbolic link"
        try_remove_file "$2"
        cp -f "$1" "$2" && return 0 || return 1
    elif [[ -f "$2.sha256sum" ]] ; then print_warning "$2 this file has sha256sum"
        try_remove_file "$2"
        try_remove_file "$2.sha256sum"
        cp -f "$1" "$2" && return 0 || return 1
    else
        [[ -e "$2/$(basename "$1")" ]] && rm -f "$2/$(basename "$1")"
        cp -f "$1" "$2" && return 0 || return 1
    fi
}
export -f try_copy_file

try_copy_file_with_checksums () {
    if [[ ! -f "$1" ]] ; then print_info "file $1 not found for copy" && return 1
    elif [[ -z "$2" ]] ; then print_error "no way to copy file $1" && return 1
    elif [[ -L "$2" ]] ; then print_warning "$2 is a file with a symbolic link"
        try_remove_file "$2"
        if cp -f "$1" "$2" ; then
            if [[ "${PW_FILESYSTEM}" == "ext2/ext3" ]] \
            || [[ "${PW_FILESYSTEM}" == "f2fs" ]] \
            || [[ "${PW_FILESYSTEM}" != "btrfs" ]]
            then
                checksum1="$(sha256sum "$1")"
                echo "${checksum1// */}" > "$2.sha256sum"
            fi
            return 0
        else
            return 1
        fi
    else
        if [[ "${PW_FILESYSTEM}" == "ext2/ext3" ]] \
        || [[ "${PW_FILESYSTEM}" == "f2fs" ]] \
        || [[ "${PW_FILESYSTEM}" != "btrfs" ]]
        then
            checksum1="$(sha256sum "$1")"
            if [[ ! -f "$2" ]] ; then
                if cp -f "$1" "$2" ; then
                    echo "${checksum1// */}" > "$2.sha256sum"
                    return 0
                else
                    return 1
                fi
            else
                if [[ ! -f "$2.sha256sum" ]] ; then
                    checksum2="$(sha256sum "$2")"
                    echo "${checksum2// */}" > "$2.sha256sum"
                else
                    checksum2="$(<"$2.sha256sum")"
                fi
            fi
            if [[ "${checksum1// */}" == "${checksum2// */}" ]] ; then
                return 0
            else
                try_remove_file "$2"
                if cp -f "$1" "$2" ; then
                    echo "${checksum1// */}" > "$2.sha256sum"
                    return 0
                else
                    return 1
                fi
            fi
        else
            [[ -e "$2/$(basename "$1")" ]] && rm -f "$2/$(basename "$1")"
            cp -f "$1" "$2" && return 0 || return 1
        fi
    fi
}
export -f try_copy_file_with_checksums

lsbash () {
    local grep_with_i grep_with_v find_name directory find_file found_successfully find_file_old find_file_old_array
    if [[ $1 =~ \/ ]] ; then
        directory=$1 ; shift
    else
        directory=$PWD
    fi

    grep_find_file1 () {
        find_file_old=$find_file
        if [[ $grep_with_i == true ]] ; then
            find_file=${find_file,,}
            find_name=${find_name,,}
        fi
        grep_find_file2 () {
            if [[ -z $1 ]] ; then
                if [[ $find_file_old != "*" ]] ; then
                    echo "$find_file_old"
                    found_successfully=1
                fi
            else
                find_file_old_array+=("$find_file_old")
            fi
        }
        if [[ $grep_with_v == true ]] ; then
            if [[ ! $find_file =~ $find_name ]] ; then
                grep_find_file2 "$@"
            fi
        else
            if [[ $find_file =~ $find_name ]] \
            || [[ -z $find_name ]] ; then
                grep_find_file2 "$@"
            fi
        fi
    }
    while true ; do
        unset grep_with_i grep_with_v
        if [[ $1 == --grep ]] ; then
            shift
            while true ; do
                # аналог grep -i
                if [[ $1 == "-i" ]] ; then
                    grep_with_i=true ; shift ; continue
                fi
                # аналог grep -v
                if [[ $1 == "-v" ]] ; then
                    grep_with_v=true ; shift ; continue
                fi
                find_name=$1 ; shift ; break
            done
        fi
        if [[ -n ${find_file_old_array[0]} ]] ; then
            for find_file in "${find_file_old_array[@]}" ; do
                unset find_file_old_array
                grep_find_file1 "$@"
            done
        else
            for find_file in "$directory"/* ; do
                find_file=${find_file//*\//}
                grep_find_file1 "$@"
            done
        fi
        if [[ -n $1 ]] ; then continue ; else break ; fi
    done
    if [[ $found_successfully == 1 ]] ; then
        return 0
    else
        return 1
    fi
}

try_copy_dir () {
    if [[ ! -d "$1" ]] ; then print_info "directory $1 not found for copy"
    elif [[ -z "$2" ]] ; then print_error "no way to copy directory $1"
    else
        cp -fr "$1" "$2" && return 0 || print_error "failed to copy directory $1 to $2" && return 1
    fi
}
export -f try_copy_dir

try_remove_file () {
    if [[ -f "$1" ]] || [[ ! -e "$1" ]] ; then
        rm -f "$1" && return 0
    fi
}
export -f try_remove_file

try_remove_dir () {
    if [[ -d "$1" ]] ; then
        rm -fr "$1" && return 0
    fi
}
export -f try_remove_dir

create_new_dir () {
    if [[ ! -d "$1" ]] ; then
        mkdir -p "$1" || return 1
    fi
    return 0
}

try_force_link_file () {
    if [[ ! -f "$1" ]] ; then
        print_warning "file not found for link: $1"
        if [[ -f "$2" ]] ; then
            try_remove_file "$2"
            print_warning "removed old link: $2"
        fi
        return 1
    elif [[ -z "$2" ]] ; then print_error "no way to link file $1" && return 1
    elif [[ -f "$2.sha256sum" ]] ; then print_warning "$2 this file has sha256sum"
        try_remove_file "$2"
        try_remove_file "$2.sha256sum"
        ln -s -f -r "$1" "$2"
        return 0
    else
        try_remove_file "$2"
        ln -s -f -r "$1" "$2"
        return 0
    fi
    return 1
}
export -f try_force_link_file

check_symlink () {
    CHK_SYMLINK_FILE="$(file "$1")"
    if [[ -n "$(echo "$CHK_SYMLINK_FILE" | grep -v "broken" | grep "symbolic link to" | awk '{print $1}')" ]] ; then
        return 0
    elif [[ -n "$(echo "$CHK_SYMLINK_FILE" | grep "broken symbolic link to" | awk '{print $1}')" ]] ; then
        print_error "remove broken symlink: $CHK_SYMLINK_FILE"
        rm -fr "$CHK_SYMLINK_FILE"
        return 1
    else
        return 1
    fi
}
export -f check_symlink

try_force_link_dir () {
    if [[ ! -d "$1" ]] ; then print_info "directory $1 not found for link"
    elif [[ -z "$2" ]] ; then print_error "no way to link directory $1"
    else
        if ln -s -f -r "$1" "$2" ; then
            return 0
        else
            print_error "failed to link directory $1 to $2"
            return 1
        fi
    fi
}
export -f try_force_link_dir

check_process () {
    [[ -z "$(ps cax | grep "$1" | awk '{print $1}')" ]] && return 0 || return 1
}
export -f check_process

try_check_sha256sum () {
    if [[ "$no_mirror" == true ]] ; then
        print_ok "Used no_mirror downloading. Skipping check sha256sum."
        return 0
    fi
    SHA256SUM_EXT=$(curl --silent -L "${1//.tar*/}.sha256sum" | awk '{print $1}')
    if [[ ${#SHA256SUM_EXT} == 64 ]] ; then
        SHA256SUM_INT=$(sha256sum "$dest" | awk '{print $1}')
        if [[ "$SHA256SUM_EXT" == "$SHA256SUM_INT" ]] ; then
            print_ok "Verification sha256sum was successfully."
            return 0
        else
            print_error "Verification sha256sum was failed."
            return 1
        fi
    else
        print_warning "sha256sum not found for $(basename "$dest") on server. Skip it."
        return 0
    fi
}

try_download () {
    export dest="$2"
    export no_mirror="false"
    local silent="false"

    case "$3" in
           silent)
                silent=true ;;
        no_mirror)
                no_mirror=true
    esac

    local filename
    if [[ -n "${PW_AUTOINSTALL_EXE}" ]] \
    && [[ "$no_mirror" == "true" ]]
    then
        filename="${PW_AUTOINSTALL_EXE//*\//}"
    else
        filename="$(basename "$1")"
    fi

    if [[ "${MIRROR}" == CLOUD ]] \
    && [[ "$no_mirror" != "true" ]]
    then
        FIRST_URL=("$url_cloud/$filename")
        read -r -a SECOND_URL <<< "$1"
    else
        read -r -a FIRST_URL <<< "$1"
        SECOND_URL=("$url_cloud/$filename")
    fi

    # If gamescope session is active, use PW_TERM for downloading
    if check_gamescope_session ; then
        $PW_TERM "echo ; echo ; echo \"Downloading: $filename. Please wait...\" \
        ; curl -f -# -A 'Mozilla/5.0 (compatible; Konqueror/2.1.1; X11)' -H 'Cache-Control: no-cache, no-store' \
        -H 'Pragma: no-cache' -L ${FIRST_URL[*]} -o \"$dest\""
        [[ "$?" != 0 ]] && return 1 || return 0
    fi

    # Normal download
    print_info "Download $filename from ${FIRST_URL[0]}..."
    if [[ "$silent" == "true" ]] ; then
        curl -f -# -A 'Mozilla/5.0 (compatible; Konqueror/2.1.1; X11)' -H 'Cache-Control: no-cache, no-store' \
        -H 'Pragma: no-cache' -L "${FIRST_URL[@]}" -o "$dest" 2>&1
    else
        # set -o pipefail
        curl -f -# -A 'Mozilla/5.0 (compatible; Konqueror/2.1.1; X11)' -H 'Cache-Control: no-cache, no-store' \
        -H 'Pragma: no-cache' -L "${FIRST_URL[@]}" -o "$dest" 2>&1 \
        | tr '\r' '\n' | sed -ur 's|[# ]+||g;s|100||g;s|0-||g;s|.*=.*||g'

        #TODO: check download errror
        # [[ "${PIPESTATUS[0]}" != 0 ]] && local curl_status="error"
        # if [[ $no_mirror != "true" ]] \
        # && [[ $curl_status != "error" ]] \
        # && try_check_sha256sum "${FIRST_URL[@]}"
        # then
        #     print_ok "File downloaded successfully: $filename from ${FIRST_URL[0]}"
        #     return 0
        # else
        #     local curl_status="error"
        # fi
    fi
}

var_winedlloverride_update () {
    export WINEDLLOVERRIDES="${1}${WINEDLLOVERRIDES:+;$WINEDLLOVERRIDES}"
}

var_vkd3d_config_update () {
    if echo "$VKD3D_CONFIG" | grep "$1"
    then return 0
    else export VKD3D_CONFIG="${1}${VKD3D_CONFIG:+;$VKD3D_CONFIG}"
    fi
}

var_radv_perftest_config_update () {
    if echo "$RADV_PERFTEST" | grep "$1"
    then return 0
    else export RADV_PERFTEST="${1}${RADV_PERFTEST:+,$RADV_PERFTEST}"
    fi
}

var_pw_vk_istance_layers_config_update () {
    if echo "$PW_VK_INSTANCE_LAYERS" | grep -q "$1"
    then return 0
    else export PW_VK_INSTANCE_LAYERS="${1}${PW_VK_INSTANCE_LAYERS:+:$PW_VK_INSTANCE_LAYERS}"
    fi
}

var_ld_library_path_update () {
    if echo "$LD_LIBRARY_PATH" | grep "$1"
    then return 0
    else export LD_LIBRARY_PATH="${1}${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
    fi
}

# GUI NOTIFY SEND
pw_notify_send () {
    local icon title body app timeout OPTIND
    app="PortProtonQt"
    timeout="5000"
    OPTIND="1"
    while getopts a:i:t: opt ; do
        case "$opt" in
            a)
                app=$OPTARG
                ;;
            i)
                case "$OPTARG" in
                    info) local OPTARG="${PORT_IMG_PATH}/notify/info.svg";;
                    warning) local OPTARG="${PORT_IMG_PATH}/notify/warning.svg";;
                    error) local OPTARG="${PORT_IMG_PATH}/notify/error.svg";;
                esac
                icon=$OPTARG
                ;;
            t)
                timeout=$OPTARG
                ;;
            *)
                echo "usage: $0
                [-a] name application (PortProtonQt default)
                [-i] info, warning, error (none default)
                [-t] timeout in ms (5000 default)" >&2
                return 1
                ;;
        esac
    done
    shift $(( OPTIND - 1 ))
    [[ "$1" == "--" ]] && shift
    title="$1" ; shift
    body="$*"

    python_module dbus_tools notify \
        -a "$app" -i "$icon" -t "$timeout" -- "$title" "$body" &>/dev/null
    return 0
}
export -f pw_notify_send

check_gamescope_session () {
    if [[ -n "$GAMESCOPE_IN_USE" ]]
    then [[ "$GAMESCOPE_IN_USE" == 1 ]] && return 0 || return 1
    fi
    if echo "${DESKTOP_SESSION}" | grep -i "gamescope" &>/dev/null ; then
        export GAMESCOPE_IN_USE=1
        return 0
    else
        export GAMESCOPE_IN_USE=0
        return 1
    fi
}

check_wayland_session () {
    if [[ -n "$WAYLAND_IN_USE" ]]
    then [[ "$WAYLAND_IN_USE" == 1 ]] && return 0 || return 1
    fi
    if echo "${XDG_SESSION_TYPE}" | grep -i "wayland" &>/dev/null ; then
        export WAYLAND_IN_USE=1
        return 0
    else
        export WAYLAND_IN_USE=0
        return 1
    fi
}
export -f check_wayland_session

check_flatpak () {
    if [[ -n "$FLATPAK_IN_USE" ]]
    then [[ "$FLATPAK_IN_USE" == 1 ]] && return 0 || return 1
    fi
    if [[ -n "${FLATPAK_ID:-}" ]]
    then
        export FLATPAK_IN_USE=1
        if grep -i "Alpine Linux" "/run/host/etc/os-release" &>/dev/null ; then
            export ALPINE_FP=1
        fi
        return 0
    else
        export FLATPAK_IN_USE=0
        return 1
    fi
}
export -f check_flatpak

check_selinux () {
    if [[ -n "$SELINUX_IN_USE" ]]
    then [[ "$SELINUX_IN_USE" == 1 ]] && return 0 || return 1
    fi
    if check_flatpak ; then
        if grep -i ^"SELINUX=enforcing" /run/host/etc/selinux/config &>/dev/null ; then
            export SELINUX_IN_USE=1
            return 0
        fi
    else
        if grep -i ^"SELINUX=enforcing" /etc/selinux/config &>/dev/null ; then
            export SELINUX_IN_USE=1
            return 0
        fi
    fi
    export SELINUX_IN_USE=0
    return 1
}
export -f check_selinux

check_vendor_gpu () {
    check_pci_driver () {
        case "$1" in
            *nvidia*)
                [[ -d /sys/bus/pci/drivers/nvidia ]] && VENDOR_GPU_USE="nvidia"
                [[ -d /sys/bus/pci/drivers/nouveau ]] && VENDOR_GPU_USE="nouveau"
                ;;
            *amd*)
                [[ -d /sys/bus/pci/drivers/amdgpu ]] && VENDOR_GPU_USE="amd"
                ;;
            *intel*)
                [[ -d /sys/bus/pci/drivers/i915 ]] && VENDOR_GPU_USE="intel"
                ;;
            *)
                [[ -d /sys/bus/pci/drivers/nvidia ]] && VENDOR_GPU_USE="nvidia"
                [[ -d /sys/bus/pci/drivers/nouveau ]] && VENDOR_GPU_USE="nouveau"
                [[ -d /sys/bus/pci/drivers/amdgpu ]] && VENDOR_GPU_USE="amd"
                [[ -d /sys/bus/pci/drivers/i915 ]] && VENDOR_GPU_USE="intel"
                ;;
        esac
    }

    if [[ $PW_GPU_USE != "disabled" ]]
    then check_pci_driver "${PW_GPU_USE,,}"
    elif [[ -n "${LSPCI_VGA}" ]]
    then check_pci_driver "${LSPCI_VGA,,}"
    else
        check_pci_driver
    fi

    echo "$VENDOR_GPU_USE"
}

unpack () {
    case $1 in
         *.tar.xz) local command="tar -Jxhf";;
         *.tar.gz) local command="tar -xhzf" ;;
        *.tar.zst) local command="tar -I zstd -xhf" ;;
            *.tar) local command="tar -xhf" ;;
    esac

    case $3 in
        silent) local silent=true ;;
    esac

    # If gamescope session is active, use PW_TERM for unpack
    if check_gamescope_session ; then
        $PW_TERM "echo ; echo ; echo \"Unpacking file: $1. Please wait...\" ; $command \"$1\" -C \"$2\""
        [[ "$?" != 0 ]] && return 1 || return 0
    elif [[ "$silent" != "true" ]] ; then
        print_info "Unpacking file: $(basename "$1") Please wait..."
        set -o pipefail
        $command "$1" -C "$2" 2>/dev/null
        [[ "${PIPESTATUS[0]}" != 0 ]] && print_error "File $1 unpacking error." && return 1 || return 0
    else
        $command "$1" -C "$2" && return 0 || return 1
    fi
}

debug_timer () {
    if [[ "$1" == "--start" ]] ; then
        START=$(date +%s%N)
        if [[ "$2" == "-s" ]] ; then
            case $3 in
                PW_TIME_IN_GAME)
                    START_PW_TIME_IN_GAME=$START ;;
                UPDATE_ETERFUND)
                    START_UPDATE_ETERFUND=$START ;;
                UPDATE_GITHUB)
                    START_UPDATE_GITHUB=$START ;;
                UPDATE_PP_GITEA)
                    START_UPDATE_PP_GITEA=$START ;;
            esac
        fi
    elif [[ "$1" == "--end" ]] ; then
        END=$(date +%s%N)
        if [[ -n "$2" ]] ; then
            if [[ "$2" == "-s" ]] ; then
                case $3 in
                    PW_TIME_IN_GAME)
                        START=$START_PW_TIME_IN_GAME ;;
                    UPDATE_ETERFUND)
                        START=$START_UPDATE_ETERFUND ;;
                    UPDATE_GITHUB)
                        START=$START_UPDATE_GITHUB ;;
                    UPDATE_PP_GITEA)
                        START=$START_UPDATE_PP_GITEA ;;
                esac
                export "$3"="$((( END - START )/1000000 ))"
            else
                DIFF=$((( END - START )/1000000 ))
                print_warning "It took $DIFF milliseconds for $2"
            fi
        else
            DIFF=$((( END - START )/1000000 ))
            print_warning "It took $DIFF milliseconds"
        fi
    fi
}

fix_icon_name_png () {
    if [[ $1 =~ [\!\%\$\&\<] ]] ; then
        local ICON_NAME_OLD=$1
        local ICON_NAME_NEW=$ICON_NAME_OLD
        local ICON_NAME_REGEX=(\! % \$ \& \<)
        for i in "${ICON_NAME_REGEX[@]}" ; do
            ICON_NAME_NEW="${ICON_NAME_NEW//$i/}"
        done
        sed -i "s|Icon=$ICON_NAME_OLD|Icon=$ICON_NAME_NEW|" "$2"
        return 0
    else
        return 1
    fi
}

# Поиск нужного .desktop файла по $PW_EXE_FILE (для показа в комментариях нужного времени)
# Параллельное создание базы по времени после завершения приложения
search_desktop_file () {
    [[ $PW_USE_SETUP_FILE == "1" ]] && return 0
    local desktop_file desktop_file_new line1 line2 FILE_SHA256SUM_ARRAY EXEC_DESKTOP ICON_NAME BROKEN_LINE FILE_SHA256SUM_FOUND FILE_SHA256SUM_NOT_FOUND
    if [[ -z $FILE_SHA256SUM ]] ; then
        read -r -a FILE_SHA256SUM_ARRAY < <(sha256sum "$PW_EXE_FILE")
        FILE_SHA256SUM=${FILE_SHA256SUM_ARRAY[0]}
        edit_db_from_gui FILE_SHA256SUM
    fi
    for desktop_file in "$PORT_DATA_PATH"/* ; do
        desktop_file_new="${desktop_file//"$PORT_DATA_PATH/"/}"
        if [[ $desktop_file_new =~ .desktop$ ]] ; then
            if [[ ! $desktop_file_new =~ (PortProton|readme) ]] ; then
                while read -r line1 ; do
                    if [[ $line1 =~ ^Exec= ]] ; then
                        if check_flatpak ; then
                            EXEC_DESKTOP=${line1//Exec=flatpak run ${FLATPAK_ID} --silent /}
                        else
                            EXEC_DESKTOP=${line1//Exec=portprotonqt --silent /}
                        fi
                    fi
                    [[ $line1 =~ ^Icon= ]] && ICON_NAME=${line1//Icon=/}
                done < "$desktop_file"
                fix_icon_name_png "$ICON_NAME" "$desktop_file"
                if [[ $PW_EXE_FILE == "${EXEC_DESKTOP//\"/}" ]] ; then
                    DESKTOP_CORRECT_FILE="$desktop_file"
                    break
                fi
            fi
        fi
    done

    while read -r -a line2 ; do
        if [[ -z ${line2[0]} ]] \
        || [[ ! ${line2[0],,} =~ .(bat|exe|msi|reg)$ ]] ; then
            BROKEN_LINE=1
            break
        fi
        if [[ ${line2[1]} == "$FILE_SHA256SUM" ]] ; then
            FILE_SHA256SUM_FOUND=1
            break
        fi
        if [[ ${line2[1]} != "$FILE_SHA256SUM" ]] \
        && [[ ${line2[0]} == "${PW_EXE_FILE// /#@_@#}" ]] ; then
            FILE_SHA256SUM_NOT_FOUND=1
            break
        fi
    done < "$PORT_WINE_TMP_PATH/statistics"

    local line3 line4 count_line i TIME_TOTAL SKIP_REPAIR
    ## Ремонты:
    # Ремонт, проверяет чтобы длинна хеш суммы была равна 64 символам, в ином случае удалит битые
    if [[ $FILE_SHA256SUM_NOT_FOUND == 1 ]] && [[ ${#line2[1]} != "64" ]] ; then
        while read -r -a line3 ; do
            if [[ ${#line3[1]} == "64" ]]
            then echo "${line3[*]}"
            fi
        done < "$PORT_WINE_TMP_PATH/statistics" > "$PORT_WINE_TMP_PATH/statistics_repair"
        try_remove_file "$PORT_WINE_TMP_PATH/statistics"
        mv -f "$PORT_WINE_TMP_PATH/statistics_repair" "$PORT_WINE_TMP_PATH/statistics"
        return 1
    fi

    # Ремонт, если есть пустые строки и непонятные строки без .exe, .bat, .msi, .reg
    if [[ $BROKEN_LINE == 1 ]] ; then
        while read -r -a line4 ; do
            if [[ -n ${line4[0]} ]] && [[ ${line4[0],,} =~ .(bat|exe|msi|reg)$ ]]
            then echo "${line4[*]}"
            fi
        done < "$PORT_WINE_TMP_PATH/statistics" > "$PORT_WINE_TMP_PATH/statistics_repair"
        try_remove_file "$PORT_WINE_TMP_PATH/statistics"
        mv -f "$PORT_WINE_TMP_PATH/statistics_repair" "$PORT_WINE_TMP_PATH/statistics"
        return 1
    fi

    # Ремонтирует путь на новый, если вдруг путь до .exe файла битый или изменился, но .exe файл он опознал
    if [[ $FILE_SHA256SUM_FOUND == 1 ]] && [[ ${line2[0]} != "${PW_EXE_FILE// /#@_@#}" ]] ; then
        sed -i "s|${line2[0]} ${line2[1]}|${PW_EXE_FILE// /#@_@#} ${line2[1]}|" "$PORT_WINE_TMP_PATH/statistics"
        line2[0]=${PW_EXE_FILE// /#@_@#}
    fi

    # Ремонт, если sha256sum изменилась, но путь до .exe тот же
    if [[ $FILE_SHA256SUM_NOT_FOUND == 1 ]] ; then
        sed -i "s|${line2[0]} ${line2[1]}|${line2[0]} $FILE_SHA256SUM|" "$PORT_WINE_TMP_PATH/statistics"
        line2[1]=$FILE_SHA256SUM
    fi

    # Когда приложения ещё нет в статистике
    [[ -z ${line2[2]} ]] && line2[2]=0
    # Ремонт, если сломалось время
    if (( line2[2] >= 999999999 )) ; then
        sed -i "s|${line2[1]} ${line2[2]}|${line2[1]} 0|" "$PORT_WINE_TMP_PATH/statistics"
        line2[2]=0
    fi
    # Ремонт, если кто-то сломал время
    if [[ ! ${line2[2]} =~ ^[0-9]+$ ]] ; then
        sed -i "/${line2[1]}/d" "$PORT_WINE_TMP_PATH/statistics"
        return 1
    fi

    ###############################
    # Общее проведённое время в секундах
    export TIME_CURRENT=${line2[2]}
    # количество запусков приложения
    export COUNT_STARTS=${line2[4]//L4-/}
    ###############################

    # Проверка новых десктоп файлов, чтобы их можно было сортировать первыми при первом создании в главном меню + ремонт
    if [[ $PW_NEW_DESKTOP == 1 ]] && [[ ${line2[3]} != NEW_DESKTOP ]] ; then
        if [[ $FILE_SHA256SUM_FOUND == 1 ]] ; then
            sed -i "s|${line2[1]} \(.*\) ${line2[3]}|${line2[1]} \1 NEW_DESKTOP|" "$PORT_WINE_TMP_PATH/statistics"
        else
            echo "${PW_EXE_FILE// /#@_@#} $FILE_SHA256SUM $TIME_CURRENT NEW_DESKTOP" >> "$PORT_WINE_TMP_PATH/statistics"
        fi
    fi
    unset PW_NEW_DESKTOP

    # Когда приложение было запущено и завершено
    if [[ -n $PW_TIME_IN_GAME ]] ; then
        TIME_TOTAL=$(( TIME_CURRENT + PW_TIME_IN_GAME ))
        if [[ $FILE_SHA256SUM_FOUND == 1 ]] ; then
            # Когда есть предыдущее время
            sed -i "s|$FILE_SHA256SUM $TIME_CURRENT|$FILE_SHA256SUM $TIME_TOTAL|" "$PORT_WINE_TMP_PATH/statistics"
        else
            # Когда только запустили приложение первый раз
            echo "${PW_EXE_FILE// /#@_@#} $FILE_SHA256SUM $TIME_TOTAL OLD_DESKTOP" >> "$PORT_WINE_TMP_PATH/statistics"
        fi
        # Для ремонта если вдруг в линии ещё что-то есть
        count_line=6
        # Здесь добавляются новые линии для статистики (L4-) важен
        if [[ -z ${line2[4]} ]] ; then
            SKIP_REPAIR=1
            sed -i "s|$FILE_SHA256SUM \(.*\)|$FILE_SHA256SUM \1 L4-1|" "$PORT_WINE_TMP_PATH/statistics"
        else
            # ремонт, если L4 по каким-то причинам сломался
            if [[ ${line2[4]} =~ ^L4 ]] ; then
                local NUMBER_OF_STARTS=$(( ${line2[4]//L4-/} + 1 ))
            else
                SKIP_REPAIR=1
                sed -i "s|$FILE_SHA256SUM \(.*\) ${line2[4]}|$FILE_SHA256SUM \1 L4-1|" "$PORT_WINE_TMP_PATH/statistics"
            fi
        fi

        if [[ $SKIP_REPAIR != 1 ]] ; then
            # Ремонт, если количество элементов массива по каким-то причина больше, чем должно быть
            if [[ -n ${line2["$count_line"]} ]] ; then
                for i in $(seq $count_line ${#line2[@]}) ; do
                    unset 'line2[$i]'
                done
                sed -i "s|${PW_EXE_FILE// /#@_@#} $FILE_SHA256SUM \(.*\)|${line2[*]}|" "$PORT_WINE_TMP_PATH/statistics"
            fi
            # Для правильной работы L4
            sed -i "s|$FILE_SHA256SUM \(.*\) ${line2[4]}|$FILE_SHA256SUM \1 L4-$NUMBER_OF_STARTS|" "$PORT_WINE_TMP_PATH/statistics"
        fi

        # Для правильной работы статистики по последнему запуску
        if [[ $SORT_WITH_TIME == "lastlaunch" ]] ; then
            LAST_LAUNCH=$(grep -o 'L5-[0-9]\+' "$PORT_WINE_TMP_PATH/statistics" | sed 's/L5-//' | sort -nr | head -1)
            [[ -z $LAST_LAUNCH ]] && LAST_LAUNCH=0
            LAST_LAUNCH=$(( LAST_LAUNCH + 1 ))
            if [[ -z ${line2[5]} ]] ; then
                sed -i "s|$FILE_SHA256SUM \(.*\)|$FILE_SHA256SUM \1 L5-$LAST_LAUNCH|" "$PORT_WINE_TMP_PATH/statistics"
            else
                sed -i "s|$FILE_SHA256SUM \(.*\) ${line2[5]}|$FILE_SHA256SUM \1 L5-$LAST_LAUNCH|" "$PORT_WINE_TMP_PATH/statistics"
            fi
        fi
    fi
    if [[ -n $PW_TIME_IN_GAME ]]
    then return 2
    else return 0
    fi
}

create_name_desktop () {
    while true ; do
        search_desktop_file
        local exit_code=$?
        case $exit_code in
            0) break ;;
            1) continue ;;
            2) return 0 ;;
            *) print_error "Broken search_desktop_file func. No exit_code." ;;
        esac
    done
    if [[ -n $DESKTOP_NAME_FILE ]] ; then
        DESKTOP_NAME_FILE_OLD=$DESKTOP_NAME_FILE
        unset DESKTOP_NAME_FILE
    fi
    if [[ -n $DESKTOP_NAME_YAD ]] ; then
        DESKTOP_NAME_FILE="${DESKTOP_NAME_YAD//.desktop/}"
        unset DESKTOP_NAME_YAD
    elif [[ -n $name_desktop ]] ; then
        DESKTOP_NAME_FILE="$name_desktop"
        unset name_desktop
    elif [[ -n $DESKTOP_CORRECT_FILE ]] ; then
        DESKTOP_NAME_FILE="${DESKTOP_CORRECT_FILE//"$PORT_DATA_PATH/"/}"
        unset DESKTOP_CORRECT_FILE
        DESKTOP_NAME_FILE="${DESKTOP_NAME_FILE//.desktop/}"
    fi

    PORTWINE_DB_DESKTOP="$(basename "${PW_EXE_FILE%.[Ee][Xx][Ee]}")"

    if [[ -n $PORTPROTON_NAME ]] ; then
        PORTPROTON_NAME_ABBR=$(make_abbreviation "$PORTPROTON_NAME")
        PORTPROTON_NAME_ACRO=$(make_acronym "$PORTPROTON_NAME")
    fi
    if [[ -n $FILE_DESCRIPTION ]] ; then
        FILE_DESCRIPTION_ABBR=$(make_abbreviation "$FILE_DESCRIPTION")
        FILE_DESCRIPTION_ACRO=$(make_acronym "$FILE_DESCRIPTION")
    fi

    if [[ -n $PORTWINE_CREATE_SHORTCUT_NAME ]] ; then
        PW_NAME_DESKTOP_PROXY="$PORTWINE_CREATE_SHORTCUT_NAME"
    elif [[ -n $DESKTOP_NAME_FILE ]] ; then
        PW_NAME_DESKTOP_PROXY="$DESKTOP_NAME_FILE"
    elif [[ -n $DESKTOP_NAME_FILE_OLD && ${PORTWINE_DB_DESKTOP^^} =~ ${DESKTOP_NAME_FILE_OLD^^} ]] ; then
        PW_NAME_DESKTOP_PROXY="$DESKTOP_NAME_FILE_OLD"
    elif [[ -n $PORTPROTON_NAME && ${PORTPROTON_NAME^^} =~ ${PORTWINE_DB_DESKTOP^^} && $PORTPROTON_NAME != "$PORTWINE_DB_DESKTOP" ]] \
    || [[ -n $PORTPROTON_NAME && ${#PORTPROTON_NAME_ABBR} -gt 2 && ${PORTWINE_DB_DESKTOP^^} =~ $PORTPROTON_NAME_ABBR ]] \
    || [[ -n $PORTPROTON_NAME && ${#PORTPROTON_NAME_ACRO} -gt 2 && ${PORTWINE_DB_DESKTOP^^} =~ ${PORTPROTON_NAME_ACRO^^} ]]
    then
        PW_NAME_DESKTOP_PROXY="$PORTPROTON_NAME"
    elif [[ -n $FILE_DESCRIPTION && ${FILE_DESCRIPTION^^} =~ ${PORTWINE_DB_DESKTOP^^} && $FILE_DESCRIPTION != "$PORTWINE_DB_DESKTOP" ]] \
    || [[ -n $FILE_DESCRIPTION && ${#FILE_DESCRIPTION_ABBR} -gt 2 && ${PORTWINE_DB_DESKTOP^^} =~ $FILE_DESCRIPTION_ABBR ]] \
    || [[ -n $FILE_DESCRIPTION && ${#FILE_DESCRIPTION_ACRO} -gt 2 && ${PORTWINE_DB_DESKTOP^^} =~ ${FILE_DESCRIPTION_ACRO^^} ]]
    then
        PW_NAME_DESKTOP_PROXY="$FILE_DESCRIPTION"
    else
        unset PORTWINE_DB_PROXY PORTWINE_DB_NEW
        PORTWINE_DB_DESKTOP="${PORTWINE_DB_DESKTOP//_/ }"
        if [[ ${PORTWINE_DB_DESKTOP:0:1} =~ [a-z] ]] ; then
            PORTWINE_DB_UPPER="${PORTWINE_DB_DESKTOP^^}"
            PORTWINE_DB_DESKTOP="${PORTWINE_DB_UPPER:0:1}${PORTWINE_DB_DESKTOP:1}"
        fi
        if (( ${#PORTWINE_DB_DESKTOP} > 3 )) ; then
            for ((i=0 ; i<${#PORTWINE_DB_DESKTOP} ; i++)) ; do
                if [[ ${PORTWINE_DB_DESKTOP:i:2} =~ [a-z]([A-Z]|[0-9]) ]] \
                && [[ ! ${PORTWINE_DB_DESKTOP:i:3} =~ [a-z]([A-Z]|[0-9])" " ]] ; then
                    PORTWINE_DB_PROXY+="${PORTWINE_DB_DESKTOP:i:1} "
                elif [[ ${PORTWINE_DB_DESKTOP:i:3} =~ [0-9][0-9][a-zA-Z] ]] ; then
                    PORTWINE_DB_PROXY+="${PORTWINE_DB_DESKTOP:i:2} "
                    ((i++))
                else
                    PORTWINE_DB_PROXY+="${PORTWINE_DB_DESKTOP:i:1}"
                fi
            done
            for ((i=0 ; i<${#PORTWINE_DB_PROXY} ; i++)) ; do
                if [[ ${PORTWINE_DB_PROXY:i:2} =~ " "[a-z] ]] ; then
                    PORTWINE_DB_UPPER="${PORTWINE_DB_PROXY:i:2}"
                    PORTWINE_DB_NEW+="${PORTWINE_DB_UPPER^^}"
                    ((i++))
                else
                    PORTWINE_DB_NEW+="${PORTWINE_DB_PROXY:i:1}"
                fi
            done
        else
            PORTWINE_DB_NEW="$PORTWINE_DB_DESKTOP"
        fi
        PW_NAME_DESKTOP_PROXY="$PORTWINE_DB_NEW"
    fi
}

get_and_set_reg_file () {
    local name_block name_for_find find_block find_file find_line count name_for_new_block name_for_find_old
    local line_reg find_number_line find_check_file name_for_set name_type_reg name_fatal name_add_or_del
    name_add_or_del=$1
    name_block=$2
    name_for_find=$3
    name_type_reg=$4
    name_for_set=$5
    name_for_new_block=$6
    name_for_find_old=$name_for_find
    name_fatal="$name_block $name_for_find"

    case $name_type_reg in
            REG_DWORD)
                name_for_find="\"$name_for_find\"=dword:"
                name_for_set=$(convert_dec_and_hex --dec "$name_for_set") ;;
            REG_SZ)
                name_for_find="\"$name_for_find\"="
                name_for_set="\"$name_for_set\"" ;;
            *)
                if [[ $name_add_or_del == --delete ]] ; then
                    name_for_find="\"$name_for_find\""
                else
                    print_error "Name type reg not set for $name_fatal"
                    return 1
                fi ;;
    esac
    name_block=${name_block//\\/\\\\\\\\}
    if [[ -n $name_for_new_block ]] ; then
        find_block=$(grep -n "\[$name_block\]" "${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}/$name_for_new_block.reg")
    else
        find_block=$(grep -n "\[$name_block\]" "${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}/"*.reg)
    fi
    if [[ -n $find_block ]] ; then
        if [[ -n $name_for_new_block ]] ; then
            find_file="${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}/$name_for_new_block.reg"
            find_line=${find_block//:*/}
        else
            find_file=${find_block//:*/}
            find_line=${find_block//$find_file:/}
            find_line=${find_line//:*/}
        fi
        count=-1
        while read -r line_reg ; do
            ((count++))
            if [[ $line_reg =~ $name_for_find ]] ; then
                if [[ $line_reg == $name_for_find$name_for_set ]] ; then
                    # когда менять не нужно, потому что такое же
                    return 0
                fi
                find_number_line=$(( count + find_line ))
                find_check_file=1
                break
            fi
            [[ -z $line_reg ]] && break
        done <<< "$(sed -n "$find_line"',$p' "$find_file")"
    fi
    if [[ $name_add_or_del == --add ]] ; then
        if [[ -z $find_block ]] ; then
            if [[ -n $name_for_new_block ]] ; then
                sed -i '$a\\n'\["$name_block"\] "${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}/$name_for_new_block.reg"
                find_file="${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}/$name_for_new_block.reg"
                find_line=$(wc -l "$find_file" | awk -F" " '{print $1}')
                find_line=$(( find_line - 1 ))
            else
                print_error "$name_fatal not found in reg files"
                return 1
            fi
        fi
        if [[ $find_check_file == 1 ]] ; then
            print_info "Change $name_for_find_old to reg file"
            sed -i "${find_number_line}s|$name_for_find.*|$name_for_find$name_for_set|" "$find_file"
        else
            print_info "Added $name_for_find_old to reg file"
            sed -i "$(( find_line + 1 ))a$name_for_find$name_for_set" "$find_file"
        fi
    elif [[ $name_add_or_del == --delete ]] ; then
        [[ $find_check_file != 1 ]] && return 0
        print_info "Delete $name_for_find_old to reg file"
        sed -i "${find_number_line}d" "$find_file"
    fi
}

convert_dec_and_hex () {
    local type=$1
    local num=$2

    case "$type" in
        --dec)
        # Преобразование из десятичного в шестнадцатеричный
        echo -n "$(printf "%08x" "$num")" ;;
        --hex)
        # Преобразование из шестнадцатеричного в десятичный
        echo $(( 0x$num )) ;;
        *)
        echo "Неверный тип преобразования. Используйте --dec или --hex." ;;
    esac
}

fixes_after_update () {
    local fixes_path line fixes_info IFS
    fixes_info=$1
    fixes_path="$PORT_WINE_TMP_PATH/fixes_apply"
    [[ ! -f $fixes_path ]] && touch "$fixes_path"

    while read -r line ; do
        if [[ $line == "$fixes_info" ]] ; then
            return 1
        fi
    done < "$fixes_path"
    echo "$fixes_info" >> "$fixes_path"
    return 0
}

pw_clear_pfx () {
    rm -f "${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}"/.dot*
    rm -f "${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}"/.prog*
    try_remove_file "${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}/.wine_ver"
    try_remove_file "${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}/system.reg"
    try_remove_file "${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}/user.reg"
    try_remove_file "${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}/userdef.reg"
    try_remove_file "${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}/winetricks.log"
    try_remove_file "${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}/.update-timestamp"
    try_remove_file "${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}/drive_c/.windows-serial"
    try_remove_dir "${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}/drive_c/windows/"
    try_remove_dir "${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}/drive_c/ProgramData/Setup"
    try_remove_dir "${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}/drive_c/ProgramData/Windows"
    try_remove_dir "${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}/drive_c/ProgramData/WindowsTask"
    try_remove_dir "${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}/drive_c/ProgramData/Package Cache"
    try_remove_dir "${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}/drive_c/users/Public/Local Settings/Application Data/Microsoft"
    try_remove_dir "${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}/drive_c/users/Public/Local Settings/Application Data/Temp"
    try_remove_dir "${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}/drive_c/users/Public/Local Settings/Temporary Internet Files"
    try_remove_dir "${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}/drive_c/users/Public/Application Data/Microsoft"
    try_remove_dir "${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}/drive_c/users/Public/Application Data/wine_gecko"
    try_remove_dir "${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}/drive_c/users/Public/Temp"
    try_remove_dir "${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}/drive_c/users/steamuser/Local Settings/Application Data/Microsoft"
    try_remove_dir "${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}/drive_c/users/steamuser/Local Settings/Application Data/Temp"
    try_remove_dir "${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}/drive_c/users/steamuser/Local Settings/Temporary Internet Files"
    try_remove_dir "${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}/drive_c/users/steamuser/Application Data/Microsoft"
    try_remove_dir "${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}/drive_c/users/steamuser/Application Data/wine_gecko"
    try_remove_dir "${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}/drive_c/users/steamuser/Temp"
    try_remove_dir "${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}/drive_c/Program Files/Internet Explorer"
    try_remove_dir "${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}/drive_c/Program Files/Windows Media Player"
    try_remove_dir "${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}/drive_c/Program Files/Windows NT"
    try_remove_dir "${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}/drive_c/Program Files (x86)/Internet Explorer"
    try_remove_dir "${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}/drive_c/Program Files (x86)/Windows Media Player"
    try_remove_dir "${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}/drive_c/Program Files (x86)/Windows NT"
    rm -f "${PORT_WINE_TMP_PATH}"/*.bin
    rm -f "${PORT_WINE_TMP_PATH}"/*.foz
    return 0
}

check_user_conf () {
    export USER_CONF="${PORT_DATA_PATH}/data/user.conf"

    if [[ ! -f "${USER_CONF}" ]] ; then
        cat << EOF > "${USER_CONF}"
#!/usr/bin/env bash
# User overides db and var settings...
# export DXVK_HUD=full
# export GALLIUM_HUD=fps
export PW_GPU_USE="disabled"
EOF
    else
        sed -i \
            -e 's/="CDN"/="CLOUD"/g' \
            -e '/export PW_SOUND_DRIVER_USE=/d' \
            "$USER_CONF"
    fi

    # shellcheck source=/dev/null
    source "$USER_CONF"
}

init_wine_ver () {
    if [[ "${PW_WINE_VER}" == "USE_SYSTEM_WINE" ]]
    then export PW_WINE_USE="USE_SYSTEM_WINE"
    elif [[ -n "${PW_WINE_VER}" ]]
    then export PW_WINE_USE="$PW_WINE_VER"
    fi
    unset PW_WINE_VER

    if [[ "${PW_WINE_USE}" == "USE_SYSTEM_WINE" ]] \
    && command -v wine &>/dev/null ; then
        export WINEDIR="$RT_PREFIX/usr"
        WINE="$RT_PREFIX$(command -v wine)"
        export WINE
        export WINELOADER="$WINE"
        WINESERVER="$RT_PREFIX$(command -v wineserver)"
        export WINESERVER
        export PW_USE_FSYNC=0
        unset WINEDLLPATH
    else
        if [[ -d "${PORT_DATA_PATH}/data/dist" ]] ; then
            IFS=$'\n'
            for dist_dir in $(lsbash "${PORT_DATA_PATH}/data/dist") ; do
                dist_dir_new=$(echo "${dist_dir}" | awk '$1=$1' | sed -e 's/[[:blank:]]*-[[:blank:]]*/-/g' -e 's/[[:blank:]]/_/g')
                if [[ ! -d "${PORT_DATA_PATH}/data/dist/${dist_dir_new^^}" ]] ; then
                    mv -- "${PORT_DATA_PATH}/data/dist/$dist_dir" "${PORT_DATA_PATH}/data/dist/${dist_dir_new^^}"
                fi
            done
            IFS="$orig_IFS"
        fi

        if [[ "$PW_WINE_USE" == PROTON_LG ]]
        then export PW_WINE_USE="${PW_PROTON_LG_VER}"
        elif [[ "$PW_WINE_USE" == WINE_LG ]]
        then export PW_WINE_USE="${PW_WINE_LG_VER}"
        fi

        PW_EXTERNAL_WINE_DIR=0
        if [[ "${PW_WINE_USE}" = /* ]] && [[ -d "${PW_WINE_USE}" ]] ; then
            export WINEDIR="${PW_WINE_USE}"
            PW_EXTERNAL_WINE_DIR=1
        else
            export WINEDIR="${PORT_DATA_PATH}/data/dist/${PW_WINE_USE^^}"
        fi
        if [[ -d "${WINEDIR}/files" && ! -d "${WINEDIR}/dist" ]] ; then
            export WINEDIR="${WINEDIR}/files"
        fi

        if [[ "$PW_USE_WOW64" == "1" ]] \
        && [[ -d "${WINEDIR}/bin-wow64" ]]
        then
            print_warning "wine wow64 mode in use!"
            export WINE="${WINEDIR}/bin-wow64/wine"
            export WINELOADER="${WINEDIR}/bin-wow64/wine"
            export WINESERVER="${WINEDIR}/bin-wow64/wineserver"
        else
            export WINE="${WINEDIR}/bin/wine"
            export WINELOADER="${WINEDIR}/bin/wine"
            export WINESERVER="${WINEDIR}/bin/wineserver"
        fi

        if [[ -d "${WINEDIR}" ]] ; then
            if [[ ! -d "${WINEDIR}/lib64/wine" ]] && [[ -d "${WINEDIR}/lib/wine/x86_64-unix" ]] ; then
                create_new_dir "${WINEDIR}/lib64/"
                try_force_link_dir "${WINEDIR}/lib/wine/" "${WINEDIR}/lib64/"
            fi
            if [[ "${PW_EXTERNAL_WINE_DIR}" != "1" ]] ; then
                [[ ! -f "${WINEDIR}/version" ]] && echo "${PW_WINE_USE}" > "${WINEDIR}/version"

                for mono_gecko_chk in "mono" "gecko" ; do
                    if check_symlink "${WINEDIR}/share/wine/${mono_gecko_chk}" ; then
                        print_info "${WINEDIR}/share/wine/${mono_gecko_chk} is symlink. OK."
                    elif [[ -d "${WINEDIR}/share/wine/${mono_gecko_chk}" ]] ; then
                        try_copy_dir "${WINEDIR}/share/wine/${mono_gecko_chk}" "${PORT_WINE_TMP_PATH}"
                        try_remove_dir "${WINEDIR}/share/wine/${mono_gecko_chk}"
                        try_force_link_dir "${PORT_WINE_TMP_PATH}/${mono_gecko_chk}" "${WINEDIR}"/share/wine/
                        print_info "Copy ${WINEDIR}/share/wine/${mono_gecko_chk} to tmp and create symlink to ${WINEDIR}/share/wine/. OK."
                    else
                        try_remove_dir "${WINEDIR}/share/wine/${mono_gecko_chk}"
                        try_force_link_dir "${PORT_WINE_TMP_PATH}/${mono_gecko_chk}" "${WINEDIR}"/share/wine
                        print_warning "${WINEDIR}/share/wine/${mono_gecko_chk} is broken symlink. Repair... OK."
                    fi
                done
            fi
        fi

        WINEDLLPATH="${WINEDIR}/lib/wine"
        [[ ! -L "${WINEDIR}/lib64/wine" ]] && WINEDLLPATH+=":${WINEDIR}/lib64/wine"
        [[ -d "${PATH_TO_GAME}" ]] && WINEDLLPATH+=":${PATH_TO_GAME}"
        export WINEDLLPATH
    fi

    if ! check_flatpak ; then
        WINE_LIBRARY_PATH="${WINEDIR}/lib"
        if [[ -d "${WINEDIR}/lib64/gstreamer-1.0" ]]
        then WINE_LIBRARY_PATH+=":${WINEDIR}/lib64"
        elif [[ -d "${WINEDIR}/lib/x86_64-linux-gnu" ]]
        then WINE_LIBRARY_PATH+=":${WINEDIR}/lib/x86_64-linux-gnu:${WINEDIR}/lib/i386-linux-gnu"
        fi
        export WINE_LIBRARY_PATH
    fi

    export MEDIACONV_BLANK_VIDEO_FILE="${WINEDIR}/share/media/blank.mkv"
    export MEDIACONV_BLANK_AUDIO_FILE="${WINEDIR}/share/media/blank.ptna"
    if  [[ -d "${WINEDIR}"/share/espeak-ng-data ]] ; then
        export ESPEAK_DATA_PATH="${WINEDIR}"/share/
    fi
    return 0
}

pw_init_runtime () {
    if [[ ! -f "${PW_WINELIB}/runtime/files/bin/vkcube" ]] \
    || [[ ! -f "${PW_WINELIB}/pressure-vessel/bin/pressure-vessel-wrap" ]]
    then
        export PW_USE_RUNTIME="0"
    fi
    if [[ "$PW_USE_RUNTIME" != "1" ]] \
    || [[ "$PW_WINE_USE" == "USE_SYSTEM_WINE" ]]
    then
        export PW_LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:${PW_PLUGINS_PATH}/portable/lib/lib64:${PW_PLUGINS_PATH}/portable/lib/lib32"
        export PW_VK_LAYER_PATH="${PW_PLUGINS_PATH}/portable/share/vulkan/implicit_layer.d"
        if [[ -z "$PW_TERM" ]] ; then
            export PW_TERM="env LD_LIBRARY_PATH=\"${PW_LD_LIBRARY_PATH}\" python3 -m portprotonqt.scripts_utils.easyterm -e"
        fi
        export pw_runtime="env"
        return 0
    fi

    if grep -i "altlinux" "/etc/os-release" &>/dev/null ; then
        export LIBGL_DRIVERS_PATH="/usr/lib/X11/modules/dri:/usr/lib64/X11/modules/dri"
        if [[ "${LSPCI_VGA,,}" == *nvidia* ]] ; then
            if [[ -f "/usr/share/vulkan/icd.d/nvidia_icd.json" ]] ; then
                VK_ADD_DRIVER_FILES="$(realpath /usr/share/vulkan/icd.d/nvidia_icd.json)"
                export VK_ADD_DRIVER_FILES
            fi
            local nvidia_lib64_path nvidia_lib32_path
            nvidia_lib64_path="$(realpath /etc/libnvidiacurrent 2>/dev/null)"
            nvidia_lib32_path="$(realpath /etc/libnvidia32current 2>/dev/null)"
            if [[ -n "$nvidia_lib64_path" ]] || [[ -n "$nvidia_lib32_path" ]] ; then
                export PRESSURE_VESSEL_APP_LD_LIBRARY_PATH="\
${LD_LIBRARY_PATH:+${LD_LIBRARY_PATH}:}\
${nvidia_lib64_path:+$nvidia_lib64_path:}\
${nvidia_lib32_path}"
            fi
        fi
    elif grep -i -E '(ROSA|RED OS)' "/etc/os-release" &>/dev/null ; then
        export LOCPATH="/run/host/usr/share/locale/"
    fi

    PW_PV_OVERRIDES="/usr/lib/pressure-vessel/overrides/lib"

    if ! check_flatpak; then
      export PW_LD_LIBRARY_PATH="\
${PW_PLUGINS_PATH}/portable/lib/lib64:\
${PW_PLUGINS_PATH}/portable/lib/lib32:\
${PW_PV_OVERRIDES}/x86_64-linux-gnu/aliases:\
${PW_PV_OVERRIDES}/i386-linux-gnu/aliases:\
/overrides/lib/x86_64-linux-gnu:\
/overrides/lib/i386-linux-gnu:\
/lib/x86_64-linux-gnu:\
/lib/i386-linux-gnu"
    fi

    export PW_PATH="${PW_PLUGINS_PATH}/portable/bin${PATH:+:$PATH}"

    if [[ "$PW_LOG" == "1" ]] ; then
        PW_ADD_TO_ARGS_IN_RUNTIME="--verbose $PW_ADD_TO_ARGS_IN_RUNTIME"
    fi

    if [[ -n "${PW_SANDBOX_HOME_PATH}" && -d "${PW_SANDBOX_HOME_PATH}" ]] ; then
        export pw_runtime="${PW_WINELIB}/pressure-vessel/bin/pressure-vessel-unruntime \
        --unshare-home \
        --home=${PW_SANDBOX_HOME_PATH} \
        --remove-game-overlay \
        --share-pid \
        ${PW_ADD_TO_ARGS_IN_RUNTIME} -- \
        env PATH=$PW_PATH "
    else
        export pw_runtime="${PW_WINELIB}/pressure-vessel/bin/pressure-vessel-unruntime \
        --share-home \
        --remove-game-overlay \
        --share-pid \
        ${PW_ADD_TO_ARGS_IN_RUNTIME} -- \
        env PATH=$PW_PATH "
    fi

    if [[ "$PW_USE_SYSTEM_VK_LAYERS" == "1" ]] ; then
        export PRESSURE_VESSEL_IMPORT_VULKAN_LAYERS=1
        unset PW_VK_LAYER_PATH
    else
        export PRESSURE_VESSEL_IMPORT_VULKAN_LAYERS=0
        export PW_VK_LAYER_PATH="${PW_PLUGINS_PATH}/portable/share/vulkan/implicit_layer.d"
    fi

    # export PRESSURE_VESSEL_GRAPHICS_PROVIDER="/"

    unset PRESSURE_VESSEL_RUNTIME_ARCHIVE
    export PRESSURE_VESSEL_COPY_RUNTIME=1
    export PRESSURE_VESSEL_GC_LEGACY_RUNTIMES=1
    export PRESSURE_VESSEL_RUNTIME=runtime
    export PRESSURE_VESSEL_RUNTIME_BASE="${PW_WINELIB}"
    export PRESSURE_VESSEL_VARIABLE_DIR="${PW_WINELIB}/var"
    export PRESSURE_VESSEL_PREFIX="${PW_WINELIB}/pressure-vessel"
    export PRESSURE_VESSEL_ARCHITECTURES="x86_64-linux-gnu:i386-linux-gnu"
    export FONTCONFIG_PATH=''

    unset PRESSURE_VESSEL_FILESYSTEMS_RO PRESSURE_VESSEL_FILESYSTEMS_RW
    for PWRTMRO in "${PW_RT_MOUNT_RO[@]}" ; do
        export PRESSURE_VESSEL_FILESYSTEMS_RO="${PRESSURE_VESSEL_FILESYSTEMS_RO:+$PRESSURE_VESSEL_FILESYSTEMS_RO:}${PWRTMRO}"
    done
    for PWRTMRW in "${PW_RT_MOUNT_RW[@]}" ; do
        export PRESSURE_VESSEL_FILESYSTEMS_RW="${PRESSURE_VESSEL_FILESYSTEMS_RW:+$PRESSURE_VESSEL_FILESYSTEMS_RW:}${PWRTMRW}"
    done
    export PW_TERM="env LD_LIBRARY_PATH=\"${PW_LD_LIBRARY_PATH}\" python3 -m portprotonqt.scripts_utils.easyterm -e"

    print_info "RUNTIME is enabled"
}

pw_mangohud_check () {
    if [[ "${PW_MANGOHUD}" == "1" ]] \
    && ! check_gamescope_session
    then
        if [[ "$PW_USE_SYSTEM_VK_LAYERS" != "1" ]] ; then
            sed -i 's/: "VK_LAYER/: "PW_VK_LAYER/' "${PW_PLUGINS_PATH}/portable/share/vulkan/implicit_layer.d"/MangoHud*.json
            var_pw_vk_istance_layers_config_update "PW_VK_LAYER_MANGOHUD_overlay64:PW_VK_LAYER_MANGOHUD_overlay32"
            print_info "Portable MangoHud is enabled"
        else
            print_info "System MangoHud is enabled"
            add_to_var PW_ADD_VAR_SLR 'MANGOHUD=1'
        fi
        # TODO: need to fix work for OpenGL without flatpak...
        MANGOHUD_LIB_NAME="libMangoHud_shim.so"
        export PW_LD_PRELOAD="${PW_LD_PRELOAD:+$PW_LD_PRELOAD:}${MANGOHUD_LIB_NAME}"
    else
        print_info "MangoHud is disabled"
    fi
    return 0
}

pw_mangohud_preview () {
    if pgrep -f "${PW_PLUGINS_PATH}/portable/bin/vkcube" ; then
        return 0
    fi
    local preview_config="${1:-}"

    if [[ -n "$preview_config" ]] ; then
        export MANGOHUD_CONFIG="$preview_config"
        print_info "MangoHud preview inline config in use: $MANGOHUD_CONFIG"
    fi

    PW_LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:${PW_PLUGINS_PATH}/portable/lib/lib64:${PW_PLUGINS_PATH}/portable/lib/lib32"
    PW_VK_LAYER_PATH="${PW_PLUGINS_PATH}/portable/share/vulkan/implicit_layer.d"

    export DISABLE_LSFGVK="1"
    export PW_MANGOHUD="1"

    pw_mangohud_check
    env \
    $PW_ADD_VAR_SLR \
    LD_LIBRARY_PATH="${PW_LD_LIBRARY_PATH}" \
    VK_ADD_IMPLICIT_LAYER_PATH="${PW_VK_LAYER_PATH}" \
    VK_ADD_LAYER_PATH="${PW_VK_LAYER_PATH}" \
    VK_INSTANCE_LAYERS="${PW_VK_INSTANCE_LAYERS}" \
    "${PW_PLUGINS_PATH}/portable/bin/vkcube"
}

pw_lsfg_vk_check () {
    if [[ "${PW_USE_LS_FRAME_GEN}" == "1" ]] ; then
        local lsfg_vk_path="$PW_PLUGINS_PATH/fake_dlss/lsfg-vk-$PW_LSFG_VK_VER"
        create_new_dir "$PW_PLUGINS_PATH/fake_dlss/"
        if [[ ! -d "$lsfg_vk_path" ]] ; then
            if try_download "github.com/Castro-Fidel/vulkan/releases/download/lsfg-vk-$PW_LSFG_VK_VER/lsfg-vk-$PW_LSFG_VK_VER.tar.xz" \
                            "${PORT_DATA_PATH}/data/tmp/lsfg-vk-$PW_LSFG_VK_VER.tar.xz" ; then
                if ! unpack "${PORT_DATA_PATH}/data/tmp/lsfg-vk-$PW_LSFG_VK_VER.tar.xz" "$PW_PLUGINS_PATH/fake_dlss/"
                then try_remove_dir "$lsfg_vk_path"
                fi
                try_remove_file "${PORT_DATA_PATH}/data/tmp/lsfg-vk-$PW_LSFG_VK_VER.tar.xz"
            fi
        fi

        export LSFGVK_DLL_PATH="$lsfg_vk_path/Lossless.dll"

        check_variables LSFGVK_ENV "1"
        check_variables LSFGVK_MULTIPLIER "3"
        check_variables LSFGVK_FLOW_SCALE "0.5"
        check_variables LSFGVK_PERFORMANCE_MODE "1"

        if [[ "$PW_USE_SYSTEM_VK_LAYERS" != "1" ]] ; then
            sed -i \
                -e 's/: "VK_LAYER/: "PW_VK_LAYER/' \
                -e "s|.*\"library_path\".*|    \"library_path\": \"$lsfg_vk_path/liblsfg-vk-layer.so\",|g" \
            "$lsfg_vk_path/VkLayer_LSFGVK_frame_generation.json"

            if check_flatpak ; then
                create_new_dir "$PORT_DATA_PATH/data/vulkan/implicit_layer.d/"
                try_force_link_file "$lsfg_vk_path/VkLayer_LSFGVK_frame_generation.json" \
                                    "$PORT_DATA_PATH/data/vulkan/implicit_layer.d/VkLayer_LS_PW_frame_generation.json"
            else
                try_force_link_file "$lsfg_vk_path/VkLayer_LSFGVK_frame_generation.json" \
                                    "$PW_PLUGINS_PATH/portable/share/vulkan/implicit_layer.d/VkLayer_LS_PW_frame_generation.json"
            fi

            print_info "Portable LSFG_VK is enabled"
        else
            print_warning "Portable LSFG_VK is disabled"
        fi
    else
        export DISABLE_LSFGVK="1"
    fi
}

pw_vkbasalt_check () {
    if [[ "${PW_VKBASALT}" == "1" ]] ; then
        if [[ "$PW_USE_SYSTEM_VK_LAYERS" != "1" ]] ; then
            sed -i 's/: "VK_LAYER/: "PW_VK_LAYER/' "${PW_PLUGINS_PATH}/portable/share/vulkan/implicit_layer.d"/vkBasalt*.json
            var_pw_vk_istance_layers_config_update "PW_VK_LAYER_VKBASALT_post_processing64:PW_VK_LAYER_VKBASALT_post_processing32"
            print_info "Portable vkBasalt is enabled"
        else
            print_info "System vkBasalt is enabled"
            export ENABLE_VKBASALT="1"
        fi
        if ! grep "${PW_PLUGINS_PATH}/reshade" "${VKBASALT_CONFIG_FILE}" &>/dev/null
        then sed -ri "s|= .*/reshade|= \"${PW_PLUGINS_PATH}\"/reshade|g" "${VKBASALT_CONFIG_FILE}"
        fi
        if [[ -n "${PW_VKBASALT_EFFECTS}" ]] && [[ -n "${PW_VKBASALT_FFX_CAS}" ]] ; then
            sed -ri "s/effects = .*/effects = ${PW_VKBASALT_EFFECTS}/g" "${VKBASALT_CONFIG_FILE}"
            sed -ri "s/casSharpness .*/casSharpness = ${PW_VKBASALT_FFX_CAS}/g" "${VKBASALT_CONFIG_FILE}"
        fi
    else
        export DISABLE_VKBASALT="1"
        print_info "vkBasalt is disabled"
    fi
    return 0
}

regdlloverrides () {
    PW_DLL_EXE=$(echo $@ | awk -F: '{print $1}')
    PW_DLL_LIB=$(echo $@ | awk -F: '{print $2}' | awk -F= '{print $1}')
    PW_DLL_SET=$(echo $@ | awk -F= '{print $NF}')
    case "${PW_DLL_SET}" in
        "n,b") PW_DLL_IN_REG="native,builtin" ;;
        "b,n") PW_DLL_IN_REG="builtin,native" ;;
          "n") PW_DLL_IN_REG="native" ;;
          "b") PW_DLL_IN_REG="builtin" ;;
            *) PW_DLL_IN_REG="" ;;
    esac
    grep 'HKCU,Software\\Wine\\AppDefaults\\'"${PW_DLL_EXE}"'\\DllOverrides,'\"${PW_DLL_LIB}\",0x2,\"${PW_DLL_IN_REG}\" "${WINEDIR}/share/wine/wine.inf"
    if [[ "$?" != "0" ]] ; then
        grep "ProtonOverrides" "${WINEDIR}/share/wine/wine.inf"
        if [[ "$?" == "0" ]] ; then
            sed -i "/\[ProtonOverrides\]/a HKCU,Software\\\Wine\\\AppDefaults\\\\${PW_DLL_EXE}\\\DllOverrides,\"${PW_DLL_LIB}\",0x2,\"${PW_DLL_IN_REG}\"" "${WINEDIR}/share/wine/wine.inf"
        else
            sed -i "/\[SteamClient.ntamd64\]/a HKCU,Software\\\Wine\\\AppDefaults\\\\${PW_DLL_EXE}\\\DllOverrides,\"${PW_DLL_LIB}\",0x2,\"${PW_DLL_IN_REG}\"" "${WINEDIR}/share/wine/wine.inf"
        fi
    fi
}

wait_wineserver () {
    while ls -l /proc/*/exe >/dev/null 2>&1 | grep -ie PortProton | grep -E 'wine(64)?-preloader|wineserver'
    do
        sleep 0.1
    done
    "$WINESERVER" -w
    return 0
}
export -f wait_wineserver

kill_portwine () {
    if [[ -n "$WINESERVER" ]] && [[ -f "$WINESERVER" ]] ; then
        "$WINESERVER" -k
    fi

    if [[ "${PW_WINE_USE}" != "USE_SYSTEM_WINE" ]] ; then
        if check_flatpak && [[ "$ALPINE_FP" == "1" ]] ; then
            wine_pids=$(ls -l /proc/*/exe >/dev/null 2>&1 | grep -ie PortProton | grep -E 'wine(64)?-preloader|wineserver' | awk -F/ '{print $3}')
            bwrap_pids=$(pgrep -f wrap | grep PortProton | head -n 1)
        else
            wine_pids=$(ls -l /proc/*/exe 2>/dev/null | grep -ie PortProton | grep -E 'wine(64)?-preloader|wineserver' | awk -F/ '{print $3}')
            bwrap_pids="$(pgrep -a wrap | grep PortProton | head -n 1 | awk '{print $1}')"
        fi
    else
        wine_pids=$(ls -l /proc/*/exe 2>/dev/null | grep -E 'wine(64)?-preloader|wineserver' | awk -F/ '{print $3}')
        unset bwrap_pids
    fi

    for pw_kill_pids in ${bwrap_pids} ${wine_pids}; do
        if ps cax | grep "${pw_kill_pids}" ; then
            kill -n 9 "${pw_kill_pids}" &>/dev/null
        fi
    done
    return 0
}
export -f kill_portwine

pw_kill_autostart () {
    if [[ -z "${2}" ]]
    then SWAIT=3
    else SWAIT="${2}"
    fi
    sleep 5
    while true ; do
        if  [[ -z "$(ps aux | grep -m 1 -i "$1" | grep -v grep | awk '{print $2}')" ]] \
        && [[ -n "$(ps aux | grep wrap | grep -v grep | grep -i "PortProton" | head -n 1)" ]]
        then
            echo -e "PID $1 not found"
            sleep "${SWAIT}"
        else
            sleep "${SWAIT}"
            if [[ "$3" == please ]]
            then kill -s SIGTERM $(ps aux | grep -m 1 -i "$1" | grep -v grep | awk '{print $2}') &>/dev/null
            else kill_portwine
            fi
            break
        fi
    done

    if [[ -n "$(lsbash "${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}"/drive_c/ | grep -m 1 ".tmp")" ]] ; then
        rm -f "${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}"/drive_c/*.tmp
    fi

    return 0
}
export -f pw_kill_autostart

stop_portproton () {
    [[ "$int_xneur" == "1" ]] && xneur &

    if [[ "$PW_USE_US_LAYOUT" == "1" ]] \
    && ! check_wayland_session \
    && command -v setxkbmap &>/dev/null
    then
        setxkbmap
    fi

    if ! check_wayland_session \
    && [[ "$(xrandr | sed -rn 's/^.*primary.* ([0-9]+x[0-9]+).*$/\1/p')" != "$PW_SCREEN_RESOLUTION" ]]
    then
        xrandr --output "$PW_SCREEN_PRIMARY" --mode "$PW_SCREEN_RESOLUTION"
    fi

    if [[ "${PW_DISABLE_COMPOSITING}" == "1" ]] \
    && ! check_gamescope_session
    then
        if [[ "${DESKTOP_SESSION}" =~ "plasma" ]] ; then
            kde_version=$(plasmashell --version 2>/dev/null | grep -oE '[0-9]+' | head -1)
            if [[ -n "$kde_version" && "$kde_version" -lt 6 ]]; then
                qdbus org.kde.KWin /Compositor resume
            fi
        elif [[ "${DESKTOP_SESSION}" =~ "mate" ]] ; then
            gsettings set org.mate.Marco.general compositing-manager true
        elif [[ "${DESKTOP_SESSION}" =~ "xfce" ]] ; then
            xfconf-query -c xfwm4 -p /general/use_compositing -s true
        elif [[ "${DESKTOP_SESSION}" =~ "cinnamon" ]] ; then
            gsettings set org.cinnamon.muffin unredirect-fullscreen-windows false
        elif [[ "${DESKTOP_SESSION}" =~ "deepin" ]] ; then
            python_module dbus_tools deepin-switch-wm &>/dev/null
        fi
    fi

    kill_portwine
    [[ -n $PW_WINELIB ]] && try_remove_dir "${PW_WINELIB}/var"
    find "${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}/drive_c/" -maxdepth 1 -type f -name "*.tmp" -delete
    pw_auto_create_shortcut
    add_in_stop_portproton
    pw_restore_power_profile

    if [[ $PW_LOG != 1 ]] && [[ -n $START_PW_TIME_IN_GAME ]] ; then
        debug_timer --end -s "PW_TIME_IN_GAME"
        PW_TIME_IN_GAME=$(( PW_TIME_IN_GAME / 1000 )) # в секундах
        create_name_desktop
    fi

    exit 0
}
export -f stop_portproton

pw_check_and_download_runtime () {
    if [[ ! -f "${PW_WINELIB}/runtime/files/bin/vkcube" ]] \
    || [[ ! -f "${PW_WINELIB}/pressure-vessel/bin/pressure-vessel-wrap" ]]
    then
        print_info "Download and install libraries..."
        if try_download "github.com/Castro-Fidel/PortWINE/releases/download/libs${PW_LIBS_VER}/libs${PW_LIBS_VER}.tar.xz" \
                        "${PORT_WINE_TMP_PATH}/libs${PW_LIBS_VER}.tar.xz" ; then
            if unpack "${PORT_WINE_TMP_PATH}/libs${PW_LIBS_VER}.tar.xz" "${PORT_WINE_TMP_PATH}/" ; then
                try_remove_file "${PORT_WINE_TMP_PATH}/libs${PW_LIBS_VER}.tar.xz"
                if lsbash "${PORT_WINE_TMP_PATH}" --grep libs_v --grep -v libs"${PW_LIBS_VER}" ; then
                    for RM_LIBS in $(lsbash "${PORT_WINE_TMP_PATH}" --grep libs_v --grep -v libs"${PW_LIBS_VER}")
                    do try_remove_dir "${PORT_WINE_TMP_PATH}/${RM_LIBS}"
                    done
                fi
            else
                try_remove_dir "${PORT_WINE_TMP_PATH}/libs${PW_LIBS_VER}"
                try_remove_file "${PORT_WINE_TMP_PATH}/libs${PW_LIBS_VER}.tar.xz"
                #TODO:
                fatal "pw_check_and_download_runtime"
            fi
        else
            fatal "pw_check_and_download_runtime"
        fi
    fi
    return 0
}

pw_check_and_download_dxvk_and_vkd3d () {
    # Download DXVK versions
    for DXVK_VAR_VER in "${DXVK_SAREK_VER}" "${DXVK_OLD_VER}" "${DXVK_NEW_VER}" ; do
        if [[ ! -d "${PW_VULKAN_DIR}/dxvk-${DXVK_VAR_VER}" ]] ; then
            print_info "Download and install DXVK v.${DXVK_VAR_VER}"
            if try_download "https://github.com/Castro-Fidel/vulkan/releases/download/dxvk-${DXVK_VAR_VER}/dxvk-${DXVK_VAR_VER}.tar.xz" \
                                      "${PW_VULKAN_DIR}/dxvk-${DXVK_VAR_VER}.tar.xz" ; then
                if unpack "${PW_VULKAN_DIR}/dxvk-${DXVK_VAR_VER}.tar.xz" "${PW_VULKAN_DIR}" ; then
                    try_remove_file "${PW_VULKAN_DIR}/dxvk-${DXVK_VAR_VER}.tar.xz"
                else
                    try_remove_file "${PW_VULKAN_DIR}/dxvk-${DXVK_VAR_VER}.tar.xz"
                    try_remove_dir "${PW_VULKAN_DIR}/dxvk-${DXVK_VAR_VER}"

                    fatal "Failed to download and unpack dxvk"
                fi
            elif try_download "https://github.com/doitsujin/dxvk/releases/download/v${DXVK_VAR_VER}/dxvk-${DXVK_VAR_VER}.tar.gz" \
                                       "${PW_VULKAN_DIR}/dxvk-${DXVK_VAR_VER}.tar.gz"  no_mirror ; then
                if unpack "${PW_VULKAN_DIR}/dxvk-${DXVK_VAR_VER}.tar.gz" "${PW_VULKAN_DIR}" ; then
                    try_remove_file "${PW_VULKAN_DIR}/dxvk-${DXVK_VAR_VER}.tar.gz"
                else
                    try_remove_file "${PW_VULKAN_DIR}/dxvk-${DXVK_VAR_VER}.tar.gz"
                    try_remove_dir "${PW_VULKAN_DIR}/dxvk-${DXVK_VAR_VER}"

                    fatal "Failed to download and unpack dxvk"
                fi
            else
                fatal "Failed to download and unpack dxvk"
            fi
        fi
    done

    # Download VKD3D versions
    for VKD3D_VAR_VER in "${VKD3D_SAREK_VER}" "${VKD3D_OLD_VER}" "${VKD3D_NEW_VER}" ; do
        if [[ ! -d "${PW_VULKAN_DIR}/vkd3d-proton-${VKD3D_VAR_VER}" ]] ; then
            print_info "Download and install VKD3D-PROTON v.${VKD3D_VAR_VER}"
            if try_download "https://github.com/Castro-Fidel/vulkan/releases/download/vkd3d-proton-${VKD3D_VAR_VER}/vkd3d-proton-${VKD3D_VAR_VER}.tar.xz" \
                                      "${PW_VULKAN_DIR}/vkd3d-proton-${VKD3D_VAR_VER}.tar.xz" ; then
                if unpack "${PW_VULKAN_DIR}/vkd3d-proton-${VKD3D_VAR_VER}.tar.xz" "${PW_VULKAN_DIR}" ; then
                    try_remove_file "${PW_VULKAN_DIR}/vkd3d-proton-${VKD3D_VAR_VER}.tar.xz"
                else
                    try_remove_file "${PW_VULKAN_DIR}/vkd3d-proton-${VKD3D_VAR_VER}.tar.xz"
                    try_remove_dir "${PW_VULKAN_DIR}/vkd3d-proton-${VKD3D_VAR_VER}"
                    fatal "Failed to download and unpack VKD3D"
                fi
            elif try_download "https://github.com/HansKristian-Work/vkd3d-proton/releases/download/v${VKD3D_VAR_VER}/vkd3d-proton-${VKD3D_VAR_VER}.tar.zst" \
                                        "${PW_VULKAN_DIR}/vkd3d-proton-${VKD3D_VAR_VER}.tar.zst" no_mirror ; then
                if unpack "${PW_VULKAN_DIR}/vkd3d-proton-${VKD3D_VAR_VER}.tar.zst" "${PW_VULKAN_DIR}" ; then
                    try_remove_file "${PW_VULKAN_DIR}/vkd3d-proton-${VKD3D_VAR_VER}.tar.zst"
                else
                    try_remove_file "${PW_VULKAN_DIR}/vkd3d-proton-${VKD3D_VAR_VER}.tar.zst"
                    try_remove_dir "${PW_VULKAN_DIR}/vkd3d-proton-${VKD3D_VAR_VER}"
                    fatal "Failed to download and unpack VKD3D"
                fi
            else
                fatal "Failed to download and unpack VKD3D"
            fi
        fi
    done

    return 0
}

pw_check_and_download_plugins () {
    if [[ ! -f "${PW_PLUGINS_PATH}/portable/lib/lib64/libvkbasalt.so" ]] ; then
        print_info "Download and install plugins${PW_PLUGINS_VER}..."
        if try_download "github.com/Castro-Fidel/wine_builds/releases/download/plugins${PW_PLUGINS_VER}/plugins${PW_PLUGINS_VER}.tar.xz" "${PORT_WINE_TMP_PATH}/plugins${PW_PLUGINS_VER}.tar.xz" ; then
            if unpack "${PORT_WINE_TMP_PATH}/plugins${PW_PLUGINS_VER}.tar.xz" "${PORT_WINE_TMP_PATH}" ; then
                try_remove_file "${PORT_WINE_TMP_PATH}/plugins${PW_PLUGINS_VER}.tar.xz"
                # TODO: drop clear prefix, and add update prefix from new plugins
                pw_clear_pfx
                if lsbash "${PORT_WINE_TMP_PATH}" --grep plugins_v --grep -v "plugins${PW_PLUGINS_VER}"
                then
                    for RM_PLUGINS in $(lsbash "${PORT_WINE_TMP_PATH}" --grep plugins_v --grep -v "plugins${PW_PLUGINS_VER}")
                    do try_remove_dir "${PORT_WINE_TMP_PATH}/${RM_PLUGINS}"
                    done
                fi
            else
                try_remove_file "${PORT_WINE_TMP_PATH}/plugins${PW_PLUGINS_VER}.tar.xz"
                try_remove_dir "${PORT_WINE_TMP_PATH}/plugins${PW_PLUGINS_VER}"
                fatal "Failed to download and unpack plugins${PW_PLUGINS_VER}"
                # export PW_PLUGINS_VER="_v$((${PW_PLUGINS_VER//_v/} - 1))"
                # export PW_PLUGINS_PATH="${PORT_WINE_TMP_PATH}/plugins${PW_PLUGINS_VER}"
            fi
        else
            fatal "Failed to download and unpack plugins${PW_PLUGINS_VER}"
            # export PW_PLUGINS_VER="_v$((${PW_PLUGINS_VER//_v/} - 1))"
            # export PW_PLUGINS_PATH="${PORT_WINE_TMP_PATH}/plugins${PW_PLUGINS_VER}"
        fi
    fi
    if command -v 7z &>/dev/null
    then export pw_7z="7z"
    else export pw_7z="${PW_PLUGINS_PATH}/portable/lib/p7zip/7z"
    fi
    return 0
}

check_dirs_and_files_in_pfx () {
        create_new_dir "${WINEPREFIX}/dosdevices"
        create_new_dir "${WINEPREFIX}/drive_c/windows/syswow64/"
        create_new_dir "${WINEPREFIX}/drive_c/windows/system32/"
        create_new_dir "${WINEPREFIX}/drive_c/tmp/.private/$USER/"
        create_new_dir "${WINEPREFIX}/drive_c/tmp/.private/steamuser/"

        [[ ! -d "${WINEPREFIX}/dosdevices/c:" ]] && try_force_link_dir "${WINEPREFIX}/drive_c/" "${WINEPREFIX}/dosdevices/c:"
        [[ ! -d "${WINEPREFIX}/dosdevices/z:" ]] && try_force_link_dir "/" "${WINEPREFIX}/dosdevices/z:"
        [[ ! -d "${WINEPREFIX}/dosdevices/h:" ]] && try_force_link_dir "$HOME" "${WINEPREFIX}/dosdevices/h:"

        if [[ ! -d "${WINEPREFIX}/dosdevices/s:" ]] \
        && [[ -d "$HOME/.local/share/Steam/steamapps/common/" ]]
        then
            try_force_link_dir "$HOME/.local/share/Steam/steamapps/common/" "${WINEPREFIX}/dosdevices/s:"
        fi

        create_new_dir "${WINEPREFIX}/drive_c/windows/Fonts/"
        LN_FONTS="arialbd.ttf courbd.ttf georgia.ttf micross.ttf msyh.ttf simsun.ttc arial.ttf cour.ttf malgun.ttf msgothic.ttc nirmala.ttf times.ttf"
        for link_font in $LN_FONTS ; do
            if [[ ! -f "${WINEPREFIX}/drive_c/windows/Fonts/${link_font}" ]] ; then
                try_force_link_file "${WINEDIR}/share/fonts/${link_font}" "${WINEPREFIX}/drive_c/windows/Fonts/${link_font}"
            fi
        done

        create_new_dir "${WINEPREFIX}/drive_c/users/steamuser"
        if [[ ! -d "${WINEPREFIX}/drive_c/users/${USER}" ]]
        then try_force_link_dir "${WINEPREFIX}/drive_c/users/steamuser" "${WINEPREFIX}/drive_c/users/${USER}"
        fi

        create_new_dir "${WINEPREFIX}/drive_c/users/Public/Documents/Steam"
        create_new_dir "${WINEPREFIX}/drive_c/users/steamuser/Documents/Steam"
        if [[ ! -d "${WINEPREFIX}/drive_c/users/steamuser/My Documents" ]]
        then try_force_link_dir "${WINEPREFIX}/drive_c/users/steamuser/Documents" "${WINEPREFIX}/drive_c/users/steamuser/My Documents"
        fi

        create_new_dir "${WINEPREFIX}/drive_c/users/steamuser/AppData/Roaming"
        if [[ ! -d "${WINEPREFIX}/drive_c/users/steamuser/Application Data" ]]
        then try_force_link_dir "${WINEPREFIX}/drive_c/users/steamuser/AppData/Roaming" "${WINEPREFIX}/drive_c/users/steamuser/Application Data"
        fi

        create_new_dir "${WINEPREFIX}/drive_c/users/steamuser/AppData/Local"
        create_new_dir "${WINEPREFIX}/drive_c/users/steamuser/Local Settings"
        if [[ ! -d "${WINEPREFIX}/drive_c/users/steamuser/Local Settings/Application Data" ]]
        then try_force_link_dir "${WINEPREFIX}/drive_c/users/steamuser/AppData/Local" "${WINEPREFIX}/drive_c/users/steamuser/Local Settings/Application Data"
        fi

        DRIVES=(d e f g i j k l m n o p q r t u v w x y)
        DEF_MOUNT_DIRS=('/media' '/mnt' '/run/media')
        MOUNT_DIRS=($(find "${DEF_MOUNT_DIRS[@]}" -maxdepth 1 -mindepth 1  -type d 2>/dev/null | sort -u))
        find -L "$WINEPREFIX/dosdevices" -maxdepth 1 -type l -exec rm -rf {} \; 2>/dev/null ;

        for drive_dir in "${MOUNT_DIRS[@]}" ; do
            if  mountpoint -q "$drive_dir" ; then
                if ! realpath "${WINEPREFIX}/dosdevices"/*: | grep -w "$drive_dir"$ &>/dev/null ; then
                    drive_num=0
                    while [[ "$drive_num" -lt "${#DRIVES[@]}" ]] ; do
                        drive_path="${WINEPREFIX}/dosdevices/${DRIVES[$drive_num]}:"
                        mount_point=$(df -P "$drive_dir" | awk 'NR==2 {print $1}')
                        mount_name=$(lsblk -no pkname "$mount_point" 2>/dev/null)

                        if [[ ! -L "$drive_path" ]] ; then
                            if [[ $(<"/sys/class/block/$mount_name/removable") != "1" ]] 2>/dev/null ; then
                                if [[ ! "$mount_point" =~ "mmc" ]] ; then
                                    ln -sf "$drive_dir" "$drive_path"
                                    print_info "Mounted ${drive_dir} to ${drive_path}"
                                    break
                                else
                                    ((drive_num++))
                                fi
                            else
                                ((drive_num++))
                            fi
                        else
                            ((drive_num++))
                        fi
                    done
                fi
            fi
        done
    }

pw_init_db () {
    if echo "$LSPCI_VGA" | grep -i -q 'nvidia.*rtx' ; then
        export PW_USE_NVAPI_AND_DLSS="1"
        export PW_USE_RAY_TRACING="1"
    fi

    if [[ -f "${PW_EXE_FILE}" ]] ; then
        PORTWINE_DB="$(basename "${PW_EXE_FILE%.[Ee][Xx][Ee]}")"
        export PORTWINE_DB
        if echo "${PORTWINE_DB}" | grep -i "_vo_\|_gv_" &>/dev/null ; then
            print_warning "Force use gamesvoice.ppdb file!"
            PORTWINE_DB_FILE="${PORT_SCRIPTS_PATH}/portwine_db/gamesvoice.ppdb"
            # shellcheck source=/dev/null
            source "${PORTWINE_DB_FILE}"
        elif [[ -f "${PW_EXE_FILE}".ppdb ]] ; then
            PORTWINE_DB_FILE="${PW_EXE_FILE}".ppdb
            if grep -q "PW_NO_" "${PORTWINE_DB_FILE}" ; then
                sed -i \
                    -e "s/PW_NO_ESYNC=.*1.*/PW_USE_ESYNC=\"0\"/g" \
                    -e "s/PW_NO_ESYNC=.*0.*/PW_USE_ESYNC=\"1\"/g" \
                    -e "s/PW_NO_FSYNC=.*1.*/PW_USE_FSYNC=\"0\"/g" \
                    -e "s/PW_NO_FSYNC=.*0.*/PW_USE_FSYNC=\"1\"/g" \
                    -e "s/PW_NO_NTSYNC=.*1.*/PW_USE_NTSYNC=\"0\"/g" \
                    -e "s/PW_NO_NTSYNC=.*0.*/PW_USE_NTSYNC=\"1\"/g" \
                "${PORTWINE_DB_FILE}"
            fi
            if grep -q "PW_GAMESCOPE" "${PORTWINE_DB_FILE}" \
            && ! grep -q "PW_GAMESCOPE_ARGS_NEW" "${PORTWINE_DB_FILE}"
            then
                # shellcheck source=/dev/null
                source "${PORTWINE_DB_FILE}"

                local -a gs_ppdb_vars=(PW_GAMESCOPE PW_GAMESCOPE_ARGS_NEW PW_GS_ENABLE_GAMESCOPE_WSI PW_GS_SDL_VIDEODRIVER_X11)

                # Rebuild args from current PW_GS_* values produced by yad widgets
                pw_gamescope_process build_args
                pw_gamescope_process sanitize

                # Keep ppdb export list consistent before re-writing gamescope keys
                sed -i '/^export PW_GS_/d' "${PORTWINE_DB_FILE}"
                sed -i '/^export PW_GAMESCOPE_ARGS_NEW=/d' "${PORTWINE_DB_FILE}"
                edit_db_from_gui "${gs_ppdb_vars[@]}"
            fi
            # shellcheck source=/dev/null
            source "${PORTWINE_DB_FILE}"
            if echo "${PW_EXE_FILE}" | grep "/prefixes/" &>/dev/null ; then
                if [[ -z $(grep -e ^"export PW_PREFIX_NAME=" "${PORTWINE_DB_FILE}" 2>/dev/null) ]] ; then
                    PW_PREFIX_NAME=$(echo "${PW_EXE_FILE}" | awk -F"/prefixes/" '{print $2}' | awk -F"/" '{print $1}')
                    edit_db_from_gui PW_PREFIX_NAME
                fi
            fi
        else
            IFS=$'\n'
            if [[ "${PORTWINE_DB,,}" =~ (setup|install|.msi$) ]] ; then
                print_info "Force used setup.ppdb files!"
                PW_FIND_DB_FILE="${PORT_SCRIPTS_PATH}/portwine_db/Setup.ppdb"
            else
                PW_FIND_DB_FILE=$(grep -ilw "#${PORTWINE_DB}.exe" "${PORT_SCRIPTS_PATH}/portwine_db"/* | sed s/".exe"/""/gi)
            fi

            if [[ $(echo "$PW_FIND_DB_FILE" | wc -l) -gt 1 ]] ; then
                fatal "More than one ppdb file found!"
            elif [[ $(echo "$PW_FIND_DB_FILE" | wc -l) -eq 1 ]] ; then
                PORTWINE_DB_FILE="${PW_FIND_DB_FILE}"
            fi
            IFS="$orig_IFS"

            if [[ -f "${PW_FIND_DB_FILE}" ]] ; then
                # shellcheck source=/dev/null
                source "${PORTWINE_DB_FILE}"
            fi

            if [[ -f "${PW_FIND_DB_FILE}" ]] \
            && [[ "${PW_DISABLED_CREATE_DB}" != 1 ]]
            then
                try_copy_file "${PW_FIND_DB_FILE}" "${PW_EXE_FILE}".ppdb
                PORTWINE_DB_FILE="${PW_EXE_FILE}".ppdb
                if echo "${PW_EXE_FILE}" | grep "/prefixes/" &>/dev/null ; then
                    if [[ -z $(grep -e ^"export PW_PREFIX_NAME=" "${PORTWINE_DB_FILE}" 2>/dev/null) ]] ; then
                        PW_PREFIX_NAME=$(echo "${PW_EXE_FILE}" | awk -F"/prefixes/" '{print $2}' | awk -F"/" '{print $1}')
                        edit_db_from_gui PW_PREFIX_NAME
                    fi
                fi
            fi
        fi

        if [[ -f "${PORTWINE_DB_FILE}" ]] ; then
            # shellcheck source=/dev/null
            source "${PORTWINE_DB_FILE}"
            export PW_WINE_VER="$PW_WINE_USE"
            init_wine_ver
            print_info "Use $PORTWINE_DB_FILE db file."
        else
            if [[ "${PW_DISABLED_CREATE_DB}" != 1 ]] ; then
                if [[ -n "${PORTWINE_DB}" ]] ; then
                    PORTWINE_DB_FILE=$(grep -il "#${PORTWINE_DB}.exe" "${PORT_SCRIPTS_PATH}/portwine_db"/*)
                    export PORTWINE_DB_FILE
                    use_exiftool "$PW_EXE_FILE"
                    grep -q "Sony" "${PW_TMPFS_PATH}/exiftool.tmp" && PW_WINE_USE="WINE_LG"
                    if [[ -z "${PORTWINE_DB_FILE}" ]] ; then
                        {
                            echo "#!/usr/bin/env bash"
                            echo "#Author: ${USER}"
                            echo "#${PORTWINE_DB}.exe"
                            echo "#Rating=1-5"
                        } > "${PW_EXE_FILE}".ppdb || fatal "Read only: $(dirname "${PW_EXE_FILE}")"
                        export PORTWINE_DB_FILE="${PW_EXE_FILE}".ppdb
                    fi
                    if [[ "${PW_EXE_FILE}" =~ "/prefixes/" ]] && \
                    [[ ! "${PW_EXE_FILE}" =~ "/prefixes/DEFAULT/" ]]
                    then
                        PW_PREFIX_NAME=$(echo "${PW_EXE_FILE}" | awk -F"/prefixes/" '{print $2}' | awk -F"/" '{print $1}')
                    fi
                    # shellcheck source=/dev/null
                    source "${PORTWINE_DB_FILE}"
                fi
                edit_db_from_gui PW_WINE_USE PW_PREFIX_NAME
            fi
        fi

        if [[ "${PW_WINE_CPU_TOPOLOGY}" == "disabled" ]] && [[ -n "${WINE_CPU_TOPOLOGY}" ]] ; then
            export PW_WINE_CPU_TOPOLOGY="${WINE_CPU_TOPOLOGY}"
        fi
        if [[ -f "${PATH_TO_GAME}/UnityPlayer.dll" ]] \
        && [[ "${PW_WINE_CPU_TOPOLOGY}" == "disabled" ]] \
        && [[ $(grep -c ^"processor" /proc/cpuinfo) -gt "8" ]]
        then
            export PW_WINE_CPU_TOPOLOGY="8:0,1,2,3,4,5,6,7"
            print_info "Automatic added fix for unity games: WINE_CPU_TOPOLOGY=8:0,1,2,3,4,5,6,7"
        fi
        if [[ -d "${PATH_TO_GAME}/MelonLoader" ]] ; then
            var_winedlloverride_update "version=n,b"
            print_info "Automatic added fix for Melon Mod-Loader"
        fi
    fi

    if [[ -z "${PATH_TO_GAME}" ]] || [[ ! -d "$(realpath "${PATH_TO_GAME}")" ]] ; then
        if [[ -f "${PW_EXE_FILE}" ]] ; then
            PATH_TO_GAME="$(dirname "$(realpath "${PW_EXE_FILE}")")"
            export PATH_TO_GAME
        fi
    fi

    return 0
}

pw_check_vulkan_extensions () {
    local ext_name="$1"
    local ext_key
    local current_device_name=""
    local current_support=""
    local vk_info_output
    local vk_gpu_info_from_repo
    local vk_gpu_info_cmd
    ext_key="supports_$(echo "${ext_name}" | tr '[:upper:]' '[:lower:]')"

    vk_gpu_info_from_repo="$(dirname "${BASH_SOURCE[0]}")/../../../../dev-scripts/vk_gpu_info"
    if [[ -x "${vk_gpu_info_from_repo}" ]] ; then
        vk_gpu_info_cmd="${vk_gpu_info_from_repo}"
    else
        vk_gpu_info_cmd="$(command -v vk_gpu_info 2>/dev/null || true)"
    fi

    if [[ -z "${vk_gpu_info_cmd}" ]] ; then
        return 1
    fi

    if ! vk_info_output="$("${vk_gpu_info_cmd}" 2>/dev/null)" ; then
        return 1
    fi

    while IFS= read -r line ; do
        case "$line" in
            "GPU #"*)
                current_device_name=""
                current_support=""
                ;;
            "device_name: "*)
                current_device_name="${line#device_name: }"
                ;;
            "${ext_key}: "*)
                current_support="${line#${ext_key}: }"
                ;;
        esac

        if [[ -n "${current_device_name}" ]] && [[ "${current_device_name}" == "${PW_GPU_USE}" ]] \
        && [[ -n "${current_support}" ]]
        then
            [[ "${current_support}" == "1" ]] && return 0 || return 1
        fi
    done <<< "${vk_info_output}"

    return 1
}

compare_versions () {
    IFS='.' read -ra a1 <<< "$1"
    IFS='.' read -ra a2 <<< "$2"
    local len=$(( ${#a1[@]} > ${#a2[@]} ? ${#a1[@]} : ${#a2[@]} ))

    for ((i=0; i<len; i++)) ; do
        local n1=$(( ${a1[i]:-0} ))
        local n2=$(( ${a2[i]:-0} ))
        if (( n1 > n2 )) ; then
            return 0
        elif (( n1 < n2 )) ; then
            return 1
        fi
    done
    return 0
}

pw_skip_get_info () {
    if [[ "${SKIP_CHECK_UPDATES_NEW}" != "1" ]] ; then
        rm -f "${PW_TMPFS_PATH}/lspci.tmp"
        if command -v lspci &>/dev/null ; then
            if ! timeout 3 lspci -k &> "${PW_TMPFS_PATH}/lspci.tmp" ; then
                print_error "lspci - broken!"
                rm -f "${PW_TMPFS_PATH}/lspci.tmp"
            fi
        else
            print_warning "lspci - not found!"
        fi

        # GALLIUM NINE
        unset FIND_D3D_MODULE D3D_MODULE_PATH
        if ! check_flatpak ; then
            FIND_D3D_MODULE="$(find /usr/ -maxdepth 4 -type f -name "d3dadapter9.so.*" 2>/dev/null)"
            if [[ -n "$FIND_D3D_MODULE" ]] ; then
                FIND_D3D_MODULE="$(dirname "$FIND_D3D_MODULE")"
                IFS=$'\n'
                for D3D_MP in $FIND_D3D_MODULE ; do
                    if [[ -n "$D3D_MODULE_PATH" ]]
                    then export D3D_MODULE_PATH="$D3D_MODULE_PATH:/run/host${D3D_MP}"
                    else export D3D_MODULE_PATH="/run/host${D3D_MP}"
                    fi
                done
                IFS="$orig_IFS"
            fi
        else
            if [[ -d "/app/lib/i386-linux-gnu/GL/default/lib/d3d" && -d "/usr/lib/x86_64-linux-gnu/GL/default/lib/d3d" ]] ; then
                export D3D_MODULE_PATH="/app/lib/i386-linux-gnu/GL/default/lib/d3d:/usr/lib/x86_64-linux-gnu/GL/default/lib/d3d"
            fi
        fi
        [[ -n $D3D_MODULE_PATH ]] && echo "$D3D_MODULE_PATH" > "${PW_TMPFS_PATH}/gallium_nine.tmp"

        if [[ -f "${PW_TMPFS_PATH}/lspci.tmp" ]] ; then
            LSPCI_VGA="$(grep -E 'VGA|3D' "${PW_TMPFS_PATH}/lspci.tmp" | tr -d '\n')"
            export LSPCI_VGA
        fi

        export SKIP_CHECK_UPDATES_NEW="1"
    fi
}

update_winetricks () {
    W_TRX_URL="https://raw.githubusercontent.com/Winetricks/winetricks/master/src/winetricks"
    W_TRX_EXT_VER="$(curl -s --list-only ${W_TRX_URL} | grep -i 'WINETRICKS_VERSION=' | sed 's/WINETRICKS_VERSION=//')"
    print_info "Version winetricks on server: ${W_TRX_EXT_VER}"
    W_TRX_INT_VER="$(grep -i 'WINETRICKS_VERSION=' "${PORT_WINE_TMP_PATH}/winetricks" | sed 's/WINETRICKS_VERSION=//')"
    print_info "Version winetricks in port: ${W_TRX_INT_VER}"
    if [[ ! -f "${PORT_WINE_TMP_PATH}/winetricks" && -n "$W_TRX_EXT_VER" ]] \
    || [[ "$W_TRX_INT_VER" != "$W_TRX_EXT_VER" && -n "$W_TRX_EXT_VER" ]]
    then
        try_remove_file "${PORT_WINE_TMP_PATH}/winetricks"
        if try_download "${W_TRX_URL}" "${PORT_WINE_TMP_PATH}/winetricks" no_mirror ; then
            W_TRX_INT_VER="$(grep -i 'WINETRICKS_VERSION=' "${PORT_WINE_TMP_PATH}/winetricks" | sed 's/WINETRICKS_VERSION=//')"
            print_info "Winetricks version in port has been updated (${W_TRX_INT_VER})"
            chmod u+x "${PORT_WINE_TMP_PATH}/winetricks"
        fi
    fi
    if  [[ -f "${PORT_WINE_TMP_PATH}/winetricks" ]] ; then
        sed -i 's/w_metadata vcrun2015 dlls \\/w_metadata !dont_use_2015! dlls \\/' "${PORT_WINE_TMP_PATH}/winetricks"
        sed -i 's/w_metadata vcrun2017 dlls \\/w_metadata !dont_use_2017! dlls \\/' "${PORT_WINE_TMP_PATH}/winetricks"
        sed -i 's/w_metadata vcrun2019 dlls \\/w_metadata !dont_use_2019! dlls \\/' "${PORT_WINE_TMP_PATH}/winetricks"
        sed -i 's/w_set_winver win2k3/w_set_winver win7/' "${PORT_WINE_TMP_PATH}/winetricks"
    fi
    return 0
}

edit_db_from_gui () {
    if [[ "${PW_DISABLED_CREATE_DB}" == "1" ]] ; then
        print_warning "Skipped edit_db_from_gui"
        return 0
    fi
    if [[ ! -w "$PORTWINE_DB_FILE" ]] ; then
        print_error "no write acces to ppdb file: $PORTWINE_DB_FILE"
        return 1
    fi
    print_info "edit_db_from_gui PORTWINE_DB_FILE=$PORTWINE_DB_FILE"
    if [[ -n "$PORTWINE_DB_FILE" ]] \
    && [[ -f "$PORTWINE_DB_FILE" ]]
    then
        for mod_db in "$@" ; do
            proxy_mod_db="${!mod_db}"
            if [[ $proxy_mod_db =~ ^(Disabled|Disable)$ ]] ; then
                proxy_mod_db=disabled
            elif [[ $proxy_mod_db =~ ^(Enabled|Enable)$ ]] ; then
                proxy_mod_db=enabled
            fi

            # HACK: Escaping backslashes and quotes for Windows paths
            proxy_mod_db=$(echo "$proxy_mod_db" | sed 's/\\/\\\\\\\\/g; s/"/\\"/g')
            proxy_mod_db_escaped=$(printf '%s\n' "$proxy_mod_db" | sed 's/[\/&]/\\&/g')

            if [[ $(<"${PORTWINE_DB_FILE}") =~ export\ ${mod_db}= ]]
            then sed -i "s|export ${mod_db}=.*|export ${mod_db}=\"${proxy_mod_db_escaped}\"|g" "${PORTWINE_DB_FILE}"
            else echo "export ${mod_db}=\"${proxy_mod_db}\"" >> "${PORTWINE_DB_FILE}"
            fi
        done
    fi
    return 0
}

edit_user_conf_from_gui () {
    for mod_db in "$@" ; do
        if [[ -z "${!mod_db}" ]] ; then
            sed -i "/^export ${mod_db}=/d" "${USER_CONF}"
            continue
        fi
        proxy_mod_db="${!mod_db}"
        if [[ $proxy_mod_db =~ ^(Disabled|Disable)$ ]] ; then
            proxy_mod_db=disabled
        elif [[ $proxy_mod_db =~ ^(Enabled|Enable)$ ]] ; then
            proxy_mod_db=enabled
        fi
        if ! grep "export ${mod_db}=" "${USER_CONF}" &>/dev/null
        then echo "export ${mod_db}=\"$proxy_mod_db\"" >> "${USER_CONF}"
        elif grep "export ${mod_db}=" "${USER_CONF}" | grep -v "#" &>/dev/null
        then
            if [[ "$(grep "export ${mod_db}=" "${USER_CONF}" | grep -v "#")" != "export ${mod_db}=\"$proxy_mod_db\"" ]]
            then sed -ri "s/^export ${mod_db}=.*/export ${mod_db}=\"$proxy_mod_db\"/" "${USER_CONF}"
            fi
        elif [[ "$(grep "export ${mod_db}=" "${USER_CONF}")" != "export ${mod_db}=$proxy_mod_db" ]]
        then sed -ri "s/.*export ${mod_db}=.*/export ${mod_db}=\"$proxy_mod_db\"/g" "${USER_CONF}"
        fi
    done
    return 0
}

# Manage USER.conf values (get, set, delete)
manage_user_conf_value () {
    local action="$1"
    local var_name="$2"
    local var_value="$3"

    if [[ -z "${action}" ]] || [[ -z "${var_name}" ]]; then
        print_error "Action and variable name must be provided"
        return 1
    fi

    if [[ ! -f "${USER_CONF}" ]]; then
        print_error "USER.conf file does not exist: ${USER_CONF}"
        return 1
    fi

    case "$action" in
        get)
            if grep -q "^export ${var_name}=" "${USER_CONF}" ; then
                # Extract the value, handling both quoted and unquoted values
                local value=$(grep "^export ${var_name}=" "${USER_CONF}" | sed -E 's/^export [^=]+=("?)(.*)\1$/\2/')
                echo "$value"
                return 0
            else
                # Variable not found in USER.conf
                return 1
            fi
            ;;
        set)
            if [[ -z "${var_value}" ]]; then
                print_error "Variable value must be provided for set action"
                return 1
            fi

            export "$var_name=$var_value"
            edit_user_conf_from_gui "$var_name"
            return 0
            ;;
        delete)
            if grep -q "^export ${var_name}=" "${USER_CONF}" ; then
                sed -i "/^export ${var_name}=/d" "${USER_CONF}"
                print_info "Removed ${var_name} from USER.conf"
            fi
            return 0
            ;;
        *)
            print_error "Invalid action: $action. Use get, set, or delete"
            return 1
            ;;
    esac
}

use_exiftool () {
    if [[ ! -f "${PW_TMPFS_PATH}/exiftool.tmp" ]] \
    || ! grep -q "$1" "${PW_TMPFS_PATH}/exiftool.tmp"
    then
        echo "$1" > "${PW_TMPFS_PATH}/exiftool.tmp"
        if ! command -v exiftool &>/dev/null \
        || ! timeout 3 exiftool "$1" &>> "${PW_TMPFS_PATH}/exiftool.tmp"
        then
            print_warning "use portable exiftool"
            env PERL5LIB="${PW_PLUGINS_PATH}/portable/lib/perl5" \
            "${PW_PLUGINS_PATH}/portable/bin/exiftool" \
            "$1" &>> "${PW_TMPFS_PATH}/exiftool.tmp"
        fi
    fi
}

pw_create_gui_png () {
    if [[ -z $name_desktop_png ]] ; then
        basename_PW_EXE_FILE="$(basename "${PW_EXE_FILE}")"
        if echo "$basename_PW_EXE_FILE" | grep -ie 'setup\|install\|\.msi$' &>/dev/null ; then
            export name_desktop_png="setup"
            return 0
        elif echo "$basename_PW_EXE_FILE" | grep -ie '\.reg$' &>/dev/null ; then
            export name_desktop_png="reg"
            return 0
        elif echo "$basename_PW_EXE_FILE"| grep -ie '\.bat$' &>/dev/null ; then
            export name_desktop_png="bat"
            return 0
        fi
    fi

    if [[ -z "$PORTPROTON_NAME" ]] \
    || [[ "$PW_NO_RESTART_PPDB" == "1" ]]
    then
        if [[ -n "${PORTWINE_CREATE_SHORTCUT_NAME}" ]] ; then
            PORTPROTON_NAME="${PORTWINE_CREATE_SHORTCUT_NAME}"
        else
            use_exiftool "$PW_EXE_FILE"
            PW_PRODUCTNAME=$(sed -n 's/^Product Name\s*:\s*//p' "${PW_TMPFS_PATH}/exiftool.tmp")
            FILE_DESCRIPTION=$(sed -n 's/^File Description\s*:\s*//p' "${PW_TMPFS_PATH}/exiftool.tmp")

            if [[ "$PW_PRODUCTNAME" =~ (Launcher|RU) ]]
            then
                PW_PRODUCTNAME=$(echo "$PW_PRODUCTNAME" | sed -r "s/(Launcher|RU)//g")
            fi

            if [[ -n "$PW_PRODUCTNAME" ]] \
            && [[ ! "$PW_PRODUCTNAME" =~ Bootstrap ]]
            then
                PORTPROTON_NAME="$PW_PRODUCTNAME"
            else
                PORTPROTON_NAME="$(basename "${PW_EXE_FILE%.[Ee][Xx][Ee]}")"
            fi
        fi

        PW_PRODUCTNAME=$(echo "$PW_PRODUCTNAME" | sed -r "s/(\`|\"|'|\!)//g")
        export PORTPROTON_NAME
        edit_db_from_gui PORTPROTON_NAME FILE_DESCRIPTION
    fi

    if [[ -z $name_desktop_png ]] ; then
        name_desktop_png="${PORTPROTON_NAME// /_}"
        if [[ $name_desktop_png =~ [\!\%\$\&\<] ]] ; then
            local ICON_NAME_REGEX=(\! % \$ \& \<)
            for i in "${ICON_NAME_REGEX[@]}" ; do
                name_desktop_png="${name_desktop_png//$i/}"
            done
        fi
    fi

    resize_png "$PW_EXE_FILE" "${PORTPROTON_NAME}"

    PORTPROTON_NAME_PNG="${PORTPROTON_NAME// /_}"
    if [[ $PORTPROTON_NAME_PNG =~ [\!\%\$\&\<] ]] ; then
        local ICON_NAME_REGEX=(\! % \$ \& \<)
        for i in "${ICON_NAME_REGEX[@]}" ; do
            PORTPROTON_NAME_PNG="${PORTPROTON_NAME_PNG//$i/}"
        done
    fi
}


pw_create_unique_exe () {
    BASEDIR_GAME="$(dirname "$PW_EXE_FILE")"
    if [[ -d "$BASEDIR_GAME" ]] ; then
        pushd "$BASEDIR_GAME" || fatal
        BASENAME_GAME_EXE="$(basename "$PW_EXE_FILE")"
        if [[ -n "$1" ]] ; then
            BASENAME_GAME="$(basename "$1" .exe).exe"
            ln -sf "$BASENAME_GAME_EXE" "$BASENAME_GAME"
            export PW_EXE_FILE="$BASEDIR_GAME/$BASENAME_GAME"
        elif [[ -n "$PORTWINE_CREATE_SHORTCUT_NAME" ]] ; then
            ln -sf "$BASENAME_GAME_EXE" "$PORTWINE_CREATE_SHORTCUT_NAME.exe"
            export PW_EXE_FILE="$BASEDIR_GAME/$PORTWINE_CREATE_SHORTCUT_NAME.exe"
        else
            print_warning "There are no arguments for creating a symbolic link! Skip it..."
        fi
        try_remove_file "${PW_EXE_FILE}.ppdb"
        popd || fatal
    fi
}

pw_optiscaler_sync_files () {
    local OPTISCALER_PATH OPTISCALER_FILES ORIGINAL_GAME_DLLS dll

    OPTISCALER_PATH="${PW_PLUGINS_PATH}/fake_dlss/optiscaler-${PW_OPTISCALER_VER}"
    OPTISCALER_FILES="dxgi.dll amd_fidelityfx_dx12.dll amd_fidelityfx_vk.dll libxess.dll \
        libxess_dx11.dll libxess_fg.dll dlssg_to_fsr3_amd_is_better.dll fakenvapi.ini \
        fakenvapi.dll OptiScaler.ini D3D12 D3D12_Optiscaler libxell.dll \
        amd_fidelityfx_upscaler_dx12.dll amd_fidelityfx_framegeneration_dx12.dll"
    ORIGINAL_GAME_DLLS="amd_fidelityfx_upscaler_dx12.dll amd_fidelityfx_vk.dll \
        amd_fidelityfx_dx12.dll libxess.dll libxess_dx11.dll libxess_fg.dll \
        amd_fidelityfx_framegeneration_dx12.dll libxell.dll D3D12"

    for dll in "nvapi64.dll" "_nvngx.dll" "nvngx.dll" ; do
        if [[ -f "$PATH_TO_GAME/${dll}.b" ]] ; then
            try_remove_file "$PATH_TO_GAME/$dll"
            mv -f "$PATH_TO_GAME/${dll}.b" "$PATH_TO_GAME/$dll" 2>/dev/null
            print_info "revert ${dll}.b to $dll"
        fi
    done

    if [[ "${PW_USE_OPTISCALER}" != "1" ]] ; then
        if [[ -f "$PATH_TO_GAME/dlssg_to_fsr3_amd_is_better.dll" ]] ; then
            for dll in $OPTISCALER_FILES ; do rm -fr "$PATH_TO_GAME/$dll"; done
            for dll in $ORIGINAL_GAME_DLLS ; do [[ -e "$PATH_TO_GAME/${dll}.b" ]] && mv -f "$PATH_TO_GAME/${dll}.b" "$PATH_TO_GAME/${dll}" 2>/dev/null; done
            try_remove_file "$PATH_TO_GAME/optiscaler_version"
            try_remove_file "$PATH_TO_GAME/dxvk.conf"
        fi
        return 0
    fi

    if [[ ! -d "$OPTISCALER_PATH" ]] && try_download "github.com/Castro-Fidel/vulkan/releases/download/optiscaler-$PW_OPTISCALER_VER/optiscaler-$PW_OPTISCALER_VER.tar.xz" "${PORT_DATA_PATH}/data/tmp/optiscaler-$PW_OPTISCALER_VER.tar.xz" ; then
        unpack "${PORT_DATA_PATH}/data/tmp/optiscaler-$PW_OPTISCALER_VER.tar.xz" "${PW_PLUGINS_PATH}/fake_dlss/" || try_remove_dir "$OPTISCALER_PATH"
        try_remove_file "${PORT_DATA_PATH}/data/tmp/optiscaler-$PW_OPTISCALER_VER.tar.xz"
    fi

    check_variables OPTISCALER_FG_TYPE "Nukems"
    sed -i "s|FGType =.*|FGType = $OPTISCALER_FG_TYPE|g" "$OPTISCALER_PATH/OptiScaler.ini"
    echo "" > "$PATH_TO_GAME/dxvk.conf"
    if [[ ! -f "$PATH_TO_GAME/dlssg_to_fsr3_amd_is_better.dll" && -f "$PATH_TO_GAME/dxgi.dll" ]] ; then
        fatal 'dxgi.dll is already present in the game folder!\nThis script uses dxgi.dll to load required files.\nRemove the mod using dxgi.dll.'
    fi
    for dll in $ORIGINAL_GAME_DLLS ; do [[ -e "$PATH_TO_GAME/$dll" && ! -e "$PATH_TO_GAME/${dll}.b" ]] && mv -f "$PATH_TO_GAME/$dll" "$PATH_TO_GAME/${dll}.b" 2>/dev/null; done
    if [[ ! -f "$PATH_TO_GAME/optiscaler_version" ]] || ! grep -q "$PW_OPTISCALER_VER" "$PATH_TO_GAME/optiscaler_version" ; then
        for dll in $OPTISCALER_FILES ; do cp -fr "$OPTISCALER_PATH/$dll" "$PATH_TO_GAME/$dll" || print_error "$OPTISCALER_PATH/$dll not found for copy!"; done
        echo "$PW_OPTISCALER_VER" > "$PATH_TO_GAME/optiscaler_version"
    fi
    export PW_USE_NVAPI_AND_DLSS="1"
    set_to_dxvk_conf nvidia_new
}

pw_prepare_gamescope_launch () {
    local gpu_vendor
    local gamescope_available="0"

    unset PW_GAMESCOPE_VARIABLES_BEFORE PW_GAMESCOPE_VARIABLES_AFTER
    if command -v gamescope &>/dev/null ; then
        gamescope_available="1"
    fi

    if [[ "${PW_GAMESCOPE}" == "1" && "${gamescope_available}" == "1" ]] \
    || check_gamescope_session
    then
        export vk_xwayland_wait_ready="false"
        gpu_vendor="$(check_vendor_gpu)"
        if [[ "${gpu_vendor}" == "amd" ]] ; then
            export RADV_DEBUG+="nodcc "
            export AMD_DEBUG="nodcc"
            if ! pw_check_vulkan_extensions "VK_EXT_image_drm_format_modifier" ; then
                export R600_DEBUG="nodcc"
            fi
        fi
        [[ "${gpu_vendor}" == "intel" ]] && export INTEL_DEBUG="norbc"
        if [[ "${gpu_vendor}" == "nvidia" ]] ; then
            PW_GAMESCOPE_VARIABLES_BEFORE+="__GL_THREADED_OPTIMIZATIONS=0 "
            PW_GAMESCOPE_VARIABLES_AFTER+="__GL_THREADED_OPTIMIZATIONS=1 "
        fi
    fi

    if [[ "${PW_GAMESCOPE}" == "1" && "${gamescope_available}" == "1" ]] \
    && ! check_gamescope_session
    then
        if [[ $PW_GPU_USE != "disabled" ]]
        then PW_ID_VIDEO=" --prefer-vk-device ${PW_vendorID}:${PW_deviceID}"
        fi

        [[ "${PW_GS_ENABLE_GAMESCOPE_WSI}" == "1" ]] && export ENABLE_GAMESCOPE_WSI="1"
        [[ "${PW_GS_SDL_VIDEODRIVER_X11}" == "1" ]] && export SDL_VIDEODRIVER="x11"
        [[ "${PW_GS_MANGOAPP}" == "1" ]] && export PW_MANGOHUD="0"
        if [[ "${PW_GS_HDR_ENABLE}" == "1" && "${PW_GS_ENABLE_GAMESCOPE_WSI}" == "1" ]] ; then
            export ENABLE_HDR_WSI="1"
            export DXVK_HDR="1"
            export GAMESCOPE_WAYLAND_DISPLAY="gamescope-0"
        fi
        if [[ -z "${PW_GAMESCOPE_ARGS_NEW// }" ]] ; then
            pw_gamescope_build_args
            [[ -n "${PW_GS_FILTER_MODE}" && "${PW_GS_FILTER_MODE}" != "disabled" ]] && export PW_WINE_FULLSCREEN_FSR="0"
        fi
        edit_db_from_gui PW_GAMESCOPE_ARGS_NEW
        export PW_RUN_GAMESCOPE="env ${PW_GAMESCOPE_VARIABLES_BEFORE}gamescope${PW_ID_VIDEO}${PW_GAMESCOPE_ARGS_NEW} env ${PW_GAMESCOPE_VARIABLES_AFTER}--"
    fi
}

pw_set_sync_runtime_vars () {
    local ULIMIT_HN

    ULIMIT_HN=$(ulimit -Hn)
    if [[ $ULIMIT_HN -lt 524288 ]] ; then
        print_warning "ESYNC dont work! (ulimit -Hn $ULIMIT_HN < 524288)"
        export PW_USE_ESYNC="0"
    elif [[ "${PW_USE_ESYNC}" == "0" ]] ; then
        export WINEESYNC="0"
        export PROTON_NO_ESYNC="1"
    else
        export WINEESYNC="1"
        export PROTON_NO_ESYNC="0"
    fi

    if [[ "${PW_USE_FSYNC}" == "0" ]] ; then
        export WINEFSYNC="0"
        export PROTON_NO_FSYNC="1"
        export WINEFSYNC_FUTEX2="0"
    else
        export WINEFSYNC="1"
        export PROTON_NO_FSYNC="0"
        export WINEFSYNC_SPINCOUNT=100
        check_variables WINEFSYNC_FUTEX2 0
    fi

    if [[ "${PW_USE_NTSYNC}" == "1" && -e "/dev/ntsync" ]] ; then
        export WINENTSYNC="1"
        export PROTON_NO_NTSYNC="0"
    else
        export WINENTSYNC="0"
        export PROTON_NO_NTSYNC="1"

        if [[ "${PW_USE_NTSYNC}" == "1" ]] ; then
            print_error "/dev/ntsync - not found!"
        fi
    fi
}

pw_enable_gamemode_basic () {
    if check_flatpak ; then
        export GAMEMODERUN=1
        PW_GAMEMODERUN_SLR="gamemoderun"
    elif command -v gamemoderun &>/dev/null ; then
        export GAMEMODERUN=1
        PW_GAMEMODERUN_SLR="gamemoderun"
        if command -v gamemoded &>/dev/null && ! pw_is_process_active gamemoded ; then
            gamemoded &>/dev/null &
            sleep 0.1
        fi
    else
        export GAMEMODERUN=1
        if [[ -n "${PW_LD_PRELOAD}" ]]; then
            export PW_LD_PRELOAD="${PW_LD_PRELOAD}:libgamemodeauto.so.0"
        else
            export PW_LD_PRELOAD="libgamemodeauto.so.0"
        fi
        if ! pw_is_process_active gamemoded ; then
            env LD_LIBRARY_PATH="${PW_PLUGINS_PATH}/portable/lib/lib64:${PW_PLUGINS_PATH}/portable/lib/lib32" \
                "${PW_PLUGINS_PATH}/portable/bin/gamemoded" &>/dev/null &
            sleep 0.1
        fi
    fi

    print_info "Gamemode will be launched."
    return 0
}

start_portproton () {
    pw_check_and_download_plugins

    if [[ "${PW_DISABLE_RUNTIME_DOWNLOAD}" == "1" ]] ; then
        try_remove_dir "${PORT_WINE_TMP_PATH}/libs${PW_LIBS_VER}"
    else
        pw_check_and_download_runtime
    fi

    pw_check_and_download_dxvk_and_vkd3d

    pw_skip_get_info
    if [[ "${PW_LOCALE_SELECT}" != "disabled" ]] && [[ -n "${PW_LOCALE_SELECT}" ]] ; then
        export LC_ALL="${PW_LOCALE_SELECT}"
        if [[ "${PW_USE_RUNTIME}" == "1" ]] && [[ "${HOST_LC_ALL}" != "${LC_ALL}" ]] ; then
            export HOST_LC_ALL="${LC_ALL}"
        fi
    else
        export PW_LOCALE_SELECT="disabled"
    fi

    WINEPREFIX="$(readlink -f "${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}")"
    export WINEPREFIX

    pw_get_pfx () {
        case "${PW_PREFIX_NAME}" in
              DOTNET) local FILE_NAME_PFX="dotpfx${DOTPFX_VER}" ;;
                   *) return 0 ;;
        esac

        local PFX_URL="github.com/Castro-Fidel/PortWINE/releases/download/${FILE_NAME_PFX}/${FILE_NAME_PFX}.tar.xz"
        local PFX_TMP="${PORT_DATA_PATH}/data/tmp/pfx"
        create_new_dir "${PFX_TMP}"

        if [[ ! -f "${WINEPREFIX}/.${FILE_NAME_PFX}" ]] ; then
            print_info "Download and install ${FILE_NAME_PFX} pfx..."
            if [[ ! -f "${PFX_TMP}/${FILE_NAME_PFX}.tar.xz" ]] ; then
                if try_download "${PFX_URL}" "${PFX_TMP}/${FILE_NAME_PFX}.tar.xz" ; then
                    if unpack "${PFX_TMP}/${FILE_NAME_PFX}.tar.xz" "${PORT_DATA_PATH}/data/prefixes/"
                    then touch "${WINEPREFIX}/.${FILE_NAME_PFX}"
                    fi
                else
                    try_remove_file "${PFX_TMP}/${FILE_NAME_PFX}.tar.xz"
                    fatal "Failed to download and unpack ${FILE_NAME_PFX}"
                fi
            else
                if unpack "${PFX_TMP}/${FILE_NAME_PFX}.tar.xz" "${PORT_DATA_PATH}/data/prefixes/"
                then touch "${WINEPREFIX}/.${FILE_NAME_PFX}"
                else
                    try_remove_file "${PFX_TMP}/${FILE_NAME_PFX}.tar.xz"
                    fatal "Failed to download and unpack ${FILE_NAME_PFX}"
                fi
            fi
            echo "based_on_dotnet" >> "${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}/winetricks.log"
        fi
        return 0
    }

    pw_get_pfx

    var_winedlloverride_update "${PW_MUST_WINEDLLOVERRIDES}"
    pw_list_install_dll_in_prefix
    if [[ "${PW_WINE_USE}" != "USE_SYSTEM_WINE" ]]
    then gui_proton_downloader "${PW_WINE_USE}"
    fi

    init_wine_ver

    if [[ "$PW_USE_OBS_VKCAPTURE" == "1" ]] ; then
        export OBS_VKCAPTURE="1"
        export PW_USE_SYSTEM_VK_LAYERS="1"
        print_warning "System mangohud, vkBasalt, obs-vk capture and other applications using vulkan layers are forcibly used."
    fi

    pw_init_runtime

    if [[ "${PW_USE_GSTREAMER}" == "1" ]] ; then
        if ! check_flatpak ; then
            if [[ -d "${WINEDIR}/lib64/gstreamer-1.0" ]]
            then export GST_PLUGIN_SYSTEM_PATH_1_0="${WINEDIR}/lib64/gstreamer-1.0:${WINEDIR}/lib/gstreamer-1.0"
            elif  [[ -d "${WINEDIR}/lib/x86_64-linux-gnu/gstreamer-1.0" ]]
            then export GST_PLUGIN_SYSTEM_PATH_1_0="${WINEDIR}/lib/x86_64-linux-gnu/gstreamer-1.0:${WINEDIR}/lib/i386-linux-gnu/gstreamer-1.0"
            fi
        fi

        create_new_dir "${PORT_WINE_TMP_PATH}/gstreamer_tmp"
        export WINE_GST_REGISTRY_DIR="${PORT_WINE_TMP_PATH}/gstreamer_tmp"

        export STEAM_COMPAT_MEDIA_PATH="${PORT_WINE_TMP_PATH}/gstreamer_tmp"
        export MEDIACONV_AUDIO_TRANSCODED_FILE="$STEAM_COMPAT_MEDIA_PATH/transcoded_audio.foz"
        export MEDIACONV_VIDEO_TRANSCODED_FILE="$STEAM_COMPAT_MEDIA_PATH/transcoded_video.foz"

        export STEAM_COMPAT_TRANSCODED_MEDIA_PATH="${PORT_WINE_TMP_PATH}/gstreamer_tmp"
        export MEDIACONV_AUDIO_DUMP_FILE="$STEAM_COMPAT_TRANSCODED_MEDIA_PATH/audiov2.foz"
        export MEDIACONV_VIDEO_DUMP_FILE="$STEAM_COMPAT_TRANSCODED_MEDIA_PATH/video.foz"

        export PROTON_MEDIA_USE_GST="1"
    else
        export PROTON_MEDIA_USE_GST="0"
    fi

    check_variables VK_LOADER_DEBUG "none"
    if [[ "${PW_LOG}" == 1 ]] \
    || [[ -n "$PW_DEBUG" ]]
    then
        check_variables GST_DEBUG "*:1"
        # check_variables WINEDEBUG "+timestamp,+pid,+tid,+seh,+unwind,+threadname,+debugstr,+loaddll,+mscoree"
        check_variables WINEDEBUG "err+all"
        check_variables WINE_MONO_TRACE "E:System.NotImplementedException"
        check_variables VKBASALT_LOG_LEVEL "error"
        check_variables VKD3D_DEBUG "warn"
        check_variables VKD3D_SHADER_DEBUG "fixme"
        check_variables DXVK_LOG_LEVEL "info"
        check_variables DXVK_NVAPI_LOG_LEVEL "info"
        check_variables FSR4_WATERMARK "1"
        check_variables DXVK_NVAPI_SET_NGX_DEBUG_OPTIONS "DLSSIndicator=1024,DLSSGIndicator=2,"
    else
        export WINEDEBUG="-all"
        unset WINE_MONO_TRACE GST_DEBUG
        check_variables VKBASALT_LOG_LEVEL "none"
        check_variables VKD3D_DEBUG "none"
        check_variables VKD3D_SHADER_DEBUG "none"
        check_variables DXVK_LOG_LEVEL "none"
        check_variables DXVK_NVAPI_LOG_LEVEL "none"
        check_variables FSR4_WATERMARK "0"
        check_variables DXVK_NVAPI_SET_NGX_DEBUG_OPTIONS "DLSSIndicator=0,DLSSGIndicator=0,"
    fi

    #disable winebth.sys as it crashes winedevice.exe
    var_winedlloverride_update "winebth.sys=d"

    pw_wineboot () {
        LIST_NATIVE_WINE_DLL_LINKS="winevulkan ir50_32 amd_ags_x64 wined3d vulkan-1"
        for dll in $LIST_NATIVE_WINE_DLL_LINKS ; do
            try_force_link_file "${WINEDIR}/lib64/wine/x86_64-windows/${dll}.dll" "${WINEPREFIX}/drive_c/windows/system32/${dll}.dll"
            try_force_link_file "${WINEDIR}/lib/wine/i386-windows/${dll}.dll" "${WINEPREFIX}/drive_c/windows/syswow64/${dll}.dll"
        done

        LIST_NATIVE_WINE_DLL_COPY="atl100 ntdll shell32"
        for dll in $LIST_NATIVE_WINE_DLL_COPY ; do
            try_copy_file "${WINEDIR}/lib64/wine/x86_64-windows/${dll}.dll" "${WINEPREFIX}/drive_c/windows/system32/${dll}.dll"
            try_copy_file "${WINEDIR}/lib/wine/i386-windows/${dll}.dll" "${WINEPREFIX}/drive_c/windows/syswow64/${dll}.dll"
        done

        LIST_ICU_DLL_LINKS="icuin68 icuuc68 icudt68"
        [[ -d "${WINEDIR}/lib/icu32" ]] && mv "${WINEDIR}/lib/icu32" "${WINEDIR}/lib/icu"
        for dll in $LIST_ICU_DLL_LINKS ; do
            if [[ -f "${WINEDIR}/lib/icu/${dll}.dll" ]] ; then
                try_force_link_file "${WINEDIR}/lib/icu/${dll}.dll" "${WINEPREFIX}/drive_c/windows/syswow64/${dll}.dll"
                try_force_link_file "${WINEDIR}/lib64/icu/${dll}.dll" "${WINEPREFIX}/drive_c/windows/system32/${dll}.dll"
            elif [[ -f "${WINEDIR}/lib/wine/icu/i386-windows/${dll}.dll" ]] ; then
                try_force_link_file "${WINEDIR}/lib/wine/icu/i386-windows/${dll}.dll" "${WINEPREFIX}/drive_c/windows/syswow64/${dll}.dll"
                try_force_link_file "${WINEDIR}/lib/wine/icu/x86_64-windows/${dll}.dll" "${WINEPREFIX}/drive_c/windows/system32/${dll}.dll"
            else
                try_remove_file "${WINEPREFIX}/drive_c/windows/syswow64/${dll}.dll"
                try_remove_file "${WINEPREFIX}/drive_c/windows/system32/${dll}.dll"
            fi
        done

        print_info "Used wineboot $@ for prefix: ${PW_PREFIX_NAME}"
        ${pw_runtime} GST_PLUGIN_SYSTEM_PATH_1_0="" LD_LIBRARY_PATH="${PW_LD_LIBRARY_PATH}:${WINE_LIBRARY_PATH}" \
        WINEDEBUG="err+all" "${WINELOADER}" wineboot $@ &>>"${PW_TMPFS_PATH}/update_pfx_log"
        wait_wineserver
        print_info "The prefix has been updated."
    }

    if [[ ! -d "${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}"/drive_c/windows ]] \
    || [[ ! -f "${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}"/userdef.reg ]] \
    || [[ ! -f "${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}"/system.reg ]] \
    || [[ ! -f "${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}"/user.reg ]]
    then
        pw_clear_pfx
        check_dirs_and_files_in_pfx
        if [[ "${PW_PREFIX_NAME}" == "DEFAULT" ]] ; then
            unpack "${PW_PLUGINS_PATH}/default_pfx.tar.xz" "${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}/" silent
            pw_wineboot -r
            echo "based_on_default" >> "${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}/winetricks.log"
        elif [[ "${PW_CHECK_AUTOINSTALL}" == 1 ]] \
        && [[ "${DISABLE_CP_DEFPFX}" != 1 ]] ; then
            unpack "${PW_PLUGINS_PATH}/default_pfx.tar.xz" "${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}/" silent
            pw_wineboot -r
            echo "based_on_default" >> "${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}/winetricks.log"
        elif [[ "${PW_CHECK_AUTOINSTALL}" == 1 ]] \
        && [[ "${DISABLE_CP_DEFPFX}" == 1 ]] ; then
            pw_wineboot -i
        elif [[ "${DISABLE_CP_DEFPFX}" == "1" ]]; then
            pw_wineboot -i
        else
            unpack "${PW_PLUGINS_PATH}/default_pfx.tar.xz" "${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}/" silent
            pw_wineboot -r
            echo "based_on_default" >> "${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}/winetricks.log"
        fi
        get_and_set_reg_file --add 'Control Panel\Desktop' 'LogPixels' 'REG_DWORD' "96" "user"
    else
        check_dirs_and_files_in_pfx
        if [[ ! -f "${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}/.wine_ver" ]] \
        || [[ ! -f "${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}/drive_c/windows/system32/shell32.dll" ]] \
        || ! grep "${PW_WINE_USE}" "${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}/.wine_ver" &>/dev/null
        then
            pw_wineboot -r
        fi
    fi

    if [[ -f "${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}/winetricks.log" ]] \
    && grep -q "based_on" "${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}/winetricks.log"
    then export PW_BASE_PFX="$(awk -F'based_on_' '$2 != "" {print $2}' "${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}/winetricks.log")"
    else export PW_BASE_PFX="none"
    fi

    rm -f "${PORT_DATA_PATH}"/data/prefixes/*/drive_c/users/*/Desktop/*.lnk

    echo "${PW_WINE_USE}" > "${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}/.wine_ver"

    pw_set_sync_runtime_vars

    # export WINE_SIMULATE_ASYNC_READ=1
    # export WINE_FSYNC_SIMULATE_SCHED_QUANTUM=1
    # export WINE_ALERT_SIMULATE_SCHED_QUANTUM=1
    # export WINE_FSYNC_YIELD_TO_WAITERS=1
    # export WINE_KERNEL_STACK_SIZE=64
    # export WINE_DISABLE_KERNEL_WRITEWATCH=1
    # export WINE_SIMULATE_WRITECOPY="1"

    if [[ "${PW_NO_WRITE_WATCH}" == 1 ]] ; then
        export WINE_DISABLE_WRITE_WATCH="1"
    fi

    if [[ "${PW_OLD_GL_STRING}" == 1 ]] ; then
        export MESA_EXTENSION_MAX_YEAR="2003" #mesa override
        export __GL_ExtensionStringVersion="17700" #nvidia override
    fi

    if [[ "${PW_VULKAN_NO_ASYNC}" == 1 ]] ; then
        export RADV_DEBUG+="llvm "
        var_vkd3d_config_update single_queue
    else
        export DXVK_ASYNC="1"
    fi

    set_to_dxvk_conf () {
        case "$1" in
            default)
                sed -i \
                    -e /'dxgi.customDeviceDesc =/c # dxgi.customDeviceDesc =' \
                    -e /'dxgi.customDeviceId =/c # dxgi.customDeviceId =' \
                    -e /'dxgi.customVendorId =/c # dxgi.customVendorId =' \
                    -e /'dxgi.hideNvidiaGpu =/c # dxgi.hideNvidiaGpu =' \
                    -e /'d3d11.cachedDynamicResources =/c # d3d11.cachedDynamicResources =' \
                    -e /'dxgi.maxFrameLatency =/c # dxgi.maxFrameLatency =' \
                    -e /'d3d9.maxFrameLatency =/c # d3d9.maxFrameLatency =' \
                    -e /'dxgi.syncInterval =/c # dxgi.syncInterval =' \
                    -e /'d3d9.presentInterval =/c # d3d9.presentInterval =' \
                    -e /'dxgi.numBackBuffers =/c # dxgi.numBackBuffers =' \
                    -e /'d3d9.numBackBuffers =/c # d3d9.numBackBuffers =' \
                    -e /'d3d9.deviceLossOnFocusLoss =/c # d3d9.deviceLossOnFocusLoss =' \
                    -e /'d3d9.countLosableResources =/c # d3d9.countLosableResources =' \
                "${DXVK_CONFIG_FILE}"

                export WINE_HIDE_NVIDIA_GPU="0"
                export WINE_HIDE_AMD_GPU="0"
                unset DXVK_NVAPI_DRIVER_VERSION DXVK_NVAPI_ALLOW_OTHER_DRIVERS WINEHAGS
                ;;

            nvidia_new)
                sed -i \
                    -e /'dxgi.customDeviceDesc =/c dxgi.customDeviceDesc = "NVIDIA GeForce RTX 4090"' \
                    -e /'dxgi.customDeviceId =/c dxgi.customDeviceId = 2684' \
                    -e /'dxgi.customVendorId =/c dxgi.customVendorId = 10de' \
                    -e /'dxgi.hideNvidiaGpu =/c dxgi.hideNvidiaGpu = False' \
                "${DXVK_CONFIG_FILE}"

                # export WINE_HIDE_AMD_GPU="1"
                export DXVK_NVAPI_DRIVER_VERSION="99999"
                export DXVK_NVAPI_ALLOW_OTHER_DRIVERS="1"
                export PW_USE_NVAPI_AND_DLSS="1"
                export PW_USE_RAY_TRACING="1"
                ;;

            low_latency)
                sed -i \
                    -e /'d3d11.cachedDynamicResources =/c d3d11.cachedDynamicResources = a' \
                    -e /'dxgi.maxFrameLatency =/c dxgi.maxFrameLatency = 1' \
                    -e /'d3d9.maxFrameLatency =/c d3d9.maxFrameLatency = 1' \
                    -e /'dxgi.syncInterval =/c dxgi.syncInterval = 0' \
                    -e /'d3d9.presentInterval =/c d3d9.presentInterval = 0' \
                    -e /'dxgi.numBackBuffers =/c dxgi.numBackBuffers = 2' \
                    -e /'d3d9.numBackBuffers =/c d3d9.numBackBuffers = 2' \
                    -e /'d3d9.deviceLossOnFocusLoss =/c d3d9.deviceLossOnFocusLoss = True' \
                    -e /'d3d9.countLosableResources =/c d3d9.countLosableResources = True' \
                    -e /'dxvk.tearFree =/c dxvk.tearFree = False' \
                "${DXVK_CONFIG_FILE}"
                ;;
        esac
    }
    set_to_dxvk_conf default

    # NVAPI, DLSS AND FAKE DLSS
    if [[ -d "$PATH_TO_GAME/Engine" ]]; then
        ue_exe_path=$(find "$PATH_TO_GAME" -maxdepth 4 -mindepth 4 -path "*Binaries/Win64/*.exe" -not -path "*/Engine/*" | head -1)
        PATH_TO_GAME=$(dirname "$ue_exe_path")
    fi

    pw_optiscaler_sync_files

    if [[ "${PW_USE_RAY_TRACING}" == "1" ]] ; then
        var_vkd3d_config_update dxr
        if [[ $(check_vendor_gpu) == "amd" ]] ; then
            var_radv_perftest_config_update rt
        fi
    else
        var_vkd3d_config_update nodxr
    fi

    if [[ "${PW_USE_NVAPI_AND_DLSS}" == "1" ]] ; then
        export DXVK_ENABLE_NVAPI="1"
        if echo "$LSPCI_VGA" | grep -i -q 'nvidia' ; then
            FIND_NVNGX="$(dirname $(find /usr/* -type f -name "nvngx.dll" 2>/dev/null | head -n 1 | awk '{print $1}'))"
            if [[ -n "$FIND_NVNGX" ]] ; then
                try_copy_file_with_checksums "${FIND_NVNGX}/nvngx.dll" "${WINEPREFIX}/drive_c/windows/system32/nvngx.dll"
                try_copy_file_with_checksums "${FIND_NVNGX}/_nvngx.dll" "${WINEPREFIX}/drive_c/windows/system32/_nvngx.dll"
                var_winedlloverride_update "nvngx,_nvngx=n"
                export NVIDIA_WINE_DLL_DIR="${FIND_NVNGX}"
            fi
        fi
    else
        export DXVK_ENABLE_NVAPI="0"
    fi

    if [[ "${PW_HEAP_DELAY_FREE}" == 1 ]]
    then export WINE_HEAP_DELAY_FREE="1"
    else export WINE_HEAP_DELAY_FREE="0"
    fi

    if [[ "${PW_WINE_ALLOW_XIM}" == 1 ]]
    then export WINE_ALLOW_XIM="1"
    else export WINE_ALLOW_XIM="0"
    fi

    if [[ "${PW_FIX_VIDEO_IN_GAME}" == 1 ]]
    then export WINE_DO_NOT_CREATE_DXGI_DEVICE_MANAGER="1"
    else export WINE_DO_NOT_CREATE_DXGI_DEVICE_MANAGER="0"
    fi

    if [[ -f "$PATH_TO_GAME/MangoHud.conf" ]] ; then
        unset MANGOHUD_CONFIG
        export MANGOHUD_CONFIGFILE="$PATH_TO_GAME/MangoHud.conf"
        print_info "Custom MangoHud.conf in use: $MANGOHUD_CONFIGFILE"
    elif [[ "${PW_MANGOHUD_USER_CONF}" == 1 ]] ; then
        unset MANGOHUD_CONFIG
    fi

    [[ "${PW_VKBASALT_USER_CONF}" == 1 ]] && unset PW_VKBASALT_EFFECTS PW_VKBASALT_FFX_CAS

    if [[ $PW_GPU_USE != "disabled" ]] ; then
        export DXVK_FILTER_DEVICE_NAME="$PW_GPU_USE"
        export VKD3D_FILTER_DEVICE_NAME="$PW_GPU_USE"
        export MESA_VK_DEVICE_SELECT_FORCE_DEFAULT_DEVICE="1"
        export MESA_VK_DEVICE_SELECT="$PW_vendorID:$PW_deviceID"
    fi

    if [[ -f "$PATH_TO_GAME/dxvk.conf" ]] ; then
        export DXVK_CONFIG_FILE="$PATH_TO_GAME/dxvk.conf"
        print_info "Custom dxvk.conf in use: $DXVK_CONFIG_FILE"
    fi

    export int_xneur=0
    if command -v xneur &>/dev/null \
    && pgrep xneur
    then
        killall xneur
        export int_xneur=1
    fi

    if [[ $(check_vendor_gpu) == "nvidia" ]] ; then
        #https://github.com/flathub/net.lutris.Lutris/pull/368#issuecomment-1751381312
        check_variables WEBKIT_DISABLE_DMABUF_RENDERER "1"
        #Для того чтобы OpenGL всегда работал через nvidia (если в PW_GPU_USE выбрана nvidia)
        check_variables __NV_PRIME_RENDER_OFFLOAD "1"
        check_variables __VK_LAYER_NV_optimus "NVIDIA_only"
        check_variables __GLX_VENDOR_LIBRARY_NAME "nvidia"
    else
        check_variables __NV_PRIME_RENDER_OFFLOAD "0"
        check_variables __VK_LAYER_NV_optimus "non_NVIDIA_only"
        unset __GLX_VENDOR_LIBRARY_NAME
    fi

    if check_gamescope_session ; then
        export PW_GAMEMODERUN_SLR=""
    elif [[ "$PW_USE_GAMEMODE" = "1" ]] \
    && [[ -n "$DBUS_SESSION_BUS_ADDRESS" ]]
    then
        if pw_is_process_active ananicy ananicy-cpp scx scx_loader falcond ; then
            export GAMEMODERUN=0
            export PW_GAMEMODERUN_SLR=""
            local current_power_profile
            current_power_profile=$(python_module power_profiles get)
            if [[ -n "$current_power_profile" && "$current_power_profile" != "performance" ]] \
            && python_module power_profiles set performance &>/dev/null
            then
                export PW_POWERPROFILECTL_PROFILE="$current_power_profile"
                pw_save_power_profile "$current_power_profile"
                print_info "Gamemode replaced by power-profiles-daemon/tuned-ppd/tlp-pd via D-Bus to avoid conflicts"
            else
                export PW_POWERPROFILECTL_PROFILE=""
            fi
        elif ! pw_enable_gamemode_basic ; then
            export GAMEMODERUN=0
            export PW_GAMEMODERUN_SLR=""
            print_info "Gamemode is not installed or disabled in vars script or db file: PW_USE_GAMEMODE=$PW_USE_GAMEMODE"
        fi
    else
        export GAMEMODERUN=0
        export PW_GAMEMODERUN_SLR=""
    fi

    pw_enable_idle_inhibit
    pw_other_fixes

    # enabled BattleEye_Runtime and EasyAntiCheat_Runtime
    if [[ "${PW_USE_EAC_AND_BE}" == 1 ]] ; then
        export PROTON_BATTLEYE_RUNTIME="${PW_PLUGINS_PATH}/BattlEye_Runtime"
        export PROTON_EAC_RUNTIME="${PW_PLUGINS_PATH}/EasyAntiCheat_Runtime"
        var_winedlloverride_update "beclient,beclient_x64=b,n"
    else
        unset PROTON_BATTLEYE_RUNTIME PROTON_EAC_RUNTIME
    fi

    if [[ "${PW_REDUCE_PULSE_LATENCY}" == 1 ]] ; then
        export PULSE_LATENCY_MSEC=60
        # export PIPEWIRE_LATENCY=128/48000
    else
        unset PULSE_LATENCY_MSEC
    fi

    if [[ "$PW_USE_US_LAYOUT" == "1" ]] \
    && ! check_wayland_session \
    && command -v setxkbmap &>/dev/null
    then
        setxkbmap -model pc101 us -print | xkbcomp - $DISPLAY &>/dev/null
    else
        export PW_USE_US_LAYOUT="0"
    fi

    D3D_EXTRAS_LIBS="d3dcompiler_33 d3dcompiler_34 d3dcompiler_35 d3dcompiler_36 d3dcompiler_37
    d3dcompiler_38 d3dcompiler_39 d3dcompiler_40 d3dcompiler_41 d3dcompiler_42 d3dcompiler_43 d3dcompiler_46
    d3dcompiler_47 d3dx10_33 d3dx10_34 d3dx10_35 d3dx10_36 d3dx10_37 d3dx10_38 d3dx10_39 d3dx10_40 d3dx10_41
    d3dx10_42 d3dx10_43 d3dx10 d3dx11_42 d3dx11_43 d3dx9_24 d3dx9_25 d3dx9_26 d3dx9_27 d3dx9_28 d3dx9_29 d3dx9_30
    d3dx9_31 d3dx9_32 d3dx9_33 d3dx9_34 d3dx9_35 d3dx9_36 d3dx9_37 d3dx9_38 d3dx9_39 d3dx9_40 d3dx9_41 d3dx9_42 d3dx9_43"
    if [[ "${PW_USE_D3D_EXTRAS}" == "1" ]] ; then
        if [[ ! -f "${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}/winetricks.log" ]] \
        || [[ -z "$(grep d3dx9 "${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}/winetricks.log")" ]]
        then
            echo "d3dx9" >> "${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}/winetricks.log"
        fi
        # try link d3d extras libs
        PATH_TO_D3DEXTRAS="${PW_PLUGINS_PATH}/d3d_extras"
        for d3d_extras_from_plugins in $D3D_EXTRAS_LIBS ; do
            try_force_link_file "${PATH_TO_D3DEXTRAS}/x64/${d3d_extras_from_plugins}.dll" "${WINEPREFIX}/drive_c/windows/system32/${d3d_extras_from_plugins}.dll"
            try_force_link_file "${PATH_TO_D3DEXTRAS}/x32/${d3d_extras_from_plugins}.dll" "${WINEPREFIX}/drive_c/windows/syswow64/${d3d_extras_from_plugins}.dll"
            var_winedlloverride_update "${d3d_extras_from_plugins}=n"
            if [[ -z "$(grep "${d3d_extras_from_plugins}" "${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}/winetricks.log")" ]] ; then
                echo "${d3d_extras_from_plugins}" >> "${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}/winetricks.log"
            fi
        done
    else
        for d3d_extras_from_plugins in $D3D_EXTRAS_LIBS ; do
            try_force_link_file "${WINEDIR}/lib/wine/i386-windows/${d3d_extras_from_plugins}.dll" "${WINEPREFIX}/drive_c/windows/syswow64/${d3d_extras_from_plugins}.dll"
            try_force_link_file "${WINEDIR}/lib64/wine/x86_64-windows/${d3d_extras_from_plugins}.dll" "${WINEPREFIX}/drive_c/windows/system32/${d3d_extras_from_plugins}.dll"
        done
    fi

    # fix physx
    PHYSX_PATH="${WINEPREFIX}/drive_c/Program Files (x86)/NVIDIA Corporation/PhysX/Common"
    for physx_dll in PhysXDevice PhysXLoader PhysXUpdateLoader ; do
        try_force_link_file "${PHYSX_PATH}/${physx_dll}.dll" "${WINEPREFIX}/drive_c/windows/syswow64/${physx_dll}.dll"
        try_force_link_file "${PHYSX_PATH}/${physx_dll}64.dll" "${WINEPREFIX}/drive_c/windows/system32/${physx_dll}64.dll"
    done
    try_force_link_file "${PHYSX_PATH}/cudart32_65.dll" "${WINEPREFIX}/drive_c/windows/syswow64/cudart32_65.dll"
    try_force_link_file "${PHYSX_PATH}/cudart64_65.dll" "${WINEPREFIX}/drive_c/windows/system32/cudart64_65.dll"

    # 3D API
    unset CP_VKD3D_FILES CP_DXVK_FILES CP_DGV2_FILES CP_WINE_FILES PATH_TO_DXVK_FILES PATH_TO_VKD3D_FILES CP_GALLIUM_NINE_FILES
    case "${PW_VULKAN_USE}" in
        0)
            # WINED3D OPENGL
            print_info "Use WINED3D OpenGL"
            unset PW_VKBASALT PW_USE_GALLIUM_ZINK PW_USE_WINED3D_VULKAN PW_USE_SUPPLIED_DXVK_VKD3D
            CP_WINE_FILES="d3d12 d3d12core d3d11 d3d10core d3d10_1 d3d10 d3d9 d3d8 dxgi"
            ;;
        1)
            # DXVK-Sarek AND VKD3D
            print_info "DXVK v.${DXVK_SAREK_VER} in use"
            print_info "VKD3D-PROTON v.${VKD3D_SAREK_VER} in use"
            PATH_TO_DXVK_FILES="${PW_VULKAN_DIR}/dxvk-${DXVK_SAREK_VER}/sarek"
            PATH_TO_VKD3D_FILES="${PW_VULKAN_DIR}/vkd3d-proton-${VKD3D_SAREK_VER}"
            CP_DXVK_FILES="d3d11 d3d10core d3d9 d3d8 dxgi"
            CP_VKD3D_FILES="d3d12"
            CP_WINE_FILES="d3d12core d3d10_1 d3d10"
            ;;
        2)
            # STABLE DXVK AND VKD3D
            print_info "DXVK v.${DXVK_OLD_VER} in use"
            print_info "VKD3D-PROTON v.${VKD3D_OLD_VER} in use"
            PATH_TO_DXVK_FILES="${PW_VULKAN_DIR}/dxvk-${DXVK_OLD_VER}"
            PATH_TO_VKD3D_FILES="${PW_VULKAN_DIR}/vkd3d-proton-${VKD3D_OLD_VER}"
            CP_DXVK_FILES="d3d11 d3d10core d3d9 d3d8 dxgi"
            CP_VKD3D_FILES="d3d12 d3d12core"
            CP_WINE_FILES="d3d10_1 d3d10"
            ;;
        6)
            # NEWEST DXVK AND VKD3D
            print_info "DXVK v.${DXVK_NEW_VER} in use"
            print_info "VKD3D-PROTON v.${VKD3D_NEW_VER} in use"
            PATH_TO_DXVK_FILES="${PW_VULKAN_DIR}/dxvk-${DXVK_NEW_VER}"
            PATH_TO_VKD3D_FILES="${PW_VULKAN_DIR}/vkd3d-proton-${VKD3D_NEW_VER}"
            CP_DXVK_FILES="d3d11 d3d10core d3d9 d3d8 dxgi"
            CP_VKD3D_FILES="d3d12 d3d12core"
            CP_WINE_FILES="d3d10_1 d3d10"
            ;;
    esac

    [[ "$PW_USE_VRCLIENT" = "1" ]] && add_to_var CP_DXVK_FILES "openvr_api_dxvk"

    if [[ $PW_USE_GALLIUM_NINE == "1" ]] \
    || [[ $PW_USE_GALLIUM_ZINK == "1" ]] \
    || [[ $PW_USE_WINED3D_VULKAN == "1" ]] ; then
        unset PATH_TO_DXVK_FILES CP_DXVK_FILES PW_USE_SUPPLIED_DXVK_VKD3D
        CP_WINE_FILES="d3d12 d3d12core d3d11 d3d10core d3d10_1 d3d10 d3d9 d3d8 dxgi"
    fi

    # GALLIUM NINE
    if [[ $PW_USE_GALLIUM_NINE == "1" ]] ; then
        print_info "Use GALLIUM-NINE (Native DX9 on MESA drivers)"
        unset PW_VKBASALT PW_MANGOHUD PW_WINE_FULLSCREEN_FSR DXVK_ENABLE_NVAPI PW_USE_VRCLIENT
        rm_from_var CP_WINE_FILES "d3d9"
        CP_GALLIUM_NINE_FILES="d3d9"
    fi

    # GALLIUM ZINK
    if [[ $PW_USE_GALLIUM_ZINK == "1" ]] ; then
        print_info "Use GALLIUM-ZINK (OpenGL on MESA vulkan drivers)"
        export  __GLX_VENDOR_LIBRARY_NAME="mesa"
        export MESA_LOADER_DRIVER_OVERRIDE="zink"
        export GALLIUM_DRIVER="zink"
        if ! check_wayland_session \
        && ! check_gamescope_session \
        && [[ "${PW_GAMESCOPE}" != "1" ]]
        then
            export LIBGL_KOPPER_DRI2="1"
        fi
        [[ $(check_vendor_gpu) == "nouveau" ]] && export NOUVEAU_USE_ZINK="1"
    fi

    # WINED3D VULKAN
    if [[ $PW_USE_WINED3D_VULKAN == "1" ]] ; then
        print_info "Use DAMAVAND (DirectX to wined3d vulkan)"
        export WINE_D3D_CONFIG="renderer=vulkan"
    else
        if [[ $PW_VULKAN_USE == "0" ]] \
        || [[ $PW_USE_GALLIUM_NINE == "1" ]] || [[ $PW_USE_GALLIUM_ZINK == "1" ]] ; then
            export WINE_D3D_CONFIG="renderer=gl"
        fi
    fi

    export __GL_YIELD="NOTHING"
    export mesa_glthread="true"

    if [[ $PW_USE_SUPPLIED_DXVK_VKD3D == "1" ]] \
    && [[ ! $PW_WINE_USE =~ (PROTON_LG|WINE_LG) ]] \
    && [[ -f "${WINEDIR}/lib64/wine/dxvk/d3d9.dll" || -f "${WINEDIR}/lib/wine/dxvk/x86_64-windows/d3d9.dll" ]] ; then
        if [[ -f "${WINEDIR}/lib64/wine/dxvk/d3d10.dll" && -f "${WINEDIR}/lib64/wine/dxvk/d3d10_1.dll" ]] ; then
            CP_DXVK_FILES="d3d11 d3d10core d3d10_1 d3d10 d3d9 dxgi"
            CP_WINE_FILES=""
        else
            CP_DXVK_FILES="d3d11 d3d10core d3d9 dxgi"
            CP_WINE_FILES="d3d10_1 d3d10"
        fi
        if [[ $PW_DGVOODOO2 != "1" ]] ; then
            if [[ -f "${WINEDIR}/lib64/wine/d8vk/d3d8.dll" ]] ; then
                try_force_link_file "${WINEDIR}/lib/wine/d8vk/d3d8.dll" "${WINEPREFIX}/drive_c/windows/syswow64/d3d8.dll"
                try_force_link_file "${WINEDIR}/lib64/wine/d8vk/d3d8.dll" "${WINEPREFIX}/drive_c/windows/system32/d3d8.dll"
                var_winedlloverride_update "d3d8=n"
            elif [[ -f "${WINEDIR}/lib64/wine/dxvk/d3d8.dll" || -f "${WINEDIR}/lib/wine/dxvk/x86_64-windows/d3d8.dll" ]]
            then add_to_var CP_DXVK_FILES "d3d8"
            else add_to_var CP_WINE_FILES "d3d8"
            fi
        fi
        if [[ -f "${WINEDIR}/lib64/wine/vkd3d-proton/d3d12core.dll" ]] \
        || [[ -f "${WINEDIR}/lib/wine/vkd3d-proton/x86_64-windows/d3d12core.dll" ]] ; then
            CP_VKD3D_FILES="d3d12 d3d12core"
        elif [[ -f "${WINEDIR}/lib64/wine/vkd3d-proton/d3d12.dll" ]] ; then
            CP_VKD3D_FILES="d3d12"
            add_to_var CP_WINE_FILES "d3d12core"
        else
            add_to_var CP_WINE_FILES "d3d12 d3d12core"
        fi
        [[ -f "${WINEDIR}/lib/wine/dxvk/x86_64-windows/d3d9.dll" ]] && PW_USE_SUPPLIED_DXVK_VKD3D="2"
    else
        PW_USE_SUPPLIED_DXVK_VKD3D="0"
    fi

    # DGVOODOO2 enable:
    if [[ "${PW_DGVOODOO2}" == "1" ]] ; then
        if [[ ! -f "${PW_VULKAN_DIR}/dgvoodoo2-${DGV2_VER}/dgVoodoo.conf" ]] ; then
            print_info "Download and install DGVOODOO2 v.${DGV2_VER}"
            if try_download "https://github.com/Castro-Fidel/vulkan/releases/download/dgvoodoo2-${DGV2_VER}/dgvoodoo2-${DGV2_VER}.tar.xz" \
            "${PW_VULKAN_DIR}/dgvoodoo2-${DGV2_VER}.tar.xz"
            then
                if unpack "${PW_VULKAN_DIR}/dgvoodoo2-${DGV2_VER}.tar.xz" "${PW_VULKAN_DIR}" ; then
                    try_remove_file "${PW_VULKAN_DIR}/dgvoodoo2-${DGV2_VER}.tar.xz"
                else
                    try_remove_file "${PW_VULKAN_DIR}/dgvoodoo2-${DGV2_VER}.tar.xz"
                    try_remove_dir "${PW_VULKAN_DIR}/dgvoodoo2-${DGV2_VER}"
                    fatal "Failed to download and unpack DGVOODOO2"
                fi
            else
                fatal "Failed to download and unpack DGVOODOO2"
            fi
        fi
        print_info "Try create symlink DGVOODOO2 files..."
        PATH_TO_DGV2_FILES="${PW_VULKAN_DIR}/dgvoodoo2-${DGV2_VER}"
        CP_DGV2_FILES="d3d9 d3d8 d3dimm ddraw glide3x glide2x glide"
        try_copy_file "${PATH_TO_DGV2_FILES}/dgVoodoo.conf" "${WINEPREFIX}/drive_c/windows/syswow64/"
        DGV2CONF="${WINEPREFIX}/drive_c/windows/syswow64/dgVoodoo.conf"
        if [[ "${PW_DGV2_DISABLE_D3D}" == "1" ]] ; then
            rm_from_var CP_DGV2_FILES "d3d9 d3d8"
        else
            try_force_link_file "${PATH_TO_DGV2_FILES}/x64/d3d9.dll" "${WINEPREFIX}/drive_c/windows/system32/d3d9.dll"
            try_remove_file "${WINEPREFIX}/drive_c/windows/system32/dgVoodoo.conf"
            try_force_link_file "${DGV2CONF}" "${WINEPREFIX}/drive_c/windows/system32/dgVoodoo.conf"

            if [[ $PW_USE_GALLIUM_NINE == "1" ]] ; then
                rm_from_var CP_GALLIUM_NINE_FILES "d3d9"
                rm_from_var CP_WINE_FILES "d3d8"
            elif [[ $PW_USE_GALLIUM_ZINK == "1" ]] || [[ $PW_USE_WINED3D_VULKAN == "1" ]] ; then
                rm_from_var CP_WINE_FILES "d3d9 d3d8"
            elif [[ $PW_USE_SUPPLIED_DXVK_VKD3D != "0" ]] ; then
                rm_from_var CP_DXVK_FILES "d3d9"
            else
                case "${PW_VULKAN_USE}" in
                    0)
                        rm_from_var CP_WINE_FILES "d3d9 d3d8"
                        ;;
                    1|2|6)
                        rm_from_var CP_DXVK_FILES "d3d9 d3d8"
                        ;;
                esac
            fi
        fi

        if [[ "${PW_DGV2_GLIDE_NAPALM}" == "1" ]] ; then
            rm_from_var CP_DGV2_FILES "glide3x"
            try_force_link_file "${PATH_TO_DGV2_FILES}/x32/glide3x-napalm.dll" "${WINEPREFIX}/drive_c/windows/syswow64/glide3x.dll"
            var_winedlloverride_update "glide3x=n"
        fi

        for wine_dgv2_dll in $CP_DGV2_FILES ; do
            try_force_link_file "${PATH_TO_DGV2_FILES}/x32/${wine_dgv2_dll}.dll" "${WINEPREFIX}/drive_c/windows/syswow64/${wine_dgv2_dll}.dll"
            var_winedlloverride_update "${wine_dgv2_dll}=n"
        done
        # DGVOODOO2 settings:
        if [[ "${PW_DGV2_USE_DX12}" == "1" ]] ; then
            if [[ "${PW_VULKAN_USE}" =~ ^(1|2|6)$ ]]
            then sed -i "s/OutputAPI = d3d11_fl11_0/OutputAPI = d3d12_fl12_0/" "$DGV2CONF"
            fi
        fi

        if [[ "${PW_DGV2_ENABLE_CRT}" == "1" ]] ; then
            sed -i "s/ScalingMode = unspecified/ScalingMode = stretched_ar_crt/" "$DGV2CONF"
        else
            if [[ "${PW_DGV2_RESAMPLING}" != "disabled" ]] ; then
                sed -i "s/ScalingMode = unspecified/ScalingMode = stretched_ar/" "$DGV2CONF"
            elif [[ "${PW_DGV2_DISPLAY_ROI}" != "disabled" ]] ; then
                sed -i "s/ScalingMode = unspecified/ScalingMode = stretched_ar/" "$DGV2CONF"
            elif [[ "${PW_DGV2_CURSOR_SCALE}" != "0" ]] ; then
                sed -i "s/ScalingMode = unspecified/ScalingMode = stretched_ar/" "$DGV2CONF"
            else
                sed -i "s/ScalingMode = unspecified/ScalingMode = stretched/" "$DGV2CONF"
            fi
        fi

        [[ "${PW_DGV2_FREE_MOUSE}" == "1" ]] && sed -i "s/FreeMouse = false/FreeMouse = true/" "$DGV2CONF"
        [[ "${PW_DGV2_FASTMEMORY}" == "1" ]] && sed -i "s/FastVideoMemoryAccess = false/FastVideoMemoryAccess = true/" "$DGV2CONF"
        [[ "${PW_DGV2_FORCE_VSYNC}" == "1" ]] && sed -i "s/ForceVerticalSync = false/ForceVerticalSync = true/" "$DGV2CONF"
        [[ "${PW_DGV2_DISABLE_MIPMAPPING}" == "1" ]] && sed -i "s/DisableMipmapping = false/DisableMipmapping = true/g" "$DGV2CONF"
        [[ "${PW_DGV2_GLIDE_GAMMA_RAMP}" != "1" ]] && sed -i "s/EnableGlideGammaRamp = true/EnableGlideGammaRamp = false/" "$DGV2CONF"
        [[ "${PW_DGV2_BLIT_STRETCH}" == "1" ]] && sed -i "s/BilinearBlitStretch = false/BilinearBlitStretch = true/" "$DGV2CONF"
        [[ "${PW_DGV2_PHONG_SHADING}" == "1" ]] && sed -i "s/PhongShadingWhenPossible = false/PhongShadingWhenPossible = true/" "$DGV2CONF"
        [[ "${PW_DGV2_16_BIT_DEPTH_BUFFER}" == "1" ]] && sed -i "s/16BitDepthBuffer = false/16BitDepthBuffer = true/" "$DGV2CONF"
        [[ "${PW_DGV2_3DFX_SPLASH_SCREEN}" == "1" ]] && sed -i "s/3DfxSplashScreen = false/3DfxSplashScreen = true/" "$DGV2CONF"
        [[ "${PW_DGV2_3DFX_WATERMARK}" == "1" ]] && sed -i "s/3DfxWatermark = false/3DfxWatermark = true/" "$DGV2CONF"
        [[ "${PW_DGV2_FILTER_POINT_SAMPLED}" == "1" ]] && sed -i "s/KeepFilterIfPointSampled = false/KeepFilterIfPointSampled = true/" "$DGV2CONF"
        [[ "${PW_DGV2_DGVOODOO_WATERMARK}" == "1" ]] && sed -i "s/dgVoodooWatermark = false/dgVoodooWatermark = true/" "$DGV2CONF"
        [[ "${PW_DGV2_EMULATING_PCI_ACCESS}" == "1" ]] && sed -i "s/ForceEmulatingTruePCIAccess = false/ForceEmulatingTruePCIAccess = true/" "$DGV2CONF"
        [[ "${PW_DGV2_INACTIVE_APP_STATE}" == "1" ]] && sed -i "s/EnableInactiveAppState = false/EnableInactiveAppState = true/" "$DGV2CONF"
        [[ "${PW_DGV2_DISPLAY_ROI}" != "disabled" ]] && sed -i "s/DisplayROI =/DisplayROI = ${PW_DGV2_DISPLAY_ROI}, pos:centered/" "$DGV2CONF"
        [[ "${PW_DGV2_FPS_LIMIT}" != "disabled" ]] && sed -i "s/FPSLimit = 0/FPSLimit = ${PW_DGV2_FPS_LIMIT}/" "$DGV2CONF"
        [[ "${PW_DGV2_BIT_DEPTH}" != "disabled" ]] && sed -i "s/DesktopBitDepth =/DesktopBitDepth = ${PW_DGV2_BIT_DEPTH}/" "$DGV2CONF"
        [[ "${PW_DGV2_CURSOR_SCALE}" != "0" ]] && sed -i "s/CursorScaleFactor = 0/CursorScaleFactor = ${PW_DGV2_CURSOR_SCALE}/" "$DGV2CONF"
        [[ "${PW_DGV2_BRIGHTNESS}" != "100" ]] && sed -i "s/Brightness = 100/Brightness = ${PW_DGV2_BRIGHTNESS}/" "$DGV2CONF"
        [[ "${PW_DGV2_COLOR}" != "100" ]] && sed -i "s/Color = 100/Color = ${PW_DGV2_COLOR}/" "$DGV2CONF"
        [[ "${PW_DGV2_CONTRAST}" != "100" ]] && sed -i "s/Contrast = 100/Contrast = ${PW_DGV2_CONTRAST}/" "$DGV2CONF"

        if [[ "${PW_DGV2_FILTERING}" != "disabled" ]] ; then
            case "$PW_DGV2_FILTERING" in
                "Point sampled") sed -i "s/\<Filtering = appdriven\>/Filtering = pointsampled/" "$DGV2CONF" ;;
                Bilinear) sed -i "s/\<Filtering = appdriven\>/Filtering = bilinear/" "$DGV2CONF" ;;
                "Linear mip") sed -i "s/\<Filtering = appdriven\>/Filtering = linearmip/" "$DGV2CONF" ;;
                Trilinear) sed -i "s/\<Filtering = appdriven\>/Filtering = trilinear/" "$DGV2CONF" ;;
                "Anisotropic 2x") sed -i "s/\<Filtering = appdriven\>/Filtering = 2/" "$DGV2CONF" ;;
                "Anisotropic 4x") sed -i "s/\<Filtering = appdriven\>/Filtering = 4/" "$DGV2CONF" ;;
                "Anisotropic 8x") sed -i "s/\<Filtering = appdriven\>/Filtering = 8/" "$DGV2CONF" ;;
                "Anisotropic 16x") sed -i "s/\<Filtering = appdriven\>/Filtering = 16/" "$DGV2CONF" ;;
            esac
            case "$PW_DGV2_FILTERING" in
                "Point sampled")
                    sed -i "s/TMUFiltering = appdriven/TMUFiltering = pointsampled/" "$DGV2CONF" ;;
                Bilinear|"Linear mip"|Trilinear|"Anisotropic 2x"|"Anisotropic 4x"|"Anisotropic 8x"|"Anisotropic 16x")
                    sed -i "s/TMUFiltering = appdriven/TMUFiltering = bilinear/" "$DGV2CONF" ;;
            esac
        fi

        if [[ "${PW_DGV2_ANTIALIASING}" != "disabled" ]] && [[ "${PW_DGV2_GLIDE_NAPALM}" != "1" ]] ; then
            sed -i "s/Antialiasing = appdriven/Antialiasing = ${PW_DGV2_ANTIALIASING}/g" "$DGV2CONF"
        elif [[ "${PW_DGV2_ANTIALIASING}" != "disabled" ]] && [[ "${PW_DGV2_GLIDE_NAPALM}" == "1" ]] ; then
            sed -i "86s/Antialiasing = appdriven/Antialiasing = ${PW_DGV2_ANTIALIASING}/" "$DGV2CONF"
        fi

        if [[ "${PW_DGV2_VRAM}" != "disabled" ]] ; then
            if [[ "${PW_DGV2_VIDEOCARD}" == "dgVoodoo2 SVGA 3D" ]] ; then
                if [[ "${PW_DGV2_VRAM}" -le "128" ]] ; then
                    sed -i "s/VRAM = 256/VRAM = ${PW_DGV2_VRAM}/" "$DGV2CONF"
                else
                    sed -i "s/VRAM = 256/VRAM = 64/" "$DGV2CONF"
                fi
            fi
            [[ "${PW_DGV2_VIDEOCARD}" == "Geforce 4 Ti 4800" ]] && [[ "${PW_DGV2_VRAM}" -ge "64" ]] && [[ "${PW_DGV2_VRAM}" -le "256" ]] \
                && sed -i "s/VRAM = 256/VRAM = ${PW_DGV2_VRAM}/" "$DGV2CONF"
            [[ "${PW_DGV2_VIDEOCARD}" == "ATI Radeon 8500" ]] && [[ "${PW_DGV2_VRAM}" -ge "64" ]] && [[ "${PW_DGV2_VRAM}" -le "256" ]] \
                && sed -i "s/VRAM = 256/VRAM = ${PW_DGV2_VRAM}/" "$DGV2CONF"
            [[ "${PW_DGV2_VIDEOCARD}" == "Matrox Parhelia-512" ]] && [[ "${PW_DGV2_VRAM}" -ge "128" ]] && [[ "${PW_DGV2_VRAM}" -le "256" ]] \
                && sed -i "s/VRAM = 256/VRAM = ${PW_DGV2_VRAM}/" "$DGV2CONF"
            [[ "${PW_DGV2_VIDEOCARD}" == "GeForce FX 5700 Ultra" ]] && [[ "${PW_DGV2_VRAM}" -ge "64" ]] && [[ "${PW_DGV2_VRAM}" -le "256" ]] \
                && sed -i "s/VRAM = 256/VRAM = ${PW_DGV2_VRAM}/" "$DGV2CONF"
            if [[ "${PW_DGV2_VIDEOCARD}" == "GeForce 9800 GT" ]] ; then
                if [[ "${PW_DGV2_VRAM}" -ge "512" ]] && [[ "${PW_DGV2_VRAM}" -le "1024" ]] ; then
                    sed -i "s/VRAM = 256/VRAM = ${PW_DGV2_VRAM}/" "$DGV2CONF"
                else
                    sed -i "s/VRAM = 256/VRAM = 512/" "$DGV2CONF"
                fi
            fi
        else
            [[ "${PW_DGV2_VIDEOCARD}" == "dgVoodoo2 SVGA 3D" ]] && sed -i "s/VRAM = 256/VRAM = 64/" "$DGV2CONF"
            [[ "${PW_DGV2_VIDEOCARD}" == "GeForce 9800 GT" ]] && sed -i "s/VRAM = 256/VRAM = 512/" "$DGV2CONF"
        fi

        if [[ "$PW_DGV2_RESOLUTION" != "disabled" ]] ; then
            case "$PW_DGV2_RESOLUTION" in
                "2x app resolution")
                    sed -i "s/Resolution = unforced/Resolution = 2x/g" "$DGV2CONF" ;;
                "3x app resolution")
                    sed -i "s/Resolution = unforced/Resolution = 3x/g" "$DGV2CONF" ;;
                "4x app resolution")
                    sed -i "s/Resolution = unforced/Resolution = 4x/g" "$DGV2CONF" ;;
                *)
                    H_RES_DGV2="${PW_DGV2_RESOLUTION:0:4}"
                    V_RES_DGV2="${PW_DGV2_RESOLUTION:5:9}"
                    sed -i "s/Resolution = unforced/Resolution = h:$H_RES_DGV2, v:$V_RES_DGV2/g" "$DGV2CONF" ;;
            esac
        fi

        if [[ "$PW_DGV2_RESAMPLING" != "disabled" ]] ; then
            case "$PW_DGV2_RESAMPLING" in
                "Point sampled") sed -i "s/Resampling = bilinear/Resampling = pointsampled/" "$DGV2CONF" ;;
                Lanczos-2) sed -i "s/Resampling = bilinear/Resampling = lanczos-2" "$DGV2CONF" ;;
                Bicubic) sed -i "s/Resampling = bilinear/Resampling = bicubic" "$DGV2CONF" ;;
                Lanczos-3) sed -i "s/Resampling = bilinear/Resampling = lanczos-3" "$DGV2CONF" ;;
            esac
        fi

        if [[ $PW_DGV2_VIDEOCARD != "dgVoodoo2 Virtual 3D" ]] ; then
            case "$PW_DGV2_VIDEOCARD" in
                "dgVoodoo2 SVGA 3D") sed -i "s/VideoCard = internal3D/VideoCard = svga/" "$DGV2CONF" ;;
                "Geforce 4 Ti 4800") sed -i "s/VideoCard = internal3D/VideoCard = geforce_ti_4800/" "$DGV2CONF" ;;
                "ATI Radeon 8500") sed -i "s/VideoCard = internal3D/VideoCard = ati_radeon_8500/" "$DGV2CONF" ;;
                "Matrox Parhelia-512") sed -i "s/VideoCard = internal3D/VideoCard = matrox_parhelia-512/" "$DGV2CONF" ;;
                "GeForce FX 5700 Ultra") sed -i "s/VideoCard = internal3D/VideoCard = geforce_fx_5700_ultra/" "$DGV2CONF" ;;
                "GeForce 9800 GT") sed -i "s/VideoCard = internal3D/VideoCard = geforce_9800_gt/" "$DGV2CONF" ;;
            esac
            if [[ "${PW_DGV2_VIDEOCARD}" == "Voodoo Graphics" ]] ; then
                sed -i "s/VideoCard = voodoo_2/VideoCard = voodoo_graphics/" "$DGV2CONF"
                sed -i "s/NumberOfTMUs = 2/NumberOfTMUs = 1/" "$DGV2CONF"
                if [[ "${PW_DGV2_ONBOARD_RAM}" == "1" ]]
                then sed -i "s/OnboardRAM = 8/OnboardRAM = 4/" "$DGV2CONF"
                else sed -i "s/OnboardRAM = 8/OnboardRAM = 2/" "$DGV2CONF"
                fi
            fi
            if [[ "${PW_DGV2_VIDEOCARD}" == "Voodoo Rush" ]] ; then
                sed -i "s/VideoCard = voodoo_2/VideoCard = voodoo_rush/" "$DGV2CONF"
                sed -i "s/NumberOfTMUs = 2/NumberOfTMUs = 1/" "$DGV2CONF"
                if [[ "${PW_DGV2_ONBOARD_RAM}" == "1" ]]
                then sed -i "s/OnboardRAM = 8/OnboardRAM = 4/" "$DGV2CONF"
                else sed -i "s/OnboardRAM = 8/OnboardRAM = 2/" "$DGV2CONF"
                fi
            fi
            if [[ "${PW_DGV2_VIDEOCARD}" == "Voodoo 2" ]] && [[ "${PW_DGV2_ONBOARD_RAM}" == "1" ]] ; then
                sed -i "s/OnboardRAM = 8/OnboardRAM = 12/" "$DGV2CONF"
            fi
            if [[ "${PW_DGV2_VIDEOCARD}" == "Voodoo Banshee" ]] ; then
                sed -i "s/VideoCard = voodoo_2/VideoCard = voodoo_banshee/" "$DGV2CONF"
                sed -i "s/NumberOfTMUs = 2/NumberOfTMUs = 1/" "$DGV2CONF"
                if [[ "${PW_DGV2_ONBOARD_RAM}" == "1" ]] ; then
                    sed -i "s/OnboardRAM = 8/OnboardRAM = 16/" "$DGV2CONF"
                fi
            fi
        fi
    else
        for rm_dgv2_dll in d3dimm glide glide2x glide3x ; do
            try_remove_file "${WINEPREFIX}/drive_c/windows/syswow64/${rm_dgv2_dll}.dll"
        done
        add_to_var CP_WINE_FILES "ddraw"
    fi

    # force use dxgi.dll from wine
    if [[ "${PW_USE_WINE_DXGI}" == "1" ]] ; then
        rm_from_var CP_DXVK_FILES "dxgi"
        add_to_var CP_WINE_FILES "dxgi"
    fi

    print_info "Try create symlink WINE files..."
    for copy_wine_dll in $CP_WINE_FILES ; do
        try_force_link_file "${WINEDIR}/lib64/wine/x86_64-windows/${copy_wine_dll}.dll" "${WINEPREFIX}/drive_c/windows/system32/${copy_wine_dll}.dll"
        try_force_link_file "${WINEDIR}/lib/wine/i386-windows/${copy_wine_dll}.dll" "${WINEPREFIX}/drive_c/windows/syswow64/${copy_wine_dll}.dll"
    done

    if [[ -n "$CP_DXVK_FILES" ]] ; then
        print_info "Try create symlink DXVK files..."
        for wine_dxvk_dll in $CP_DXVK_FILES ; do
            case "$PW_USE_SUPPLIED_DXVK_VKD3D" in
                2)
                    try_force_link_file "${WINEDIR}/lib/wine/dxvk/i386-windows/${wine_dxvk_dll}.dll" "${WINEPREFIX}/drive_c/windows/syswow64/${wine_dxvk_dll}.dll"
                    try_force_link_file "${WINEDIR}/lib/wine/dxvk/x86_64-windows/${wine_dxvk_dll}.dll" "${WINEPREFIX}/drive_c/windows/system32/${wine_dxvk_dll}.dll" ;;
                1)
                    try_force_link_file "${WINEDIR}/lib/wine/dxvk/${wine_dxvk_dll}.dll" "${WINEPREFIX}/drive_c/windows/syswow64/${wine_dxvk_dll}.dll"
                    try_force_link_file "${WINEDIR}/lib64/wine/dxvk/${wine_dxvk_dll}.dll" "${WINEPREFIX}/drive_c/windows/system32/${wine_dxvk_dll}.dll" ;;
                0)
                    try_force_link_file "${PATH_TO_DXVK_FILES}/x32/${wine_dxvk_dll}.dll" "${WINEPREFIX}/drive_c/windows/syswow64/${wine_dxvk_dll}.dll"
                    try_force_link_file "${PATH_TO_DXVK_FILES}/x64/${wine_dxvk_dll}.dll" "${WINEPREFIX}/drive_c/windows/system32/${wine_dxvk_dll}.dll" ;;
            esac
            if [[ $PW_USE_OPTISCALER == "1" ]] && [[ $wine_dxvk_dll == "dxgi" ]]
            then var_winedlloverride_update "dxgi=n,b"
            else var_winedlloverride_update "${wine_dxvk_dll}=n"
            fi
        done
        create_new_dir "${PATH_TO_DXVK_FILES}/dxvk_cache"
        check_variables DXVK_STATE_CACHE_PATH "${PATH_TO_DXVK_FILES}"/dxvk_cache
        export DXVK_STATE_CACHE="1"
    fi

    if [[ "$DXVK_ENABLE_NVAPI" == "1" ]] ; then
        print_info "Try create symlink NVAPI files..."
        if [[ $PW_USE_SUPPLIED_DXVK_VKD3D == "2" ]] && [[ -f "${WINEDIR}/lib/wine/nvapi/x86_64-windows/nvapi64.dll" ]] ; then
            try_force_link_file "${WINEDIR}/lib/wine/nvapi/i386-windows/nvapi.dll" "${WINEPREFIX}/drive_c/windows/syswow64/nvapi.dll"
            try_force_link_file "${WINEDIR}/lib/wine/nvapi/x86_64-windows/nvapi64.dll" "${WINEPREFIX}/drive_c/windows/system32/nvapi64.dll"
            try_force_link_file "${WINEDIR}/lib/wine/nvapi/x86_64-windows/nvofapi64.dll" "${WINEPREFIX}/drive_c/windows/system32/nvofapi64.dll"
        elif [[ $PW_USE_SUPPLIED_DXVK_VKD3D == "1" ]] && [[ -f "${WINEDIR}/lib64/wine/nvapi/nvapi64.dll" ]] ; then
            try_force_link_file "${WINEDIR}/lib/wine/nvapi/nvapi.dll" "${WINEPREFIX}/drive_c/windows/syswow64/nvapi.dll"
            try_force_link_file "${WINEDIR}/lib64/wine/nvapi/nvapi64.dll" "${WINEPREFIX}/drive_c/windows/system32/nvapi64.dll"
            try_force_link_file "${WINEDIR}/lib64/wine/nvapi/nvofapi64.dll" "${WINEPREFIX}/drive_c/windows/system32/nvofapi64.dll"
        else
            try_force_link_file "${PW_VULKAN_DIR}/dxvk-${DXVK_NEW_VER}/x32/nvapi.dll" "${WINEPREFIX}/drive_c/windows/syswow64/nvapi.dll"
            try_force_link_file "${PW_VULKAN_DIR}/dxvk-${DXVK_NEW_VER}/x64/nvapi64.dll" "${WINEPREFIX}/drive_c/windows/system32/nvapi64.dll"
            try_force_link_file "${PW_VULKAN_DIR}/dxvk-${DXVK_NEW_VER}/x64/nvofapi64.dll" "${WINEPREFIX}/drive_c/windows/system32/nvofapi64.dll"
        fi
        var_winedlloverride_update "nvapi64,nvofapi64,nvapi=n;nvcuda=b"
    else
        try_remove_file "${WINEPREFIX}/drive_c/windows/syswow64/nvapi.dll"
        try_remove_file "${WINEPREFIX}/drive_c/windows/system32/nvapi64.dll"
        try_remove_file "${WINEPREFIX}/drive_c/windows/system32/nvofapi64.dll"
    fi

    if [[ -n "$CP_VKD3D_FILES" ]] ; then
        print_info "Try create symlink VKD3D files..."
        for wine_vkd3d_dll in $CP_VKD3D_FILES ; do
            case "$PW_USE_SUPPLIED_DXVK_VKD3D" in
                2)
                    if [[ $wine_vkd3d_dll =~ d3d12 ]] ; then
                        try_force_link_file "${WINEDIR}/lib/wine/vkd3d-proton/i386-windows/${wine_vkd3d_dll}.dll" "${WINEPREFIX}/drive_c/windows/syswow64/${wine_vkd3d_dll}.dll"
                        try_force_link_file "${WINEDIR}/lib/wine/vkd3d-proton/x86_64-windows/${wine_vkd3d_dll}.dll" "${WINEPREFIX}/drive_c/windows/system32/${wine_vkd3d_dll}.dll"
                    fi ;;
                1)
                    if [[ $wine_vkd3d_dll =~ d3d12 ]] ; then
                        try_force_link_file "${WINEDIR}/lib/wine/vkd3d-proton/${wine_vkd3d_dll}.dll" "${WINEPREFIX}/drive_c/windows/syswow64/${wine_vkd3d_dll}.dll"
                        try_force_link_file "${WINEDIR}/lib64/wine/vkd3d-proton/${wine_vkd3d_dll}.dll" "${WINEPREFIX}/drive_c/windows/system32/${wine_vkd3d_dll}.dll"
                    fi ;;
                0)
                    try_force_link_file "${PATH_TO_VKD3D_FILES}/x86/${wine_vkd3d_dll}.dll" "${WINEPREFIX}/drive_c/windows/syswow64/${wine_vkd3d_dll}.dll"
                    try_force_link_file "${PATH_TO_VKD3D_FILES}/x64/${wine_vkd3d_dll}.dll" "${WINEPREFIX}/drive_c/windows/system32/${wine_vkd3d_dll}.dll" ;;
            esac
            var_winedlloverride_update "${wine_vkd3d_dll}=n"
        done
        create_new_dir "${PATH_TO_VKD3D_FILES}/vkd3d_cache"
        check_variables VKD3D_SHADER_CACHE_PATH "${PATH_TO_VKD3D_FILES}/vkd3d_cache"
    fi

    # некоторым играм для любых 3D api для правильной работы wined3d необходимо чтобы эти библиотеки всегда были
    PATH_TO_VKD3D_FILES="${PW_VULKAN_DIR}/vkd3d-proton-${VKD3D_NEW_VER}" # используется git версия
    try_force_link_file "${PATH_TO_VKD3D_FILES}/x86/libvkd3d-1.dll" "${WINEPREFIX}/drive_c/windows/syswow64/libvkd3d-1.dll"
    try_force_link_file "${PATH_TO_VKD3D_FILES}/x86/libvkd3d-shader-1.dll" "${WINEPREFIX}/drive_c/windows/syswow64/libvkd3d-shader-1.dll"
    try_force_link_file "${PATH_TO_VKD3D_FILES}/x64/libvkd3d-1.dll" "${WINEPREFIX}/drive_c/windows/system32/libvkd3d-1.dll"
    try_force_link_file "${PATH_TO_VKD3D_FILES}/x64/libvkd3d-shader-1.dll" "${WINEPREFIX}/drive_c/windows/system32/libvkd3d-shader-1.dll"

    # GALLIUM NINE
    if [[ "$CP_GALLIUM_NINE_FILES" == "d3d9" ]] && [[ -f "${PW_TMPFS_PATH}/gallium_nine.tmp" ]] ; then
        PATH_TO_GALLIUM_NINE_FILES="${PW_PLUGINS_PATH}/gallium_nine_v.${PW_GALLIUM_NINE_VER}"
        if [[ ! -d "$PATH_TO_GALLIUM_NINE_FILES" ]] ; then
            if try_download "github.com/Castro-Fidel/vulkan/releases/download/gallium_nine_v.${PW_GALLIUM_NINE_VER}/gallium_nine_v.${PW_GALLIUM_NINE_VER}.tar.xz" \
                            "${PORT_DATA_PATH}/data/tmp/gallium_nine_v.${PW_GALLIUM_NINE_VER}.tar.xz" ; then
                if ! unpack "${PORT_DATA_PATH}/data/tmp/gallium_nine_v.${PW_GALLIUM_NINE_VER}.tar.xz" "$PW_PLUGINS_PATH/"
                then try_remove_dir "$PATH_TO_GALLIUM_NINE_FILES"
                fi
                try_remove_file "${PORT_DATA_PATH}/data/tmp/gallium_nine_v.${PW_GALLIUM_NINE_VER}.tar.xz"
            fi
        fi
        print_info "Try create symlink GALLIUM_NINE files..."
        try_force_link_file "${PATH_TO_GALLIUM_NINE_FILES}/lib32/d3d9-nine.dll.so" "${WINEPREFIX}/drive_c/windows/syswow64/d3d9.dll"
        try_force_link_file "${PATH_TO_GALLIUM_NINE_FILES}/lib64/d3d9-nine.dll.so" "${WINEPREFIX}/drive_c/windows/system32/d3d9.dll"
        export D3D_MODULE_PATH="$(<"${PW_TMPFS_PATH}/gallium_nine.tmp")"
        print_info "D3D_MODULE_PATH=$D3D_MODULE_PATH"
        var_winedlloverride_update "d3d9=n"
    fi

    if [[ "$PW_USE_VRCLIENT" = "1" ]] ; then
        if [[ ! -d "${WINEPREFIX}/drive_c/vrclient/bin" ]] ; then
            create_new_dir "${WINEPREFIX}/drive_c/vrclient/bin"
            try_force_link_file "${WINEDIR}"/lib/wine/i386-windows/vrclient.dll "${WINEPREFIX}/drive_c/vrclient/bin/vrclient.dll"
            try_force_link_file "${WINEDIR}"/lib64/wine/x86_64-windows/vrclient_x64.dll "${WINEPREFIX}/drive_c/vrclient/bin/vrclient_x64.dll"
        fi
    else
        var_winedlloverride_update "wineopenxr,vrclient,vrclient_x64,openvr_api_dxvk="
    fi

    if [[ "${PW_USE_SHADER_CACHE}" == "1" ]] ; then
        create_new_dir "${PW_VULKAN_DIR}/gl_shader_cache"
        create_new_dir "${PW_VULKAN_DIR}/mesa_shader"
        check_variables __GL_SHADER_DISK_CACHE "1"
        check_variables __GL_SHADER_DISK_CACHE_PATH "${PW_VULKAN_DIR}/gl_shader_cache"
        check_variables __GL_SHADER_DISK_CACHE_SIZE "50000000000"
        check_variables __GL_SHADER_DISK_CACHE_SKIP_CLEANUP "1"
        check_variables MESA_SHADER_CACHE_DIR "${PW_VULKAN_DIR}/mesa_shader"
    else
        export __GL_SHADER_DISK_CACHE="0"
        export DXVK_STATE_CACHE="disable"
        export VKD3D_SHADER_CACHE_PATH="0"
    fi

    if [[ "${PW_WINE_FULLSCREEN_FSR}" == "1" ]] \
    && ! check_gamescope_session
    then
        export WINE_FULLSCREEN_FSR="1"
        export WINE_FULLSCREEN_FSR_STRENGTH="2"
        export WINE_FULLSCREEN_INTEGER_SCALING="0"
    else
        export WINE_FULLSCREEN_FSR="0"
        unset WINE_FULLSCREEN_FAKE_CURRENT_RES WINE_FULLSCREEN_FSR_STRENGTH WINE_FULLSCREEN_INTEGER_SCALING
    fi

    if [[ "${PW_WINE_CPU_TOPOLOGY}" != "disabled" ]] ; then
        export WINE_CPU_TOPOLOGY="${PW_WINE_CPU_TOPOLOGY}"
    fi

    if [[ -n "${PW_VK_ICD_FILENAMES}" ]] ; then
        export VK_ICD_FILENAMES="${PW_VK_ICD_FILENAMES}"
        export VK_DRIVER_FILES="${PW_VK_ICD_FILENAMES}"
    fi

    if [[ "${PW_MESA_GL_VERSION_OVERRIDE}" != "disabled" ]] ; then
        export MESA_GL_VERSION_OVERRIDE="${PW_MESA_GL_VERSION_OVERRIDE}"
        if [[ $PW_MESA_GL_VERSION_OVERRIDE = 3.2COMPAT ]] ; then
            export MESA_GLSL_VERSION_OVERRIDE="150"
        else
            MESA_GLSL_VERSION_OVERRIDE="${PW_MESA_GL_VERSION_OVERRIDE//./}"
            export MESA_GLSL_VERSION_OVERRIDE="${MESA_GLSL_VERSION_OVERRIDE//COMPAT/}0"
        fi
    fi

    if [[ "${PW_VKD3D_FEATURE_LEVEL}" != "disabled" ]] ; then
        export VKD3D_FEATURE_LEVEL="${PW_VKD3D_FEATURE_LEVEL}"
    fi

    if [[ "${PW_MESA_VK_WSI_PRESENT_MODE}" != "disabled" ]] ; then
        export MESA_VK_WSI_PRESENT_MODE="${PW_MESA_VK_WSI_PRESENT_MODE}"
        case "$PW_MESA_VK_WSI_PRESENT_MODE" in
            immediate|mailbox)
                check_variables vblank_mode "0"
                check_variables __GL_SYNC_TO_VBLANK "0"
                ;;
            relaxed|fifo)
                check_variables vblank_mode "1"
                check_variables __GL_SYNC_TO_VBLANK "1"
                ;;
        esac
    elif [[ "${PW_USE_LS_FRAME_GEN}" == "1" ]] ; then
        # export MESA_VK_WSI_PRESENT_MODE="fifo"
        # unset vblank_mode __GL_SYNC_TO_VBLANK
        :
    fi
    export LSFGVK_EXPERIMENTAL_PRESENT_MODE="$MESA_VK_WSI_PRESENT_MODE"

    #run_winetricks_from_db
    if [[ -n "${PW_MUST_HAVE_DLL}" ]] ; then
        PW_DLL_INSTALL="$(echo "${PW_MUST_HAVE_DLL} ${PW_DLL_INSTALL}" | awk '{ for(i=1;i<=NF;i++){a[$i]++} }END{ for(i in a){printf("%s ",i)} }' )"
        export PW_DLL_INSTALL
    fi

    if [[ -n "${PW_DLL_INSTALL}" ]] ; then
        export PW_DLL_NEED_INSTALL=""
        export USE_WT_FROM_DB=0
        if [[ ! -f "${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}/winetricks.log" ]] ; then
            touch "${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}/winetricks.log"
        fi
        for need_install_dll_to_pfx in ${PW_DLL_INSTALL} ; do
            if [[ "${need_install_dll_to_pfx}" == vcrun201[5-9] ]] \
            || [[ "${need_install_dll_to_pfx}" == vcrun2022 ]] ; then
                need_install_dll_to_pfx="vcrun2022"
                sed -i '/vcrun2015/d' "${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}/winetricks.log"
                sed -i '/vcrun2017/d' "${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}/winetricks.log"
                sed -i '/vcrun2019/d' "${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}/winetricks.log"
            fi
            grep "${need_install_dll_to_pfx}" "${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}/winetricks.log" &>/dev/null
            if [[ "$?" == "1" ]] ; then
                if [[ -z "${PW_DLL_NEED_INSTALL}" ]]
                then export PW_DLL_NEED_INSTALL="${need_install_dll_to_pfx}"
                else export PW_DLL_NEED_INSTALL="${need_install_dll_to_pfx} ${PW_DLL_NEED_INSTALL}"
                fi
                export USE_WT_FROM_DB=1
            fi
        done
        if [[ "${USE_WT_FROM_DB}" == "1" ]] ; then
            update_winetricks
            echo "START WINETRICKS..." >> "${PW_TMPFS_PATH}/update_pfx_log"
            echo "Try to install DLL in prefix: ${PW_DLL_NEED_INSTALL}" >> "${PW_TMPFS_PATH}/update_pfx_log"
            print_info "Try to install DLL in prefix: ${PW_DLL_NEED_INSTALL}"
            ${pw_runtime} LD_LIBRARY_PATH="${PW_LD_LIBRARY_PATH}" GST_PLUGIN_SYSTEM_PATH_1_0="" \
            "${PORT_WINE_TMP_PATH}/winetricks" -q -f ${PW_DLL_NEED_INSTALL} | tee -a "${PW_TMPFS_PATH}/update_pfx_log"
            wait_wineserver
            kill_portwine
        fi
    fi

    if [[ -f "${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}/system.reg" ]] \
    && ! grep -iq "Microsoft Windows $PW_WINDOWS_VER" "${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}/system.reg"
    then
        if [[ -n $PW_WINDOWS_VER ]] \
        && [[ $(echo "$PW_WINDOWS_VER" | sed 's/.*/\L&/') == "xp" ]]
        then
            export PW_WINDOWS_VER="xp64"
        fi
        ${pw_runtime} LD_LIBRARY_PATH="${PW_LD_LIBRARY_PATH}:${WINE_LIBRARY_PATH}" GST_PLUGIN_SYSTEM_PATH_1_0="" \
        "${WINELOADER}" winecfg -v $(echo "win${PW_WINDOWS_VER}" | sed 's/.*/\L&/')
        wait_wineserver
        kill_portwine
        echo "Set to win${PW_WINDOWS_VER}"
    fi

    if [[ $PW_EXE_FILE == *-Shipping.exe ]] ; then
        echo "Disable EAC"
        [[ -z "$LAUNCH_PARAMETERS" ]] && export LAUNCH_PARAMETERS+=" -eac-nop-loaded "
    fi

    if [[ $PW_DINPUT_PROTOCOL == "1" ]] ; then
        get_and_set_reg_file --add 'System\CurrentControlSet\Services\winebus' 'DisableHidraw' 'REG_DWORD' "0" "system"
        get_and_set_reg_file --add 'System\CurrentControlSet\Services\winebus' 'Enable SDL' 'REG_DWORD' "0" "system"
    else
        get_and_set_reg_file --add 'System\CurrentControlSet\Services\winebus' 'DisableHidraw' 'REG_DWORD' "1" "system"
        get_and_set_reg_file --add 'System\CurrentControlSet\Services\winebus' 'Enable SDL' 'REG_DWORD' "1" "system"
    fi

    if check_wayland_session \
    && [[ $PW_USE_NATIVE_WAYLAND == "1" || $PW_USE_DXVK_HDR == "1" ]]
    then
        [[ $PW_USE_DXVK_HDR == "1" ]] && export DXVK_HDR="1"
        export WINE_WAYLAND_HACKS="1"
        export PROTON_NO_STEAMINPUT="1"
        export WAYLANDDRV_NO_IME="1"
        export PROTON_USE_XALIA="0"

        if [[ -d "$WINEDIR/share/X11/locale" ]] ; then
            check_variables "XLOCALEDIR" "$WINEDIR/share/X11/locale"
        fi

        var_winedlloverride_update "winex11.drv=d;winewayland.drv=b"
        get_and_set_reg_file --add 'Software\Wine\Drivers' 'Graphics' 'REG_SZ' "x11,wayland" "user"

        print_warning "Wayland in use. Force dpi=96"
        export PW_FORCE_SYSTEM_DPI="1"
        export PW_WINE_DPI_VALUE="96"

        if [[ -f "$WINEDIR/lib/libxkbregistry.so" ]] \
        || [[ -f "$WINEDIR/lib/x86_64-linux-gnu/libxkbregistry.so" ]]
        then print_info "runtime in use with native wayland."
        else
            print_warning "Wine is not support native wayland with runtime! Force disabled SLR."
            export PW_USE_RUNTIME="0"
        fi
    else
        export GST_GL_WINDOW="x11"
        unset WINE_WAYLAND_HACKS DXVK_HDR
        check_variables PROTON_USE_XALIA 0
        get_and_set_reg_file --delete 'Software\Wine\Drivers' 'Graphics'
    fi

    if [[ "${PW_FORCE_SYSTEM_DPI}" == "1" ]] ; then
        if [[ $PW_WINE_DPI_VALUE =~ (disabled|recommended|96) ]] ; then
            get_and_set_reg_file --add 'Control Panel\Desktop' 'LogPixels' 'REG_DWORD' "96" "user"
        else
            get_and_set_reg_file --add 'Control Panel\Desktop' 'LogPixels' 'REG_DWORD' "$PW_WINE_DPI_VALUE" "user"
        fi
    fi

    case "$PW_SOUND_DRIVER_USE" in
        pulse) get_and_set_reg_file --add 'Software\Wine\Drivers' 'Audio' 'REG_SZ' "pulse" "user" ;;
         alsa) get_and_set_reg_file --add 'Software\Wine\Drivers' 'Audio' 'REG_SZ' "alsa" "user" ;;
          oss) get_and_set_reg_file --add 'Software\Wine\Drivers' 'Audio' 'REG_SZ' "oss" "user" ;;
            *) get_and_set_reg_file --delete 'Software\Wine\Drivers' 'Audio' ;;
    esac

    add_in_start_portproton

    if [[ "$FULL_LN" == russian ]] ; then
        for chk_lang_and_uname in "steam_emu.ini" "steam_api.ini" "steam_api64.ini" "SteamConfig.ini" ; do
            if [[ -f "${PATH_TO_GAME}/${chk_lang_and_uname}" ]] ; then
                sed -i "/^Language/c\Language=${FULL_LN}" "${PATH_TO_GAME}/${chk_lang_and_uname}"
                sed -i "/^UserName/c\UserName=${USER}" "${PATH_TO_GAME}/${chk_lang_and_uname}"
                sed -i "/^PlayerName/c\PlayerName=${USER}" "${PATH_TO_GAME}/${chk_lang_and_uname}"
            fi
        done
    fi

    if [[ "${PW_DISABLE_COMPOSITING}" == "1" ]] \
    && ! check_gamescope_session
    then
        if [[ "${DESKTOP_SESSION}" =~ "plasma" ]] ; then
            kde_version=$(plasmashell --version 2>/dev/null | grep -oE '[0-9]+' | head -1)
            if [[ -n "$kde_version" && "$kde_version" -lt 6 ]]; then
                qdbus org.kde.KWin /Compositor suspend
            fi
        elif [[ "${DESKTOP_SESSION}" =~ "mate" ]] ; then
            gsettings set org.mate.Marco.general compositing-manager false
        elif [[ "${DESKTOP_SESSION}" =~ "xfce" ]] ; then
            xfconf-query -c xfwm4 -p /general/use_compositing -s false
        elif [[ "${DESKTOP_SESSION}" =~ "cinnamon" ]] ; then
            gsettings set org.cinnamon.muffin unredirect-fullscreen-windows true
        elif [[ "${DESKTOP_SESSION}" =~ "deepin" ]] ; then
            python_module dbus_tools deepin-switch-wm &>/dev/null
        fi
    fi

    pw_prepare_gamescope_launch

    # fixed msxml3 with new wine
    get_and_set_reg_file --delete 'Software\Wine\DllOverrides' '*msxml3'

    pw_mangohud_check
    pw_vkbasalt_check
    pw_lsfg_vk_check
}

pw_run () {
    if [[ "$PW_USE_TERMINAL" == 1 ]] \
    && [[ "${PRESSURE_VESSEL_TERMINAL:-}" != "tty" ]]
    then
        local pw_terminal_command
        printf -v pw_terminal_command "%q " pw_run "$@"
        PRESSURE_VESSEL_TERMINAL=tty $PW_TERM "$pw_terminal_command"
        return $?
    fi

    if [[ -n "${PATH_TO_GAME}" ]] \
    && [[ -d "${PATH_TO_GAME}" ]]
    then
        :
    elif [[ -f "$PW_EXE_FILE" ]]
    then
        PATH_TO_GAME="$( cd "$( dirname "${PW_EXE_FILE}" )" >/dev/null 2>&1 && pwd )"
    else
        PATH_TO_GAME="${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}/drive_c" || :
    fi
    cd "${PATH_TO_GAME}" || fatal "${PATH_TO_GAME} not found"

    if file "$PW_EXE_FILE" | grep -q "x86-64" ; then
        check_variables WINE_LARGE_ADDRESS_AWARE "0"
    else
        check_variables WINE_LARGE_ADDRESS_AWARE "1"
    fi

    PW_LD_LIBRARY_PATH="${PW_LD_LIBRARY_PATH}:${WINE_LIBRARY_PATH}"

    echo "##### Current variables #####" > "$PW_TMPFS_PATH/var.log"
    env | grep -E '^(DXVK_|VKD3D_|WINE|PATH|PW_)' \
        | grep -vE '^PW_GENERATE_' \
        | tee -a "$PW_TMPFS_PATH/var.log"

    proxy_launch_parameters=${LAUNCH_PARAMETERS//\\\\/\\}
    if [[ "$PW_USE_RUNTIME" == 1 ]] \
    && [[ "$PW_WINE_USE" != "USE_SYSTEM_WINE" ]]
    then
        unset PORT_SCRIPTS_PATH
        export OLDPWD="$(realpath "$PATH_TO_GAME")"
        if [[ "${PW_LOG}" == 1 ]] ; then
            echo "export PW_BASE_PFX=$PW_BASE_PFX" >> "$PW_LOG_FILE"
            echo "WINEDLLOVERRIDES=${WINEDLLOVERRIDES}" >> "${PW_LOG_FILE}"
            echo "------------------------------------" >> "${PW_LOG_FILE}"
            [[ -f "${PW_TMPFS_PATH}/update_pfx_log" ]] && cat "${PW_TMPFS_PATH}/update_pfx_log" >> "${PW_LOG_FILE}"
            echo "-" >> "${PW_LOG_FILE}"
            echo "Log WINE:" >> "${PW_LOG_FILE}"
            echo ""
            print_info "Log from RUNTIME and WINE:"
            ${PW_RUN_GAMESCOPE} \
            ${PW_INHIBIT_SLR} \
            ${PW_TASKSET_SLR} \
            ${pw_runtime} \
            LD_LIBRARY_PATH="${PW_LD_LIBRARY_PATH}" \
            LD_PRELOAD="${PW_LD_PRELOAD}" \
            VK_ADD_IMPLICIT_LAYER_PATH="${PW_VK_LAYER_PATH}" \
            VK_ADD_LAYER_PATH="${PW_VK_LAYER_PATH}" \
            VK_INSTANCE_LAYERS=${PW_VK_INSTANCE_LAYERS} \
            ${PW_GAMEMODERUN_SLR} \
            ${PW_ADD_VAR_SLR} \
            "${WINELOADER}" "$@" ${proxy_launch_parameters} &>>"${PW_LOG_FILE}"
        else
            if [[ "$PW_USE_TERMINAL" == 1 ]] ; then
                pw_init_runtime
            fi
            echo ""
            echo "Log WINE:" > "${PW_LOG_FILE}"
            ${PW_RUN_GAMESCOPE} \
            ${PW_INHIBIT_SLR} \
            ${PW_TASKSET_SLR} \
            ${pw_runtime} \
            LD_LIBRARY_PATH="${PW_LD_LIBRARY_PATH}" \
            LD_PRELOAD="${PW_LD_PRELOAD}" \
            VK_ADD_IMPLICIT_LAYER_PATH="${PW_VK_LAYER_PATH}" \
            VK_ADD_LAYER_PATH="${PW_VK_LAYER_PATH}" \
            VK_INSTANCE_LAYERS="${PW_VK_INSTANCE_LAYERS}" \
            ${PW_GAMEMODERUN_SLR} \
            ${PW_ADD_VAR_SLR} \
            "${WINELOADER}" "$@" ${proxy_launch_parameters} &>>"${PW_LOG_FILE}"
            print_info "Update prefix log:"
            [[ -f "${PW_TMPFS_PATH}/update_pfx_log" ]] && cat "${PW_TMPFS_PATH}/update_pfx_log"
            echo
            print_info "Log from RUNTIME and WINE:"
            awk '! a[$0]++' "${PW_LOG_FILE}"
            echo
        fi
    else
        if [[ "${PW_LOG}" == 1 ]] ; then
            echo "WINEDLLOVERRIDES=${WINEDLLOVERRIDES}" >> "${PW_LOG_FILE}"
            echo "------------------------------------" >> "${PW_LOG_FILE}"
            [[ -f "${PW_TMPFS_PATH}/update_pfx_log" ]] && cat "${PW_TMPFS_PATH}/update_pfx_log" >> "${PW_LOG_FILE}"
            echo "-" >> "${PW_LOG_FILE}"
            echo "Log WINE:" >> "${PW_LOG_FILE}"
            echo ""
            print_info "Log WINE:"
            env FAKE_VAR= \
            LD_LIBRARY_PATH="${PW_LD_LIBRARY_PATH}" \
            LD_PRELOAD="${PW_LD_PRELOAD}" \
            VK_ADD_IMPLICIT_LAYER_PATH="${PW_VK_LAYER_PATH}" \
            VK_ADD_LAYER_PATH="${PW_VK_LAYER_PATH}" \
            VK_INSTANCE_LAYERS="${PW_VK_INSTANCE_LAYERS}" \
            ${PW_RUN_GAMESCOPE} \
            ${PW_GAMEMODERUN_SLR} \
            ${PW_ADD_VAR_SLR} \
            ${PW_INHIBIT_SLR} \
            ${PW_TASKSET_SLR} \
            "${WINELOADER}" "$@" ${proxy_launch_parameters} &>>"${PW_LOG_FILE}"
            wait_wineserver
        else
            print_info "Update prefix log:"
            [[ -f "${PW_TMPFS_PATH}/update_pfx_log" ]] && cat "${PW_TMPFS_PATH}/update_pfx_log"
            echo ""
            echo "Log WINE:" > "${PW_LOG_FILE}"
            print_info "Log WINE:"
            env FAKE_VAR= \
            LD_LIBRARY_PATH="${PW_LD_LIBRARY_PATH}" \
            LD_PRELOAD="${PW_LD_PRELOAD}" \
            VK_ADD_IMPLICIT_LAYER_PATH="${PW_VK_LAYER_PATH}" \
            VK_ADD_LAYER_PATH="${PW_VK_LAYER_PATH}" \
            VK_INSTANCE_LAYERS="${PW_VK_INSTANCE_LAYERS}" \
            ${PW_RUN_GAMESCOPE} \
            ${PW_GAMEMODERUN_SLR} \
            ${PW_ADD_VAR_SLR} \
            ${PW_INHIBIT_SLR} \
            ${PW_TASKSET_SLR} \
            "${WINELOADER}" "$@" ${proxy_launch_parameters}
            wait_wineserver
        fi
    fi
}
export -f pw_run

steamplay_launch () {
    pw_check_and_download_plugins

    if [[ -n "${PW_EXE_FILE:-}" ]]; then
        local proton_runner
        local steamplay_ld_library_path
        cd "$(dirname "${PW_EXE_FILE}")"
        export PATH_TO_GAME="$(pwd)"
        export PORTWINE_DB_FILE="${PW_EXE_FILE}.ppdb"
        [[ -f "${PORTWINE_DB_FILE}" ]] && source "${PORTWINE_DB_FILE}"
        export PW_USE_SUPPLIED_DXVK_VKD3D="1"

        steamplay_ld_library_path="${LD_LIBRARY_PATH}:${STEAM_RUNTIME_LIBRARY_PATH}:${PW_PLUGINS_PATH}/portable/lib/lib64:${PW_PLUGINS_PATH}/portable/lib/lib32"
        [[ -d "${HOME}/.local/share/Steam/ubuntu12_32" ]] && steamplay_ld_library_path="${steamplay_ld_library_path}:${HOME}/.local/share/Steam/ubuntu12_32"
        [[ -d "${HOME}/.local/share/Steam/ubuntu12_64" ]] && steamplay_ld_library_path="${steamplay_ld_library_path}:${HOME}/.local/share/Steam/ubuntu12_64"

        if [[ -f "$PATH_TO_GAME/MangoHud.conf" ]] ; then
            unset MANGOHUD_CONFIG
            export MANGOHUD_CONFIGFILE="$PATH_TO_GAME/MangoHud.conf"
            print_info "Custom MangoHud.conf in use: $MANGOHUD_CONFIGFILE"
        elif [[ "${PW_MANGOHUD_USER_CONF}" == 1 ]] ; then
            unset MANGOHUD_CONFIG
        fi

        pw_optiscaler_sync_files

        PORT_WINE_PREFIX="$STEAM_COMPAT_DATA_PATH/pfx"

        pw_prepare_gamescope_launch

        if check_gamescope_session ; then
            export PW_GAMEMODERUN_SLR=""
        elif [[ "$PW_USE_GAMEMODE" = "1" ]] \
        && [[ -n "$DBUS_SESSION_BUS_ADDRESS" ]]
        then
            pw_enable_gamemode_basic
        fi

        pw_enable_idle_inhibit

        pw_set_sync_runtime_vars

        # Mangohud, VkBasalt, LSFG
        if [[ "$PW_USE_SYSTEM_VK_LAYERS" == "1" ]] ; then
            unset PW_VK_LAYER_PATH
        else
            export PW_VK_LAYER_PATH="${PW_PLUGINS_PATH}/portable/share/vulkan/implicit_layer.d"
        fi

        pw_mangohud_check
        pw_vkbasalt_check
        pw_lsfg_vk_check

        export VK_ADD_IMPLICIT_LAYER_PATH="${PW_VK_LAYER_PATH}"
        export VK_ADD_LAYER_PATH="${PW_VK_LAYER_PATH}"
        export VK_INSTANCE_LAYERS="${PW_VK_INSTANCE_LAYERS}"

        [[ $PW_LOG != 1 ]] && debug_timer --start -s "PW_TIME_IN_GAME"

        if [[ "${PW_WINE_USE,,}" != *proton* ]] ; then
            fatal "Steamplay don\`t work with ${PW_WINE_USE}!"
        else
            init_wine_ver
        fi

        check_proton_runner () {
            if [[ -x "${STEAM_COMPAT_TOOL_PATHS%%:*}/proton" ]] ; then
                proton_runner="${STEAM_COMPAT_TOOL_PATHS%%:*}/proton"
            elif [[ "${PW_WINE_USE:-}" = /* ]] && [[ -x "${PW_WINE_USE}/proton" ]] ; then
                proton_runner="${PW_WINE_USE}/proton"
            elif [[ -x "${PORT_DATA_PATH}/data/dist/${PW_WINE_USE^^}/proton" ]] ; then
                proton_runner="${PORT_DATA_PATH}/data/dist/${PW_WINE_USE^^}/proton"
                export PW_WINE_USE="${PW_WINE_USE^^}"
            elif [[ -x "${WINEDIR}/proton" ]] ; then
                proton_runner="${WINEDIR}/proton"
            elif [[ -x "${WINEDIR%/files}/proton" ]] ; then
                proton_runner="${WINEDIR%/files}/proton"
            else
                return 1
            fi
            return 0
        }

        if ! check_proton_runner ; then
            gui_proton_downloader "${PW_WINE_USE}"
            init_wine_ver
            if ! check_proton_runner ; then
                fatal "$PW_WINE_USE not found!"
            fi
        fi

        # Winetricks
        if [[ -n "${PW_DLL_INSTALL:-}" ]] ; then
            update_winetricks
            PATH="${PATH}:${PW_PLUGINS_PATH}/portable/bin" LD_LIBRARY_PATH="${steamplay_ld_library_path}" \
                "${PORT_WINE_TMP_PATH}/winetricks" -q ${PW_DLL_INSTALL}
        fi

        # Virtual Desktop
        if [[ "${PW_VIRTUAL_DESKTOP}" == "1" ]] ; then
            if [[ "${PW_SCREEN_RESOLUTION:-}" != *x* ]] ; then
                if [[ -f "${PW_TMPFS_PATH}/xrandr.tmp" ]] ; then
                    PW_SCREEN_RESOLUTION="$(sed -rn 's/^.*primary.* ([0-9]+x[0-9]+).*$/\1/p' "${PW_TMPFS_PATH}/xrandr.tmp")"
                fi
                [[ "${PW_SCREEN_RESOLUTION:-}" != *x* ]] && PW_SCREEN_RESOLUTION="1920x1080"
            fi
            "${proton_runner}" "run" reg add "HKEY_CURRENT_USER\\Software\\Wine\\Explorer\\Desktops" /v "PortProton" /d "${PW_SCREEN_RESOLUTION}" /f &>/dev/null
            "${proton_runner}" "run" reg add "HKEY_CURRENT_USER\\Software\\Wine\\Explorer" /v "Desktop" /d "PortProton" /f &>/dev/null
            print_info "Steam Play virtual desktop enabled in registry: ${PW_SCREEN_RESOLUTION}"
        else
            "${proton_runner}" "run" reg delete "HKEY_CURRENT_USER\\Software\\Wine\\Explorer" /v "Desktop" /f &>/dev/null
            "${proton_runner}" "run" reg delete "HKEY_CURRENT_USER\\Software\\Wine\\Explorer\\Desktops" /v "PortProton" /f &>/dev/null
            print_info "Steam Play virtual desktop disabled in registry"
        fi

        print_info "$proton_runner in use."
        ${PW_RUN_GAMESCOPE} \
        env \
        LD_LIBRARY_PATH="${steamplay_ld_library_path}" \
        LD_PRELOAD="${LD_PRELOAD:+$LD_PRELOAD:}${PW_LD_PRELOAD}" \
        ${PW_ADD_VAR_SLR} \
        ${PW_GAMEMODERUN_SLR} \
        ${PW_TASKSET_SLR} \
        "${proton_runner}" waitforexitandrun "${PW_EXE_FILE}" "$@"
        if [[ $PW_LOG != 1 ]] && [[ -n $START_PW_TIME_IN_GAME ]] ; then
            debug_timer --end -s "PW_TIME_IN_GAME"
            PW_TIME_IN_GAME=$(( PW_TIME_IN_GAME / 1000 ))
            search_desktop_file
        fi
    fi
}

portwine_launch () {
    start_portproton
    unset PW_VD_TMP
    if [[ "${PW_VIRTUAL_DESKTOP}" == "1" ]] ; then
        PW_VD_TMP=(explorer "/desktop=PortProton,${PW_SCREEN_RESOLUTION}")
    fi

    [[ $PW_LOG != 1 ]] && debug_timer --start -s "PW_TIME_IN_GAME"
    if [[ -n "${LAUNCH_URI}" ]] ; then
        export WINEFSYNC="1"
        pw_run start /high /b "${LAUNCH_URI}" &
        unset GAMEPID
        while true ; do
            sleep 5
            if [[ -z "$GAMEPID" ]] ; then
                GAMEPID="$(pgrep -fa 'EpicPortal|epicusername|epiclocale|AUTH_LOGIN' | awk '{print $1}' | head -n 1)"
            else
                if waitpid "$GAMEPID" ; then
                    sleep 1
                    GAMEPID="$(pgrep -fa 'EpicPortal|epicusername|epiclocale|AUTH_LOGIN' | awk '{print $1}' | head -n 1)"
                    [[ -z "$GAMEPID" ]] && break || continue
                fi
            fi
        done
    else
        if [[ -n "${PW_RUN_AFTER_EXE:-}" ]] \
        && [[ -f "${PW_RUN_AFTER_EXE}" ]] \
        && [[ "${PW_RUN_AFTER_EXE}" != "${PW_EXE_FILE}" ]] \
        && [[ "${PW_EXE_FILE,,}" =~ \.exe$ ]]
        then
            local wait_delay wait_delay_int run_after_bat
            wait_delay="${PW_RUN_AFTER_DELAY:-3}"
            wait_delay_int="${wait_delay%%.*}"
            [[ "${wait_delay_int}" =~ ^[0-9]+$ ]] || wait_delay_int="3"

            run_after_bat="${PW_TMPFS_PATH}/pw_run_after_exe_${PW_PREFIX_NAME:-DEFAULT}_$$.bat"

            cat > "${run_after_bat}" <<EOF
@echo off
start "" "z:${PW_EXE_FILE}"
timeout /t ${wait_delay_int} /nobreak
start "" "z:${PW_RUN_AFTER_EXE}"
EOF

            pw_run "${PW_VD_TMP[@]}" cmd /c "z:${run_after_bat}"
            try_remove_file "${run_after_bat}"
        else
            case "${PW_EXE_FILE,,}" in
                *.exe)
                    pw_run "${PW_VD_TMP[@]}" ${WINE_WIN_START} "${PW_EXE_FILE}"
                ;;
                *.bat)
                    PW_USE_TERMINAL=1
                    pw_run "${PW_VD_TMP[@]}" "${PW_EXE_FILE}"
                ;;
                *.msi)
                    pw_run "${PW_VD_TMP[@]}" msiexec /i "${PW_EXE_FILE}"
                ;;
                *.reg)
                    pw_run "${PW_VD_TMP[@]}" regedit "${PW_EXE_FILE}"
                ;;
                *)
                    pw_run "${PW_VD_TMP[@]}" winefile
                ;;
            esac
        fi
    fi
}

# GUI GET OTHER WINE
gui_proton_downloader () {
    try_remove_file "${PW_TMPFS_PATH}/tmp_installed_wine"
    try_remove_file "${PW_TMPFS_PATH}/tmp_set_wine"
    create_new_dir "${PORT_DATA_PATH}/data/dist"

    PW_WINE_USE="$1"
    if [[ "${PW_WINE_USE^^}" == PROTON_LG ]]
    then PW_WINE_USE="${PW_PROTON_LG_VER}"
    elif [[ "${PW_WINE_USE^^}" == WINE_*_LG ]] || [[ "${PW_WINE_USE^^}" == WINE_LG ]]
    then PW_WINE_USE="${PW_WINE_LG_VER}"
    fi
    export PW_WINE_USE

    if [[ "${PW_WINE_USE}" = /* ]] && [[ -d "${PW_WINE_USE}" ]] ; then
        return 0
    elif [[ -d "${PORT_DATA_PATH}/data/dist/${PW_WINE_USE^^}" ]] ; then
        return 0
    fi

    METADATA_URL="https://git.linux-gaming.ru/Boria138/PortProton-Wine-Metadata/raw/branch/main/wine_metadata.json"
    METADATA=$(curl  -A 'PortProton' -s "$METADATA_URL")
    if [[ -z "$METADATA" ]] ; then
        fatal "failed to fetch metadata"
    fi

    pw_download_get_wine () {
        local URL_VERSION_PROTON_GIT
        local VERSION="$1"
        local ALL_CATEGORIES=$(echo "$METADATA" | jq -r 'keys[]' 2>/dev/null)
        print_info "Download and install ${VERSION}..."
        URL_VERSION_PROTON_GIT=$(echo "$METADATA" | jq -r --arg version "$VERSION" '
        to_entries[] | .value[]? | select((.name | ascii_downcase) == ($version | ascii_downcase)) | .url
        ' 2>/dev/null | head -n 1)
        if [[ -z "$URL_VERSION_PROTON_GIT" ]]; then
            fatal "no URL found for version ${VERSION}"
        fi
        FILENAME=$(echo "$URL_VERSION_PROTON_GIT" | awk -F/ '{print $NF}')
        if [[ "$URL_VERSION_PROTON_GIT" =~ (_LG|_HYP|_STEAM) ]]; then
            USE_MIRROR=""
        else
            USE_MIRROR="no_mirror"
        fi
        if try_download "${URL_VERSION_PROTON_GIT}" "${PORT_DATA_PATH}/data/tmp/$FILENAME" "$USE_MIRROR" ; then
            if unpack "${PORT_DATA_PATH}/data/tmp/${FILENAME}" "${PORT_DATA_PATH}/data/dist/" ; then
                try_remove_file "${PORT_DATA_PATH}/data/tmp/${FILENAME}"
                if [[ -n "${PW_EXE_FILE}" ]] ; then
                    PW_WINE_USE=${VERSION^^}
                    edit_db_from_gui PW_WINE_USE
                fi
            else
                try_remove_file "${PORT_DATA_PATH}/data/tmp/${FILENAME}"
                try_remove_dir "${PORT_DATA_PATH}/data/dist/${FILENAME}"
                fatal "Failed to download and unpack WINE"
            fi
        else
            fatal "Failed to download and unpack WINE"
        fi
    }

    pw_download_get_wine "$PW_WINE_USE"
}
export -f gui_proton_downloader

# GUI EDIT_DB
gui_edit_db () {
    KEY_EDIT_DB_GUI=$RANDOM
    DISABLE_EDIT_DB_LIST=""
    PW_EDIT_DB_LIST=(PW_MANGOHUD PW_MANGOHUD_USER_CONF PW_VKBASALT PW_VKBASALT_USER_CONF PW_DGVOODOO2
    PW_USE_ESYNC PW_USE_FSYNC PW_USE_NTSYNC PW_USE_RAY_TRACING PW_USE_NVAPI_AND_DLSS PW_USE_OPTISCALER
    PW_USE_LS_FRAME_GEN PW_WINE_FULLSCREEN_FSR PW_HIDE_NVIDIA_GPU PW_VIRTUAL_DESKTOP PW_USE_TERMINAL
    PW_USE_GAMEMODE PW_USE_INHIBIT_SLEEP PW_USE_D3D_EXTRAS PW_FIX_VIDEO_IN_GAME PW_REDUCE_PULSE_LATENCY
    PW_USE_US_LAYOUT PW_USE_GSTREAMER PW_USE_SHADER_CACHE PW_USE_WINE_DXGI PW_USE_EAC_AND_BE
    PW_USE_SYSTEM_VK_LAYERS PW_USE_OBS_VKCAPTURE PW_DISABLE_COMPOSITING PW_USE_RUNTIME PW_DINPUT_PROTOCOL
    PW_USE_GALLIUM_ZINK PW_USE_GALLIUM_NINE PW_USE_WINED3D_VULKAN PW_USE_SUPPLIED_DXVK_VKD3D
    PW_USE_NATIVE_WAYLAND PW_USE_DXVK_HDR PW_GAMESCOPE)

    if check_wayland_session
    then DISABLE_EDIT_DB_LIST+=" PW_USE_US_LAYOUT"
    else DISABLE_EDIT_DB_LIST+=" PW_USE_NATIVE_WAYLAND"
    fi
    if [[ ! -e "/var/run/dbus/system_bus_socket" ]] ; then
        DISABLE_EDIT_DB_LIST+=" PW_USE_INHIBIT_SLEEP"
    fi
    if [[ $PW_WINE_USE =~ (PROTON_LG|WINE_LG) ]] || [[ $PW_VULKAN_USE == "0" ]] ; then
        DISABLE_EDIT_DB_LIST+=" PW_USE_SUPPLIED_DXVK_VKD3D"
    fi

    if [[ ! -f "${PW_WINELIB}/runtime/files/bin/vkcube" ]] \
    || [[ ! -f "${PW_WINELIB}/pressure-vessel/bin/pressure-vessel-wrap" ]]
    then
        DISABLE_EDIT_DB_LIST+=" PW_USE_RUNTIME"
    fi

    # GALLIUM NINE
    [[ ! -f "${PW_TMPFS_PATH}/gallium_nine.tmp" ]] && DISABLE_EDIT_DB_LIST+=" PW_USE_GALLIUM_NINE"
    [[ $PW_VULKAN_USE == "1" ]] && add_to_array "PW_EDIT_DB_LIST"

    if [[ "$PW_VULKAN_USE" == "0" ]] ; then
        DISABLE_EDIT_DB_LIST+=" PW_VKBASALT PW_VKBASALT_USER_CONF PW_USE_RAY_TRACING PW_USE_OBS_VKCAPTURE PW_USE_GALLIUM_ZINK PW_USE_WINED3D_VULKAN"
    fi

    [[ ! -e "/dev/ntsync" ]] && DISABLE_EDIT_DB_LIST+=" PW_USE_NTSYNC"

    if [[ -n "$PW_SOUND_DRIVER_USE" ]] \
    && [[ "$PW_SOUND_DRIVER_USE" != "disabled" ]]
    then
        SOUND_DRIVER_VAR="$PW_SOUND_DRIVER_USE"
    else
        SOUND_DRIVER_VAR="disabled"
    fi

    if ! check_flatpak \
    && ! compare_versions "$(ldd --version | head -n 1 | awk '{print $NF}')" "2.38"
    then
        export PW_USE_LS_FRAME_GEN="0"
    fi

    if [[ "${PW_WINE_CPU_TOPOLOGY}" == *[0-9]:* ]] \
    && [[ "${PW_WINE_CPU_TOPOLOGY}" != "disabled" ]]
    then
        CPU_LIMIT_VAR="${PW_WINE_CPU_TOPOLOGY%%:*}"
    else
        CPU_LIMIT_VAR="disabled"
    fi

    declare -A NODE_MAP
    NUMA_NODE_LIST=""
    INDEX=0
    while read -r line; do
        NODE_MAP[$INDEX]="$line"
        NUMA_NODE_LIST+="$INDEX "
        ((INDEX++))
    done < <( lscpu | grep -Po "NUMA node\d+ CPU\(s\):\s+\K.*" )
    # удаляем последний пробел, чтобы в combobox не было «0 »
    NUMA_NODE_LIST="${NUMA_NODE_LIST% }"

    if [[ -n "${PW_CPU_NUMA_NODE_INDEX}" ]] && [[ "${PW_CPU_NUMA_NODE_INDEX}" != "disabled" ]]; then
        NUMA_NODE_INDEX="${PW_CPU_NUMA_NODE_INDEX}"
    else
        NUMA_NODE_INDEX="disabled"
    fi

    if [[ $NUMA_NODE_INDEX =~ ^[0-9]+$ ]] && [[ -v NODE_MAP[$NUMA_NODE_INDEX] ]] ; then
        NUMA_CORES="${NODE_MAP[$NUMA_NODE_INDEX]}"
        PW_CPU_NUMA_NODE_INDEX="$NUMA_NODE_INDEX"
        PW_TASKSET_SLR="taskset -c $NUMA_CORES"
    else
        PW_CPU_NUMA_NODE_INDEX="disabled"
        PW_TASKSET_SLR=""
    fi
    export PW_CPU_NUMA_NODE_INDEX PW_TASKSET_SLR

    if [[ $CPU_LIMIT =~ ^[0-9]+$ ]] ; then
        PW_WINE_CPU_TOPOLOGY="${CPU_LIMIT}:$(seq -s, 0 $(( CPU_LIMIT - 1 )))"
    else
        PW_WINE_CPU_TOPOLOGY="disabled"
    fi
    export PW_WINE_CPU_TOPOLOGY

    PW_EDIT_DB_FINAL_LIST=("${PW_EDIT_DB_LIST[@]}" LAUNCH_PARAMETERS PW_RUN_AFTER_EXE \
    PW_RUN_AFTER_DELAY PW_WINDOWS_VER PW_DLL_INSTALL WINEDLLOVERRIDES PW_WINE_CPU_TOPOLOGY \
    PW_MESA_GL_VERSION_OVERRIDE PW_VKD3D_FEATURE_LEVEL PW_LOCALE_SELECT PW_MESA_VK_WSI_PRESENT_MODE \
    PW_SOUND_DRIVER_USE PW_CPU_NUMA_NODE_INDEX PW_TASKSET_SLR)

    edit_db_from_gui "${PW_EDIT_DB_FINAL_LIST[@]}"

    if [[ -z "$MANGOHUD_CONFIG" ]] ; then
        MONITOR_HEIGHT="$(echo "$PW_SCREEN_RESOLUTION" | awk -F'x' '{print $2}')"
        MH_FONT_SIZE="font_size=$(( MONITOR_HEIGHT / 45 ))"

        if [[ -n "$MH_FONT_SIZE" ]]
        then MANGOHUD_CONFIG="$DEFAULT_MANGOHUD_CONFIG,$MH_FONT_SIZE"
        else MANGOHUD_CONFIG="$DEFAULT_MANGOHUD_CONFIG"
        fi

        edit_db_from_gui MANGOHUD_CONFIG
    fi
}

# Gamescope configuration and processing
# Common data for all gamescope functions
pw_gamescope_get_config() {
    case "$1" in
        --bool-vars)
            echo "\
PW_GS_FULLSCREEN PW_GS_FORCE_FULLSCREEN PW_GS_BORDERLESS_WINDOW PW_GS_MANGOAPP \
PW_GS_FORCE_GRAB_CURSOR PW_GS_HDR_FORCE_HEATMAP PW_GS_SDR_GAMMUT_WIDENESS \
PW_GS_FORCE_GRAB_KEYBOARD PW_GS_HDR_ENABLE PW_GS_HDR_ITM_ENABLE PW_GS_BACKEND_SDL \
PW_GS_FORCE_COMPOSITION PW_GS_HDR_FORCE_SUPPORT PW_GS_HDR_FORCE_OUTPUT \
PW_GS_EXPOSE_WAYLAND PW_GS_REALTIME_SCHEDULING \
"
            ;;
        --flag-to-var)
            cat <<'EOF'
-f:PW_GS_FULLSCREEN
--force-windows-fullscreen:PW_GS_FORCE_FULLSCREEN
-b:PW_GS_BORDERLESS_WINDOW
--force-grab-cursor:PW_GS_FORCE_GRAB_CURSOR
-g:PW_GS_FORCE_GRAB_KEYBOARD
--hdr-enabled:PW_GS_HDR_ENABLE
--hdr-itm-enabled:PW_GS_HDR_ITM_ENABLE
--sdr-gamut-wideness:PW_GS_SDR_GAMMUT_WIDENESS
--force-composition:PW_GS_FORCE_COMPOSITION
--hdr-debug-force-support:PW_GS_HDR_FORCE_SUPPORT
--hdr-debug-force-output:PW_GS_HDR_FORCE_OUTPUT
--hdr-debug-heatmap:PW_GS_HDR_FORCE_HEATMAP
--expose-wayland:PW_GS_EXPOSE_WAYLAND
--rt:PW_GS_REALTIME_SCHEDULING
--mangoapp:PW_GS_MANGOAPP
EOF
            ;;
        --var-to-arg)
            cat <<'EOF'
PW_GS_FULLSCREEN:-f
PW_GS_FORCE_FULLSCREEN:--force-windows-fullscreen
PW_GS_BORDERLESS_WINDOW:-b
PW_GS_FORCE_GRAB_CURSOR:--force-grab-cursor
PW_GS_FORCE_GRAB_KEYBOARD:-g
PW_GS_HDR_ENABLE:--hdr-enabled
PW_GS_HDR_ITM_ENABLE:--hdr-itm-enabled
PW_GS_SDR_GAMMUT_WIDENESS:--sdr-gamut-wideness
PW_GS_FORCE_COMPOSITION:--force-composition
PW_GS_HDR_FORCE_SUPPORT:--hdr-debug-force-support
PW_GS_HDR_FORCE_OUTPUT:--hdr-debug-force-output
PW_GS_HDR_FORCE_HEATMAP:--hdr-debug-heatmap
PW_GS_EXPOSE_WAYLAND:--expose-wayland
PW_GS_REALTIME_SCHEDULING:--rt
PW_GS_MANGOAPP:--mangoapp
PW_GS_BACKEND_SDL:--backend sdl
EOF
            ;;
        --arg-to-var)
            cat <<'EOF'
-W:PWGS_OUTPUT_WIDTH
-H:PWGS_OUTPUT_HEIGHT
-r:PW_GS_FRAME_LIMIT
-m:PW_GS_MAX_SCALE_FACTOR
-S:PW_GS_SCALER_MODE
-F:PW_GS_FILTER_MODE
--sharpness:PW_GS_UPSCALE_SHARPNESS
-s:PW_GS_MOUSE_SENSITIVITY
--hdr-sdr-content-nits:PW_GS_SDR_CONTENT_NITS
--hdr-itm-sdr-nits:PW_GS_ITM_SDR_NITS
--hdr-itm-target-nits:PW_GS_ITM_TARGET_NITS
-w:PWGS_INTERNAL_WIDTH
-h:PWGS_INTERNAL_HEIGHT
EOF
            ;;
        --defaults)
            cat <<'EOF'
PW_GS_SHOW_RESOLUTION:disabled
PW_GS_INTERNAL_RESOLUTION:1.0
PW_GS_FRAME_LIMIT:disabled
PW_GS_MAX_SCALE_FACTOR:0.0
PW_GS_SCALER_MODE:disabled
PW_GS_FILTER_MODE:disabled
PW_GS_UPSCALE_SHARPNESS:10
PW_GS_MOUSE_SENSITIVITY:0.0
PW_GS_SDR_CONTENT_NITS:400
PW_GS_ITM_SDR_NITS:0
PW_GS_ITM_TARGET_NITS:0
EOF
            ;;
    esac
}

# Unified gamescope processing function
# Usage: pw_gamescope_process <command>
# Commands: build_args, reset_vars, sanitize, parse_args
pw_gamescope_process () {
    local cmd="$1"
    local gs_var gs_val gs_arg gs_next gs_arg_i
    local -a gs_args_input gs_args_output

    case "$cmd" in
        reset_vars)
            # Reset all boolean variables to 0
            for gs_var in $(pw_gamescope_get_config --bool-vars) ; do
                printf -v "$gs_var" "%s" "0"
            done
            # Reset value variables to defaults
            while IFS=':' read -r gs_var gs_val ; do
                [[ -n "$gs_var" ]] && printf -v "$gs_var" "%s" "$gs_val"
            done <<< "$(pw_gamescope_get_config --defaults)"
            ;;

        build_args)
            PW_GAMESCOPE_ARGS_NEW=""
            # Build toggle flags
            while IFS=':' read -r gs_var gs_arg ; do
                [[ -n "$gs_var" && "${!gs_var}" == "1" ]] && PW_GAMESCOPE_ARGS_NEW+=" ${gs_arg}"
            done <<< "$(pw_gamescope_get_config --var-to-arg)"

            # Add resolution settings
            if [[ -n "${PW_GS_SHOW_RESOLUTION}" && "${PW_GS_SHOW_RESOLUTION}" != "disabled" ]] ; then
                local pwgs_res_sw pwgs_res_sh pwgs_res_iw pwgs_res_ih
                pwgs_res_sw="${PW_GS_SHOW_RESOLUTION%%x*}"
                pwgs_res_sh="${PW_GS_SHOW_RESOLUTION##*x}"
                pwgs_res_sw="${pwgs_res_sw%%-*}"
                pwgs_res_sh="${pwgs_res_sh%%-*}"
                PW_GAMESCOPE_ARGS_NEW+=" -W ${pwgs_res_sw} -H ${pwgs_res_sh}"

                if [[ -n "${PW_GS_INTERNAL_RESOLUTION}" && "${PW_GS_INTERNAL_RESOLUTION}" != "0.0" ]] ; then
                    pwgs_res_iw=$(awk -v w="$pwgs_res_sw" -v r="$PW_GS_INTERNAL_RESOLUTION" 'BEGIN { printf "%d", w * r }')
                    pwgs_res_ih=$(awk -v h="$pwgs_res_sh" -v r="$PW_GS_INTERNAL_RESOLUTION" 'BEGIN { printf "%d", h * r }')
                    PW_GAMESCOPE_ARGS_NEW+=" -w ${pwgs_res_iw} -h ${pwgs_res_ih}"
                fi
            fi

            # Add value-based flags
            [[ -n "${PW_GS_FRAME_LIMIT}" && "${PW_GS_FRAME_LIMIT}" != "disabled" ]] && PW_GAMESCOPE_ARGS_NEW+=" -r ${PW_GS_FRAME_LIMIT}"
            [[ -n "${PW_GS_MAX_SCALE_FACTOR}" && "${PW_GS_MAX_SCALE_FACTOR}" != "0.0" ]] && PW_GAMESCOPE_ARGS_NEW+=" -m ${PW_GS_MAX_SCALE_FACTOR}"
            [[ -n "${PW_GS_SCALER_MODE}" && "${PW_GS_SCALER_MODE}" != "disabled" ]] && PW_GAMESCOPE_ARGS_NEW+=" -S ${PW_GS_SCALER_MODE}"

            # Handle filter mode (with legacy support)
            if [[ -n "${PW_GS_FILTER_MODE}" && "${PW_GS_FILTER_MODE}" != "disabled" ]] ; then
                if [[ "${PW_GS_FILTER_MODE_OLD}" == "true" ]] ; then
                    [[ "${PW_GS_FILTER_MODE}" == "fsr" ]] && PW_GAMESCOPE_ARGS_NEW+=" -U"
                    [[ "${PW_GS_FILTER_MODE}" == "nis" ]] && PW_GAMESCOPE_ARGS_NEW+=" -Y"
                else
                    PW_GAMESCOPE_ARGS_NEW+=" -F ${PW_GS_FILTER_MODE}"
                fi
                PW_GAMESCOPE_ARGS_NEW+=" --sharpness ${PW_GS_UPSCALE_SHARPNESS}"
            fi

            # Add remaining value flags
            [[ -n "${PW_GS_MOUSE_SENSITIVITY}" && "${PW_GS_MOUSE_SENSITIVITY}" != "0.0" ]] && PW_GAMESCOPE_ARGS_NEW+=" -s ${PW_GS_MOUSE_SENSITIVITY}"
            [[ -n "${PW_GS_SDR_CONTENT_NITS}" && "${PW_GS_SDR_CONTENT_NITS}" != "400" ]] && PW_GAMESCOPE_ARGS_NEW+=" --hdr-sdr-content-nits ${PW_GS_SDR_CONTENT_NITS}"
            [[ -n "${PW_GS_ITM_SDR_NITS}" && "${PW_GS_ITM_SDR_NITS}" != "0" ]] && PW_GAMESCOPE_ARGS_NEW+=" --hdr-itm-sdr-nits ${PW_GS_ITM_SDR_NITS}"
            [[ -n "${PW_GS_ITM_TARGET_NITS}" && "${PW_GS_ITM_TARGET_NITS}" != "0" ]] && PW_GAMESCOPE_ARGS_NEW+=" --hdr-itm-target-nits ${PW_GS_ITM_TARGET_NITS}"
            ;;

        sanitize)
            local gs_disabled="Disabled" gs_disable="Disable"
            PW_GAMESCOPE_ARGS_NEW="${PW_GAMESCOPE_ARGS_NEW//${gs_disabled}/}"
            PW_GAMESCOPE_ARGS_NEW="${PW_GAMESCOPE_ARGS_NEW//${gs_disable}/}"
            read -r -a gs_args_input <<< "${PW_GAMESCOPE_ARGS_NEW}"

            for ((gs_arg_i=0; gs_arg_i<${#gs_args_input[@]}; gs_arg_i++)) ; do
                gs_arg="${gs_args_input[$gs_arg_i]}"
                gs_next="${gs_args_input[$((gs_arg_i + 1))]}"
                case "${gs_arg}" in
                    -f|-b|-g|--force-windows-fullscreen|--force-grab-cursor|--hdr-enabled|--hdr-itm-enabled|--sdr-gamut-wideness|--force-composition|--hdr-debug-force-support|--hdr-debug-force-output|--hdr-debug-heatmap|--expose-wayland|--rt|--mangoapp|-U|-Y)
                        gs_args_output+=("${gs_arg}") ;;
                    --backend|-W|-H|-w|-h|-r|-m|-S|-F|-s|--sharpness|--hdr-sdr-content-nits|--hdr-itm-sdr-nits|--hdr-itm-target-nits)
                        if [[ -n "${gs_next}" && ! "${gs_next}" =~ ^- ]] ; then
                            gs_args_output+=("${gs_arg}" "${gs_next}")
                            ((gs_arg_i++))
                        fi ;;
                esac
            done

            PW_GAMESCOPE_ARGS_NEW="${gs_args_output[*]}"
            [[ -n "${PW_GAMESCOPE_ARGS_NEW}" ]] && PW_GAMESCOPE_ARGS_NEW=" ${PW_GAMESCOPE_ARGS_NEW}"
            ;;

        parse_args)
            local -A flag_map val_map
            # Load flag mappings
            while IFS=':' read -r gs_arg gs_var ; do
                [[ -n "$gs_arg" ]] && flag_map[$gs_arg]="$gs_var"
            done <<< "$(pw_gamescope_get_config --flag-to-var)"
            # Load value mappings
            while IFS=':' read -r gs_arg gs_var ; do
                [[ -n "$gs_arg" ]] && val_map[$gs_arg]="$gs_var"
            done <<< "$(pw_gamescope_get_config --arg-to-var)"

            # Reset and parse
            pw_gamescope_process reset_vars
            read -r -a gs_args_input <<< "${PW_GAMESCOPE_ARGS_NEW}"

            for ((gs_arg_i=0; gs_arg_i<${#gs_args_input[@]}; gs_arg_i++)) ; do
                gs_arg="${gs_args_input[$gs_arg_i]}"
                gs_var="${flag_map[$gs_arg]}"

                if [[ -n "$gs_var" ]] ; then
                    printf -v "$gs_var" "%s" "1"
                    continue
                fi

                case "$gs_arg" in
                    --backend)
                        gs_next="${gs_args_input[$((gs_arg_i + 1))]}"
                        [[ "$gs_next" == "sdl" ]] && PW_GS_BACKEND_SDL="1"
                        ;;
                    -U) PW_GS_FILTER_MODE="fsr" ;;
                    -Y) PW_GS_FILTER_MODE="nis" ;;
                    *)
                        gs_var="${val_map[$gs_arg]}"
                        if [[ -n "$gs_var" ]] ; then
                            gs_next="${gs_args_input[$((gs_arg_i + 1))]}"
                            if [[ -n "$gs_next" && ! "$gs_next" =~ ^- ]] ; then
                                printf -v "$gs_var" "%s" "$gs_next"
                                ((gs_arg_i++))
                            fi
                        fi
                        ;;
                esac
            done

            # Reconstruct resolution and internal scaling
            if [[ -n "${PWGS_OUTPUT_WIDTH}" && -n "${PWGS_OUTPUT_HEIGHT}" ]] ; then
                PW_GS_SHOW_RESOLUTION="${PWGS_OUTPUT_WIDTH}x${PWGS_OUTPUT_HEIGHT}"
            fi
            [[ ! "${PW_GS_SHOW_RESOLUTION}" =~ ^[0-9]+x[0-9]+$ ]] && PW_GS_SHOW_RESOLUTION="disabled"

            if [[ "${PW_GS_SHOW_RESOLUTION}" != "disabled" && -n "${PWGS_INTERNAL_WIDTH}" && -n "${PWGS_INTERNAL_HEIGHT}" ]] ; then
                local out_w out_h
                out_w="${PW_GS_SHOW_RESOLUTION%%x*}"
                out_h="${PW_GS_SHOW_RESOLUTION##*x}"
                if [[ "$out_w" != "0" && "$out_h" != "0" ]] ; then
                    if [[ "${PWGS_INTERNAL_WIDTH}" == "$out_w" && "${PWGS_INTERNAL_HEIGHT}" == "$out_h" ]] ; then
                        PW_GS_INTERNAL_RESOLUTION="1.0"
                    else
                        PW_GS_INTERNAL_RESOLUTION="$(awk -v iw="${PWGS_INTERNAL_WIDTH}" -v ow="$out_w" 'BEGIN { printf "%.1f", iw / ow }')"
                    fi
                fi
            fi
            ;;
    esac
}

# RESIZE PNG FILE
resize_png () {
    if [[ -z "$1" ]] || [[ -z "$2" ]] ; then
        print_error "no argument specified for resize_png"
        return 1
    else
        local RESIZE_FILE RESIZE_NAME_PNG
        RESIZE_FILE="$1"
        RESIZE_NAME_PNG="${2// /_}"
    fi

    if [[ $RESIZE_NAME_PNG =~ ru.linux_gaming.PortProton/data/img/ ]]
    then RESIZE_NAME_PNG=${RESIZE_NAME_PNG/*ru.linux_gaming.PortProton\/data\/img\//}
    fi

    if [[ $RESIZE_NAME_PNG =~ [\!\%\$\&\<] ]] ; then
        local ICON_NAME_REGEX=(\! % \$ \& \<)
        for i in "${ICON_NAME_REGEX[@]}" ; do
            RESIZE_NAME_PNG="${RESIZE_NAME_PNG//$i/}"
        done
    fi

    if [[ -f "${PORT_DATA_PATH}/data/img/${RESIZE_NAME_PNG}.png" ]] \
    || [[ ! -f "${RESIZE_FILE}" ]] \
    || [[ ! ${RESIZE_FILE,,} =~ .exe$ ]]
    then
        return 0
    fi

    try_remove_file "${PORT_DATA_PATH}/data/img/launcher.png"
    try_remove_file "${PORT_DATA_PATH}/data/img/Launcher.png"

    python3 -m portprotonqt.scripts_utils.shortcut_tools thumbnail \
    "$(readlink -f "${RESIZE_FILE}")" \
    "${PORT_DATA_PATH}/data/img/${RESIZE_NAME_PNG}.png"
}

portwine_create_shortcut () {
    if [[ ! -e $PW_EXE_FILE ]]
    then return 1
    elif [[ $(basename "$PW_EXE_FILE") =~ (unins0|uninstall|remove) ]]
    then return 0
    fi
    pw_create_gui_png

    check_variables PW_SHORTCUT_MENU "TRUE"
    check_variables PW_SHORTCUT_DESKTOP "TRUE"

    unset name_desktop
    create_name_desktop
    export name_desktop="$PW_NAME_DESKTOP_PROXY"
    portwine_output_yad_shortcut
}

portwine_output_yad_shortcut () {

        [[ ! -e "${PW_EXE_FILE}" ]] && return 1

        pw_create_gui_png
        unset name_desktop
        check_variables PW_SHORTCUT_MENU "TRUE"
        check_variables PW_SHORTCUT_DESKTOP "TRUE"

        if [[ -z $name_desktop ]] ; then
            create_name_desktop
            export name_desktop="$PW_NAME_DESKTOP_PROXY"
        fi

        if ! python3 -m portprotonqt.scripts_utils.shortcut_tools shortcut \
        "${PW_EXE_FILE}" \
        "${name_desktop}"
        then
            return 1
        fi

        if [[ "${PW_SHORTCUT_MENU}" == "TRUE" ]] ; then
            try_remove_file "${HOME}/.local/share/applications/${name_desktop}.desktop"
            cp -f "${PORT_DATA_PATH}/${name_desktop}.desktop" "${HOME}/.local/share/applications/"
        fi

        if [[ "${PW_SHORTCUT_DESKTOP}" == "TRUE" ]] ; then
            if [[ -d "${HOME}/Desktop" ]] ; then
                cp -f "${PORT_DATA_PATH}/${name_desktop}.desktop" "${HOME}/Desktop/"
            elif [[ -d "${HOME}/Рабочий стол" ]] ; then
                cp -f "${PORT_DATA_PATH}/${name_desktop}.desktop" "${HOME}/Рабочий стол/"
            elif [[ $(xdg-user-dir DESKTOP) ]] ; then
                cp -f "${PORT_DATA_PATH}/${name_desktop}.desktop" "$(xdg-user-dir DESKTOP)"
            fi
        fi

        export PW_NEW_DESKTOP="1"

        if [[ "$PW_NO_RESTART_PPDB" != "1" ]] \
        || [[ -z ${LINKS[0]} ]]
        then
            exit 0
        fi
}

parse_lnk () {
    prefix_name=$(echo "$1" | awk -F"/prefixes/" '{print $2}' | awk -F"/" '{print $1}')
    if fix_icon_name=$(grep -i "Icon File Name" "${PW_TMPFS_PATH}/exiftool.tmp" 2>/dev/null) && [[ "${fix_icon_name//*.exe/true}" == "true" ]] ; then
        exe_path=$(sed -n 's/^Icon File Name\s*:\s*//p' "${PW_TMPFS_PATH}/exiftool.tmp")
    else
        exe_path=$(sed -n 's/^Local Base Path\s*:\s*//p' "${PW_TMPFS_PATH}/exiftool.tmp")
    fi
    get_lnk_path "${exe_path}"
    link_name=$(sed -n 's/^File Name\s*:\s*//p' "${PW_TMPFS_PATH}/exiftool.tmp" | sed 's|\.lnk||')
    link_cmd=$(sed -n 's/^Command Line Arguments\s*:\s*//p' "${PW_TMPFS_PATH}/exiftool.tmp")
}

get_lnk_path () {
    link_drive=$(echo "$1" | cut -d: -f1 | awk '{print tolower($0)}')
    link_path=$(echo "$1" | sed 's|%ProgramFiles(x86)%|C:\\Program Files (x86)|gi;s|%ProgramFiles%|C:\\Program Files|gi' | sed "s|^.|${PORT_DATA_PATH}/data/prefixes/${prefix_name:-${PW_PREFIX_NAME:-DEFAULT}}/dosdevices/${link_drive}|g" | sed 's/\\/\//g')
}

pw_auto_create_shortcut () {
    if [[ "${PW_CHECK_AUTOINSTALL}" == "1" ]] \
    || [[ "${PW_NO_AUTO_CREATE_SHORTCUT}" == "1" ]] \
    || [[ -z "${PW_EXE_FILE}" ]] \
    || echo "${PW_EXE_FILE}" | grep -i "gc_api.exe\|vkplay\|pulseonline\|hoyoplay_launcher_pp" &>/dev/null
    then
        print_warning "Skipping auto create shortcut"
        return 0
    fi

    if [[ "${PW_EXE_FILE}" =~ EpicGamesLauncher.exe$ ]]; then
        for item_file in "${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}/drive_c/ProgramData/Epic/EpicGamesLauncher/Data/Manifests/"*".item"; do
            if [[ -f "${item_file}" ]]; then
                exe_path=$(jq -r '.InstallLocation + "\\" + .LaunchExecutable' "${item_file}")
                get_lnk_path "${exe_path}"
                PORTWINE_CREATE_SHORTCUT_NAME=$(jq -r '.DisplayName' "${item_file}")
                if ! exe_path="$(realpath "${link_path}" 2>/dev/null)" || [[ ! -f "${exe_path}" ]]; then
                    print_warning "Link broken for: ${PORTWINE_CREATE_SHORTCUT_NAME}"
                elif [[ ! -f "${exe_path}.ppdb" ]]; then
                    unset FILE_SHA256SUM DESKTOP_NAME_FILE DESKTOP_CORRECT_FILE
                    item_id=$(jq -r '.AppName' "${item_file}")
                    PW_EXE_FILE="${exe_path}"
                    PORTWINE_DB_FILE="${PW_EXE_FILE}.ppdb"
                    LAUNCH_URI="com.epicgames.launcher://apps/${item_id}?action=launch&silent=true"
                    pw_init_db
                    export PW_NO_RESTART_PPDB="1"
                    edit_db_from_gui PW_PREFIX_NAME LAUNCH_URI
                    unset name_desktop_png
                    portwine_create_shortcut
                fi
            fi
        done
        return 0
    fi

    unset LINKS
    print_info "checking *.lnk files"
    for link_file in "${PORT_DATA_PATH}"/data/prefixes/*/drive_c/users/${USER}/Desktop/*.lnk \
                     "${PORT_DATA_PATH}"/data/prefixes/*/drive_c/users/Public/Desktop/*.lnk
    do
        [[ ! -f $link_file ]] && continue
        link_file=$(readlink -f "$link_file")
        LINKS+=("${link_file// /#@_@#}")
    done

    [[ -z "${LINKS[0]}" ]] && return 0
    read -r -a SORTED_LINKS < <(echo "${LINKS[@]}" | tr ' ' '\n' | sort -u | tr '\n' ' ')

    for link_file in "${SORTED_LINKS[@]//#@_@#/ }" ; do
        use_exiftool "${link_file}"
        parse_lnk "${link_file}"
        link_path="${link_path//\.exe\//\.exe}"
        if exe_path="$(realpath "${link_path}" 2>/dev/null)" ; then
            export PW_EXE_FILE="$exe_path"
        elif exe_path="$(realpath "${link_path//\/Games\//\/games\//}" 2>/dev/null)" ; then
            export PW_EXE_FILE="$exe_path"
        elif exe_path="$(realpath "${link_path//\/Games\//\/GAMES\//}" 2>/dev/null)" ; then
            export PW_EXE_FILE="$exe_path"
        else
            print_warning "Link broken for: $link_name"
            continue
        fi
        print_info "Created link for: $link_name"
        PORTPROTON_NAME="$link_name"
        resize_png "$PW_EXE_FILE" "${PORTPROTON_NAME}"
        export PW_NO_RESTART_PPDB=1
        unset name_desktop_png
        portwine_create_shortcut
    done
}
export -f pw_auto_create_shortcut

portwine_search_shortcut () {
    unset PW_DELETE_SHORTCUT_MENU PW_DELETE_SHORTCUT_STEAM PW_DELETE_SHORTCUT_DESKTOP
    if [[ -n "${PW_EXE_FILE}" ]]; then
        PW_DELETE_MENU="$(grep -il "${PW_EXE_FILE}" "${HOME}/.local/share/applications"/*.desktop 2>/dev/null)"
        read -r -d '' -a PW_DELETE_SHORTCUT_MENU <<< "${PW_DELETE_SHORTCUT_MENU[*]} ${PW_DELETE_MENU// /#@_@#}"

        PW_DELETE_PP="$(grep -il "${PW_EXE_FILE}" "${PORT_DATA_PATH}"/*.desktop 2>/dev/null)"
        read -r -d '' -a PW_DELETE_SHORTCUT_MENU <<< "${PW_DELETE_SHORTCUT_MENU[*]} ${PW_DELETE_PP// /#@_@#}"

        PW_DELETE_STEAM="$(grep -il "${PW_EXE_FILE}" "${STEAM_SCRIPTS}"/*.sh 2>/dev/null)"
        read -r -d '' -a PW_DELETE_SHORTCUT_STEAM <<< "${PW_DELETE_SHORTCUT_STEAM[*]} ${PW_DELETE_STEAM// /#@_@#}"

        if [[ -d "${HOME}/Desktop" ]] ; then
            PW_DELETE_DESKTOP="$(grep -il "${PW_EXE_FILE}" "${HOME}/Desktop"/*.desktop 2>/dev/null)"
            read -r -d '' -a PW_DELETE_SHORTCUT_DESKTOP <<< "${PW_DELETE_SHORTCUT_DESKTOP[*]} ${PW_DELETE_DESKTOP// /#@_@#}"
        fi
        if [[ -d "${HOME}/Рабочий стол" ]] ; then
            PW_DELETE_DESKTOP="$(grep -il "${PW_EXE_FILE}" "${HOME}/Рабочий стол"/*.desktop 2>/dev/null)"
            read -r -d '' -a PW_DELETE_SHORTCUT_DESKTOP <<< "${PW_DELETE_SHORTCUT_DESKTOP[*]} ${PW_DELETE_DESKTOP// /#@_@#}"
        fi
        if [[ $(xdg-user-dir DESKTOP) ]] ; then
            PW_DELETE_DESKTOP="$(grep -il "${PW_EXE_FILE}" "$(xdg-user-dir DESKTOP)"/*.desktop 2>/dev/null)"
            read -r -d '' -a PW_DELETE_SHORTCUT_DESKTOP <<< "${PW_DELETE_SHORTCUT_DESKTOP[*]} ${PW_DELETE_DESKTOP// /#@_@#}"
        fi
    fi
}

pw_create_prefix_backup_cli () {
    PW_PREFIX_NAME="$1"
    PW_PREFIX_TO_BACKUP="$2"

    python3 -m portprotonqt.scripts_utils.prefix_backup --port-data-path "${PORT_DATA_PATH}" \
        backup "${PW_PREFIX_NAME}" "${PW_PREFIX_TO_BACKUP}"
    return $?
}

pw_is_legacy_prefix_backup () {
    [[ "$(head -c 4 "$1" 2>/dev/null)" == "hsqs" ]]
}

pw_unpack_legacy_prefix () {
    PW_PREFIX_NAME=$(basename "${PW_BACKUP_FILE}")
    PW_PREFIX_NAME="${PW_PREFIX_NAME%.[Pp][Pp][Aa][Cc][Kk]}"

    unset PW_SANDBOX_HOME_PATH
    pw_init_runtime

    try_remove_file "${PORT_WINE_TMP_PATH}/pp_pfx_unpack_error"
    echo "#!/usr/bin/env bash
    unsquashfs -no-xattrs -f -d \
    \"${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}\" \"$PW_BACKUP_FILE\" \
    || echo \"ERROR\" > \"${PORT_WINE_TMP_PATH}/pp_pfx_unpack_error\"
    " > "${PORT_WINE_TMP_PATH}/pp_pfx_unpack.sh"

    chmod u+x "${PORT_WINE_TMP_PATH}/pp_pfx_unpack.sh"
    ${pw_runtime} ${PW_TERM} "${PORT_WINE_TMP_PATH}/pp_pfx_unpack.sh"

    if grep "ERROR" "${PORT_WINE_TMP_PATH}/pp_pfx_unpack_error" &>/dev/null; then
        try_remove_file "${PORT_WINE_TMP_PATH}/pp_pfx_unpack_error"
        try_remove_file "${PORT_WINE_TMP_PATH}/pp_pfx_unpack.sh"
        return 1
    fi
    try_remove_file "${PORT_WINE_TMP_PATH}/pp_pfx_unpack_error"
    try_remove_file "${PORT_WINE_TMP_PATH}/pp_pfx_unpack.sh"
    if [[ -f "${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}/.create_shortcut" ]] ; then
        while read -r line
        do
            export PW_EXE_FILE="$PORT_DATA_PATH/data/prefixes/$PW_PREFIX_NAME/$line"
            portwine_output_yad_shortcut
        done < "$PORT_DATA_PATH/data/prefixes/$PW_PREFIX_NAME/.create_shortcut"
    fi
    return 0
}

pw_unpack_prefix () {
    PW_BACKUP_FILE="$1"

    PW_PREFIX_NAME=$(basename "${PW_BACKUP_FILE}")
    PW_PREFIX_NAME="${PW_PREFIX_NAME%.[Pp][Pp][Aa][Cc][Kk]}"

    if pw_is_legacy_prefix_backup "${PW_BACKUP_FILE}" ; then
        pw_unpack_legacy_prefix
        return $?
    fi

    python3 -m portprotonqt.scripts_utils.prefix_backup --port-data-path "${PORT_DATA_PATH}" \
        restore "${PW_BACKUP_FILE}"
    return $?
}
