#!/usr/bin/env bash
# shellcheck source=/dev/null

### project ###

PREFIX="/usr"
PROGNAME="SteamTinkerLaunch"
NICEPROGNAME="Steam Tinker Launch"
PROGVERS="v12.12"
PROGCMD="${0##*/}"
SHOSTL="stl"
GHURL="https://github.com"
AGHURL="https://api.github.com"
PROJECTPAGE="$GHURL/sonic2kk/${PROGNAME,,}"
PPW="$PROJECTPAGE/wiki"
CURWIKI="$PPW"
STARTDEBUG=1
ONSTEAMDECK=0

### internal dependencies ###
#STARTINTDEPS
GIT="git"
PGREP="pgrep"
PIDOF="pidof"
PKILL="pkill"
TAR="tar"
UNZIP="unzip"
WGET="wget"
XDO="xdotool"
XPROP="xprop"
XRANDR="xrandr"
XWININFO="xwininfo"
XXD="xxd"
#ENDINTDEPS

### (optionally) used programs ###
GAMEMODERUN="gamemoderun"
GAMESCOPE="gamescope"
NYRNA="nyrna"
STEAM="steam"
RECO="resetcollections"
STERECO="$STEAM ${STEAM}://${RECO}"
STRACE="strace"
WINECFG="winecfg"
WICO="wineconsole"
SYSWINETRICKS="winetricks"
REPLAY="replay-sorcery"
INNOEXTRACT="innoextract"
CABEXTRACT="cabextract"
LSUSB="lsusb"
JQ="jq"
CONVERT="convert"
IDENTIFY="identify"
RSYNC="rsync"
CONTY="conty.sh"
SEVZA="7za"
PERES="peres"
GDB="gdb"
XDGMIME="xdg-mime"
XDGO="xdg-open"
OBSCAP="obs-gamecapture"

CHECKHMD=1
X32D="x32dbg"
X64D="x64dbg"
FACO="favorites.conf"
MENSO="menusort.conf"
MENUBLOCK="menublock.conf"
DSHM="/dev/shm"
STLSHM="$DSHM/${PROGNAME,,}"
MTEMP="$STLSHM/menutemp"
STLICON="$STLSHM/${PROGNAME,,}-steam-checked.png"
NOICON="$STLSHM/empty.png"
FAVPIC="$STLSHM/fav.jpg"
DFDIR="$STLSHM/desktopfiles"
CLOSETMP="$STLSHM/${PROGNAME,,}-closing.tmp"
PROTBUMPTEMP="$STLSHM/protonbump.tmp"
KILLSWITCH="$STLSHM/KillSwitch"
TEMPLOG="$STLSHM/${PROGNAME,,}.log"
PRELOG="$STLSHM/prelog.log"
APPMALOG="$STLSHM/listAppManifests.log"
GGDLOG="$STLSHM/getGameData.log"
WINRESLOG="$STLSHM/winres.log"
SHADLOG="$STLSHM/shaderupdate.log"
GWIDFILE="$STLSHM/${PROGNAME,,}-sbsgwid"
PIDLOCK="$STLSHM/pid.lock"
LAMOINST="$STLSHM/LastMOInst.txt"
GDBGAMERUN="$STLSHM/gdbgamerun.sh"
GDBRUN="$STLSHM/gdbrun.sh"
VRINITLOCK="$STLSHM/vrinit.lock"
IGCSINITLOCK="$STLSHM/igcsinit.lock"
VRINITRESULT="$STLSHM/vrinit.conf"
VWRUN="$STLSHM/vwrun.txt"
STELILIST="$STLSHM/SteamLibraries.txt"
UUUPATCH="${PROGNAME,,}-uuu-patch"
UUUPATCHCOMMAND="$STLSHM/${UUUPATCH}.sh"
GCD="GameCfgDiffers"
OVFS="openvr_fsr"
OVRA="openvr_api.dll"
OVRMOD="openvr_mod.cfg"
GWXTEMP="$STLSHM/gamewinXID.txt"
TRAYCUSC="$STLSHM/customscript"
TEMPGPIDFILE="$STLSHM/gamepid.txt"
STLSETENTRIES="$STLSHM/setentries.txt"
CLOSEVARS="$STLSHM/closevars.txt"
STLRAWENTRIES="$STLSHM/rawentries.txt"
STLNOBLOCKENTRIES="$STLSHM/noblockentries.txt"
STLCATSORTENTRIES="$STLSHM/catsortentries.txt"
UPWINTMPL="$STLSHM/upwintmpl.txt"
STLMINWIN="$STLSHM/minwin.txt"
STLMENUVALBLOCKCFG="$STLSHM/$MENUBLOCK"
VARSIN="$STLSHM/vars-in.txt"
FUPDATE="$STLSHM/fupdate.txt"
STPAVARS="$STLSHM/steampaths.txt"
PROTONCSV="$STLSHM/ProtonCSV.txt"
SWRF="$STLSHM/SWR.txt"
UWRF="$STLSHM/UWR.txt"
EWRF="$STLSHM/EWR.txt"
NON="none"
NOPE="nope"
TMPL="template"
DLWINEVERSION="$NON"
GAMENAME="$NON"
EARLYUSEWINE=0
FAVMENU="$MTEMP/favmenu"
GAMEMENU="$MTEMP/gamemenu"
GAMETEMPMENU="$MTEMP/gametemplmenu"
GLOBALMENU="$MTEMP/globalmenu"
GAMMENU="Game Menu"
SETMENU="Settings Menu"
FAVOMENU="Favorite Menu"
LOSE="Local Settings"
APDA="Application Data"
APD="AppData"
ADRO="$APD/Roaming"
ADLO="$APD/Local"
ADLOLO="$APD/LocalLow"
EAGA="EA Games"
LAGA="Larian Studios"
BIOW="BioWare"
SAGE="Saved Games"
CDPR="CD Projekt Red"
LSAD="$LOSE/$APDA"
RUNCONTY="$NON"
WINX="800"
WINY="600"
F1ACTION="bash -c OpenWiki"
F1ACTIONCG="bash -c setColGui"
BTS="backup-timestamp"
DUMMYBIN="echo"
STLAIDSIZE="12"
FPBIN="/app/utils/bin"
INFLATPAK=0
WDIB="wine-discord-ipc-bridge"
FIXGAMESCOPE=0
SMALLDESK=0
VTX_DOTNET_ROOT="c:\\Program Files\\dotnet\\\\"
STLQUIET=0
SLRAID="1070560"  # Hardcoded SLR AppID for native games -- See `setSLRReap`

### default vars ###

if [ -z "$XDG_CONFIG_HOME" ]; then
	STLCFGDIR="$HOME/.config/${PROGNAME,,}"													# either hardcoded config dir
else
	STLCFGDIR="$XDG_CONFIG_HOME/${PROGNAME,,}"												# or in XDG_CONFIG_HOME if the user set the variable
fi

#486
function wip {
if [ -z "$XDG_CACHE_HOME" ]; then
	STLCACHEDIR="$HOME/.cache/${PROGNAME,,}"
else
	STLCACHEDIR="$XDG_CACHE_HOME/${PROGNAME,,}"
fi

if [ -z "$XDG_DATA_HOME" ]; then
	STLDATADIR="$HOME/.local/share/${PROGNAME,,}"
else
	STLDATADIR="$XDG_DATA_HOME/${PROGNAME,,}"
fi
}

SYSTEMSTLCFGDIR="$PREFIX/share/${PROGNAME,,}"												# systemwide config dir
BASELOGDIR="$STLCFGDIR/logs"																# base logfile dir
DEFLOGDIR="$BASELOGDIR/${PROGNAME,,}"																# default logfile dir

if [ -z "$LOGDIR" ]; then
	LOGDIR="$DEFLOGDIR"
fi

LOGDIRID="$LOGDIR/id"

LOGDIRTI="$LOGDIR/title"
STLPROTONLOGDIR="$BASELOGDIR/proton"
STLPROTONIDLOGDIR="$STLPROTONLOGDIR/id"
STLPROTONTILOGDIR="$STLPROTONLOGDIR/title"
STLDXVKLOGDIR="$BASELOGDIR/dxvk"
STLWINELOGDIR="$BASELOGDIR/wine"
STLVKD3DLOGDIR="$BASELOGDIR/vkd3d"
STLGLLOGDIR="$BASELOGDIR/gamelaunch"
STLGLLOGDIRID="$STLGLLOGDIR/id"
STLGLLOGDIRTI="$STLGLLOGDIR/title"
PLAYTIMELOGDIR="$BASELOGDIR/playtime"
STLGAMEDIR="$STLCFGDIR/gamecfgs"
STLGUIDIR="$STLCFGDIR/guicfgs"
STLGAMEDIRID="$STLGAMEDIR/id"
STLCUSTVARSDIR="$STLGAMEDIR/customvars"
GLOBCUSTVARS="$STLCUSTVARSDIR/global-custom-vars.conf"
STLGAMEDIRTI="$STLGAMEDIR/title"
STLCOLLECTIONDIR="$STLCFGDIR/collections"
STLREGDIR="$STLCFGDIR/regs"
STLDLDIR="$STLCFGDIR/downloads"
STLBACKDIR="$STLCFGDIR/backup"
BACKEX="$STLBACKDIR/exclude"
HIDEDIR="$STLCFGDIR/hide"
STLTEMPDIR="$STLCFGDIR/temp"
CODA="compatdata"
STLCOMPDAT="$STLCFGDIR/$CODA"
METADIR="$STLCFGDIR/meta"
GEMETA="$METADIR/id/general"
CUMETA="$METADIR/id/custom"
EVMETAID="$METADIR/eval/id"
EVMETASKIPID="$EVMETAID/skip"
EVMETACUSTOMID="$EVMETAID/custom"
EVMETAADDONID="$EVMETAID/addon"
EVMETATITLE="$METADIR/eval/title"
EVMETAOLD="$METADIR/eval/old"
EVALSC="evaluatorscript"
GECUST="get-current-step"
ISCRI="iscriptevaluator"
LIINPA="linux_install_path"
STEWOS="Steamworks Shared"
LECO="legacycompat"
FRSTATE="$STLSHM/firuState.txt"
TIGEMETA="$METADIR/title/general"
TICUMETA="$METADIR/title/custom"
DRC="drive_c"
DRCU="$DRC/users"
DRCW="$DRC/windows"
STUS="steamuser"
SUBADIR="$STLBACKDIR/$STUS"
SUBADIRID="$SUBADIR/id"
SUBADIRTI="$SUBADIR/title"
RSSUB="reshade-shaders"
WTDLDIR="$STLDLDIR/winetricks"
DLWT="$WTDLDIR/src/winetricks"
STLSHADDIR="$STLDLDIR/shaders"
SHADREPOLIST="$STLSHADDIR/repolist.txt"
SHADERREPOBLOCKLIST="$STLSHADDIR/repoblocklist.txt"
TWEAKDIR="$STLCFGDIR/tweaks"																# the parent directory for all user tweakfiles
USERTWEAKDIR="$TWEAKDIR/user"																# the place for the users own main tweakfiles
TWEAKCMDDIR="$TWEAKDIR/cmd"																	# dir for scriptfiles used by tweakfiles
SBSTWEAKDIR="$TWEAKDIR/sbs"																	# directory for optional config overrides for easier side-by-side VR gaming
MO2DLDIR="$STLDLDIR/mo2"
HMMDLDIR="$STLDLDIR/hedgemodmanager"
HMMVERFILE="$HMMDLDIR/hmmver.txt"
CONTYDLDIR="$STLDLDIR/conty"
X64DBGDLDIR="$STLDLDIR/$X64D"
GEOELFDLDIR="$STLDLDIR/geo11"
WDIBDLDIR="$STLDLDIR/${WDIB}"
EWDIB="${WDIB//-}"
RUNWDIB="$WDIBDLDIR/${EWDIB}.exe"
LGEOELFSYM="$GEOELFDLDIR/latest"
CUSTOMFALLBACKPIC="$STLDLDIR/custom-fallback.png"
VTX="vortex"
VOGAT="${VTX}games.txt"
STLVORTEXDIR="$STLCFGDIR/$VTX"
VORTEXDLDIR="$STLDLDIR/$VTX"
VORTSETCMD="$STLSHM/vortset.cmd"
VTST="$STLSHM/vsetup.txt"
SPEK="SpecialK"
SPEKDLDIR="$STLDLDIR/${SPEK,,}"
FWS="FlawlessWidescreen"
FWSDLDIR="$STLDLDIR/${FWS,,}"
YADAIDLDIR="$STLDLDIR/yadappimage"
DOTN="dotnet"
MO2="mo2"
STLMO2DIR="$STLCFGDIR/$MO2"
STLMO2DLDATDIR="$STLMO2DIR/dldata"
MO="ModOrganizer"
HMM="HedgeModManager"
HMMNICE="Hedge Mod Manager"
HMMSTABLE="stable"
HMMDEV="nightly"
HMMAUTO="auto"
HMMDF="$HMM-${PROGNAME,,}.desktop"
HMMDFDL="$HMM-${PROGNAME,,}-dl.desktop"
HMMDFPA="$HOME/.local/share/applications/$HMMDF"  # .desktop file to open HMM
HMMDFDLPA="$HOME/.local/share/applications/$HMMDFDL"  # .desktop file to 
MORDIR="$DRC/Modding"
MOERDIR="$MORDIR/MO2"
MOERPATH="$MOERDIR/${MO}.exe"
STLHMMDIR="$STLCFGDIR/${HMM,,}"
DOCS="Documents"
MYDOCS="My $DOCS"
MYGAMES="My Games"
PLACEHOLDERAID="31337"
PLACEHOLDERGN="Placeholder"
DPRS="Depressurizer"
DPRSDLDIR="$STLDLDIR/${DPRS,}"
DEPS="Dependencies"
DEPSGE="${DEPS}Gui.exe"
DEPSDLDIR="$STLDLDIR/${DEPS,}"
DEPSLATDIR="$DEPSDLDIR/latest"
DEPSL64="$DEPSLATDIR/64/$DEPSGE"
DEPSL32="$DEPSLATDIR/32/$DEPSGE"
MAHU="mangohud"
MANGOAPP="mangoapp"
MAHUCFGDIR="$STLCFGDIR/$MAHU"
MAHUCID="$MAHUCFGDIR/id"
MAHUCTI="$MAHUCFGDIR/title"
MAHUTMPL="$MAHUCFGDIR/$MAHU-${PROGNAME,,}-template.conf"
MAHULOGDIR="$BASELOGDIR/$MAHU"
MAHULID="$MAHULOGDIR/id"
MAHULTI="$MAHULOGDIR/title"
PFX86="Program Files (x86)"
PFX86S="$PFX86/Steam"
APIN="appinfo"
SLO="Steam Launch Option"
SOMEPOPULARWINEPAKS="dotnet4 quartz xact"
SOMEWINEDEBUGOPTIONS="-all,+steam,+vrclient,+vulkan"
SGDBDIMOPTS="600x900,342x482,660x930"
SGDBSTYOPTS="alternate,blurred,white_logo,material,no_logo"
GETSTAID="99[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]99"

STLGAMES="$STLCFGDIR/games"
STLGDESKD="$STLGAMES/desktop"
STLIDFD="$STLGAMES/desktopfiles"
STLISLDFD="$STLGAMES/sldesktopfiles"
STLAPPINFOIDDIR="$STLGAMES/$APIN"
STLGHEADD="$STLGAMES/header"
STLGSAD="$STLGAMES/standalone"
STLGICONS="$STLGAMES/icons"
STLGDECKCOMPAT="$STLGAMES/deckinfo"
STLGICO="$STLGICONS/ico"
STLGZIP="$STLGICONS/zip"
STLGPNG="$STLGICONS/png"
STLGSAPD="$STLGSAD/titles"
STLGSACD="$STLGSAD/$CODA"
STLGPEVKD="$STLGAMES/pev"
MO2INSTFAIL="$STLSHM/${MO}-failed.txt"
ABSGAMEEXEPATH="$NON"
GEOELF="geo-11"
ISORIGIN=0

#STLGSCPTD="$STLGAMES/scripts"
NOGAMES=",70_2260196511,228980,858280,961940,1054830,1070560,1113280,1245040,1391110,1420170,"
# Taken from GE-Proton7-24 changelog, removing some duplicates
WINE_FSR_CUSTOM_RESOLUTIONS=(
	# 1080p
	"960x540"
	"1129x635"
	"1280x720"
	"1477x831"

	# 2K
	"1506x847"
	"1706x960"
	"1970x1108"

	# Ultra-Wide
	"1720x720"
	"2024x847"
	"2293x960"
	"2646x1108"

	# 4K
	"1920x1080"
	"2259x1270"
	"2560x1440"
	"2954x1662"

	# 32:9 (5120x1440) -- Samsung Neo G9
	"2560x720"
	"3012x847"
	"3413x960"
	"3839x1108"
)

#PROTON37="858280"
#PROTON316="961940"
#PROTON42="1054830"
#PROTON411="1113280"
#PROTON50="1245040"
#PROTON513="1420170"

function setGNID {
	# only keep alphabet chars
	INGN="$(tr -cd '[:alnum:]' <<< "${1^^}")"
	INGN="${INGN//[[:digit:]]/}"
	MIDNUMSIZE=$((STLAIDSIZE -4))

	if [ "${#INGN}" -gt "$MIDNUMSIZE" ]; then
		INGN="${INGN:0:MIDNUMSIZE}"
	fi

	while [ "${#INGN}" -lt "$MIDNUMSIZE" ]; do
		INGN="${INGN}A"
	done

	ALPHARR=(A B C D E F G H I J K L M N O P Q R S T U V W X Y Z)

	function numberOut {
		for n in "${!ALPHARR[@]}"; do
			if [ "${ALPHARR[$n]}" == "$1" ]; then
				NUM="$((n +1))"
				if [ "$NUM" -gt 9 ]; then
					printf "%s" "${NUM:1:1}"
				else
					printf "%s" "${NUM:0:1}"
				fi
			fi
		done
	}

	function outNum {
		i=0
		while [ "$i" -lt "${#1}" ]; do
			numberOut "${1:$i:1}"
			i=$((i+1))
		done
		printf "\n"
	}

	MIDNUM="$(outNum "$INGN")"
	echo "99${MIDNUM}99"
}

function initAID {
	STLPLAY=0
	if [ -n "$STEAM_COMPAT_APP_ID" ]; then
		AID="$STEAM_COMPAT_APP_ID"
		writelog "INFO" "${FUNCNAME[0]} - Set AID from STEAM_COMPAT_APP_ID to '$AID'" "P"
	fi

	if [ -z "$AID" ] || [ "$AID" -eq "0" ]; then
		# shellcheck disable=SC2154		# SteamAppId comes from Steam

		if [ -z "$SteamAppId" ]; then
			if grep -q "^play" <<< "$@" && [ -n "$2" ] && [ -z "$3" ] && [ "$2" != "gui" ] && [ "$2" != "ed" ]; then
				STLPLAY=1
				if [ "$2" -eq "$2" ] 2>/dev/null ; then
					AID="$2"
				elif [ -f "$2" ]; then
					GN="${2##*/}"
					AID="$(setGNID "$GN")"
				fi
				writelog "INFO" "${FUNCNAME[0]} - Set AID to '$PROGCMD' ID '$AID'" "P"
			elif grep -q "^play" <<< "$@" && [ -f "$3" ]; then
				STLPLAY=1
				GN="${3##*/}"
				AID="$2"	

				writelog "INFO" "${FUNCNAME[0]} - Set AID to '$PROGCMD' ID '$AID'" "P"
			else
				AID="$PLACEHOLDERAID"
				writelog "INFO" "${FUNCNAME[0]} - Set AID to PLACEHOLDERAID '$AID'" "P"
			fi
		else
			if [ "$SteamAppId" -eq "0" ]; then
				AID="${STEAM_COMPAT_DATA_PATH##*/}"
				writelog "INFO" "${FUNCNAME[0]} - Set AID from STEAM_COMPAT_DATA_PATH '$STEAM_COMPAT_DATA_PATH' to '${STEAM_COMPAT_DATA_PATH##*/}', because SteamAppId is '$SteamAppId'" "P"
			else
				AID="$SteamAppId"
				writelog "INFO" "${FUNCNAME[0]} - Set AID to SteamAppId '$SteamAppId' coming from Steam" "P"
			fi
		fi
	fi

	if [ -n "$STEAM_COMPAT_DATA_PATH" ]; then
		OSCDP="$STEAM_COMPAT_DATA_PATH"
		writelog "INFO" "${FUNCNAME[0]} - Set OSCDP to STEAM_COMPAT_DATA_PATH '$STEAM_COMPAT_DATA_PATH'" "P"
	fi
}

STLFAVMENUCFG="$STLCFGDIR/$FACO"															# optional config (in fact just a list with variables) which holds all entries for the individual favorites menu
STLMENUSORTCFG="$STLCFGDIR/$MENSO"															# holds the category sort order for all menus
STLMENUBLOCKCFG="$STLCFGDIR/$MENUBLOCK"
#STARTEDITORCFGLIST
STLDEFGLOBALCFG="$STLCFGDIR/global.conf"													# global config
STLDEFGAMECFG="$STLCFGDIR/default_template.conf"											# the default config template used to create new per game configs - will be auto created if not found

function setSDCfg {
STLSDLCFG="$STLCFGDIR/steamdeck.conf"														# Steam Deck config
}

function setAIDCfgs {
STLGAMECFG="$STLGAMEDIRID/$AID.conf"														# the game specific config file which is used by the launched game - created from $STLDEFGAMECFG if not found
TWEAKCFG="$USERTWEAKDIR/$AID.conf"															# the game specific shareable config tweak overrides
SBSTWEAKCFG="$SBSTWEAKDIR/$AID.conf"														# the game specific shareable config sbs tweak overrides
LOGFILE="$LOGDIRID/$AID.log"																	
GAMECUSTVARS="$STLCUSTVARSDIR/$AID.conf"													# game specific config file for user defined custom variables
}

STLURLCFG="$STLCFGDIR/url.conf"																# url config
CUSTOMPROTONLIST="$STLCFGDIR/protonlist.txt"												# plain textfile with additional user proton versions
VORTEXSTAGELIST="$STLVORTEXDIR/stages.txt"													# plain textfile with Vortex Stage directories - one per Steam Library partition
SEENVORTEXGAMES="$STLVORTEXDIR/$CODA/seen$VOGAT"
EXGLOB="$BACKEX/exclude-global.txt"
#ENDEDITORCFGLIST

STLLANGDIR="$STLCFGDIR/lang"
STLDEFLANG="english"

STLDXVKDIR="$STLCFGDIR/dxvk"																# base dxvk config dir from where default per game configs are automatically parsed
ISGAME=0																					# 1=game was launched, 2=windows game, 3=linux game
WFEAR="waitforexitandrun"
SA="steamapps"
SAC="$SA/common"
L2EA="link2ea"
CTD="compatibilitytools.d"
SLR="SteamLinuxRuntime"
STERU="steam-runtime"
BIWI="bin/wine"
DBW="dist/$BIWI"
FBW="files/$BIWI"
STLPROTDIR="$STLCFGDIR/proton"
STLPROTCOMPDATDIR="$STLPROTDIR/$CODA"
STLPROTSTUSDIR="$STLPROTDIR/$STUS"
STLEARLYPROTCONF="$STLPROTDIR/earlyproton.conf"
PROCU="proton/custom"
CTVDF="compatibilitytool.vdf"
TOMA="toolmanifest.vdf"
LIFOVDF="libraryfolders.vdf"
SCV="sharedconfig.vdf"
AIVDF="$APIN.vdf"
AITXT="$APIN.txt"
AAVDF="appcache/$AIVDF"
APVDF="appcache/packageinfo.vdf"
USDA="userdata"
SCVDF="shortcuts.vdf"
SRSCV="7/remote/$SCV"
LCV="localconfig.vdf"
COCOV="config/config.vdf"
SCSHVDF="screenshots.vdf"
SCRSH="760/$SCSHVDF"
LASTRUN="$LOGDIR/lastrun.txt"
SAIT="steam_appid.txt"
DXGI="dxgi.dll"
D3D9="d3d9.dll"
D3D47="d3dcompiler_47.dll"
OGL32="opengl32.dll"
D3D47DLDIR="$STLDLDIR/${D3D47%.*}"
SOMEWINEDLLOVERRIDES="dinput8=n,b!dxgi=n,b!d3d9=n,b!${D3D47//.dll}=n,b!xaudio2_7=n,b"
RS_DX_DEST="$DXGI"
RS_D9_DEST="$D3D9"
RESH="ReShade"
RSSU="${RESH}_Setup"
RSINI="${RESH}.ini"
RSTXT="${RESH}.txt"
IGCS="IGCSInjector"
UUU="UniversalUE4Unlocker"
LFM="launchFavMenu"
LGAM="launchGameMenu"
LGATM="launchGameTemplateMenu"
LGLM="launchGlobalMenu"
LCM="launchCategoryMenu"
HEADLINEFONT="larger"
FONTSIZES="!xx-small!x-small!small!smaller!medium!large!larger!!x-large!xx-large!"
SREG="system.reg"
NSGA="non-steam game"
SGA="set game artwork"
BTVP="$DRC/Program Files/Black Tree Gaming Ltd/${VTX^}"
VTXRAA="resources/app.asar"
RABP="${VTXRAA}.unpacked/bundledPlugins"

# make SC happy:
GUI_CUSTOMCMD=""
################

function setSteamPath {
	HSR="$HOME/.steam/root"
	HSS="$HOME/.steam/steam"

	if [ -z "${!1}" ]; then
		if [ -e "${HSR}/${2}" ]; then
			# readlink might be better in both STPAs here to be distribution independant, possible side effects not tested!
			STPA="$(readlink -f "${HSR}/${2}")"
			export "$1"="$STPA"
			echo "$1=\"$STPA\"" >> "$STPAVARS"
			writelog "INFO" "${FUNCNAME[0]} - Set '$1' to '$STPA'"
		elif [ -e "${HSS}/${2}" ]; then
			STPA="$(readlink -f "${HSS}/${2}")"
			export "$1"="$STPA"
			echo "$1=\"$STPA\"" >> "$STPAVARS"
			writelog "INFO" "${FUNCNAME[0]} - Set '$1' to '$STPA'"
		else
			writelog "WARN" "${FUNCNAME[0]} - '$2' not found for variable '$1' in '$HSR' or '$HSS'!"
		fi	
	else
		writelog "SKIP" "${FUNCNAME[0]} - '$1' already defined as '${!1}'"
		echo "$1=\"${!1}\"" >> "$STPAVARS"
	fi
}

function setSteamPaths {
	if [ -f "$STPAVARS" ] && grep -q "^SUSDA" "$STPAVARS" ; then
		writelog "INFO" "${FUNCNAME[0]} - Reading Steam Path variables from '$STPAVARS'"
		loadCfg "$STPAVARS" X
	else
		setSteamPath "SROOT"
		mkProjDir "$SROOT/$CTD"
		setSteamPath "SUSDA" "$USDA"
		setSteamPath "DEFSTEAMAPPS" "$SA"
		setSteamPath "DEFSTEAMAPPSCOMMON" "$SAC"
		setSteamPath "CFGVDF" "$COCOV"
		setSteamPath "LFVDF" "$SA/$LIFOVDF"
		setSteamPath "FAIVDF" "$AAVDF"
		setSteamPath "PIVDF" "$APVDF"
		setSteamPath "STEAMCOMPATOOLS" "$CTD"
		setSteamPath "ICODIR" "steam/games"

		if [ -z "$STEAM_COMPAT_CLIENT_INSTALL_PATH" ]; then
			export STEAM_COMPAT_CLIENT_INSTALL_PATH="$SROOT"
			echo "STEAM_COMPAT_CLIENT_INSTALL_PATH=\"$SROOT\"" >> "$STPAVARS"
		fi

		if [ -f "$STLDEFGLOBALCFG" ] && grep -q "^STEAMUSERID=" "$STLDEFGLOBALCFG" ; then
			STEAMUSERID="$(grep "^STEAMUSERID=" "$STLDEFGLOBALCFG" | grep -o "[[:digit:]]*")"
			STUIDPATH="$SUSDA/$STEAMUSERID"
		else
			if [ -d "$SUSDA" ]; then
			# this works for 99% of all users, because most do have 1 steamuser on their system
				STUIDPATH="$(find "$SUSDA" -maxdepth 1 -type d -name "[1-9]*" | head -n1)"
				STEAMUSERID="${STUIDPATH##*/}"
			else
				writelog "WARN" "${FUNCNAME[0]} - Steam '$USDA' directory not found, other variables depend on it - Expect problems" "E"
			fi
		fi

		SUIC="$STUIDPATH/config"
		FLCV="$SUIC/$LCV"

		{
		echo "STUIDPATH=\"$STUIDPATH\""
		echo "STEAMUSERID=\"$STEAMUSERID\""
		echo "SUIC=\"$SUIC\""
		echo "FLCV=\"$FLCV\""
		} >> "$STPAVARS"

		writelog "INFO" "${FUNCNAME[0]} - Found SteamUserId '$STEAMUSERID'"
	fi
}

function setAwkBin {
	if [ -z "$AWKBIN" ];then
		if [ -x "$(command -v "gawk")" ]; then
			AWKBIN="gawk"
			if [ -z "$1" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Found '$AWKBIN' as an 'awk' variant. It should work without any issues, because 'gawk' was tested completely"
			fi
		elif [ -x "$(command -v "mawk")" ]; then
			AWKBIN="mawk"
			if [ -z "$1" ]; then
				writelog "WARN" "${FUNCNAME[0]} - Only found '$AWKBIN' as an 'awk' variant. It might be incompatible in several functions, as only 'gawk' was tested completely!"
			fi
		elif [ -x "$(command -v "awk")" ]; then
			AWKBIN="mawk"
			if [ -z "$1" ]; then
				writelog "WARN" "${FUNCNAME[0]} - Only found '$AWKBIN' as an 'awk' variant. It might be incompatible in several functions, as only 'gawk' was tested completely!"
			fi
		fi	
		
		if [ -z "$AWKBIN" ];then
			writelog "ERROR" "${FUNCNAME[0]} - No 'awk' variant found, but at least one is required (best would be 'gawk') - Can't continue" "E"
			exit
		else
			export AWKBIN="$AWKBIN"
		fi
	fi
}

function awk {
	if [ -z "$AWKBIN" ];then
		setAwkBin "X"
	fi
	"$AWKBIN" "$@"
}

function OpenWikiPage {
	if [ -n "$1" ]; then
		if grep -q "$PPW" <<< "$1"; then
			WIKURL="$1"
		else
			WIKURL="$PPW/$1"
		fi
	else
		if [ -n "$CURWIKI" ]; then
			WIKURL="$CURWIKI"
		fi
	fi
	
	if [ -n "$WIKURL" ]; then
		if [ "$ONSTEAMDECK" -eq 1 ]; then
			# Only open wiki on Steam Deck Game Mode
			if [ "$FIXGAMESCOPE" -eq 0 ]; then
				writelog "INFO" "${FUNCNAME[0]} - Opening wiki URL '$WIKURL' using xdg-open on Steam Deck since Yad AppImage does not have WebKit support" 
				"$XDGO" "$WIKURL"
			else
				writelog "SKIP" "${FUNCNAME[0]} - Running in Steam Deck Game Mode - Opening wiki page using xdg-open here may not work or may have undesired results - Skipping"
			fi
		else
			TITLE="${PROGNAME}-Wiki"
			pollWinRes "$TITLE"
			"$YAD" --window-icon="$STLICON" --title="$TITLE" --on-top --center "$WINDECO" --html --uri="$WIKURL" "$GEOM" >/dev/null 2>/dev/null	
		fi
	fi
}

function OpenWiki {
	"${PROGCMD}" wiki "$CURWIKI"
}

export -f OpenWiki

function StatusWindow {
	YAD=yad
    TITLE="${PROGNAME}-$3"
    pollWinRes "$TITLE"
	writelog "INFO" "${FUNCNAME[0]} - for '$1'"

    RUNFUNC="$2"
    $RUNFUNC |
    while read -r line; do
		echo "# ${line}";
	done | "$YAD" --window-icon="$STLICON" --title="$TITLE" --on-top --progress --progress-text="$1..." --pulsate --center --no-buttons --auto-close "$WINDECO" "$GEOM"
}

function setColGui {
	HAVCOL=0
	if grep -q "^COLCOUNT" "$CURGUICFG"; then
		CCR="$(grep "^COLCOUNT" "$CURGUICFG" | cut -d '=' -f2)"
		CURCOL="${CCR//\"}"
		HAVCOL=1
	else
		CURCOL=1
	fi

	export CURWIKI="$PPW/Gui-Columns"

	TITLE="${FUNCNAME[0]}"
	WTR="${CURGUICFG##*/}"
	WINTITLE="${WTR//.conf}"
	SELCOL="$("$YAD" --f1-action="$F1ACTION" --center --form --separator="\n" --field="Columns in $WINTITLE":NUM "$CURCOL" --title="$TITLE" "$GEOM")"
	
	if [ -z "$SELCOL" ] || [ "$SELCOL" -eq 0 ]; then
		SELCOL=1
	fi

	if [ "$HAVCOL" -eq 0 ]; then
		echo "COLCOUNT=\"$SELCOL\"" >> "$CURGUICFG"
	else
		if [ "$CURCOL" -ne "$SELCOL" ]; then
			sed "s:COLCOUNT=\"$CURCOL\":COLCOUNT=\"$SELCOL\":g" -i "$CURGUICFG"
		fi
	fi
}
export -f setColGui

function dlCheck {
	function chkFile {
		if [ "$FLCHK" == "stat" ]; then
			ISCHK="$("$FLCHK" -c%s "$DLDST" | cut -d ' ' -f1)"
		else
			ISCHK="$("$FLCHK" "$DLDST" | cut -d ' ' -f1)"
		fi
		CHKTXT="$(strFix "$NOTY_CHK" "$FLCHK" "$DLDST")"
		writelog "INFO" "${FUNCNAME[0]} - $CHKTXT"
		notiShow "$CHKTXT" "S"

		if [ "$ISCHK" == "$INCHK" ];then
			CHKTXT="$(strFix "$NOTY_CHKOK" "$FLCHK" "${DLDST##*/}" "$ISCHK")"
			writelog "INFO" "${FUNCNAME[0]} - $CHKTXT"
			notiShow "$CHKTXT" "S"
		else
			CHKTXT="$(strFix "$NOTY_CHKNOK" "${DLDST##*/}" "$ISCHK" "$INCHK")"
			writelog "WARN" "${FUNCNAME[0]} - $CHKTXT"
			notiShow "$CHKTXT" "S"
		fi
		sleep 2
	}

	DLSRC="$1"
	DLDST="$2"
	FLCHK="$3"
	DLTITLE="$4"
	INCHK="$5"

	if [ "$FLCHK" != "C" ]; then
		if [ -f "$DLDST" ] && [ "$FLCHK" != "X" ]; then
			chkFile
		else
			if [ "$DLTITLE" != "$NON" ]; then
				writelog "INFO" "${FUNCNAME[0]} - $DLTITLE"
				notiShow "$(strFix "$NOTY_DLCUSTOMPROTON" "$DLDST")" "S"
				if grep -q "show-progress" <<< "$("$WGET" --help)" && [ "$ONSTEAMDECK" -eq 0 ]; then
					writelog "INFO" "${FUNCNAME[0]} - '$WGET -q --show-progress $DLSRC -O $DLDST'"
					"$WGET" -q --show-progress "$DLSRC" -O "$DLDST" 2>&1 | sed -u -e "s:\.::g;s:.*K::g;s:^[[:space:]]*::g" | grep -v "SSL_INIT"
				else
					writelog "INFO" "${FUNCNAME[0]} - '$WGET -q $DLSRC -O $DLDST'"
					"$WGET" -q "$DLSRC" -O "$DLDST" 2>&1 | sed -u -e "s:\.::g;s:.*K::g;s:^[[:space:]]*::g" | grep -v "SSL_INIT"
				fi
			else
				"$WGET" -q "$DLSRC" -O "$DLDST" 1>/dev/null 2>&1 
			fi
		fi
	else
		FLCHK="$1"
		DLDST="$2"
		INCHK="$4"
		writelog "INFO" "${FUNCNAME[0]} - Only checking already downloaded file '$DLDST'"
		chkFile
	fi

	if [ -n "$INCHK" ] && [ "$INCHK" != "$NON" ]; then
		if [ "$FLCHK" == "X" ]; then
			notiShow "$(strFix "$NOTY_DLCUSTOMPROTON2" "$DLDST")" "S"
			writelog "INFO" "${FUNCNAME[0]} - $(strFix "$NOTY_DLCUSTOMPROTON2" "$DLDST")"
		elif [ "$FLCHK" != "C" ]; then
			chkFile
		fi
	fi
}

function getGamePic {
	if [ "$DLGAMEDATA" -eq 1 ] && [ "$STLPLAY" -eq 0 ]; then
		DLPIC="$1"
		if [[ ( ! -f "$DLPIC" || ! -s "$DLPIC" ) && "$STLPLAY" -eq 0 ]]; then
			DLTITLE="Downloading picture for game '$(basename "${1//.jpg/}")'"
			dlCheck "$2" "$DLPIC" "X" "$DLTITLE"
		fi
	fi
}

function getGameName {
	if [ -n "$GN" ]; then
		writelog "INFO" "${FUNCNAME[0]} - Using 'GN' as Game Name: '$GN'"
		GNRAW="$GN"
	elif [ -f "$STLGAMEDIRID/$1.conf" ]; then
		GNRAW="$(grep "#GAMENAME" "$STLGAMEDIRID/$1.conf" | cut -d '=' -f2)"
		writelog "INFO" "${FUNCNAME[0]} - Found Game Name '$GNRAW' in '$STLGAMEDIRID/$1.conf'"
	elif grep -q "_${1}\." <<< "$(listAppManifests)" ; then
		APPMA="$(grep "_${1}\." <<< "$(listAppManifests)")"
		if [ -f "$APPMA" ]; then
			GNRAW1="$(grep "\"name\"" "$APPMA" | awk -F '"name"' '{print $NF}')"
			GNRAW="$(awk '{$1=$1};1' <<< "$GNRAW1")"
			writelog "INFO" "${FUNCNAME[0]} - Found Game Name '$GNRAW' in '$APPMA'"
		else
			writelog "SKIP" "${FUNCNAME[0]} - file '$APPMA' not found"
		fi
	elif [ -f "$STLAPPINFOIDDIR/${1}.bin" ]; then
		GNRAW="$(getAppInfoData "$AID" "name")"
		writelog "INFO" "${FUNCNAME[0]} - Found Game Name '$GNRAW' in '$STLAPPINFOIDDIR/${1}.bin'"
	else
		if [ "$DLGAMEDATA" -eq 1 ]; then
			APIURL="https://api.steampowered.com/ISteamApps/GetAppList/v2"
			APIDL="$STLDLDIR/SteamApps.json"
			MAXAGE=1440
			writelog "INFO" "${FUNCNAME[0]} - Downloading gamedata for '$1'"

			if [ ! -f "$APIDL" ] || test "$(find "$APIDL" -mmin +"$MAXAGE")"; then
				dlCheck	"$APIURL" "$APIDL" "X" "Downloading $APIDL"
			fi
		fi

		if [ -f "$APIDL" ]; then
			if [ ! -x "$(command -v "$JQ")" ]; then
				writelog "WARN" "${FUNCNAME[0]} - Can't get data from '$APIDL' because '$JQ' is not installed"
			else
				writelog "INFO" "${FUNCNAME[0]} - Searching Game Name for '$1' in $APIDL"
				GNRAW="$("$JQ" ".applist.apps[] | select (.appid==$1) | .name" "$APIDL")"
				
				if [ -n "$GNRAW" ]; then
					writelog "INFO" "${FUNCNAME[0]} - Found Game Name '$GNRAW' in $APIDL"
				fi
			fi
		else
			writelog "SKIP" "${FUNCNAME[0]} - file '$APIDL' not found"
		fi
	fi
	writelog "INFO" "${FUNCNAME[0]} - Outgoing game name is '${GNRAW//\"/}'"

	GAMENAME="${GNRAW//\"/}"
}

function writeDesktopFile {
	DESTDTF="$2"
	DESTPIC="$3"

	if [ -f "$DESTDTF" ]; then
		writelog "SKIP" "${FUNCNAME[0]} - $DESTDTF already exists"
	else
		getGameName "$1"
		if [ -z "$GAMENAME" ]; then
			writelog "SKIP" "${FUNCNAME[0]} - Could not find gamename for game id '$1'"
		elif [ -n "$GAMENAME" ] && [ "$GAMENAME" != "$NON" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Creating '$DESTDTF' for '$GAMENAME' ($1)"
			{
				echo "[Desktop Entry]"
				echo "Name=${GAMENAME//\"/}"
				echo "Comment=$DF_COMMENT"
				echo "Exec=steam steam://rungameid/$1"
				echo "Icon=$DESTPIC"
				echo "Terminal=false"
				echo "Type=Application"
				echo "Categories=Game;"
			} >> "$DESTDTF"
		fi
	fi
}

function createDesktopIconFile {
	
	if [ "$1" -eq "$1" ] 2>/dev/null; then
		AID="$1"
	else
		AID="$(getIDFromTitle "$1")"
	fi

	WANTGPNG="$STLGPNG/${AID}.png"

	if [ "$STLPLAY" -eq 1 ]; then
		mkProjDir "$STLISLDFD"
		INTDTFILE="$STLISLDFD/$AID.desktop"
	else
		mkProjDir "$STLIDFD"
		INTDTFILE="$STLIDFD/$AID.desktop"
	fi

	if [ -f "$INTDTFILE" ]; then
		writelog "INFO" "${FUNCNAME[0]} - Already have an internal desktop file '$INTDTFILE'"
	else
		if [ -n "$AID" ] && [ ! -f "$WANTGPNG" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Don't have a desktop icon yet - trying to create it"
			if [ "$STLPLAY" -eq 1 ]; then
				if [ -n "$4" ]; then
					GAMENAME="$3"
					HAVEPA="$4"
					standaloneGameIcon "$WANTGPNG" "$AID" "$GAMENAME" "$HAVEPA"
				else
					writelog "WARN" "${FUNCNAME[0]} - Not enough arguments passes to create an icon - got '$*'"
				fi
			else
				getGameIcon
			fi
		fi

		# create desktop file internally for optionally using it on the desktop
		if [ -f "$WANTGPNG" ] && [ ! -f "$INTDTFILE" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Creating $INTDTFILE"
			if [ "$STLPLAY" -eq 1 ]; then
				if [ -n "$4" ]; then
					GAMENAME="$3"
					HAVPA="$4"
					standaloneDesktopFile "$INTDTFILE" "$WANTGPNG" "$AID" "$GAMENAME" "$HAVEPA"
				else
					writelog "WARN" "${FUNCNAME[0]} - Not enough arguments passes to create a desktopfile - got '$*'"
				fi
			else
				writeDesktopFile "$AID" "$INTDTFILE" "$WANTGPNG"
			fi
		fi
	fi

	# set desktop file mode from command line:
	if [ -f "$INTDTFILE" ] && [ "$CREATEDESKTOPICON" -eq 0 ] && [ -n "$2" ]; then
		CREATEDESKTOPICON="$2"
	fi

	# copy the desktop file to the system
	if [ -f "$INTDTFILE" ] && [ "$CREATEDESKTOPICON" -ne 0 ]; then
		if [ "$CREATEDESKTOPICON" -eq "1" ] || [ "$CREATEDESKTOPICON" -eq "3" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Creating desktop icon for '$AID' on the desktop"
			cp "$INTDTFILE" "$HOME/Desktop/" 2>/dev/null
		fi

		if [ "$CREATEDESKTOPICON" -eq "2" ] || [ "$CREATEDESKTOPICON" -eq "3" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Creating desktop icon for '$AID' for the desktop application menu"
			cp "$INTDTFILE" "$HOME/.local/share/applications/" 2>/dev/null	
		fi	
	fi
}

function getOwnedHexAids {
	if [ -z "$PIVDF" ]; then
		setSteamPaths
	fi

	if [ -f "$PIVDF" ]; then
		writelog "INFO" "${FUNCNAME[0]} - Searching in '$PIVDF' for HexAids"
		HAIDS="61707069647300023000"
		"$XXD" -c "$(wc -c "$PIVDF")" -p "$PIVDF" | sed -E "s:$HAIDS:\n$HAIDS:g" | grep -o "$HAIDS.\{0,6\}" | sed "s:$HAIDS::"
	else
		writelog "SKIP" "${FUNCNAME[0]} - '$PIVDF' not found"
	fi	
}

function getOwnedAids {
	mkProjDir "$STLSHM"
	OAIDLIST="$STLSHM/owned-aids.txt"
	if [ ! -f "$OAIDLIST" ]; then
		while read -r line; do
			getAidFromHexAid "$line" >> "$OAIDLIST"
		done <<< "$(getOwnedHexAids)"
		
		sort -n -u "$OAIDLIST" -o "$OAIDLIST"
	fi
	
	if [ -f "$OAIDLIST" ]; then
		cat "$OAIDLIST"
	fi
}

function getAidFromHexAid {
	unset REVAID
	while read -r line; do
		REVAID="$REVAID${line}"
	done <<< "$(fold -2 <<< "$1" | tac)"
	printf "%d\n" "0x$REVAID"
}

function getHexAidForAid {
	unset HEXAID
	if [ -f "$GEMETA/$1.conf" ]; then
		loadCfg "$GEMETA/$1.conf" X
	fi
		
	if [ -n "$HEXAID" ]; then
		if [ -z "$2" ]; then
			echo "$HEXAID"
		fi
	else
		HXTST="$(printf '%x\n' "$1" | fold -w2 | tail -n1)"

		if [ "${#HXTST}" -eq 1 ]; then
			SHEX1="$(printf '0%x\n' "$1" | fold -w2 | tac)";
		else
			SHEX1="$(printf '%x\n' "$1" | fold -w2 | tac)";
		fi

		while read -r line; do
			HEXAID="$HEXAID${line}"
		done <<< "$SHEX1"
		
		if [ -z "$2" ]; then
			echo "$HEXAID"
		fi
		touch "$FUPDATE"
		touch "$GEMETA/$1.conf"
		updateConfigEntry "HEXAID" "$HEXAID" "$GEMETA/$1.conf"
	fi
}

function getRawAppIDInfo {
	AIIDRAW="$STLAPPINFOIDDIR/${1}.bin"

	if [ -z "$FAIVDF" ]; then
		setSteamPaths
	fi
	
	if [ -z "$LOGRAWINFO" ]; then
		LOGRAWINFO=1
	fi
	
	if [ -s "$AIIDRAW" ] && [ -z "$2" ]; then
		if [ -z "$LOGRAWINFO" ]; then
			LOGRAWINFO=1
		fi

		if [ "$LOGRAWINFO" -eq 1 ]; then
			writelog "INFO" "${FUNCNAME[0]} - Found raw $APIN file '$AIIDRAW'"
		fi
	else
		if [ -n "$2" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Updating raw $APIN file '$AIIDRAW'"
		fi

		if [ ! -s "$AIIDRAW" ]; then
			rm "$AIIDRAW" 2>/dev/null
		fi

		HEXAID="$(getHexAidForAid "$1")"
		HAID="02617070696400"
	
		SHMAIVDF="$STLSHM/${AIVDF//\.vdf/\.hex}"
		if [ ! -f "$SHMAIVDF" ]; then
			"$XXD" -c "$(wc -c "$FAIVDF")" -p "$FAIVDF" "$SHMAIVDF"
		fi
		sed -E "s:$HAID:\n$HAID:g" "$SHMAIVDF" | grep "^${HAID}${HEXAID}00" | "$XXD" -r -p - "$AIIDRAW"
	fi
}

function getAppInfoData {
	# $1=AID; $2=category; optional $3=skip stdout; optional $4=force writing metadata again
	if [ -n "$2" ] && [ "$STLPLAY" -eq 0 ]; then
		AILIST="$GLOBALMISCDIR/$AITXT"
		if ! [ -f "$AILIST" ]; then
			SCRIPTDIR="$( realpath "$0" )"
			SCRIPTDIR="${SCRIPTDIR%/*}"

			writelog "INFO" "${FUNCNAME[0]} - No '$AITXT' found in Global Misc Dir '$GLOBALMISCDIR', checking for one in the script dir '$SCRIPTDIR'"
			if [ -f "$SCRIPTDIR/misc/$AITXT" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Found '$AITXT' in '$SCRIPTDIR/misc' - Using this"
				AILIST="$SCRIPTDIR/misc/$AITXT"
			else
				writelog "INFO" "${FUNCNAME[0]} - Could not find '$AITXT' in script directory - giving up"
			fi
		fi

		if grep -q "$2" "$AILIST"; then

			UPDAT="${2^^}"
			unset "$UPDAT"

			if [ -f "$GEMETA/$1.conf" ]; then
				loadCfg "$GEMETA/$1.conf" X
			fi
			
			if [ -n "${!UPDAT}" ] && [ -z "$4" ]; then
				if [ -z "$3" ]; then
					writelog "INFO" "${FUNCNAME[0]} - Got value '${!UPDAT}' for '$UPDAT' from '$GEMETA/$1.conf'"
					echo "${!UPDAT}"
				fi
			else
				LOGRAWINFO=0
				getRawAppIDInfo "$1"
				SRCHEX="$STLAPPINFOIDDIR/$1.bin"

				if [ -f "$SRCHEX" ]; then
					if [ -z "$3" ]; then
						writelog "INFO" "${FUNCNAME[0]} - Retrieving data for '$2' from '$SRCHEX'"
					fi

					HVAR="$(echo -n "$2" | "$XXD" -ps)"
					unset HXOUT

					if [ "$2" == "metacritic_score" ]; then
						UPVALHX="$("$XXD" -c "$(wc -c "$SRCHEX")" -p "$SRCHEX" | sed -E "s:$HVAR:\n$HVAR:g" | grep "^$HVAR" | head -c "$(( $(wc -c <<< "$HVAR") + 3))" | tail -c2)"
						if [ -n "$UPVALHX" ]; then
							UPVAL="$((16#$UPVALHX))"
						fi
					else
						OCOUNT=0
						ZCOUNT=0
						while read -r line; do
							if [ "$line" == "01" ]; then
								OCOUNT=$((OCOUNT+1))
								if [[ "$OCOUNT" -eq 2 ]]; then
									break
								fi
							elif [ "$line" == "00" ] ; then
								ZCOUNT=$((ZCOUNT+1))
								if [[ "$ZCOUNT" -eq 2 ]]; then
									break
								fi
							else
								HXOUT="$HXOUT$line"
							fi
						done <<< "$("$XXD" -c "$(wc -c "$SRCHEX")" -p "$SRCHEX" | sed -E "s:01$HVAR:\n01$HVAR:g" | grep "^01$HVAR" | fold -2)"
						UPVALHX="${HXOUT//${HVAR}00/}"
						UPVALHX1="${UPVALHX//${HVAR}/}"
						UPVALHXO="${UPVALHX1%*00}"				
						
						UPVAL="$("$XXD" -r -p - <<< "$UPVALHXO")"
					fi

					if [ -n "$UPVAL" ]; then
						touch "$FUPDATE"
						touch "$GEMETA/$1.conf"
						updateConfigEntry "$UPDAT" "$UPVAL" "$GEMETA/$1.conf"
						if [ -z "$3" ]; then
							echo "$UPVAL"
						fi
					fi
				fi
			fi
		else
			writelog "SKIP" "${FUNCNAME[0]} - '$2' is not in '$AILIST'"
		fi
	fi
}

function writeAllAIMeta {
	if [ -n "$1" ] && [ "$1" -eq "$1" ]; then
		if [ -n "$2" ]; then
			rm "$STLAPPINFOIDDIR/${1}.bin" 2>/dev/null
		fi
		AILIST="$GLOBALMISCDIR/$AITXT"
		while read -r line; do
		 	getAppInfoData "$1" "$line" X "$2"
		done < "$GLOBALMISCDIR/$AITXT"
	else
		writelog "SKIP" "${FUNCNAME[0]} - need SteamAppId as arg 1"
	fi
}

function getGameIcon {
	function IcotoPng {
		if [ -x "$(command -v "$CONVERT" 2>/dev/null)" ]; then
			if [ -x "$(command -v "$IDENTIFY" 2>/dev/null)" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Determining largest ico in '$WANTGICO' using '$IDENTIFY'"
				LICO="$("$IDENTIFY" "$WANTGICO" | sort -n -k3 | tail -n1 | grep -oP '\[\K[^\]]+')"
			else
				writelog "INFO" "${FUNCNAME[0]} - Command '$IDENTIFY' not found, using first ico in '$WANTGICO'"
				LICO="0"
			fi

			if [ -z "$LICO" ] || [ "$LICO" -ne "$LICO" ] 2>/dev/null; then
				writelog "INFO" "${FUNCNAME[0]} - No specific ico found using the first one in '$WANTGICO'"
				LICO="0"		
			fi

			if [ "$LICO" -eq "$LICO" ] 2>/dev/null; then
				writelog "INFO" "${FUNCNAME[0]} - Converting ico '$LICO' in '$WANTGICO' to '$WANTGPNG' using command: $CONVERT ${WANTGICO}[${LICO}] $WANTGPNG"
				"$CONVERT" "${WANTGICO}[${LICO}]" "$WANTGPNG"
			fi
		else
			writelog "SKIP" "${FUNCNAME[0]} - Command '$CONVERT' not found, so converting '$WANTGICO' to '$WANTGPNG' is not possible - skipping"
		fi	
	}

	function getIco {
		WANTGICO="$STLGICO/${AID}.ico"
		if [ -f "$WANTGICO" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Already have game ico '$WANTGICO'"
			IcotoPng
		else
			ICONAME="$(getAppInfoData "$AID" "clienticon")"
			if [ -n "$ICONAME" ]; then
				ICOPATH="$ICODIR/${ICONAME}.ico"
				if [ -f "$ICOPATH" ]; then
					writelog "INFO" "${FUNCNAME[0]} - Found ico for '$AID' under '$ICOPATH'"
					cp "$ICOPATH" "$WANTGICO"
					IcotoPng
				else
					writelog "SKIP" "${FUNCNAME[0]} - Absolute path for Steam ico '$ICONAME' not valid - skipping"
				fi
			else
				writelog "SKIP" "${FUNCNAME[0]} - Could not find the icon name for '$AID' in $APIN - skipping"
			fi
		fi		
	}
	
	function extractGZip {
		BIGGESTPNG="$("$UNZIP" -l "$WANTGZIP" | grep "\.png" | sort -n | tail -n1 | awk -F ':[0-9][0-9]   ' '{print $NF}')" # weak 'awk' might break here(?)
		if [ -n "$BIGGESTPNG" ];then
			writelog "INFO" "${FUNCNAME[0]} - Extracting biggest png file '$BIGGESTPNG' in archive '$WANTGZIP' to '$WANTGPNG'"
			writelog "INFO" "${FUNCNAME[0]} - $UNZIP -dqq ${WANTGPNG//.png} $WANTGZIP $BIGGESTPNG"
			"$UNZIP" -q -d "${WANTGPNG//.png}" "$WANTGZIP" "$BIGGESTPNG"
			mv "${WANTGPNG//.png}/$BIGGESTPNG" "$WANTGPNG"
			rm -rf "${WANTGPNG//.png}"
		else
			writelog "SKIP" "${FUNCNAME[0]} - Could not determine the biggest png file in archive '$WANTGZIP'- skipping"
		fi
	}

	if [ -z "$AID" ]; then
		writelog "SKIP" "${FUNCNAME[0]} - Don't have a Steam gameid - skipping"
	else
		WANTGPNG="$STLGPNG/${AID}.png"
		if [ -f "$WANTGPNG" ]; then
			writelog "Info" "${FUNCNAME[0]} - Already have game icon png '$WANTGPNG' - nothing to to"
		else
			if [ -z "$ICODIR" ]; then
				setSteamPaths
			fi
			
			if [ ! -d "$ICODIR" ]; then
				writelog "SKIP" "${FUNCNAME[0]} - Steam ico directory not found - skipping"
			else
				WANTGZIP="$STLGZIP/${AID}.zip"
				if [ -f "$WANTGZIP" ]; then
					writelog "INFO" "${FUNCNAME[0]} - Already have game icon zip '$WANTGZIP' - extracting"
					extractGZip "$WANTGZIP" "$WANTGPNG"
				else
					writelog "INFO" "${FUNCNAME[0]} - Looking for icon hash in $APIN"
					
					LICONZIP="$(getAppInfoData "$AID" "linuxclienticon")"
					if [ -n "$LICONZIP" ]; then
						LICONPATH="$ICODIR/${LICONZIP}.zip"
						if [ -f "$LICONPATH" ]; then
							writelog "INFO" "${FUNCNAME[0]} - Found icon zip for '$AID' under '$LICONPATH'"
							cp "$LICONPATH" "$WANTGZIP"
							extractGZip "$WANTGZIP" "$WANTGPNG"
						else
							writelog "INFO" "${FUNCNAME[0]} - Absolute path for Steam icon zip '$LICONZIP' not valid - trying to find ico instead"
							getIco
						fi
					else
						writelog "SKIP" "${FUNCNAME[0]} - Could not find the icon zip for '$AID' in $APIN - trying to find ico instead"
						getIco
					fi
				fi
			fi
		fi
	fi
}

function getGameData {
	if ! grep -q ",${1}," <<< "$NOGAMES" && [ "$STLPLAY" -eq 0 ]; then
		DLPIC="$STLGHEADD/$1.jpg"
		if [ ! -f "$DLPIC" ] || [ ! -s "$DLPIC" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Downloading picture '$DLPIC' from '$STASSURL/$1/header.jpg'" "X" "$GGDLOG"
			getGamePic "$DLPIC" "$STASSURL/$1/header.jpg"
		fi

		DESTDTF="$STLGDESKD/$1.desktop"
		if [ ! -f "$DESTDTF" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Creating desktopfile '$DESTDTF'" "X" "$GGDLOG"
			writeDesktopFile "$1" "$DESTDTF" "$DLPIC"
		fi
	fi
}

function getParsableGameList {
	if [ -z "$SUSDA" ] || [ -z "$STUIDPATH" ]; then
		setSteamPaths
	fi
	if [ -d "$SUSDA" ]; then
		SC="$STUIDPATH/$SRSCV"
		APPI="Apps"
		APPO="StartMenuShortcutCheck"
		LIST="$(awk "/$APPI/,/$APPO/" "$SC" | grep -v "$APPI\|$APPO" | awk '{printf "%s+",$0} END {print ""}' | sed 's/"[0-9][0-9]/\n&/g')"
		LISTCNT="$(wc -l <<< "$LIST")"
		writelog "INFO" "${FUNCNAME[0]} - Found '$LISTCNT' parsable Game Entries in '$SC'"
		if [ "$LISTCNT" -eq 0 ]; then
			writelog "SKIP" "${FUNCNAME[0]} - No game found in any Steam collection"
		fi
		echo "$LIST"
	else
		writelog "SKIP" "${FUNCNAME[0]} - '$SUSDA' not found - this should not happen! - skipping"
	fi
}

function getInstalledGamesFromCollection {
	CAT="$1"

	if [ -n "$CAT" ]; then
		while read -r CATAID; do
		echo "$CATAID"
		done <<< "$(getParsableGameList | grep "\"$CAT\"" | sed "s:\"::g" | sort -n | cut -d '+' -f1)"
	fi
}

function listInstalledGameIDs {
	while read -r APPMA; do
		grep -Eo "[[:digit:]]*" <<< "${APPMA##*/}"
	done <<< "$(listAppManifests)"
}

function getGameDataForInstalledGames {
	if [ "$(listInstalledGameIDs | wc -l)" -eq 0 ]; then
		writelog "SKIP" "${FUNCNAME[0]} - No installed games found!"
	else
		while read -r CATAID; do
			if [ -n "$CATAID" ]; then
				getGameData "$CATAID"
			fi
		done <<< "$(listInstalledGameIDs)"
	fi
}

function checkSGDbApi {
	if [ -z "$SGDBAPIKEY" ] || [ "$SGDBAPIKEY" == "$NON" ]; then
		writelog "SKIP" "${FUNCNAME[0]} - No SteamGrid Api Key found - Get one at '${STEAMGRIDDBAPI}'"
		writelog "SKIP" "${FUNCNAME[0]} - and save it in the Global Config ('SGDBAPIKEY')"
		return 1
	else
		return 0
	fi	
}

# Takes a list of appids separated by newlines
function getGrids {
	if checkSGDbApi && [ "$STLPLAY" -eq 0 ]; then
		# Split into batches of 100 games - too many and cloudflare blocks requests because of a too big header file
		while mapfile -t -n 100 ary && ((${#ary[@]})); do
			PART=$(printf '%s\n' "${ary[@]}")
			# If the whole batch has no grids we get a 404 and wget gives an error. --content-on-error ensures we still get the response json and the following logic still works
			RESPONSE="$("$WGET" --content-on-error --header="Authorization: Bearer $SGDBAPIKEY" -q "${STEAMGRIDDBAPI}/$(echo "$PART" | awk '{print $1}' | paste -s -d, -)?styles=${SGDBSTYLES}&dimensions=${SGDBDIMS}&types=${SGDBTYPES}&nsfw=${SGDBNSFW}&humor=${SGDBHUMOR}" -O - 2> >(grep -v "SSL_INIT"))"

			if ! "$JQ" -e '.success' 1> /dev/null <<< "$RESPONSE"; then
				writelog "INFO" "${FUNCNAME[0]} - The server response wasn't 'success' for this batch of requested games."
				continue
			fi

			# catch single grid without downloads
			RESPONSE_LENGTH=$("$JQ" '.data | length' <<< "$RESPONSE")
			if [ "$RESPONSE_LENGTH" = 0 ]; then
				writelog "INFO" "${FUNCNAME[0]} - No grid found to download - maybe loosen filters?"
				continue
			fi

			# TODO: This could be handled by the http return value - 200 is single-part - 207 is multi-part
			# Rewrite response object to fit the following loop if the response isn't multi-part
			if "$JQ" -e ".data[0].url" 1> /dev/null <<< "$RESPONSE"; then
				RESPONSE="{\"success\":true,\"data\":[$RESPONSE]}"
				RESPONSE_LENGTH=1
			fi

			for i in $(seq 0 $(("$RESPONSE_LENGTH" - 1))); do
				# match the current json array member against the appid list
				# this assumes we get the same order back we put in before
				APPID=$(sed "$((i + 1))q;d" <<< "$PART")

				if ! "$JQ" -e ".data[$i].success" 1> /dev/null <<< "$RESPONSE"; then
					writelog "INFO" "${FUNCNAME[0]} - The server response for '$APPID' wasn't 'success'"
					continue
				fi
				if ! URLSTR=$("$JQ" -e -r ".data[$i].data[0].url" <<< "$RESPONSE"); then
					writelog "INFO" "${FUNCNAME[0]} - No grid found to download for '$APPID' - maybe loosen filters?"
					continue
				fi

				GRIDDLURL="${URLSTR//\"}"
				if grep -q "^https" <<< "$GRIDDLURL"; then
					DLSRC="${GRIDDLURL//\"}"

					if [ "$SGDBDLTOSTEAM" -eq 1 ]; then
						if [ -z "$SUSDA" ]; then
							setSteamPaths
						fi
						if [ -d "$SUIC" ]; then
							GRIDDLDIR="${SUIC}/grid"
						fi
					else
						GRIDDLDIR="$STLDLDIR/steamgriddb"
					fi

					mkProjDir "$GRIDDLDIR"
			
					DLDST="$GRIDDLDIR/${APPID}p.${GRIDDLURL##*.}"
					STARTDL=1
					
					if [ -f "$DLDST" ]; then
						if [ "$SGDBHASFILE" == "skip" ]; then
							writelog "INFO" "${FUNCNAME[0]} - Download of existing file is set to '$SGDBHASFILE' - doing nothing"
							STARTDL=0
						elif [ "$SGDBHASFILE" == "backup" ]; then
							BACKDIR="${GRIDDLDIR}/backup"
							mkProjDir "$BACKDIR"
							writelog "INFO" "${FUNCNAME[0]} - Backup existing file into '$BACKDIR', because SGDBHASFILE is set to '$SGDBHASFILE'"
							mv "$DLDST" "$BACKDIR"
						elif [ "$SGDBHASFILE" == "replace" ]; then
							writelog "INFO" "${FUNCNAME[0]} - Replacing existing file '$DLDST', because SGDBHASFILE is set to '$SGDBHASFILE'"
							rm "$DLDST" 2>/dev/null
						fi
					fi
					
					if [ "$STARTDL" -eq 1 ]; then
						dlCheck "$DLSRC" "$DLDST" "X" "Downloading '$DLSRC' to '$DLDST'"
					fi
				else
					writelog "INFO" "${FUNCNAME[0]} - No grid found to download for '$APPID' - maybe loosen filters?"
				fi
			done
		done <<< "${1}"
	fi
}

function getGridsForOwnedGames {
	if checkSGDbApi; then
		getGrids "$(getOwnedAids)"
	fi
}

function getGridsForInstalledGames {
	if checkSGDbApi; then
		if [ "$(listInstalledGameIDs | wc -l)" -eq 0 ]; then
			writelog "SKIP" "${FUNCNAME[0]} - No installed games found!"
		else
			getGrids "$(listInstalledGameIDs)"
		fi
	fi
}

function getDataForAllGamesinSharedConfig {
	while read -r CATAID; do
		getGameData "$CATAID"
	done <<< "$(getParsableGameList | cut -d '+' -f1 | sed "s:\"::g" | grep "[0-9]" | sort -n)"
}

function getActiveSteamCollections {
	getParsableGameList | grep "\"tags\"" | awk -F '{+' '{print $NF}' | sed 's/\"/'$'\\\n/g' | sort -u | grep -i "^[a-z]"
}

function createCollectionMenus {
	# create launcher menu for all installed games
	DFIDIR="$DFDIR/installed"
	mkProjDir "$DFIDIR"

	if [ "$(listInstalledGameIDs | wc -l)" -eq 0 ]; then
		writelog "SKIP" "${FUNCNAME[0]} - No installed games found!"
	else
		while read -r CATGAME; do
			if [ -n "$CATGAME" ] && [ ! -h "$DFIDIR/$CATGAME.desktop" ] && [ -f "$STLGDESKD/$CATGAME.desktop" ]; then
				ln -s "$STLGDESKD/$CATGAME.desktop" "$DFIDIR"
			fi
		done <<< "$(listInstalledGameIDs)"
	fi

	# create launcher menu for collection '$1'
	if [ -n "$1" ] && [ "$1" == "update" ] && [ "$(find "$DFDIR" -name "*.desktop" | wc -l)" -gt 0 ]; then
		find "$DFDIR" -name "*.desktop" -exec rm {} \;
	fi
	
	if [ "$(find "$DFDIR" -name "*.desktop" | wc -l)" -eq 0 ]; then
		while read -r CAT; do
			DFCDIR="$DFDIR/$CAT"
			mkProjDir "$DFCDIR"
			while read -r CATGAME; do
				if [ -f "$STLGDESKD/$CATGAME.desktop" ]; then
					if [ ! -h "$DFCDIR/$CATGAME.desktop" ]; then
						ln -s "$STLGDESKD/$CATGAME.desktop" "$DFCDIR"
					fi
				fi
			done <<< "$(getInstalledGamesFromCollection "$CAT")"
		done < <(getActiveSteamCollections)
	fi
}

function listSteamLibraries {
	function getBIF {
		local REGEX='"(BaseInstallFolder[^"]*|path)"\s+"(.*)"\s*$'
		in="$1"
		if [[ $in =~ $REGEX ]] && [ -n "${BASH_REMATCH[2]}" ]; then
			echo "${BASH_REMATCH[2]}/$SA"
		else
			writelog "WARN" "${FUNCNAME[0]} - Failed to parse Base Install Folder from '$in'"
		fi
	}

	function listSLs {
		if [ -f "$CFGVDF" ] || [ -f "$LFVDF" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Searching appmanifest files in '$CFGVDF' and '$LFVDF'" "X" "$APPMALOG"
			while read -r BIF; do
				getBIF "$BIF"
			done <<< "$(grep "\"BaseInstallFolder\|\"path\"" "$CFGVDF" "$LFVDF" 2>/dev/null)" | sort -u
		else
			writelog "SKIP" "${FUNCNAME[0]} - Neither file CFGVDF '$CFGVDF' nor file LFVDF '$LFVDF' found - this should not happen! - skipping"
		fi
	}
	
	MAXAGE=360
	if [ ! -f "$STELILIST" ] || test "$(find "$STELILIST" -mmin +"$MAXAGE")"; then
		writelog "INFO" "${FUNCNAME[0]} - (Re-)creating '$STELILIST'"
		rm "$STELILIST" 2>/dev/null
		listSLs | sort -u > "$STELILIST"
	else
		writelog "SKIP" "${FUNCNAME[0]} - not recreating already available '$STELILIST'"
	fi
}

function setSteamLibraryPaths {
	while read -r lpath; do
		# Ignores library folders if they are not valid directories -- This var comes from Steam but apparently can still have invalid library folders.
		# Noticed this when I removed a drive that had a Steam library folder, this didn't cause any major issues aside from a 'find' warning from the cmpath while loop - Could be a Steam bug?
		if [ ! -d "$lpath" ]; then
			writelog "WARN" "${FUNCNAME[0]} - Library folder '$lpath' does not seem to be a valid directory, even though this comes from Steam itself - Ignoring, but please report if this is invalid or causes issues"
			continue
		fi

		if [ -z "$STEAM_COMPAT_LIBRARY_PATHS" ]; then
			STEAM_COMPAT_LIBRARY_PATHS="$lpath"  # This var should come from Steam, even the Proton script uses it
		else
			if ! grep -q "$lpath" <<< "$STEAM_COMPAT_LIBRARY_PATHS" ; then
				STEAM_COMPAT_LIBRARY_PATHS="$STEAM_COMPAT_LIBRARY_PATHS:$lpath"
			fi
		fi

		while read -r cmpath; do
			if [ -n "$cmpath" ]; then
				if [ -z "$STEAM_COMPAT_MOUNTS" ]; then
					STEAM_COMPAT_MOUNTS="$cmpath"
				else
					if ! grep -q "$cmpath" <<< "$STEAM_COMPAT_MOUNTS" ; then
						STEAM_COMPAT_MOUNTS="$STEAM_COMPAT_MOUNTS:$cmpath"
					fi
				fi

				if [ -z "$STEAM_COMPAT_TOOL_PATHS" ]; then
					STEAM_COMPAT_TOOL_PATHS="$cmpath"
				else
					if ! grep -q "$cmpath" <<< "$STEAM_COMPAT_TOOL_PATHS" ; then
						STEAM_COMPAT_TOOL_PATHS="$STEAM_COMPAT_TOOL_PATHS:$cmpath"
					fi
				fi
			fi
		done <<< "$(find "$lpath" -mindepth 2 -maxdepth 2 -type d \( -name "Proton" -o -name "$STEWOS" -o -name "${SLR}*" \))"
	done < "$STELILIST"

	export STEAM_COMPAT_LIBRARY_PATHS
	export STEAM_COMPAT_MOUNTS
	export STEAM_COMPAT_TOOL_PATHS

	writelog "INFO" "${FUNCNAME[0]} - STEAM_COMPAT_LIBRARY_PATHS set to '$STEAM_COMPAT_LIBRARY_PATHS'"
	writelog "INFO" "${FUNCNAME[0]} - STEAM_COMPAT_MOUNTS set to '$STEAM_COMPAT_MOUNTS'"
	writelog "INFO" "${FUNCNAME[0]} - STEAM_COMPAT_TOOL_PATHS set to '$STEAM_COMPAT_TOOL_PATHS'"
}

function listAppManifests {
	function findAppMa {
		if [ -d "$1" ]; then
			find "$1" -mindepth 1 -maxdepth 1 -type f -name "appmanifest_*.acf"
		fi
	}

	# getBIF takes a string containing a BaseInstallFolder or path and returns the 
	function getBIF {
		# REGEX needs to be a variable, quoted string literals are not treated as regexps by test
		# BASH_REMATCH[1] will be the key (BaseInstallFolder* or path)
		# BASH_REMATCH[2] will be the value (the actual steam library folder)
		local REGEX='"(BaseInstallFolder[^"]*|path)"\s+"(.*)"\s*$'
		in="$1"

		# Test the regex against input, then print the extracted path to stdout
		if [[ $in =~ $REGEX ]] && [ -n "${BASH_REMATCH[2]}" ]; then
			echo "${BASH_REMATCH[2]}/$SA"
		else
			writelog "WARN" "${FUNCNAME[0]} - Failed to parse Base Install Folder from '$in'"
		fi
	}

	function listAllAppMas {
		if [ -d "$DEFSTEAMAPPS" ]; then
			findAppMa "$DEFSTEAMAPPS"
		else
			writelog "SKIP" "${FUNCNAME[0]} - '$DEFSTEAMAPPS' not found - this should not happen! - skipping"
		fi

		if [ -f "$CFGVDF" ] || [ -f "$LFVDF" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Searching appmanifest files in '$CFGVDF' and '$LFVDF'" "X" "$APPMALOG"
			while read -r BIF; do
				findAppMa "$(getBIF "$BIF")"
			done <<< "$(grep "\"BaseInstallFolder\|\"path\"" "$CFGVDF" "$LFVDF" 2>/dev/null)" | sort -u
		else
			writelog "SKIP" "${FUNCNAME[0]} - Neither file CFGVDF '$CFGVDF' nor file LFVDF '$LFVDF' found - this should not happen! - skipping"
		fi
	}
	
	listAllAppMas | sort -u
}

function createCollectionList {
	function listCAT {
		while read -r CATMENU; do
			echo "${CATMENU##*/}"
		done <<< "$(find "$DFDIR" -mindepth 1 -maxdepth 1 -type d)"
	}
	CATLIST="$(listCAT | sort -u | tr '\n' '!' | sed "s:^!::" | sed "s:!$::")"
} 

function setGeom {
	GEOM="--geometry=${WINX}x${WINY}+${POSX}+${POSY}"
}

function pollWinRes {
	TITLE="$1"
	POSX=0
	POSY=0
	unset COLCOUNT

	if [ "$ONSTEAMDECK" -eq 1 ]; then
		SCREENRES="1280x800"
		WINX=1280
		WINY=800
		setGeom
	else
		SCREENRES="$(getScreenRes r)"
	fi
	
	if [ -z "$SCREENRES" ]; then  SCREENRES="any"; fi

	if [ "$FIXGAMESCOPE" -eq 0 ]; then  # skip this if FIXGAMESCOPE is 1 - so for now only if running in GameMode on the Steam Deck
		TEMPL="template"
		GAMEGUICFG="$STLGUIDIR/$SCREENRES/${AID}/${TITLE}.conf"
		TEMPLGUICFG="$STLGUIDIR/$SCREENRES/${TEMPL}/${TITLE}.conf"
		GLOBTEMPLGUICFG="$GLOBALSTLGUIDIR/$SCREENRES/${TEMPL}/${TITLE}.conf"

		mkProjDir "${GAMEGUICFG%/*}"
		mkProjDir "${TEMPLGUICFG%/*}"
		
		if [ -f "$TEMPLGUICFG" ] && [ ! -f "$GAMEGUICFG" ]; then
			loadCfg "$TEMPLGUICFG" X
			setGeom
			writelog "INFO" "${FUNCNAME[0]} - Using GEOM '$GEOM' from '$TEMPLGUICFG'" "$WINRESLOG"
		elif [ -f "$GLOBTEMPLGUICFG" ] && [ ! -f "$GAMEGUICFG" ]; then
			loadCfg "$GLOBTEMPLGUICFG" X
			setGeom
			writelog "INFO" "${FUNCNAME[0]} - Using GEOM '$GEOM' from '$GLOBTEMPLGUICFG'" "$WINRESLOG"
		elif [ -f "$GAMEGUICFG" ]; then
			loadCfg "$GAMEGUICFG" X
			setGeom
			writelog "INFO" "${FUNCNAME[0]} - Using GEOM '$GEOM' from '$GAMEGUICFG'" "$WINRESLOG"
		else
			touch "$GAMEGUICFG"
			echo "WINX=\"$WINX\"" > "$GAMEGUICFG"
			echo "WINY=\"$WINY\"" >> "$GAMEGUICFG"

			if [ -z "$GEOM" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Using harmless '--center' as variable 'GEOM', because there are multiple side-effects in yad if the string is empty"
				GEOM="--center"
			fi

			writelog "INFO" "${FUNCNAME[0]} - Creating initial '$GAMEGUICFG' with unused default values" "$WINRESLOG"
		fi
	fi

	if [ -n "$2" ]; then
		DEFCOL="$2"
	else
		DEFCOL=1
	fi
	
	if [ -z "$COLCOUNT" ]; then
		if [ "$ONSTEAMDECK" -eq 0 ]; then
			updateConfigEntry "COLCOUNT" "$DEFCOL" "$GAMEGUICFG"
		fi
		COLCOUNT="$DEFCOL"
	fi
	
	CURGUICFG="$GAMEGUICFG"
	export CURGUICFG="$CURGUICFG"

	if [ "$FIXGAMESCOPE" -eq 0 ]; then
		updateWinRes "$TITLE" "$GAMEGUICFG" "$TEMPLGUICFG" &
	fi
}

function openGameLauncher {
	function GLgui {
		LISTDIR="$DFDIR/$1"
		if [ -d "$LISTDIR" ] && [ "$(find "$LISTDIR" -name "*.desktop" | wc -l)" -ge 1 ]; then
			"$YAD" --f1-action="$F1ACTION" --icons --window-icon="$STLICON" --read-dir="$LISTDIR" "$WINDECO" --title="$TITLE" --single-click --keep-icon-size --center --compact --sort-by-name "$GEOM"
		else
			writelog "SKIP" "${FUNCNAME[0]} - No games found in '$LISTDIR' or directory itself not found"
		fi
	}

	if grep -q "update" <<< "$@"; then
		createCollectionMenus "update"
	else
		createCollectionMenus "dummy"
	fi

	if [ "$(find "$DFDIR" -name "*.desktop" | wc -l)" -eq 0 ]; then
		writelog "INFO" "${FUNCNAME[0]} - No desktop file found in '$DFDIR'"
		if [ "$1" == "auto" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Found argument 'auto'. Automatically creating/downloading required data for all installed games found"
			getGameDataForInstalledGames
			if [ -n "$2" ] && [ "$2" == "update" ]; then
				createCollectionMenus "$2"
			else
				createCollectionMenus "dummy"
			fi
		else
			writelog "INFO" "${FUNCNAME[0]} - Either add argument 'auto' to automatically create/download required data or check '$PROGCMD --help'"
			exit
		fi
	fi

	export CURWIKI="$PPW/Game-Launcher"
	TITLE="${PROGNAME}-Launcher"
	pollWinRes "$TITLE" 

	if [ -z "$1" ] || [ "$1" == "auto" ] || [ "$1" == "update" ]; then
		GLgui "installed"
	else
		if [ "$1" == "menu" ]; then
			createCollectionList
			CATMENU="$("$YAD" --f1-action="$F1ACTION" --window-icon="$STLICON" --center "$WINDECO" --form --scroll --separator="\n" --quoted-output \
			--text="$(spanFont "$GUI_CHOOSECAT" "H")" \
			--field="$GUI_CHOOSECATS":CB "$(cleanDropDown "installed" "$CATLIST")" \
			--title="$TITLE" "$GEOM"
			)"
			
			if [ -n "${CATMENU//\'}" ]; then
				GLgui "${CATMENU//\'}"
			fi
		elif [ "$1" == "last" ]; then
			if [ -f "$LASTRUN" ]; then
				PREVAID="$(grep "^PREVAID" "$LASTRUN" | cut -d '=' -f2)"
				if [ -n "$PREVAID" ]; then
					AID="${PREVAID//\"}"
					if [ -f "$STLGDESKD/$AID.desktop" ]; then
						writelog "INFO" "${FUNCNAME[0]} - '$1' selected, so opening splash for '$STLGDESKD/$AID.desktop'"
						DFCDIR="$DFDIR/last"
						mkProjDir "$DFCDIR"
						cp "$STLGDESKD/$AID.desktop" "$DFCDIR"
						GLgui "$1"
					else
						writelog "SKIP" "${FUNCNAME[0]} - '$1' selected, but file '$STLGDESKD/$AID.desktop' not found"
					fi
				fi
			fi
		elif [ -d "$DFDIR/$1" ]; then
			GLgui "$1"
		else
			writelog "SKIP" "${FUNCNAME[0]} - Steam Collection '$1' not found in '$DFDIR'"
			writelog "SKIP" "${FUNCNAME[0]} - Only found '$(ls "$DFDIR")'"
		fi
	fi
}

function DBGMS {
	echo "$(date) - $1" >> "$STLSHM/DBGMS.txt"
}

function resetAID {
	if [ -n "$1" ]; then
		if [ -n "${1##*[!0-9]*}" ]; then
			AID="$1"
		else
			if [ "$1" == "last" ]; then
				if [ -f "$LASTRUN" ]; then
					PREVAID="$(grep "^PREVAID" "$LASTRUN" | cut -d '=' -f2)"
					if [ -n "$PREVAID" ]; then
						AID="${PREVAID//\"}"
						PREVGAME="$(grep "^PREVGAME" "$LASTRUN" | cut -d '=' -f2)"
						if [ -n "$PREVGAME" ]; then
							GN="${PREVGAME//\"}"
						fi
					fi
				else
					AID="$PLACEHOLDERAID"
				fi
			fi
		fi
	fi
	# should not happen, but just in case it is still empty, set the placeholders
	if [ -z "$AID" ]; then
		AID="$PLACEHOLDERAID"
	fi

	if [ "$AID" == "$PLACEHOLDERAID" ]; then
		GN="$PLACEHOLDERGN"
	fi
	setAIDCfgs
}

function setGN {
	if [ -z "$GN" ]; then
		getGameName "$1"
		GN="$GAMENAME"
	fi
}

function createSymLink {
	if [ ! -L "$3" ] && [ -e "$2" ]; then
		ln -s "$2" "$3"
		writelog "INFO" "$1 - Set symlink from '$2' to '$3'"
	else
		if [ -L "$3" ] && [ -z "$4" ]; then
			writelog "INFO" "$1 - Symlink '$3' already exists"
		fi

		if [ ! -e "$2" ]; then
			writelog "INFO" "$1 - '$2' does not exists"
		fi
	fi
}

function linkLog {
	if [ -z "$GN" ]; then
		writelog "SKIP" "${FUNCNAME[0]} - Skipping symlinking logfile - no valid game name found"
	else
		createSymLink "${FUNCNAME[0]}" "$LOGFILE" "$LOGDIRTI/$GN.log"
	fi
}

function setGlobalAIDCfgs {
	GLOBALSBSTWEAKCFG="$GLOBALSBSTWEAKS/$AID.conf"
	GLOBALTWEAKCFG="$GLOBALTWEAKS/$AID.conf"
}

function setCompatDataTitle {
	if [ "$STORECOMPDATTITLE" -eq 1 ] && [ -n "$OSCDP" ]; then
		mkProjDir "$STLCOMPDAT"
		COMPDATTITLE="$STLCOMPDAT/$GN"
		if readlink "$COMPDATTITLE" >/dev/null ; then
			writelog "INFO" "${FUNCNAME[0]} - Symlink $COMPDATTITLE already exists"
			if [ "$(readlink "$COMPDATTITLE")" == "$OSCDP" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Symlink '$COMPDATTITLE' already points to the correct directory '$OSCDP'"
			else
				writelog "INFO" "${FUNCNAME[0]} - Symlink '$COMPDATTITLE' points to '$(readlink "$COMPDATTITLE")' which is not the correct directory '$OSCDP' - renewing!"
				rm "$COMPDATTITLE"
				createSymLink "${FUNCNAME[0]}" "$OSCDP" "$COMPDATTITLE"
			fi
		else
			createSymLink "${FUNCNAME[0]}" "$OSCDP" "$COMPDATTITLE"
		fi
	fi
}

function setGameVars {
	getGameOS "$@"
	# common
	if [ -n "$STEAM_COMPAT_INSTALL_PATH" ]; then
		EFD="$STEAM_COMPAT_INSTALL_PATH"
	else
		EFD="$(dirname "$GP")"
	fi

	GFD="$(awk -F 'common' '{print $1}' <<< "$EFD")common/$(awk -F 'common' '{print $NF}' <<< "$EFD" | cut -d'/' -f2)" # f.e. used for vortex symlinks
	GN="$(grep -oE 'common/[^\/]+' <<< "$EFD" | awk -F 'common/' '{print $NF}')"				# THIS is hopefully the proper game name

	if [ -z "$STEAM_COMPAT_TOOL_PATHS" ] || [ "$STEAM_COMPAT_TOOL_PATHS" == "" ]; then
		HAVESCTP=0
	else
		HAVESCTP=1
		ORG_STEAM_COMPAT_TOOL_PATHS="$STEAM_COMPAT_TOOL_PATHS"
	fi

	if [ -n "$STEAM_COMPAT_INSTALL_PATH" ]; then
		STECOSHAPA="$STEAM_COMPAT_SHADER_PATH"
	fi

	# maybe loop through all paths possibly in STEAM_COMPAT_LIBRARY_PATHS?
	if [ -d "$STEAM_COMPAT_LIBRARY_PATHS" ]; then
		APPMAFE="${STEAM_COMPAT_LIBRARY_PATHS}/appmanifest_${AID}.acf"
	else
	# this should cover it though as well already
		APPMAFE="$(listAppManifests | grep -m1 "${1}.acf")"
	fi

	REAPSESTR="reaper SteamLaunch"

	if grep -q "$REAPSESTR" <<< "$@"; then
		HAVEREAP=1
	else
		HAVEREAP=0
	fi
	
	if grep -q "$SLR" <<< "$@"; then
		HAVESLR=1
	else
		HAVESLR=0
	fi

	INSTLSTR="${PROGNAME}/${PROGCMD}"
	if grep -q "$INSTLSTR" <<< "$@"; then
		HAVEINSTL=1
	else
		HAVEINSTL=0
	fi

	# first put the initial command line into an array - who knows if we need it again
	while read -r INGARG; do
		mapfile -t -O "${#INGCMD[@]}" INGCMD <<< "$INGARG"
	done <<< "$(printf "%s\n" "$@")"

	# then put the reaper command into an array, as it is the first command in the line
	if [ "$HAVEREAP" -eq 1 ]; then
		FOUNDREAP=0
		while read -r INGARG; do
			if [ "$FOUNDREAP" -eq 0 ]; then
				mapfile -t -O "${#REAPCMD[@]}" REAPCMD <<< "$INGARG"
				if [ "$INGARG" == "--" ]; then
					FOUNDREAP=1
				fi
			else
				mapfile -t -O "${#WIPAGCMD[@]}" WIPAGCMD <<< "$INGARG"
			fi
		done <<< "$(printf "%s\n" "${INGCMD[@]}")"
	else
		while read -r INGARG; do
			mapfile -t -O "${#WIPAGCMD[@]}" WIPAGCMD <<< "$INGARG"
		done <<< "$(printf "%s\n" "${INGCMD[@]}")"
	fi
	THISREAP="${REAPCMD[*]}"
	THISREAP="${THISREAP% SteamLaunch*}"
	if [ -z "$LASTREAP" ] || { [ -n "$LASTREAP" ] && [ "$LASTREAP" != "$THISREAP" ];}; then
		updateConfigEntry "LASTREAP" "$THISREAP" "$STLDEFGLOBALCFG"
	fi

	# if the SLR is called from command line put it into an array as well
	if [ "$HAVESLR" -eq 1 ]; then
		FOUNDSLR=0
		while read -r ORGARG; do
			if [ "$FOUNDSLR" -eq 0 ]; then
				mapfile -t -O "${#RUNSLR[@]}" RUNSLR <<< "$ORGARG"
				if [ "$ORGARG" == "--" ]; then
					FOUNDSLR=1
				fi
			else
				mapfile -t -O "${#WIPBGCMD[@]}" WIPBGCMD <<< "$ORGARG"
			fi
		done <<< "$(printf "%s\n" "${WIPAGCMD[@]}")"
	else
		while read -r ORGARG; do
			mapfile -t -O "${#WIPBGCMD[@]}" WIPBGCMD <<< "$ORGARG"
		done <<< "$(printf "%s\n" "${WIPAGCMD[@]}")"	
	fi

	if [ -z "$LASTSLR" ] || { [ -n "$LASTSLR" ] && [ "$LASTSLR" != "${RUNSLR[*]}" ];}; then
		updateConfigEntry "LASTSLR" "${RUNSLR[*]}" "$STLDEFGLOBALCFG"
	fi

	# put the proton path into an array as well if provided from command line
	if [ "$HAVEINPROTON" -eq 1 ]; then
		FOUNDIPRO=0
		while read -r ORGARG; do
			if [ "$FOUNDIPRO" -eq 0 ]; then
				mapfile -t -O "${#INPROTCMD[@]}" INPROTCMD <<< "$ORGARG"
				if [ "$ORGARG" == "$WFEAR" ]; then
					FOUNDIPRO=1
				fi
			else
				mapfile -t -O "${#WIPCGCMD[@]}" WIPCGCMD <<< "$ORGARG"
			fi
		done <<< "$(printf "%s\n" "${WIPBGCMD[@]}")"
			
		if [ "${INPROTCMD[-1]}" == "$WFEAR" ]; then
			# removing last INPROTCMD element as it is '$WFEAR'
			unset "INPROTCMD[-1]"
		fi

		INPROTV="$(setProtonPathVersion "${INPROTCMD[*]}")"
	else
		while read -r ORGARG; do
			mapfile -t -O "${#WIPCGCMD[@]}" WIPCGCMD <<< "$ORGARG"
		done <<< "$(printf "%s\n" "${WIPBGCMD[@]}")"	
	fi

	# put the own $PROGCMD command into an array if provided from command line
	if [ "$HAVEINSTL" -eq 1 ]; then
		FOUNDINSTL=0
		while read -r ORGARG; do
			if [ "$FOUNDINSTL" -eq 0 ]; then
				mapfile -t -O "${#INSTLCMD[@]}" INSTLCMD <<< "$ORGARG"
				if [[ "$ORGARG" =~ $INSTLSTR ]]; then
					FOUNDINSTL=1
				fi
			else
				mapfile -t -O "${#WIPDGCMD[@]}" WIPDGCMD <<< "$ORGARG"
			fi
		done <<< "$(printf "%s\n" "${WIPCGCMD[@]}")"
	else
		while read -r ORGARG; do
			mapfile -t -O "${#WIPDGCMD[@]}" WIPDGCMD <<< "$ORGARG"
		done <<< "$(printf "%s\n" "${WIPCGCMD[@]}")"	
	fi

	if grep -q "$SLR" <<< "${WIPDGCMD[@]}"; then
		HAVESLRCT=1
	else
		HAVESLRCT=0
	fi
	
	if [ "$HAVESLRCT" -eq 1 ]; then
		FOUNDSLR=0
		while read -r ORGARG; do
			if [ "$FOUNDSLR" -eq 0 ]; then
				mapfile -t -O "${#RUNSLRCT[@]}" RUNSLRCT <<< "$ORGARG"
				if [ "$ORGARG" == "--" ]; then
					FOUNDSLR=1
				fi
			else
				mapfile -t -O "${#ORGFGCMD[@]}" ORGFGCMD <<< "$ORGARG"
			fi
		done <<< "$(printf "%s\n" "${WIPDGCMD[@]}")"
	else
		while read -r ORGARG; do
			mapfile -t -O "${#ORGFGCMD[@]}" ORGFGCMD <<< "$ORGARG"
		done <<< "$(printf "%s\n" "${WIPDGCMD[@]}")"	
	fi
	
	# what is left now is the game executable and its command line arguments - splitting

	FOUNDORGGCMD=0
	while read -r ORGARG; do
		if [ "$FOUNDORGGCMD" -eq 0 ]; then
			mapfile -t -O "${#ORGGCMD[@]}" ORGGCMD <<< "$ORGARG"
			if [[ "$ORGARG" =~ $GP ]]; then
				FOUNDORGGCMD=1
			fi
		else
			mapfile -t -O "${#ORGCMDARGS[@]}" ORGCMDARGS <<< "$ORGARG"
		fi
	done <<< "$(printf "%s\n" "${ORGFGCMD[@]}")"

	if [ "${ORGGCMD[0]}" == "$WFEAR" ]; then
		# removing first ORGGCMD element as it is '$WFEAR'
		unset "ORGGCMD[0]"
	fi

	if [ -z "$GAMEEXE" ]; then
		GAMEEXE="${ORGGCMD[*]}"
		GAMEEXE="${GAMEEXE##*/}"
	fi
}

function getGameOS {
	function setLin {
		if [ -f "$OSCHECKGAMEEXE" ]; then
			GP="$OSCHECKGAMEEXE"
		else
			GPRAW="$(printf "%s\n" "$@" | grep -m1 "$SAC")"
			if grep -q "/./" <<< "$GPRAW"; then
				GP="${GPRAW//\/.\//\/}"
			else
				GP="$GPRAW"
			fi
		fi
		ABSGAMEEXEPATH="$GP"
		GE="${GP##*/}"																			# the game executable
		ISGAME=3																				# no STEAM_COMPAT_DATA_PATH, so it is no windows game		
	}

	function setWin {
		if [ -f "$OSCHECKGAMEEXE" ]; then
			GP="$OSCHECKGAMEEXE"
		else
			GP="$(printf "%s\n" "$@" | grep -v "proton\|$SLR" | grep -m1 "$SAC")"				# the absolute game path of the windows game exe
		fi
		ABSGAMEEXEPATH="$GP"
		GPFX="$STEAM_COMPAT_DATA_PATH/pfx"														# currently used WINEPREFIX
		GE="$(awk -F '.exe' '{print $1}' <<< "${GP##*/}")"										# just the windows game exe name
		writelog "INFO" "${FUNCNAME[0]} - '$GE' determined to be a Windows Game"
		ISGAME=2		
	}
	if [ "$STLPLAY" -eq 0 ]; then
		if [ "$ABSGAMEEXEPATH" == "$NON" ]; then 
			writelog "INFO" "${FUNCNAME[0]} - Starting game OS detection"

			while read -r INGARG; do
				if grep -q "$STEAM_COMPAT_INSTALL_PATH" <<< "$INGARG"; then
					OSCHECKGAMEEXE="$INGARG"
				fi
				mapfile -t -O "${#OSCHECKINGCMD[@]}" OSCHECKINGCMD <<< "$INGARG"
			done <<< "$(printf "%s\n" "$@")"
		
			if [ -n "$STEAM_COMPAT_DATA_PATH" ]; then
				if grep -q "$L2EA" <<< "$@"; then
					ISORIGIN=1
				fi

				if [ "$ISORIGIN" -eq 1 ]; then
					writelog "INFO" "${FUNCNAME[0]} - Found '$L2EA' in the command line, so this is a Windows game!"
					setWin "$@"
				elif [ -f "$OSCHECKGAMEEXE" ]; then
					writelog "INFO" "${FUNCNAME[0]} - Making some checks on '$OSCHECKGAMEEXE' to determine the OS version of the game"
					if grep -q "shell script" <<< "$(file "$(realpath "$OSCHECKGAMEEXE")")" || grep -q "ELF.*.LSB" <<< "$(file "$(realpath "$OSCHECKGAMEEXE")")" ; then
						writelog "INFO" "${FUNCNAME[0]} - Looks like this is a Linux game!"
						setLin "$@"
					elif grep -q "PE32" <<< "$(file "$OSCHECKGAMEEXE")"; then
						writelog "INFO" "${FUNCNAME[0]} - Looks like this is a Windows game!"
						setWin "$@"
					else
						writelog "WARN" "${FUNCNAME[0]} - Could not determine OS version of '$OSCHECKGAMEEXE' (add check?), so assuming this is a Windows game"
						setWin "$@"
					fi
				else
					writelog "WARN" "${FUNCNAME[0]} - Could not extract the full game binary path from the incoming game launch command, so assuming this is a Windows game!"
					setWin "$@"
				fi
			else
				writelog "INFO" "${FUNCNAME[0]} - STEAM_COMPAT_DATA_PATH is not defined, so this is either a Linux Game or no game was started at all"
				setLin "$@"
			fi
		else
			writelog "SKIP" "${FUNCNAME[0]} - ISGAME is already set to '$ISGAME' - nothing to determine"
		fi
	fi
}

function setCustomGameVars {
	# there doesn't seem to be a possibility to distinguish game platform based on given variables, so using at least a basic arch check on the exe:
	GP="$(printf "%s\n" "$@" | grep -v "$WFEAR" | head -n1)"

	getGameOS "$@"

	GE="$(awk -F '.exe' '{print $1}' <<< "${GP##*/}")"
	EFD="$(dirname "$GP")"
	# need to just guess here, because of missing fix strings
	GFD="$EFD"
	GN="$GE"

	while read -r ORGARG; do
		mapfile -t -O "${#ORGGCMD[@]}" ORGGCMD <<< "$ORGARG"
	done <<< "$(printf "%s\n" "$@")"
	if [ "${ORGGCMD[0]}" == "$WFEAR" ]; then
		# removing first ORGGCMD element as it is '$WFEAR'
		unset "ORGGCMD[0]"
	fi
}

function prepareGUI {
	WINDECO="--undecorated"
	if [ -n "$USEWINDECO" ]; then
		if [ "$USEWINDECO" -eq 1 ]; then
			WINDECO="--decorated"
		fi
	fi
}

function createLanguageList {
	function listLANG {
		while read -r RSPF; do
			TLANG="${RSPF//.txt/}"
			TLANG="${TLANG##*/}"
			printf '%s!' "$TLANG"
		done <<< "$(find "$STLLANGDIR" -name "*.txt")"

		while read -r RSPF; do
			TLANG="${RSPF//.txt/}"
			TLANG="${TLANG##*/}"
			printf '%s!' "$TLANG"
		done <<< "$(find "$GLOBALSTLLANGDIR" -name "*.txt")"
	}
	LANGYADLIST="$(listLANG)"
}

function loadLangFile {
	local SCRIPTDIR
	local LOCALLANGFILE

	if [ -n "$1" ]; then
		writelog "INFO" "${FUNCNAME[0]} - Language from command line is '$1'" "P"

		LANGFILENAME="$1"
		if [ -z "$GLOBALSTLLANGDIR" ]; then
			GLOBLANG="$SYSTEMSTLCFGDIR/lang/"
			writelog "INFO" "${FUNCNAME[0]} - SYSTEMSTLCFGDIR is '$SYSTEMSTLCFGDIR'" "P"
		else
			GLOBLANG="$GLOBALSTLLANGDIR"
			writelog "INFO" "${FUNCNAME[0]} - GLOBALSTLLANGDIR is '$GLOBALSTLLANGDIR'" "P"
		fi

		if [ -f "$LANGFILENAME" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Loading command line langfile '$LANGFILENAME'" "P"
			source "$LANGFILENAME"
			STLLANG="$(cut -d '.' -f1 <<< "${LANGFILENAME##*/}")"
			LAFI="$STLLANGDIR/${STLLANG}.txt"
			if [ ! -f "$LAFI" ]; then
				mkProjDir "$STLLANGDIR"
				cp "$LANGFILENAME" "$LAFI"
			fi
		else
			writelog "INFO" "${FUNCNAME[0]} - Command line language '$LANGFILENAME' is no file - trying to find its absolute path" "P"

			LAFI="$STLLANGDIR/${LANGFILENAME}.txt"
			
			SCRIPTDIR="$( realpath "$0" )"
			SCRIPTDIR="${SCRIPTDIR%/*}"
			LOCALLANGFILE="$SCRIPTDIR/lang/${LANGFILENAME}.txt"

			if [ -f "$LAFI" ]; then
				# If langfile in ~/.config/steamtinkerlaunch/lang exists, and we have a langfile installed globally or in the scriptdir, update the user-installed langfile
				writelog "INFO" "${FUNCNAME[0]} - Found user-installed $LAFI, attempting to update it"
				UPDATELANGFILEPATH=""
				if [ -f "$SYSTEMSTLCFGDIR/lang/${LANGFILENAME}.txt" ]; then
					UPDATELANGFILEPATH="$SYSTEMSTLCFGDIR/lang/${LANGFILENAME}.txt"  # Globally installed langfile (or stlprefix langfile on steam deck) - This one takes priority as it is assumed to be the most up to date
				elif [ -f "$LOCALLANGFILE" ]; then
					UPDATELANGFILEPATH="$LOCALLANGFILE" # langfile from scriptdir (on steam deck first-time install this would be the install directory)
				fi

				if [ -n "$UPDATELANGFILEPATH" ]; then
					writelog "INFO" "${FUNCNAME[0]} - Found lang file to replace the existing user-installed file with under '$UPDATELANGFILEPATH'"
					rm "$LAFI"
					cp "$UPDATELANGFILEPATH" "$LAFI"
				else
					writelog "INFO" "${FUNCNAME[0]} - No lang file to replace existing user-installed file with, not updating langfile"
				fi

				writelog "INFO" "${FUNCNAME[0]} - Loading found user-installed $LAFI" "P"
				source "$LAFI"
				STLLANG="$(cut -d '.' -f1 <<< "${LANGFILENAME##*/}")"
			elif [ -f "$LOCALLANGFILE" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Loading language file from script directory '$LOCALLANGFILE'"
				source "$LOCALLANGFILE"
				STLLANG="$(cut -d '.' -f1 <<< "${LOCALLANGFILE##*/}")"
			else
				LAFI="$GLOBLANG/${LANGFILENAME}.txt"

				if [ -f "$LAFI" ]; then
					writelog "INFO" "${FUNCNAME[0]} - Loading found system wide $LAFI" "P"
					source "$LAFI"
				else
					writelog "ERROR" "${FUNCNAME[0]} - Language file '$LAFI' could not be found" "P"
				fi
			fi
		fi
	fi
}

function loadLanguage {
	writelog "INFO" "${FUNCNAME[0]} - First load the default language '$STLDEFLANG' to make sure all variables are filled"
	loadLangFile "$STLDEFLANG"

	saveCfg "$STLDEFGLOBALCFG" X
	loadCfg "$STLDEFGLOBALCFG" X

	writelog "INFO" "${FUNCNAME[0]} - Loading STLLANG from '$STLDEFGLOBALCFG'"

	ARGSLANG="$(awk -F 'lang=' '{print $2}' <<< "$@" | cut -d ' ' -f1)"
	if [ -n "$ARGSLANG" ]; then
		STLLANG="$ARGSLANG"
		writelog "INFO" "${FUNCNAME[0]} - STLLANG from command line' is '$STLLANG'"

	elif [ -f "$STLDEFGLOBALCFG" ]; then
		STLLRAW="$(grep "^STLLANG" "$STLDEFGLOBALCFG" | cut -d '=' -f2)"
		STLLANG="${STLLRAW//\"/}"
		writelog "INFO" "${FUNCNAME[0]} - STLLANG from '$STLDEFGLOBALCFG' is '$STLLANG'"
	else
		writelog "WARN" "${FUNCNAME[0]} - Could not determine STLLANG"
	fi

	if [ -n "$STLLANG" ] && [ "$STLLANG" != "$STLDEFLANG" ]; then 
		writelog "INFO" "${FUNCNAME[0]} - Now load the language file '$STLLANG'"
		loadLangFile "$STLLANG"
		touch "$FUPDATE"
		updateConfigEntry "STLLANG" "$STLLANG" "$STLDEFGLOBALCFG"
	fi
	
#		touch "$STLSHM/lola-$AID.txt"
	
	if [ -z "$DESC_STLLANG" ]; then # example variable, if it is empty it means no language file was loaded above
		writelog "ERROR" "${FUNCNAME[0]} - ###############################" "E"
		writelog "ERROR" "${FUNCNAME[0]} - No language file could be loaded! For the initial setup at least one file (default english) is required" "E"
		writelog "ERROR" "${FUNCNAME[0]} - You can ether copy a valid file to '$STLLANGDIR' or '$SYSTEMSTLCFGDIR/lang' or provide an absolute path via command line using the lang= option" "E"
		writelog "ERROR" "${FUNCNAME[0]} - ###############################" "E"
		exit
	fi
}

function setProtonPathVersion {
	if [ -n "$INPROTV" ]; then
		writelog "INFO" "${FUNCNAME[0]} - Using directly known '$INPROTV' as Proton Version for '$1'"
		echo "$INPROTV"
	else
		if [ -n "$1" ]; then
			PRTPATH="$1"
			CTVDF="$(dirname "$PRTPATH")/$CTVDF"
			PPV="$(dirname "$PRTPATH")/version"
			if [ -f "$CTVDF" ]; then
				PROTVOUT="$(grep "display_name" "$CTVDF" | grep -v "e.g." | sed "s:\" \":\";\":g" | cut -d ';' -f2)"
			elif [ -f "$PPV" ]; then
				PROTVOUT="$(awk '{print $2}' < "$PPV")"
			fi

			if [ -z "$PROTVOUT" ]; then
				# if no useful version was provided - hardcode it here:
				if grep -q "Proton 3.7" <<<"$PRTPATH"; then
					PROTVOUT="proton-3.7-8"
				else
					# fallback if everything fails - in the rare cases where this unknown proton version is used this might cause problems
					# if you need it open an issue and it will get a hardcoded entry as well
					PROTVOUT="proton-unknown-$((900 + RANDOM % 100))"
				fi
			fi
			#writelog "INFO" "${FUNCNAME[0]} - Setting the Proton Version for '$1' to '${PROTVOUT//\"/}'"	# checking $PROTONCSV should be enough
			echo "${PROTVOUT//\"/}"
		fi
	fi
}

function fillProtonCSV {
	if [ -n "$1" ]; then
		protonfileV="$1"
	else
		protonfileV="$(setProtonPathVersion "$PROTBIN")"
	fi

	if [ -n "$protonfileV" ]; then
		PCSV="\"${protonfileV//\"/}\";\"$(readlink -f "$PROTBIN")\""
		if [[ ! " ${ProtonCSV[*]} " =~ $PCSV ]]; then  # $PCSV can always be read if interested
			mapfile -t -O "${#ProtonCSV[@]}" ProtonCSV <<< "$PCSV"
		else
			writelog "SKIP" "${FUNCNAME[0]} - '$PCSV' is already in the Proton array"
		fi
	fi
}

function printProtonArr {
	printf "%s\n" "${ProtonCSV[@]//\"/}"
}

function delEmptyFile {
	if [ -f "$1" ]; then
		if [ "$(wc -l < "$1")" -le 1 ]; then
			writelog "INFO" "${FUNCNAME[0]} - Removing empty file '$1'"
			rm "$1" 2>/dev/null
		fi
	fi
}

function rmDupLines {
	if grep -q "gawk" <<< "$AWKBIN"; then
		gawk -i inplace '!visited[$0]++' "$1"
	else
		awk '!seen[$0]++' "$1" > "$STLSHM/${FUNCNAME[0]}"
		cp "$STLSHM/${FUNCNAME[0]}" "$1"
		rm "$STLSHM/${FUNCNAME[0]}" 2>/dev/null
	fi
}

function getAvailableProtonVersions {
	# skip this function if a linux game was started
	if [ "$ISGAME" -eq 2 ] || [ -n "$2" ]; then
		# ...and if USEWINE is enabled	
		if [ -n "$USEWINE" ] && [ "$USEWINE" -eq 1 ]; then
			writelog "SKIP" "${FUNCNAME[0]} - USEWINE is enabled - skipping this function"
		elif [ -f "$STLGAMECFG" ] && grep -q "USEWINE=\"1\"" "$STLGAMECFG" ; then
			writelog "SKIP" "${FUNCNAME[0]} - USEWINE is enabled in the to-be-loaded gameconfig '$STLGAMECFG' - skipping this function"
			# could still be enabled via steamcollection, but this would be an overkill here, as ${FUNCNAME[0]} is non-fatal
		else
			delEmptyFile "$PROTONCSV"

			# find new proton versions in CUSTPROTEXTDIR
			if [ ! -f "$CUSTOMPROTONLIST" ] || [ "$(find "$CUSTPROTEXTDIR" -mindepth 1 -maxdepth 1 -type d | wc -l)" -gt "$(wc -l < "$CUSTOMPROTONLIST")" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Updating protonlist '$CUSTOMPROTONLIST' with possible new proton versions from '$CUSTPROTEXTDIR'"
				find "$CUSTPROTEXTDIR" -type f -name "proton" >> "$CUSTOMPROTONLIST"
			fi

			if [ ! -f "$PROTONCSV" ] || { [ -n "$1" ] && [ "$1" = "up" ]; } || [ "$1" == "F" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Initially creating an array with available Proton versions"

				# following symlinks (find -L) and using maxdepth 2 to avoid duplicates caused by _(user created)_ symlinks

				# user installed compatibilitytool:
				if [ -d "$STEAMCOMPATOOLS" ]; then
					writelog "INFO" "${FUNCNAME[0]} - Adding Proton versions found in STEAMCOMPATOOLS '$STEAMCOMPATOOLS'"
					while read -r PROTBIN; do
						if [ -f "$PROTBIN" ]; then
							writelog "INFO" "${FUNCNAME[0]} - Found proton directory: '$PROTBIN'"
							fillProtonCSV
						fi
					done <<< "$(find -L "$STEAMCOMPATOOLS" -mindepth 2 -maxdepth 2 -type f -name "proton")"	
				else
					writelog "SKIP" "${FUNCNAME[0]} - Directory STEAMCOMPATOOLS '$STEAMCOMPATOOLS' not found - skipping"
				fi
				
				if [ -n "$STEAM_EXTRA_COMPAT_TOOLS_PATHS" ]; then
					writelog "INFO" "${FUNCNAME[0]} - Adding Proton versions found in STEAM_EXTRA_COMPAT_TOOLS_PATHS '$STEAM_EXTRA_COMPAT_TOOLS_PATHS'"
					while read -r extrapath; do
						writelog "INFO" "${FUNCNAME[0]} - Searching for Proton version in '$extrapath'"
						while read -r PROTBIN; do
							if [ -f "$PROTBIN" ]; then
								writelog "INFO" "${FUNCNAME[0]} - Found proton directory: '$PROTBIN'"
								fillProtonCSV
							fi
						done <<< "$(find -L "$extrapath" -mindepth 2 -maxdepth 2 -type f -name "proton")"
					done <<< "$(tr ':' '\n' <<< "$STEAM_EXTRA_COMPAT_TOOLS_PATHS")"
				else
					if [ -d "$SYSSTEAMCOMPATOOLS" ]; then
						writelog "INFO" "${FUNCNAME[0]} - Adding Proton versions found in SYSSTEAMCOMPATOOLS '$SYSSTEAMCOMPATOOLS'"
						while read -r PROTBIN; do
							if [ -f "$PROTBIN" ]; then
								writelog "INFO" "${FUNCNAME[0]} - Found proton directory: '$PROTBIN'"
								fillProtonCSV
							fi
						done <<< "$(find -L "$SYSSTEAMCOMPATOOLS" -mindepth 2 -maxdepth 2 -type f -name "proton")"
					else
						writelog "SKIP" "${FUNCNAME[0]} - Directory SYSSTEAMCOMPATOOLS '$SYSSTEAMCOMPATOOLS' not found - skipping"
					fi
				fi
			
				# official proton versions installed via Steam in default SteamLibrary 
				if ! grep -q "\"path\".*.\"$SROOT\"" "$LFVDF"; then
					if [ -d "$DEFSTEAMAPPSCOMMON" ]; then
						writelog "INFO" "${FUNCNAME[0]} - Adding Proton versions found in DEFSTEAMAPPSCOMMON '$DEFSTEAMAPPSCOMMON'"
						while read -r protondir; do
							PROTBIN="$protondir/proton"
							if [ -f "$PROTBIN" ]; then
								writelog "INFO" "${FUNCNAME[0]} - Found proton directory: '$protondir'"
								fillProtonCSV
							fi
						done <<< "$(find -L "$DEFSTEAMAPPSCOMMON" -mindepth 2 -maxdepth 2 -type f -name "proton")"	
					else
						writelog "SKIP" "${FUNCNAME[0]} - Directory DEFSTEAMAPPSCOMMON '$DEFSTEAMAPPSCOMMON' not found - this should not happen! - skipping"
					fi
				fi

				# official proton versions installed via Steam in additional SteamLibrary Paths
				if [ -f "$CFGVDF" ] || [ -f "$LFVDF" ]; then
					if ! grep -q "BaseInstallFolder\|\"path\"" "$CFGVDF" "$LFVDF" 2>/dev/null; then
						writelog "INFO" "${FUNCNAME[0]} - No additional Steam Libraries configured in '$CFGVDF' or '$LFVDF' - so no need to search in there"
					else
						writelog "INFO" "${FUNCNAME[0]} - Adding Proton versions found in additional SteamLibrary Paths"
						while read -r protondir; do
							PROTBIN="$protondir/proton"
							if [ -f "$PROTBIN" ]; then
								writelog "INFO" "${FUNCNAME[0]} - Found proton directory: '$protondir'"
								fillProtonCSV
							fi
						done <<< "$(while read -r SLP; do if [ -d "${SLP//\"/}/$SAC" ]; then find "${SLP//\"/}/$SAC" -mindepth 1 -maxdepth 1 -type d -name "Proton*"; fi; done <<< "$(grep "BaseInstallFolder\|\"path\"" "$CFGVDF" "$LFVDF" 2>/dev/null | rev | cut -f1 | rev | sort -u)")"
					fi
				else
					writelog "SKIP" "${FUNCNAME[0]} - Neither file CFGVDF '$CFGVDF' nor file LFVDF '$LFVDF' found - this should not happen! - skipping"
				fi

				# custom Proton List:
				if [ -f "$CUSTOMPROTONLIST" ]; then
					writelog "INFO" "${FUNCNAME[0]} - Adding Proton versions found in CUSTOMPROTONLIST '$CUSTOMPROTONLIST'"

					rmDupLines "$CUSTOMPROTONLIST"
					sed '/^$/d' -i "$CUSTOMPROTONLIST"

					while read -r PROTLINE; do
						writelog "INFO" "${FUNCNAME[0]} - Checking line '$PROTLINE' in '$CUSTOMPROTONLIST'"

						if grep -q ";" <<< "$PROTLINE"; then
							PROTBIN="$(cut -d ';' -f2 <<< "$PROTLINE")"
							PROTVERS="$(cut -d ';' -f1 <<< "$PROTLINE")"
							writelog "INFO" "${FUNCNAME[0]} - Adding '$PROTVERS' to the list"
							fillProtonCSV "$PROTVERS"
						elif [ -f "$PROTLINE" ]; then
							writelog "INFO" "${FUNCNAME[0]} - File '$PROTLINE' exists - adding it to the list"
							PROTBIN="$PROTLINE"
							fillProtonCSV
						else
							writelog "INFO" "${FUNCNAME[0]} - Removing invalid line '$PROTLINE' from '$CUSTOMPROTONLIST'"
							mapfile -t -O "${#ProtonMissing[@]}" ProtonMissing <<< "$PROTLINE"
						fi
					done <<< "$(grep -v "^#" "$CUSTOMPROTONLIST")"

					# remove files from custom list which do not exist (anymore)
					if [ -n "${ProtonMissing[0]}" ]; then
						while read -r NOPROT; do
							sed "/${NOPROT//\//\\/}/d" -i "$CUSTOMPROTONLIST"
						done <<< "$(printf "%s\n" "${ProtonMissing[@]}")"
						unset ProtonMissing
					fi
				fi
			else
				writelog "INFO" "${FUNCNAME[0]} - Creating an array with available Proton versions using the file '$PROTONCSV' which was created during a previous run"
				mapfile -t -O "${#ProtonCSV[@]}" ProtonCSV < "$PROTONCSV"
			fi
			printProtonArr > "$PROTONCSV"
			rmDupLines "$PROTONCSV"
		fi
	fi
}

function setDefaultCfgValues {

	function setDefaultCfgValuesurl {
		if [ -z "$PROJECTPAGE" ]						; then	PROJECTPAGE="$GHURL/sonic2kk/steamtinkerlaunch"; fi
		if [ -z "$CP_PROTONTKG" ]						; then	CP_PROTONTKG="$GHURL/Frogging-Family/wine-tkg-git"; fi
		if [ -z "$CP_PROTONGE" ]						; then	CP_PROTONGE="$GHURL/GloriousEggroll/proton-ge-custom"; fi
		if [ -z "$CP_PROTONSTL" ]						; then	CP_PROTONSTL="$GHURL/frostworx/steamtinkerlaunch-tweaks"; fi
		if [ -z "$DL_D3D47_64" ]						; then	DL_D3D47_64="https://lutris.net/files/tools/dll/$D3D47"; fi
		if [ -z "$DL_D3D47_32" ]						; then	DL_D3D47_32="http://dege.freeweb.hu/dgVoodoo2/bin/D3DCompiler_47.zip"; fi
		if [ -z "$RESHADEDLURL" ]						; then	RESHADEDLURL="https://reshade.me/downloads"; fi
		if [ -z "$RESHADEPROJURL" ]						; then	RESHADEPROJURL="https://github.com/crosire/reshade"; fi
		if [ -z "$VORTEXPROJURL" ]						; then  VORTEXPROJURL="$GHURL/Nexus-Mods/${VTX^}"; fi
		if [ -z "$DXVKURL" ]							; then	DXVKURL="$GHURL/doitsujin/dxvk"; fi
		if [ -z "$XLIVEURL" ]							; then	XLIVEURL="$GHURL/ThirteenAG/Ultimate-ASI-Loader/releases/download/v4.61/Ultimate-ASI-Loader.zip"; fi
		if [ -z "$STASSURL" ]							; then	STASSURL="https://steamcdn-a.akamaihd.net/steam/apps"; fi
		if [ -z "$WINETRICKSURL" ]						; then	WINETRICKSURL="$GHURL/Winetricks/winetricks"; fi
		if [ -z "$X64DBGURL" ]							; then	X64DBGURL="$GHURL/x64dbg/x64dbg/releases/tag/snapshot";fi
		if [ -z "$STEAMGRIDDBAPI" ]						; then	STEAMGRIDDBAPI="https://www.steamgriddb.com/api/v2/grids/steam";fi
		if [ -z "$CONTYRELURL" ]						; then	CONTYRELURL="$GHURL/Kron4ek/Conty/releases"; fi
		if [ -z "$MO2PROJURL" ]							; then  MO2PROJURL="$GHURL/ModOrganizer2/modorganizer"; fi
		if [ -z "$HMMPROJURL" ]                         ; then  HMMPROJURL="$GHURL/thesupersonic16/HedgeModManager"; fi
		if [ -z "$CW_KRON4EK" ]							; then	CW_KRON4EK="$GHURL/Kron4ek/Wine-Builds/releases"; fi
		if [ -z "$IGCSZIP" ]							; then	IGCSZIP="$GHURL/FransBouma/InjectableGenericCameraSystem/releases/download/IGCSInjector_102/IGCSInjector_v102.zip"; fi
		if [ -z "$UUUURL" ]								; then	UUUURL="https://framedsc.github.io/GeneralGuides/universal_ue4_consoleunlocker.htm#downloading-the-uuu"; fi
		if [ -z "$OVRFSRURL" ]							; then	OVRFSRURL="$GHURL/fholger/$OVFS/releases"; fi
		if [ -z "$DPRSRELURL" ]							; then	DPRSRELURL="$GHURL/${DPRS}/${DPRS}/releases"; fi
		if [ -z "$DEPURL" ]								; then	DEPURL="$GHURL/lucasg/${DEPS}/releases";fi
		if [ -z "$SPEKURL" ]							; then	SPEKURL="https://sk-data.special-k.info/";fi
		if [ -z "$SPEKGHURL" ]							; then	SPEKGHURL="$GHURL/${SPEK}O/${SPEK}/releases";fi
		if [ -z "$SPEKCOMPURL" ]						; then	SPEKCOMPURL="https://www.pcgamingwiki.com/wiki/List_of_games_compatible_with_Special_K#Compatibility_list";fi
		if [ -z "$FWSURL" ]								; then	FWSURL="https://www.${FWS,,}.org/fws";fi
		if [ -z "$YAIURL" ]								; then	YAIURL="$GHURL/frostworx/steamtinkerlaunch-tweaks/releases/download"; fi
		if [ -z "$WINERELOADURL" ]						; then	WINERELOADURL="https://gist.githubusercontent.com/rbernon/cdbdc1b0e892f91e7449fcf3dda80bb7/raw/d8cf549bf751d99ed0fe515e36f99ff5c01b7287"; fi
		if [ -z "$GEOELFURL" ]							; then	GEOELFURL="http://helixmod.blogspot.com/2022/06/announcing-new-geo-11-3d-driver.html"; fi
		if [ -z "$WDIBURL" ]							; then	WDIBURL="$GHURL/0e4ef622/$WDIB/releases"; fi
	}

	function setDefaultCfgValuesglobal {
		if [ -z "$STLLANG" ]							; then	STLLANG="$STLDEFLANG"; fi
		if [ -z "$SKIPINTDEPCHECK" ]					; then	SKIPINTDEPCHECK="0"; fi
		if [ -z "$STRACEDIR" ]							; then	STRACEDIR="$LOGDIR"; fi
		if [ -z "$LOGDIR" ]								; then	LOGDIR="$DEFLOGDIR"; fi
		if [ -z "$LOGLEVEL" ]							; then	LOGLEVEL="2"; fi
		if [ -z "$RESETLOG" ]							; then	RESETLOG="1"; fi
		if [ -z "$STLEDITOR" ]							; then	STLEDITOR="$(command -v "geany")"; fi
		if [ -z "$MAXASK" ]								; then	MAXASK="3"; fi
		if [ -z "$BROWSER" ]							; then	BROWSER="$(command -v "firefox")"; fi
		if [ -z "$NOTY" ]								; then	NOTY="$(command -v "notify-send")"; fi
		if [ -z "$NOTYARGS" ]							; then	NOTYARGS="-i $STLICON -a $PROGNAME"; fi
		if [ -z "$USENOTIFIER" ]						; then	USENOTIFIER="1"; fi
		if [ -z "$NETMON" ]								; then	NETMON="$(command -v "netstat")"; fi
		if [ -z "$NETOPTS" ]							; then	NETOPTS="-taucp -W"; fi
		if [ -z "$NETMONDIR" ]							; then	NETMONDIR="$LOGDIR"; fi
		if [ -z "$VRVIDEOPLAYER" ]						; then	VRVIDEOPLAYER="$(command -v "vr-video-player")"; fi
		if [ -z "$GLOBALCOLLECTIONDIR" ]				; then	GLOBALCOLLECTIONDIR="$SYSTEMSTLCFGDIR/collections"; fi
		if [ -z "$GLOBALMISCDIR" ]						; then	GLOBALMISCDIR="$SYSTEMSTLCFGDIR/misc"; fi
		if [ -z "$GLOBALSBSTWEAKS" ]					; then	GLOBALSBSTWEAKS="$SYSTEMSTLCFGDIR/misc/sbstweaks"; fi
		if [ -z "$GLOBALTWEAKS" ]						; then	GLOBALTWEAKS="$SYSTEMSTLCFGDIR/tweaks"; fi
		if [ -z "$GLOBALEVALDIR" ]						; then	GLOBALEVALDIR="$SYSTEMSTLCFGDIR/eval"; fi
		if [ -z "$GLOBALSTLLANGDIR" ]					; then	GLOBALSTLLANGDIR="$SYSTEMSTLCFGDIR/lang"; fi
		if [ -z "$GLOBALSTLGUIDIR" ]					; then	GLOBALSTLGUIDIR="$SYSTEMSTLCFGDIR/guicfgs"; fi
		if [ -z "$BOXTRONCMD" ]							; then	BOXTRONCMD="/usr/share/boxtron/run-dosbox"; fi
		if [ -z "$BOXTRONARGS" ]						; then	BOXTRONARGS="--wait-before-run"; fi
		if [ -z "$ROBERTACMD" ]							; then	ROBERTACMD="$STEAMCOMPATOOLS/roberta/run-vm"; fi
		if [ -z "$ROBERTAARGS" ]						; then	ROBERTAARGS="--wait-before-run"; fi
		if [ -z "$LUXTORPEDACMD" ]						; then	LUXTORPEDACMD="$STEAMCOMPATOOLS/luxtorpeda/luxtorpeda"; fi
		if [ -z "$LUXTORPEDAARGS" ]						; then	LUXTORPEDAARGS="wait-before-run"; fi
		if [ -z "$RSVERS" ]								; then	RSVERS="5.4.2"; fi
		if [ -z "$AUTOBUMPRESHADE" ]					; then	AUTOBUMPRESHADE="0"; fi
		if [ -z "$DOWNLOAD_RESHADE" ]					; then	DOWNLOAD_RESHADE="1"; fi
		if [ -z "$RESHADESRCDIR" ]						; then	RESHADESRCDIR="$STLDLDIR/reshade"; fi
		if [ -z "$D3D47_64" ]							; then	D3D47_64="${D3D47//./_64.}"; fi
		if [ -z "$D3D47_32" ]							; then	D3D47_32="${D3D47//./_32.}"; fi
		if [ -z "$RS_64" ]								; then	RS_64="ReShade64.dll"; fi
		if [ -z "$RS_32" ]								; then	RS_32="ReShade32.dll"; fi
		if [ -z "$RS_64_VK" ]							; then	RS_64_VK="ReShade64.json"; fi
		if [ -z "$RS_32_VK" ]							; then	RS_32_VK="ReShade32.json"; fi
		if [ -z "$DLSHADER" ]							; then	DLSHADER="1"; fi
		if [ -z "$SAVESETSIZE" ]						; then	SAVESETSIZE="1"; fi
		if [ -z "$STARTMENU" ]							; then	STARTMENU="Menu"; fi
		if [ -z "$USEWINDECO" ]							; then	USEWINDECO="1"; fi
		if [ -z "$HEADLINEFONT" ]						; then	HEADLINEFONT="larger"; fi
		if [ -z "$USETRAYICON" ]						; then	USETRAYICON="1"; fi
		if [ -z "$USEGAMEPICS" ]						; then	USEGAMEPICS="1"; fi
		if [ -z "$USECUSTOMFALLBACKPIC" ]				; then	USECUSTOMFALLBACKPIC="0"; fi
		if [ -z "$GITHUBUSER" ]							; then	GITHUBUSER="$NON"; fi
		if [ -z "$DLGAMEDATA" ]							; then	DLGAMEDATA="1"; fi
		if [ -z "$USEPDBRATING" ]						; then	USEPDBRATING="1"; fi
		if [ -z "$PDBRATINGCACHE" ]						; then	PDBRATINGCACHE="1"; fi
		if [ -z "$DLWINETRICKS" ]						; then	DLWINETRICKS="0"; fi
		if [ -z "$AUTOLASTPROTON" ]						; then	AUTOLASTPROTON="1"; fi
		if [ -z "$AUTOPULLPROTON" ]						; then	AUTOPULLPROTON="1"; fi
		if [ -z "$CUSTPROTDLDIR" ]						; then	CUSTPROTDLDIR="$STLDLDIR/$PROCU"; fi
		if [ -z "$CUSTPROTEXTDIR" ]						; then	CUSTPROTEXTDIR="$STLCFGDIR/$PROCU"; fi
		if [ -z "$WINEDLDIR" ]							; then	WINEDLDIR="$STLDLDIR/wine"; fi
		if [ -z "$WINEEXTDIR" ]							; then	WINEEXTDIR="$STLCFGDIR/wine"; fi
		if [ -z "$USEVORTEXPROTON" ]					; then	USEVORTEXPROTON="$NON"; fi
		if [ -z "$VORTEXCOMPDATA" ]						; then	VORTEXCOMPDATA="$STLVORTEXDIR/$CODA"; fi
		if [ -z "$VORTEXDOWNLOADPATH" ]					; then	VORTEXDOWNLOADPATH="$STLVORTEXDIR/downloads"; fi
		if [ -z "$USEVORTEXPRERELEASE" ]				; then	USEVORTEXPRERELEASE="0"; fi
		if [ -z "$DISABLE_AUTOSTAGES" ]					; then	DISABLE_AUTOSTAGES="0"; fi
		if [ -z "$NOSTEAMSTLDEF" ]						; then	NOSTEAMSTLDEF="0"; fi
		if [ -z "$SGDBAPIKEY" ]							; then	SGDBAPIKEY="$NON"; fi
		if [ -z "$SGDBSTYLES" ]							; then	SGDBSTYLES="$SGDBSTYOPTS"; fi
		if [ -z "$SGDBDIMS" ]							; then	SGDBDIMS="$SGDBDIMOPTS"; fi
		if [ -z "$SGDBTYPES" ]							; then	SGDBTYPES="animated,static"; fi
		if [ -z "$SGDBNSFW" ]							; then	SGDBNSFW="any"; fi
		if [ -z "$SGDBHUMOR" ]							; then	SGDBHUMOR="any"; fi
		if [ -z "$SGDBDLTOSTEAM" ]						; then	SGDBDLTOSTEAM="0"; fi
		if [ -z "$SGDBHASFILE" ]						; then	SGDBHASFILE="skip"; fi
		if [ -z "$SGDBAUTODL" ]							; then	SGDBAUTODL="$NON"; fi
		if [ -z "$STORECOMPDATTITLE" ]					; then	STORECOMPDATTITLE="1"; fi
		if [ -z "$CUSTCONTY" ]							; then	CUSTCONTY="$NON"; fi
		if [ -z "$UPDATECONTY" ]						; then	UPDATECONTY="1"; fi
		if [ -z "$LOGPLAYTIME" ]						; then	LOGPLAYTIME="1"; fi
		if [ -z "$YAD" ]								; then	YAD="$(command -v "yad")"; fi
		if [ -z "$DPRSCOMPDATA" ]						; then	DPRSCOMPDATA="$STLCFGDIR/${DPRS,}/$CODA"; fi
		if [ -z "$USEDPRSPROTON" ]						; then	USEDPRSPROTON="$NON"; fi
		if [ -z "$DPRSUSEVDFSYMLINKS" ]					; then	DPRSUSEVDFSYMLINKS="0"; fi
		if [ -z "$DPRSPAUTOUP" ]						; then	DPRSPAUTOUP="0"; fi
		if [ -z "$DEPSAUTOUP" ]							; then	DEPSAUTOUP="0"; fi
		if [ -z "$MO2COMPDATA" ]						; then	MO2COMPDATA="$STLMO2DIR/$CODA"; fi
		if [ -z "$HMMCOMPDATA" ]                        ; then  HMMCOMPDATA="$STLHMMDIR/$CODA"; fi
		if [ -z "$HMMDLVER" ]                           ; then  HMMDLVER="$HMMSTABLE"; fi
		if [ -z "$USEMO2PROTON" ]						; then	USEMO2PROTON="$NON"; fi
		if [ -z "$USEHMMPROTON" ]                       ; then  USEHMMPROTON="$NON"; fi
		if [ -z "$USETERM" ]							; then	USETERM="$(command -v "xterm")"; fi
		if [ -z "$TERMARGS" ]							; then	TERMARGS="-e"; fi
	}

	function setDefaultCfgValuesdefault_template {
		if [ -z "$KEEPSTLOPEN" ]						; then	KEEPSTLOPEN="0"; fi
		if [ -z "$USESLR" ]								; then	USESLR="1"; fi
		if [ -z "$FORCESLR" ]							; then	FORCESLR="0"; fi
		if [ -z "$USEREAP" ]							; then	USEREAP="1"; fi
		if [ -z "$FORCEREAP" ]							; then	FORCEREAP="0"; fi
		if [ -z "$USEPROTON" ]							; then	USEPROTON="$(getDefaultProton)"; fi
		if [ -z "$REDIRCOMPDATA" ]						; then	REDIRCOMPDATA="disabled"; fi
		if [ -z "$REDIRSTEAMUSER" ]						; then	REDIRSTEAMUSER="disabled"; fi
		if [ -z "$AUTOBUMPGE" ]							; then	AUTOBUMPGE="0"; fi
		if [ -z "$AUTOBUMPPROTON" ]						; then	AUTOBUMPPROTON="0"; fi
		if [ -z "$USECUSTOMCMD" ]						; then	USECUSTOMCMD="0"; fi
		if [ -z "$CUSTOMCMD" ]							; then	CUSTOMCMD="$DUMMYBIN"; fi
		if [ -z "$CUSTOMCMD_ARGS" ]						; then	CUSTOMCMD_ARGS="$NON"; fi
		if [ -z "$ONLY_CUSTOMCMD" ]						; then	ONLY_CUSTOMCMD="0";	fi
		if [ -z "$FORK_CUSTOMCMD" ]						; then	FORK_CUSTOMCMD="0";	fi
		if [ -z "$EXTPROGS_CUSTOMCMD" ]					; then  EXTPROGS_CUSTOMCMD="0"; fi
		if [ -z "$CUSTOMCMDFORCEWIN" ]					; then  CUSTOMCMDFORCEWIN="0"; fi
		if [ -z "$WAITFORCUSTOMCMD" ]					; then	WAITFORCUSTOMCMD="0"; fi
		if [ -z "$INJECT_CUSTOMCMD" ]					; then	INJECT_CUSTOMCMD="0"; fi
		if [ -z "$INJECTWAIT" ]							; then	INJECTWAIT="0";	fi
		if [ -z "$USEIGCS" ]							; then	USEIGCS="0"; fi
		if [ -z "$UUUSEIGCS" ]							; then	UUUSEIGCS="0"; fi
		if [ -z "$IGCSWAIT" ]							; then	IGCSWAIT="0"; fi
		if [ -z "$UUUSEPATCH" ]							; then	UUUSEPATCH="0"; fi
		if [ -z "$UUUPATCHWAIT" ]						; then	UUUPATCHWAIT="0"; fi
		if [ -z "$UUUSEVR" ]							; then	UUUSEVR="0"; fi
		if [ -z "$GAMEARGS" ]							; then	GAMEARGS="$NON"; fi
		if [ -z "$HARDARGS" ]							; then	HARDARGS="$NOPE"; fi
		if [ -z "$USEGAMEMODERUN" ]						; then	USEGAMEMODERUN="0";	fi
		if [ -z "$USEGAMESCOPE" ]						; then	USEGAMESCOPE="0"; fi
		if [ -z "$GAMESCOPE_ARGS" ]						; then	GAMESCOPE_ARGS="--"; fi
		if [ -z "$USEOBSCAP" ]							; then	USEOBSCAP="0"; fi
		if [ -z "$USEZINK" ]							; then	USEZINK="0"; fi
		if [ -z "$USEPRIMERUN" ]						; then	USEPRIMERUN="0"; fi
		if [ -z "$TOGSTEAMWEBHELPER" ]					; then	TOGSTEAMWEBHELPER="0"; fi
		if [ -z "$USEMANGOHUD" ]						; then	USEMANGOHUD="0"; fi
		if [ -z "$USEMANGOAPP" ]						; then	USEMANGOAPP="0"; fi
		if [ -z "$MAHUBIN" ]							; then	MAHUBIN="$(command -v "$MAHU")"; fi
		if [ -z "$MAHUARGS" ]							; then	MAHUARGS="$NON"; fi
		if [ -z "$LDPMAHU" ]							; then	LDPMAHU="0"; fi
		if [ -z "$MAHUVAR" ]							; then	MAHUVAR="0"; fi
		if [ -z "$USEMANGOHUDSTLCFG" ]					; then	USEMANGOHUDSTLCFG="0";	fi
		if [ -z "$ENABLE_VKBASALT" ]					; then	ENABLE_VKBASALT="0"; fi
		if [ -z "$RUN_NYRNA" ]							; then	RUN_NYRNA="0"; fi
		if [ -z "$RUN_REPLAY" ]							; then	RUN_REPLAY="0";	fi
		if [ -z "$RUN_X64DBG" ]							; then	RUN_X64DBG="0";	fi
		if [ -z "$RUN_GDB" ]							; then	RUN_GDB="0";	fi
		if [ -z "$USE_WDIB" ]							; then	USE_WDIB="0";	fi
		if [ -z "$USEVORTEX" ]							; then	USEVORTEX="0"; fi
		if [ -z "$WAITVORTEX" ]							; then	WAITVORTEX="2"; fi
		if [ -z "$RUN_VORTEX_WINETRICKS" ]				; then	RUN_VORTEX_WINETRICKS="0"; fi
		if [ -z "$RUN_VORTEX_WINECFG" ]					; then	RUN_VORTEX_WINECFG="0";fi
		if [ -z "$CHANGE_PULSE_LATENCY" ] 				; then	CHANGE_PULSE_LATENCY="0"; fi
		if [ -z "$STL_PULSE_LATENCY_MSEC" ]				; then	STL_PULSE_LATENCY_MSEC="60"; fi
		if [ -z "$TOGGLEWINDOWS" ]						; then	TOGGLEWINDOWS="0"; fi
		if [ -z "$RUN_WINETRICKS" ]						; then	RUN_WINETRICKS="0"; fi
		if [ -z "$WINETRICKSPAKS" ]						; then	WINETRICKSPAKS="$NON"; fi
		if [ -z "$RUN_WINECFG" ]						; then	RUN_WINECFG="0"; fi
		if [ -z "$USEWINE" ]							; then	USEWINE="0"; fi
		if [ -z "$WINEVERSION" ]						; then	WINEVERSION="$DUMMYBIN"; fi
		if [ -z "$WINEDEFAULT" ]						; then	WINEDEFAULT="$DUMMYBIN"; fi
		if [ -z "$USEWICO" ]							; then	USEWICO="0"; fi
		if [ -z "$VIRTUALDESKTOP" ]						; then	VIRTUALDESKTOP="0"; fi
		if [ -z "$VDRES" ]								; then	VDRES="$NON"; fi
		if [ -z "$USEBOXTRON" ]							; then	USEBOXTRON="0"; fi
		if [ -z "$USEROBERTA" ]							; then	USEROBERTA="0"; fi
		if [ -z "$USELUXTORPEDA" ]						; then	USELUXTORPEDA="0"; fi
		if [ -z "$REGEDIT" ]							; then	REGEDIT="0"; fi
		if [ -z "$USEGEOELF" ]							; then	USEGEOELF="0"; fi
		if [ -z "$AUTOGEOELF" ]							; then	AUTOGEOELF="0"; fi
		if [ -z "$INSTALL_RESHADE" ]					; then	INSTALL_RESHADE="0"; fi
		if [ -z "$RESHADE_DEPTH3D" ]					; then	RESHADE_DEPTH3D="0"; fi
		if [ -z "$USERESHADE" ]							; then	USERESHADE="0"; fi
		if [ -z "$CUSTOMCMDRESHADE" ]					; then	CUSTOMCMDRESHADE="0"; fi
		if [ -z "$RESHADEUPDATE" ]						; then	RESHADEUPDATE="0"; fi
		if [ -z "$RSOVRD" ] 							; then  RSOVRD="0"; fi
		if [ -z "$RSOVRVERS" ] 							; then  RSOVRVERS="$RSVERS"; fi
		if [ -z "$CHOOSESHADERS" ]						; then	CHOOSESHADERS="0"; fi
		if [ -z "$ALTEXEPATH" ]							; then	ALTEXEPATH="/tmp"; fi
		if [ -z "$ARCHALTEXE" ]							; then	ARCHALTEXE="$DUMMYBIN"; fi
		if [ -z "$USEOPENVRFSR" ]						; then	USEOPENVRFSR="0"; fi
		if [ -z "$RUNSBSVR" ]							; then	RUNSBSVR="0"; fi
		if [ -z "$RUNSBS" ]								; then	RUNSBS="0"; fi
		if [ -z "$VRVIDEOPLAYERARGS" ]					; then	VRVIDEOPLAYERARGS="--flat"; fi
		if [ -z "$SBSZOOM" ]							; then	SBSZOOM="1.0"; fi
		if [ -z "$SBSVRGEOELF" ]						; then	SBSVRGEOELF="0"; fi
		if [ -z "$SBSVRRS" ]							; then	SBSVRRS="0"; fi
		if [ -z "$SBSRS" ]								; then	SBSRS="0"; fi
		if [ -z "$MINVRWINH" ] 							; then	MINVRWINH="640"; fi
		if [ -z "$WAITFORTHISPID" ]						; then	WAITFORTHISPID="$NON"; fi
		if [ -z "$WAITEDITOR" ]							; then	WAITEDITOR="2"; fi
		if [ -z "$HELPURL" ]							; then	HELPURL="$NON"; fi
		if [ -z "$CREATEDESKTOPICON" ]					; then	CREATEDESKTOPICON="0"; fi
		if [ -z "$STEAMAPPIDFILE" ]						; then	STEAMAPPIDFILE="0"; fi
		if [ -z "$CHECKCOLLECTIONS" ]					; then	CHECKCOLLECTIONS="1"; fi
		if [ -z "$BACKUPSTEAMUSER" ]					; then	BACKUPSTEAMUSER="0"; fi
		if [ -z "$RESTORESTEAMUSER" ]					; then	RESTORESTEAMUSER="$NON"; fi
		if [ -z "$USESUSYM" ]							; then	USESUSYM="0"; fi
		if [ -z "$USEGLOBSUSYM" ]						; then	USEGLOBSUSYM="0"; fi
		if [ -z "$STRACERUN" ]							; then	STRACERUN="0"; fi
		if [ -z "$STRACEOPTS" ]							; then	STRACEOPTS="-f -t -e trace=file"; fi
		if [ -z "$USENETMON" ]							; then	USENETMON="0"; fi
		if [ -z "$BLOCKINTERNET" ]						; then	BLOCKINTERNET="0"; fi
		if [ -z "$USE_STLDXVKCFG" ]						; then	USE_STLDXVKCFG="0"; fi
		if [ -z "$DXVK_HUD" ]							; then	DXVK_HUD="0"; fi
		if [ -z "$DXVK_LOG_LEVEL" ]						; then	DXVK_LOG_LEVEL="$NON"; fi
		if [ -z "$DXVK_LOG_PATH" ]						; then	DXVK_LOG_PATH="$STLDXVKLOGDIR"; fi
		if [ -z "$DXVK_SCALE" ]							; then	DXVK_SCALE="1.0"; fi
		if [ -z "$DXVK_FPSLIMIT" ]                      ; then  DXVK_FPSLIMIT="none"; fi
		if [ -z "$DXVK_ASYNC" ]							; then	DXVK_ASYNC="0"; fi
		if [ -z "$DXVK_HDR" ]							; then  DXVK_HDR="0"; fi
		if [ -z "$PROTON_LOG" ]							; then	PROTON_LOG="0"; fi
		if [ -z "$PROTON_LOG_DIR" ]						; then	PROTON_LOG_DIR="$STLPROTONIDLOGDIR"; fi
		if [ -z "$USEWINEDEBUGPROTON" ]					; then	USEWINEDEBUGPROTON="0"; fi
		if [ -z "$WINE_LOG_DIR" ]						; then	WINE_LOG_DIR="$STLWINELOGDIR"; fi
		if [ -z "$PROTON_DEBUG_DIR" ]					; then	PROTON_DEBUG_DIR="/tmp"; fi
		if [ -z "$PROTON_USE_WINED3D" ]					; then	PROTON_USE_WINED3D="0"; fi
		if [ -z "$PROTON_NO_D3D11" ]					; then	PROTON_NO_D3D11="0"; fi
		if [ -z "$PROTON_NO_D3D10" ]					; then	PROTON_NO_D3D10="0"; fi
		if [ -z "$PROTON_NO_ESYNC" ]					; then	PROTON_NO_ESYNC="0"; fi
		if [ -z "$PROTON_NO_FSYNC" ]					; then	PROTON_NO_FSYNC="0"; fi
		if [ -z "$ENABLE_WINESYNC" ]					; then	ENABLE_WINESYNC="0"; fi
		if [ -z "$PROTON_ENABLE_NVAPI" ]				; then	PROTON_ENABLE_NVAPI="0"; fi
		if [ -z "$PROTON_HIDE_NVIDIA_GPU" ]				; then	PROTON_HIDE_NVIDIA_GPU="1"; fi
		if [ -z "$STL_VKD3D_CONFIG" ]					; then	STL_VKD3D_CONFIG="$NON"; fi
		if [ -z "$STL_VKD3D_DEBUG" ]					; then	STL_VKD3D_DEBUG="$NON"; fi
		if [ -z "$STL_VKD3D_SHADER_DEBUG" ]				; then	STL_VKD3D_SHADER_DEBUG="$NON"; fi
		if [ -z "$STL_VKD3D_LOG_FILE" ]					; then	STL_VKD3D_LOG_FILE="$NON"; fi
		if [ -z "$STL_VKD3D_VULKAN_DEVICE" ]			; then	STL_VKD3D_VULKAN_DEVICE="$NON"; fi
		if [ -z "$STL_VKD3D_FILTER_DEVICE_NAME" ]		; then	STL_VKD3D_FILTER_DEVICE_NAME="$NON"; fi
		if [ -z "$STL_VKD3D_DISABLE_EXTENSIONS" ]		; then	STL_VKD3D_DISABLE_EXTENSIONS="$NON"; fi
		if [ -z "$STL_VKD3D_TEST_DEBUG" ]				; then	STL_VKD3D_TEST_DEBUG="0"; fi
		if [ -z "$STL_VKD3D_TEST_FILTER" ]				; then	STL_VKD3D_TEST_FILTER="$NON"; fi
		if [ -z "$STL_VKD3D_TEST_EXCLUDE" ]				; then	STL_VKD3D_TEST_EXCLUDE="$NON"; fi
		if [ -z "$STL_VKD3D_TEST_PLATFORM" ]			; then	STL_VKD3D_TEST_PLATFORM="$NON"; fi
		if [ -z "$STL_VKD3D_TEST_BUG" ]					; then	STL_VKD3D_TEST_BUG="$NON"; fi
		if [ -z "$STL_VKD3D_PROFILE_PATH" ]				; then	STL_VKD3D_PROFILE_PATH="$NON"; fi
		if [ -z "$USEDLSS" ]							; then	USEDLSS="0"; fi
		if [ -z "$USERAYTRACING" ]						; then	USERAYTRACING="0"; fi
		if [ -z "$PROTON_FORCE_LARGE_ADDRESS_AWARE" ]	; then	PROTON_FORCE_LARGE_ADDRESS_AWARE="1"; fi
		if [ -z "$PROTON_DUMP_DEBUG_COMMANDS" ]			; then	PROTON_DUMP_DEBUG_COMMANDS="0"; fi
		if [ -z "$CLEANPROTONTEMP" ]					; then	CLEANPROTONTEMP="0"; fi
		if [ -z "$WINE_FULLSCREEN_INTEGER_SCALING" ]	; then	WINE_FULLSCREEN_INTEGER_SCALING="0"; fi
		if [ -z "$WINE_FULLSCREEN_FSR" ]				; then	WINE_FULLSCREEN_FSR="0"; fi
		if [ -z "$WINE_FULLSCREEN_FSR_STRENGTH" ]		; then	WINE_FULLSCREEN_FSR_STRENGTH="2"; fi
		if [ -z "$WINE_FULLSCREEN_FSR_MODE" ]			; then  WINE_FULLSCREEN_FSR_MODE="none"; fi
		if [ -z "$WINE_FULLSCREEN_FSR_CUSTOM_MODE" ]	; then  WINE_FULLSCREEN_FSR_CUSTOM_MODE="none"; fi
		if [ -z "$STLWINEDEBUG" ]						; then	STLWINEDEBUG="-all"; fi
		if [ -z "$STLWINEDLLOVERRIDES" ]				; then	STLWINEDLLOVERRIDES="$NON"; fi
		if [ -z "$USERSTART" ]							; then	USERSTART="$DUMMYBIN"; fi
		if [ -z "$USERSTOP" ]							; then	USERSTOP="$DUMMYBIN"; fi	
		if [ -z "$AUTOCONTY" ]							; then	AUTOCONTY="0"; fi
		if [ -z "$USECONTY" ]							; then	USECONTY="0"; fi
		if [ -z "$CRASHGUESS" ]							; then	CRASHGUESS="60"; fi
		if [ -z "$ONLYWICO" ]							; then	ONLYWICO="0"; fi
		if [ -z "$GAMESCREENRES" ]						; then	GAMESCREENRES="$NON"; fi
		if [ -z "$FIXSYMLINKS" ]						; then	FIXSYMLINKS="0"; fi
		if [ -z "$UNSYMLINK" ]							; then	UNSYMLINK="0"; fi
		if [ -z "$DELPFX" ]								; then	DELPFX="0"; fi
		if [ -z "$RUN_DEPS" ]							; then	RUN_DEPS="0"; fi
		if [ -z "$SORTGARGS" ]							; then	SORTGARGS="0"; fi
		if [ -z "$MO2MODE" ]							; then	MO2MODE="disabled"; fi
		if [ -z "$WAITMO2" ]							; then	WAITMO2="2"; fi
		if [ -z "$USESPECIALK" ]						; then	USESPECIALK="0"; fi
		if [ -z "$SDLUSEWAYLAND" ]						; then  SDLUSEWAYLAND="0"; fi
		if [ -z "$STLRAD_PFTST" ]                       ; then  STLRAD_PFTST="none"; fi
		if [ -z "$SPEKVERS" ]							; then	SPEKVERS="default"; fi
		if [ -z "$AUTOSPEK" ]							; then	AUTOSPEK="0"; fi
		if [ -z "$USEFWS" ]								; then	USEFWS="0"; fi
		if [ -z "$USEPEV_PELDD" ]						; then	USEPEV_PELDD="0"; fi
		if [ -z "$USEPEV_PEPACK" ]						; then	USEPEV_PEPACK="0"; fi
		if [ -z "$USEPEV_PERES" ]						; then	USEPEV_PERES="0"; fi
		if [ -z "$USEPEV_PESCAN" ]						; then	USEPEV_PESCAN="0"; fi
		if [ -z "$USEPEV_PESEC" ]						; then	USEPEV_PESEC="0"; fi
		if [ -z "$USEPEV_PESTR" ]						; then	USEPEV_PESTR="0"; fi
		if [ -z "$USEPEV_READPE" ]						; then	USEPEV_READPE="0"; fi
	}
	
	"${FUNCNAME[0]}$1"
}

function saveCfg {

	function saveCfgurl {

		setDefaultCfgValues "$2"
		
		if [ -f "$1" ]; then
			updateConfigFile "$1" "${FUNCNAME[0]}" "$3"
		else
			#STARTsaveCfgurl
			{
			echo "## config Version: $PROGVERS"
			echo "##########################"
			echo "## Url Config:"
			echo "##########################"
			echo "PROJECTPAGE=\"$PROJECTPAGE\""
			echo "##########################"
			echo "## Proton GE DL URL"
			echo "CP_PROTONGE=\"$CP_PROTONGE\""
			echo "## Proton TKG DL URL"
			echo "CP_PROTONTKG=\"$CP_PROTONTKG\""
			echo "## Proton STL DL URL"
			echo "CP_PROTONSTL=\"$CP_PROTONSTL\""
			echo "## Wine Kron4ek URL"
			echo "CW_KRON4EK=\"$CW_KRON4EK\""
			echo "## d3d47 64bit DL URL "
			echo "DL_D3D47_64=\"$DL_D3D47_64\""
			echo "## d3d47 32bit DL URL"
			echo "DL_D3D47_32=\"$DL_D3D47_32\""
			echo "## Dxvk Project URL"
			echo "DXVKURL=\"$DXVKURL\""				
			echo "## ${RESH} DL URL"
			echo "RESHADEDLURL=\"$RESHADEDLURL\""
			echo "## ${RESH} Project URL"
			echo "RESHADEPROJURl=\"$RESHADEPROJURL\""
			echo "## ${VTX^} Project URL"
			echo "VORTEXPROJURL=\"$VORTEXPROJURL\""
			echo "## Xlive DL URL"
			echo "XLIVEURL=\"$XLIVEURL\""
			echo "## Steam Asset URL"
			echo "STASSURL=\"$STASSURL\""
			echo "## winetricks URL"
			echo "WINETRICKSURL=\"$WINETRICKSURL\""
			echo "## x64dbg URL"
			echo "X64DBGURL=\"$X64DBGURL\""
			echo "## SteamGridDB Api URL"
			echo "STEAMGRIDDBAPI=\"$STEAMGRIDDBAPI\""
			echo "## Conty DL URL"
			echo "CONTYRELURL=\"$CONTYRELURL\""
			echo "## Mod Organizer 2 Project URL"
			echo "MO2PROJURL=\"$MO2PROJURL\""
			echo "## HedgeModManager Project URL"
			echo "HMMPROJURL=\"$HMMPROJURL\""
			echo "## $DPRS DL URL"
			echo "DPRSRELURL=\"$DPRSRELURL\""
			echo "## $DEPS URL"
			echo "DEPURL=\"$DEPURL\""
			echo "## $SPEK URL"
			echo "SPEKURL=\"$SPEKURL\""
			echo "## $SPEK GH URL"
			echo "SPEKGHURL=\"$SPEKGHURL\""
			echo "## $SPEK compatibility URL"
			echo "SPEKCOMPURL=\"$SPEKCOMPURL\""
			echo "## $FWS DL URL"
			echo "FWSURL=\"$FWSURL\""
			echo "## $YAD appimage url"
			echo "YAIURL=\"$YAIURL\""
			echo "## wine reload URL"
			echo "WINERELOADURL=\"$WINERELOADURL\""
			echo "## $GEOELF url"
			echo "GEOELFURL=\"$GEOELFURL\""
			echo "## $WDIBURL url"
			echo "WDIBURL=\"$WDIBURL\""
			} >> "$1"
			#ENDsaveCfgurl
		fi
	}
	
	function saveCfggui {

		setDefaultCfgValues "$2"
		
		if [ -f "$1" ]; then
			updateConfigFile "$1" "${FUNCNAME[0]}" "$3"
		else
			#STARTsaveCfggui
			{
			echo "## config Version: $PROGVERS"
			echo "##########################"
			echo "## Settings Selection GUI:"
			echo "WINX=\"$WINX\""
			echo "WINY=\"$WINY\""
			echo "POSX=\"$POSX\""
			echo "POSY=\"$POSY\""		
			} >> "$1"
			#ENDsaveCfggui
		fi
	}

	function saveCfgglobal {

		setDefaultCfgValues "$2"

		if [ -f "$1" ]; then
			updateConfigFile "$1" "${FUNCNAME[0]}" "$3"
		else
			#STARTsaveCfgglobal
			{
			echo "## config Version: $PROGVERS"
			echo "##########################"
			echo "## $DESC_STLLANG"
			echo "STLLANG=\"$STLLANG\""
			echo "## $DESC_SKIPINTDEPCHECK"
			echo "SKIPINTDEPCHECK=\"$SKIPINTDEPCHECK\""
			echo "## $DESC_YAD"
			echo "YAD=\"$YAD\""
			echo "## $DESC_CUSTPROTDLDIR"
			echo "CUSTPROTDLDIR=\"$CUSTPROTDLDIR\""
			echo "## $DESC_CUSTPROTEXTDIR"
			echo "CUSTPROTEXTDIR=\"$CUSTPROTEXTDIR\""
			echo "## $DESC_CUPROTOCOMPAT"
			echo "CUPROTOCOMPAT=\"$CUPROTOCOMPAT\""
			echo "## $DESC_WINEDLDIR"
			echo "WINEDLDIR=\"$WINEDLDIR\""
			echo "## $DESC_WINEEXTDIR"
			echo "WINEEXTDIR=\"$WINEEXTDIR\""			
			echo "## $DESC_AUTOLASTPROTON"
			echo "AUTOLASTPROTON=\"$AUTOLASTPROTON\""
			echo "## $DESC_STRACEDIR"
			echo "STRACEDIR=\"$STRACEDIR\""
			echo "## $(strFix "$DESC_LOGDIR" "$PROGNAME")"
			echo "LOGDIR=\"$LOGDIR\""
			echo "## $DESC_LOGLEVEL"
			echo "LOGLEVEL=\"$LOGLEVEL\""
			echo "## $DESC_RESETLOG"
			echo "RESETLOG=\"$RESETLOG\""
			echo "## $DESC_STLEDITOR"
			echo "STLEDITOR=\"$STLEDITOR\""
			echo "## $DESC_MAXASK"
			echo "MAXASK=\"$MAXASK\""
			echo "## $DESC_BROWSER"
			echo "BROWSER=\"$BROWSER\""
			echo "## $DESC_USENOTIFIER"
			echo "USENOTIFIER=\"$USENOTIFIER\""
			echo "## $DESC_NOTY"
			echo "NOTY=\"$NOTY\""
			echo "## $DESC_NOTYARGS"
			echo "NOTYARGS=\"$NOTYARGS\""
			echo "## $DESC_NETMON"
			echo "NETMON=\"$NETMON\""
			echo "## $DESC_NETOPTS"
			echo "NETOPTS=\"$NETOPTS\""
			echo "## $DESC_NETMONDIR"
			echo "NETMONDIR=\"$NETMONDIR\""
			echo "## $DESC_VRVIDEOPLAYER"
			echo "VRVIDEOPLAYER=\"$VRVIDEOPLAYER\""
			echo "## $DESC_GLOBALSBSTWEAKS"
			echo "GLOBALSBSTWEAKS=\"$GLOBALSBSTWEAKS\""
			echo "## $DESC_GLOBALTWEAKS"
			echo "GLOBALTWEAKS=\"$GLOBALTWEAKS\""
			echo "## $DESC_GLOBALCOLLECTIONDIR"
			echo "GLOBALCOLLECTIONDIR=\"$GLOBALCOLLECTIONDIR\""
			echo "## $DESC_GLOBALMISCDIR"
			echo "GLOBALMISCDIR=\"$GLOBALMISCDIR\""
			echo "## $DESC_GLOBALEVALDIR"
			echo "GLOBALEVALDIR=\"$GLOBALEVALDIR\""
			echo "## $DESC_GLOBALSTLLANGDIR"
			echo "GLOBALSTLLANGDIR=\"$GLOBALSTLLANGDIR\""
			echo "## $DESC_GLOBALSTLGUIDIR"
			echo "GLOBALSTLGUIDIR=\"$GLOBALSTLGUIDIR\""
			echo "## $DESC_BOXTRONCMD"
			echo "BOXTRONCMD=\"$BOXTRONCMD\""
			echo "## $DESC_BOXTRONARGS"
			echo "BOXTRONARGS=\"$BOXTRONARGS\""
			echo "## $DESC_ROBERTACMD"
			echo "ROBERTACMD=\"$ROBERTACMD\""
			echo "## $DESC_ROBERTAARGS"
			echo "ROBERTAARGS=\"$ROBERTAARGS\""
			echo "## $DESC_LUXTORPEDACMD"
			echo "LUXTORPEDACMD=\"$LUXTORPEDACMD\""
			echo "## $DESC_LUXTORPEDAARGS"
			echo "LUXTORPEDAARGS=\"$LUXTORPEDAARGS\""
			echo "## $DESC_DOWNLOAD_RESHADE"
			echo "DOWNLOAD_RESHADE=\"$DOWNLOAD_RESHADE\""
			echo "## $DESC_RSVERS"
			echo "RSVERS=\"$RSVERS\""
			echo "## $DESC_AUTOBUMPRESHADE"
			echo "AUTOBUMPRESHADE=\"$AUTOBUMPRESHADE\""
			echo "## $DESC_RESHADESRCDIR"
			echo "RESHADESRCDIR=\"$RESHADESRCDIR\""
			echo "## $DESC_D3D47_64"
			echo "D3D47_64=\"$D3D47_64\""
			echo "## $DESC_D3D47_32"
			echo "D3D47_32=\"$D3D47_32\""
			echo "## $DESC_RS_64"
			echo "RS_64=\"$RS_64\""
			echo "## $DESC_RS_32"
			echo "RS_32=\"$RS_32\""
			echo "## $DESC_RS_64_VK"
			echo "RS_64_VK=\"$RS_64_VK\""
			echo "## $DESC_RS_32_VK"
			echo "RS_32_VK=\"$RS_32_VK\""
			echo "## $DESC_DLSHADER"
			echo "DLSHADER=\"$DLSHADER\""
			echo "## $DESC_SAVESETSIZE"
			echo "SAVESETSIZE=\"$SAVESETSIZE\""
			echo "## $DESC_STARTMENU"
			echo "STARTMENU=\"$STARTMENU\""
			echo "## $DESC_HEADLINEFONT"
			echo "HEADLINEFONT=\"$HEADLINEFONT\""
			echo "## $DESC_USEWINDECO"
			echo "USEWINDECO=\"$USEWINDECO\""
			echo "## $DESC_USETRAYICON"
			echo "USETRAYICON=\"$USETRAYICON\""
			echo "## $DESC_USEGAMEPICS"
			echo "USEGAMEPICS=\"$USEGAMEPICS\""
			echo "## $DESC_USECUSTOMFALLBACKPIC"
			echo "USECUSTOMFALLBACKPIC=\"$USECUSTOMFALLBACKPIC\""
			echo "## $DESC_GITHUBUSER"
			echo "GITHUBUSER=\"$GITHUBUSER\""
			echo "## $DESC_DLGAMEDATA"
			echo "DLGAMEDATA=\"$DLGAMEDATA\""
			echo "## $DESC_USEPDBRATING"
			echo "USEPDBRATING=\"$USEPDBRATING\""
			echo "## $DESC_PDBRATINGCACHE"
			echo "PDBRATINGCACHE=\"$PDBRATINGCACHE\""
			echo "## $DESC_DLWINETRICKS"
			echo "DLWINETRICKS=\"$DLWINETRICKS\""
			echo "## $DESC_USEVORTEXPROTON"
			echo "USEVORTEXPROTON=\"$USEVORTEXPROTON\""
			echo "## $DESC_VORTEXCOMPDATA"
			echo "VORTEXCOMPDATA=\"$VORTEXCOMPDATA\""
			echo "## $DESC_VORTEXDOWNLOADPATH"
			echo "VORTEXDOWNLOADPATH=\"$VORTEXDOWNLOADPATH\""
			echo "## $DESC_USEVORTEXPRERELEASE"
			echo "USEVORTEXPRERELEASE=\"$USEVORTEXPRERELEASE\""
			echo "## $(strFix "$DESC_DISABLE_AUTOSTAGES" "$PROGNAME")"
			echo "DISABLE_AUTOSTAGES=\"$DISABLE_AUTOSTAGES\""
			echo "## $DESC_NOSTEAMSTLDEF"
			echo "NOSTEAMSTLDEF=\"$NOSTEAMSTLDEF\""
			echo "## $DESC_SGDBAPIKEY"
			echo "SGDBAPIKEY=\"$SGDBAPIKEY\""
			echo "## $DESC_SGDBSTYLES"
			echo "SGDBSTYLES=\"$SGDBSTYLES\""
			echo "## $DESC_SGDBDIMS"
			echo "SGDBDIMS=\"$SGDBDIMS\""
			echo "## $DESC_SGDBTYPES"
			echo "SGDBTYPES=\"$SGDBTYPES\""
			echo "## $DESC_SGDBNSFW"
			echo "SGDBNSFW=\"$SGDBNSFW\""
			echo "## $DESC_SGDBHUMOR"
			echo "SGDBHUMOR=\"$SGDBHUMOR\""
			echo "## $DESC_SGDBDLTOSTEAM"
			echo "SGDBDLTOSTEAM=\"$SGDBDLTOSTEAM\""
			echo "## $DESC_SGDBHASFILE"
			echo "SGDBHASFILE=\"$SGDBHASFILE\""
			echo "## $DESC_SGDBAUTODL"
			echo "SGDBAUTODL=\"$SGDBAUTODL\""
			echo "## $DESC_STORECOMPDATTITLE"
			echo "STORECOMPDATTITLE=\"$STORECOMPDATTITLE\""
			echo "## $DESC_CUSTCONTY"
			echo "CUSTCONTY=\"$CUSTCONTY\""
			echo "## $DESC_UPDATECONTY"
			echo "UPDATECONTY=\"$UPDATECONTY\""
			echo "## $DESC_LOGPLAYTIME"
			echo "LOGPLAYTIME=\"$LOGPLAYTIME\""
			echo "## $DESC_DPRSCOMPDATA"
			echo "DPRSCOMPDATA=\"$DPRSCOMPDATA\""
			echo "## $DESC_USEDPRSPROTON"
			echo "USEDPRSPROTON=\"$USEDPRSPROTON\""
			echo "## $DESC_DPRSUSEVDFSYMLINKS"
			echo "DPRSUSEVDFSYMLINKS=\"$DPRSUSEVDFSYMLINKS\""
			echo "## $DESC_DPRSPAUTOUP"
			echo "DPRSPAUTOUP=\"$DPRSPAUTOUP\""
			echo "## $DESC_DEPSAUTOUP"
			echo "DEPSAUTOUP=\"$DEPSAUTOUP\""
			echo "## $DESC_MO2COMPDATA"
			echo "MO2COMPDATA=\"$MO2COMPDATA\""
			echo "## $DESC_USEMO2PROTON"
			echo "USEMO2PROTON=\"$USEMO2PROTON\""
			echo "## $DESC_HMMCOMPDATA"
			echo "HMMCOMPDATA=\"$HMMCOMPDATA\""
			echo "## $DESC_USEHMMPROTON"
			echo "USEHMMPROTON=\"$USEHMMPROTON\""
			echo "## $DESC_HMMDLVER"
			echo "HMMDLVER=\"$HMMDLVER\""
			echo "## $DESC_USETERM"
			echo "USETERM=\"$USETERM\""
			echo "## $DESC_TERMARGS"
			echo "TERMARGS=\"$TERMARGS\""

			} >> "$1"
			#ENDsaveCfgglobal
		fi
		updateEditor "$1"
	}

	function saveCfgdefault_template {

		setDefaultCfgValues "$2"

		if [ -f "$1" ]; then
			updateConfigFile "$1" "${FUNCNAME[0]}" "$3"
		else
			#STARTsaveCfgdefault_template
			{
			echo "## config Version: $PROGVERS"
			echo "##########################"
			echo "## $DESC_KEEPSTLOPEN"
			echo "KEEPSTLOPEN=\"$KEEPSTLOPEN\""
			echo "## $DESC_USESLR"
			echo "USESLR=\"$USESLR\""
			echo "## $DESC_FORCESLR"
			echo "FORCESLR=\"$FORCESLR\""
			echo "## $DESC_USEREAP"
			echo "USEREAP=\"$USEREAP\""
			echo "## $DESC_FORCEREAP"
			echo "FORCEREAP=\"$FORCEREAP\""
			echo "## $DESC_USEPROTON"
			echo "USEPROTON=\"$USEPROTON\""
			echo "## $DESC_REDIRCOMPDATA"
			echo "REDIRCOMPDATA=\"$REDIRCOMPDATA\""
			echo "## $DESC_REDIRSTEAMUSER"
			echo "REDIRSTEAMUSER=\"$REDIRSTEAMUSER\""
			echo "## $DESC_AUTOBUMPGE"
			echo "AUTOBUMPGE=\"$AUTOBUMPGE\""
			echo "## $DESC_AUTOBUMPPROTON"
			echo "AUTOBUMPPROTON=\"$AUTOBUMPPROTON\""
			echo "## $DESC_USECUSTOMCMD"
			echo "USECUSTOMCMD=\"$USECUSTOMCMD\""
			echo "## $DESC_CUSTOMCMD"
			echo "CUSTOMCMD=\"$CUSTOMCMD\""
			echo "## $DESC_CUSTOMCMD_ARGS"
			echo "CUSTOMCMD_ARGS=\"$CUSTOMCMD_ARGS\""
			echo "## $DESC_ONLY_CUSTOMCMD"
			echo "ONLY_CUSTOMCMD=\"$ONLY_CUSTOMCMD\""
			echo "## $DESC_FORK_CUSTOMCMD"
			echo "FORK_CUSTOMCMD=\"$FORK_CUSTOMCMD\""
			echo "## $DESC_EXTPROGS_CUSTOMCMD"
			echo "EXTPROGS_CUSTOMCMD=\"$EXTPROGS_CUSTOMCMD\""
			echo "## $DESC_CUSTOMCMD_FORCEWIN"
			echo "CUSTOMCMDFORCEWIN=\"$CUSTOMCMDFORCEWIN\""
			echo "## $DESC_WAITFORCUSTOMCMD"
			echo "WAITFORCUSTOMCMD=\"$WAITFORCUSTOMCMD\""
			echo "## $DESC_INJECT_CUSTOMCMD"
			echo "INJECT_CUSTOMCMD=\"$INJECT_CUSTOMCMD\""
			echo "## $DESC_INJECTWAIT"
			echo "INJECTWAIT=\"$INJECTWAIT\""
			echo "## $DESC_USEIGCS"
			echo "USEIGCS=\"$USEIGCS\""
			echo "## $DESC_UUUSEIGCS"
			echo "UUUSEIGCS=\"$UUUSEIGCS\""
			echo "## $DESC_IGCSWAIT"
			echo "IGCSWAIT=\"$IGCSWAIT\""
			echo "## $DESC_UUUSEPATCH"
			echo "UUUSEPATCH=\"$UUUSEPATCH\""
			echo "## $DESC_UUUPATCHWAIT"
			echo "UUUPATCHWAIT=\"$UUUPATCHWAIT\""
			echo "## $DESC_UUUSEVR"
			echo "UUUSEVR=\"$UUUSEVR\""
			echo "## $DESC_GAMEARGS"
			echo "GAMEARGS=\"$GAMEARGS\""
			echo "## $DESC_HARDARGS"
			echo "HARDARGS=\"$HARDARGS\""
			echo "## $DESC_USEGAMEMODERUN"
			echo "USEGAMEMODERUN=\"$USEGAMEMODERUN\""
			echo "## $DESC_USEGAMESCOPE"
			echo "USEGAMESCOPE=\"$USEGAMESCOPE\""
			echo "## $DESC_GAMESCOPE_ARGS"
			echo "GAMESCOPE_ARGS=\"$GAMESCOPE_ARGS\""
			echo "## $DESC_USEOBSCAP"
			echo "USEOBSCAP=\"$USEOBSCAP\""
			echo "## $DESC_USEZINK"
			echo "USEZINK=\"$USEZINK\""
			echo "## $DESC_USEPRIMERUN"
			echo "USEPRIMERUN=\"$USEPRIMERUN\""
			echo "## $DESC_TOGSTEAMWEBHELPER"
			echo "TOGSTEAMWEBHELPER=\"$TOGSTEAMWEBHELPER\""
			echo "## $DESC_USEMANGOHUD"
			echo "USEMANGOHUD=\"$USEMANGOHUD\""
			echo "## $DESC_USEMANGOAPP"
			echo "USEMANGOAPP=\"$USEMANGOAPP\""
			echo "## $DESC_MAHUBIN"
			echo "MAHUBIN=\"$MAHUBIN\""
			echo "## $DESC_MAHUARGS"
			echo "MAHUARGS=\"$MAHUARGS\""
			echo "## $DESC_LDPMAHU"
			echo "LDPMAHU=\"$LDPMAHU\""
			echo "## $DESC_MAHUVAR"
			echo "MAHUVAR=\"$MAHUVAR\""
			echo "## $DESC_USEMANGOHUDSTLCFG"
			echo "USEMANGOHUDSTLCFG=\"$USEMANGOHUDSTLCFG\""
			echo "## $DESC_ENABLE_VKBASALT"
			echo "ENABLE_VKBASALT=\"$ENABLE_VKBASALT\""
			echo "## $DESC_RUN_NYRNA"
			echo "RUN_NYRNA=\"$RUN_NYRNA\""
			echo "## $DESC_RUN_REPLAY"
			echo "RUN_REPLAY=\"$RUN_REPLAY\""
			echo "## $DESC_RUN_X64DBG"
			echo "RUN_X64DBG=\"$RUN_X64DBG\""
			echo "## $DESC_RUN_GDB"
			echo "RUN_GDB=\"$RUN_GDB\""
			echo "## $DESC_USE_WDIB"
			echo "USE_WDIB=\"$USE_WDIB\""
			echo "## $DESC_USEVORTEX"
			echo "USEVORTEX=\"$USEVORTEX\""
			echo "## $DESC_WAITVORTEX"
			echo "WAITVORTEX=\"$WAITVORTEX\""
			echo "## $DESC_RUN_VORTEX_WINETRICKS"
			echo "RUN_VORTEX_WINETRICKS=\"$RUN_VORTEX_WINETRICKS\""
			echo "## $DESC_RUN_VORTEX_WINECFG"
			echo "RUN_VORTEX_WINECFG=\"$RUN_VORTEX_WINECFG\""
			echo "## $DESC_CHANGE_PULSE_LATENCY"
			echo "CHANGE_PULSE_LATENCY=\"$CHANGE_PULSE_LATENCY\""
			echo "## $DESC_STL_PULSE_LATENCY_MSEC"
			echo "STL_PULSE_LATENCY_MSEC=\"$STL_PULSE_LATENCY_MSEC\""
			echo "## $DESC_TOGGLEWINDOWS"
			echo "TOGGLEWINDOWS=\"$TOGGLEWINDOWS\""
			echo "## $DESC_RUN_WINETRICKS"
			echo "RUN_WINETRICKS=\"$RUN_WINETRICKS\""
			echo "## $DESC_WINETRICKSPAKS"
			echo "WINETRICKSPAKS=\"$WINETRICKSPAKS\""
			echo "## $DESC_RUN_WINECFG"
			echo "RUN_WINECFG=\"$RUN_WINECFG\""
			echo "## $DESC_USEWINE"
			echo "USEWINE=\"$USEWINE\""
			echo "## $DESC_USEWICO"
			echo "USEWICO=\"$USEWICO\""
			echo "## $DESC_WINEVERSION"
			echo "WINEVERSION=\"$WINEVERSION\""
			echo "## $DESC_WINEDEFAULT"
			echo "WINEDEFAULT=\"$WINEDEFAULT\""
			echo "## $DESC_VIRTUALDESKTOP"
			echo "VIRTUALDESKTOP=\"$VIRTUALDESKTOP\""
			echo "## $DESC_VDRES"
			echo "VDRES=\"$VDRES\""
			echo "## $DESC_USEBOXTRON"
			echo "USEBOXTRON=\"$USEBOXTRON\""
			echo "## $DESC_USEROBERTA"
			echo "USEROBERTA=\"$USEROBERTA\""
			echo "## $DESC_USELUXTORPEDA"
			echo "USELUXTORPEDA=\"0\""
			echo "## $DESC_REGEDIT"
			echo "REGEDIT=\"$REGEDIT\""
			echo "## $DESC_USEGEOELF"
			echo "USEGEOELF=\"$USEGEOELF\""
			echo "## $DESC_AUTOGEOELF"
			echo "AUTOGEOELF=\"$AUTOGEOELF\""
			echo "## $DESC_INSTALL_RESHADE"
			echo "INSTALL_RESHADE=\"$INSTALL_RESHADE\""
			echo "## $DESC_RESHADE_DEPTH3D"
			echo "RESHADE_DEPTH3D=\"$RESHADE_DEPTH3D\""
			echo "## $DESC_USERESHADE"
			echo "USERESHADE=\"$USERESHADE\""
			echo "## $DESC_CUSTOMCMDRESHADE"
			echo "CUSTOMCMDRESHADE=\"$CUSTOMCMDRESHADE\""
			echo "## $DESC_RESHADEUPDATE"
			echo "RESHADEUPDATE=\"$RESHADEUPDATE\""
			echo "## $DESC_RESHADEOVERRIDETOGGLE"
			echo "RSOVRD=\"$RSOVRD\""
			echo "## $DESC_RESHADEOVERRIDEVERSION"
			echo "RSOVRVERS=\"$RSOVRVERS\""
			echo "## $DESC_CHOOSESHADERS"
			echo "CHOOSESHADERS=\"$CHOOSESHADERS\""
			echo "## $DESC_ALTEXEPATH"
			echo "ALTEXEPATH=\"$ALTEXEPATH\""
			echo "## $DESC_ARCHALTEXE"
			echo "ARCHALTEXE=\"$ARCHALTEXE\""
			echo "## $DESC_USEOPENVRFSR"
			echo "USEOPENVRFSR=\"$USEOPENVRFSR\""
			echo "## $DESC_RUNSBSVR"
			echo "RUNSBSVR=\"$RUNSBSVR\""
			echo "## $DESC_VRVIDEOPLAYERARGS"
			echo "VRVIDEOPLAYERARGS=\"$VRVIDEOPLAYERARGS\""
			echo "## $DESC_SBSZOOM"
			echo "SBSZOOM=\"$SBSZOOM\""
			echo "## $DESC_SBSVRGEOELF"
			echo "SBSVRGEOELF=\"$SBSVRGEOELF\""
			echo "## $DESC_SBSVRRS"
			echo "SBSVRRS=\"$SBSVRRS\""
			echo "## $DESC_SBSRS"
			echo "SBSRS=\"$SBSRS\""
			echo "## $DESC_MINVRWINH"
			echo "MINVRWINH=\"$MINVRWINH\""
			echo "## $DESC_WAITFORTHISPID"
			echo "WAITFORTHISPID=\"$WAITFORTHISPID\""
			echo "## $DESC_WAITEDITOR"
			echo "WAITEDITOR=\"$WAITEDITOR\""
			echo "## $DESC_STEAMAPPIDFILE"
			echo "STEAMAPPIDFILE=\"$STEAMAPPIDFILE\""
			echo "## $DESC_CHECKCOLLECTIONS"
			echo "CHECKCOLLECTIONS=\"$CHECKCOLLECTIONS\""
			echo "## $DESC_BACKUPSTEAMUSER"
			echo "BACKUPSTEAMUSER=\"$BACKUPSTEAMUSER\""
			echo "## $DESC_RESTORESTEAMUSER"
			echo "RESTORESTEAMUSER=\"$RESTORESTEAMUSER\""
			echo "## $DESC_USESUSYM"
			echo "USESUSYM=\"$USESUSYM\""
			echo "## $DESC_USEGLOBSUSYM"
			echo "USEGLOBSUSYM=\"$USEGLOBSUSYM\""
			echo "## $DESC_USE_STLDXVKCFG"
			echo "USE_STLDXVKCFG=\"$USE_STLDXVKCFG\""
			echo "## $(strFix "$DESC_DXVKVARS" "$DXVKURL")"
			echo "DXVK_HUD=\"$DXVK_HUD\""
			echo "## $DESC_DXVK_LOG_LEVEL"
			echo "DXVK_LOG_LEVEL=\"$DXVK_LOG_LEVEL\""
			echo "## $DESC_DXVK_LOG_PATH"
			echo "DXVK_LOG_PATH=\"$DXVK_LOG_PATH\""
			echo "## $DESC_DXVK_SCALE"
			echo "DXVK_SCALE=\"$DXVK_SCALE\""
			echo "## $DESC_DXVK_FPSLIMIT"
			echo "DXVK_FPSLIMIT=\"$DXVK_FPSLIMIT\""
			echo "## $DESC_DXVK_ASYNC"
			echo "DXVK_ASYNC=\"$DXVK_ASYNC\""
			echo "## $DESC_DXVK_HDR"
			echo "DXVK_HDR=\"$DXVK_HDR\""
			echo "## $DESC_STRACERUN"
			echo "STRACERUN=\"$STRACERUN\""
			echo "## $DESC_STRACEOPTS"
			echo "STRACEOPTS=\"$STRACEOPTS\""
			echo "## $DESC_USENETMON"
			echo "USENETMON=\"$USENETMON\""
			echo "## $DESC_BLOCKINTERNET"
			echo "BLOCKINTERNET=\"$BLOCKINTERNET\""
			echo "## $DESC_PROTON_LOG"
			echo "PROTON_LOG=\"$PROTON_LOG\""
			echo "## $DESC_PROTON_LOG_DIR"
			echo "PROTON_LOG_DIR=\"$PROTON_LOG_DIR\""
			echo "## $DESC_USEWINEDEBUGPROTON"
			echo "USEWINEDEBUGPROTON=\"$USEWINEDEBUGPROTON\""
			echo "## $DESC_PROTON_DUMP_DEBUG_COMMANDS"
			echo "PROTON_DUMP_DEBUG_COMMANDS=\"$PROTON_DUMP_DEBUG_COMMANDS\""
			echo "## $DESC_PROTON_DEBUG_DIR"
			echo "PROTON_DEBUG_DIR=\"$PROTON_DEBUG_DIR\""
			echo "## $DESC_PROTON_USE_WINED3D"
			echo "PROTON_USE_WINED3D=\"$PROTON_USE_WINED3D\""
			echo "## $DESC_PROTON_NO_D3D11"
			echo "PROTON_NO_D3D11=\"$PROTON_NO_D3D11\""
			echo "## $DESC_PROTON_NO_D3D10"
			echo "PROTON_NO_D3D10=\"$PROTON_NO_D3D10\""
			echo "## $DESC_PROTON_NO_ESYNC"
			echo "PROTON_NO_ESYNC=\"$PROTON_NO_ESYNC\""
			echo "## $DESC_PROTON_NO_FSYNC"
			echo "PROTON_NO_FSYNC=\"$PROTON_NO_FSYNC\""
			echo "## $DESC_ENABLE_WINESYNC"
			echo "ENABLE_WINESYNC=\"$ENABLE_WINESYNC\""
			echo "## $DESC_PROTON_ENABLE_NVAPI"
			echo "PROTON_ENABLE_NVAPI=\"$PROTON_ENABLE_NVAPI\""
			echo "## $DESC_PROTON_HIDE_NVIDIA_GPU"
			echo "PROTON_HIDE_NVIDIA_GPU=\"$PROTON_HIDE_NVIDIA_GPU\""
			echo "## $DESC_USEDLSS"
			echo "USEDLSS=\"$USEDLSS\""
			echo "## $DESC_USERAYTRACING"
			echo "USERAYTRACING=\"$USERAYTRACING\""
			echo "## $DESC_PROTON_FORCE_LARGE_ADDRESS_AWARE"
			echo "PROTON_FORCE_LARGE_ADDRESS_AWARE=\"$PROTON_FORCE_LARGE_ADDRESS_AWARE\""
			echo "## $DESC_WINE_FULLSCREEN_INTEGER_SCALING"
			echo "WINE_FULLSCREEN_INTEGER_SCALING=\"$WINE_FULLSCREEN_INTEGER_SCALING\""
			echo "## $DESC_WINE_FULLSCREEN_FSR"
			echo "WINE_FULLSCREEN_FSR=\"$WINE_FULLSCREEN_FSR\""
			echo "## $DESC_WINE_FULLSCREEN_FSR_STRENGTH"
			echo "WINE_FULLSCREEN_FSR_STRENGTH=\"$WINE_FULLSCREEN_FSR_STRENGTH\""
			echo "## $DESC_CLEANPROTONTEMP"
			echo "CLEANPROTONTEMP=\"$CLEANPROTONTEMP\""
			echo "## $DESC_STLWINEDEBUG"
			echo "STLWINEDEBUG=\"$STLWINEDEBUG\""
			echo "## $DESC_STLWINEDLLOVERRIDES"
			echo "STLWINEDLLOVERRIDES=\"$STLWINEDLLOVERRIDES\""
			echo "## $DESC_WINE_LOG_DIR"
			echo "WINE_LOG_DIR=\"$WINE_LOG_DIR\""
			echo "## $DESC_USERSTART"
			echo "USERSTART=\"$USERSTART\""
			echo "## $DESC_USERSTOP"
			echo "USERSTOP=\"$USERSTOP\""
			echo "## $DESC_AUTOCONTY"
			echo "AUTOCONTY=\"$AUTOCONTY\""
			echo "## $DESC_USECONTY"
			echo "USECONTY=\"$USECONTY\""
			echo "## $DESC_CRASHGUESS"
			echo "CRASHGUESS=\"$CRASHGUESS\""
			echo "## $DESC_ONLYWICO"
			echo "ONLYWICO=\"$ONLYWICO\""
			echo "## $DESC_GAMESCREENRES"
			echo "GAMESCREENRES=\"$GAMESCREENRES\""
			echo "## Default Help URL"
			echo "HELPURL=\"$HELPURL\""
			echo "## Desktop Icon Mode"
			echo "CREATEDESKTOPICON=\"$CREATEDESKTOPICON\""
			echo "## $DESC_FIXSYMLINKS"
			echo "FIXSYMLINKS=\"$FIXSYMLINKS\""
			echo "## $DESC_UNSYMLINK"
			echo "UNSYMLINK=\"$UNSYMLINK\""
			echo "## $DESC_DELPFX"
			echo "DELPFX=\"$DELPFX\""
			echo "## $DESC_RUN_DEPS"
			echo "RUN_DEPS=\"$RUN_DEPS\""
			echo "## $DESC_SORTGARGS"
			echo "SORTGARGS=\"$SORTGARGS\""
			echo "## $DESC_WAITMO2"
			echo "WAITMO2=\"$WAITMO2\""
			echo "## $DESC_MO2MODE"
			echo "MO2MODE=\"$MO2MODE\""
			echo "## $DESC_USESPECIALK"
			echo "USESPECIALK=\"$USESPECIALK\""
			echo "## $DESC_SDLUSEWAYLAND"
			echo "SDLUSEWAYLAND=\"$SDLUSEWAYLAND\""
			echo "## $DESC_STLRAD_PFTST"
			echo "STLRAD_PFTST=\"$STLRAD_PFTST\""
			echo "## $DESC_SPEKVERS"
			echo "SPEKVERS=\"$SPEKVERS\""
			echo "## $DESC_AUTOSPEK"
			echo "AUTOSPEK=\"$AUTOSPEK\""
			echo "## $DESC_USEFWS"
			echo "USEFWS=\"$USEFWS\""
			echo "## $DESC_USEPEV_PELDD"
			echo "USEPEV_PELDD=\"$USEPEV_PELDD\""
			echo "## $DESC_USEPEV_PEPACK"
			echo "USEPEV_PEPACK=\"$USEPEV_PEPACK\""
			echo "## $DESC_USEPEV_PERES"
			echo "USEPEV_PERES=\"$USEPEV_PERES\""
			echo "## $DESC_USEPEV_PESCAN"
			echo "USEPEV_PESCAN=\"$USEPEV_PESCAN\""
			echo "## DESC_USEPEV_PESEC"
			echo "USEPEV_PESEC=\"$USEPEV_PESEC\""
			echo "## $DESC_USEPEV_PESTR"
			echo "USEPEV_PESTR=\"$USEPEV_PESTR\""
			echo "## $DESC_USEPEV_READPE"
			echo "USEPEV_READPE=\"$USEPEV_READPE\""
			echo "## $DESC_STL_VKD3D_CONFIG"
			echo "STL_VKD3D_CONFIG=\"$STL_VKD3D_CONFIG\""
			echo "## $DESC_STL_VKD3D_DEBUG"
			echo "STL_VKD3D_DEBUG=\"$STL_VKD3D_DEBUG\""
			echo "## $DESC_STL_VKD3D_SHADER_DEBUG"
			echo "STL_VKD3D_SHADER_DEBUG=\"$STL_VKD3D_SHADER_DEBUG\""
			echo "## $DESC_STL_VKD3D_LOG_FILE"
			echo "STL_VKD3D_LOG_FILE=\"$STL_VKD3D_LOG_FILE\""
			echo "## $DESC_STL_VKD3D_VULKAN_DEVICE"
			echo "STL_VKD3D_VULKAN_DEVICE=\"$STL_VKD3D_VULKAN_DEVICE\""
			echo "## $DESC_STL_VKD3D_FILTER_DEVICE_NAME"
			echo "STL_VKD3D_FILTER_DEVICE_NAME=\"$STL_VKD3D_FILTER_DEVICE_NAME\""
			echo "## $DESC_STL_VKD3D_DISABLE_EXTENSIONS"
			echo "STL_VKD3D_DISABLE_EXTENSIONS=\"$STL_VKD3D_DISABLE_EXTENSIONS\""
			echo "## $DESC_STL_VKD3D_TEST_DEBUG"
			echo "STL_VKD3D_TEST_DEBUG=\"$STL_VKD3D_TEST_DEBUG\""
			echo "## $DESC_STL_VKD3D_TEST_FILTER"
			echo "STL_VKD3D_TEST_FILTER=\"$STL_VKD3D_TEST_FILTER\""
			echo "## $DESC_STL_VKD3D_TEST_EXCLUDE"
			echo "STL_VKD3D_TEST_EXCLUDE=\"$STL_VKD3D_TEST_EXCLUDE\""
			echo "## $DESC_STL_VKD3D_TEST_PLATFORM"
			echo "STL_VKD3D_TEST_PLATFORM=\"$STL_VKD3D_TEST_PLATFORM\""
			echo "## $DESC_STL_VKD3D_TEST_BUG"
			echo "STL_VKD3D_TEST_BUG=\"$STL_VKD3D_TEST_BUG\""
			echo "## $DESC_STL_VKD3D_PROFILE_PATH"
			echo "STL_VKD3D_PROFILE_PATH=\"$STL_VKD3D_PROFILE_PATH\""	
			} >> "$1"

			#ENDsaveCfgdefault_template
		fi
	}

	SCFG="$(basename "${1//.conf/}")"
	"${FUNCNAME[0]}$SCFG" "$1" "$SCFG" "$2"

	if grep "$STLCFGDIR" "$1" >/dev/null ; then
		writelog "UPDATE" "${FUNCNAME[0]} - Replacing '$STLCFGDIR' with 'STLCFGDIR' in '$1'"
		sed "s:$STLCFGDIR:STLCFGDIR:g" -i "$1"
	fi
}

function notiShow {
	if [ "$ONSTEAMDECK" -eq 1 ] && [ "$FIXGAMESCOPE" -eq 1 ]; then
		writelog "INFO" "${FUNCNAME[0]} - Skipping notifier on SteamDeck Game Mode"
		USENOTIFIER=0 # might avoid a 2nd try during this session
	elif [ "$STLQUIET" -eq 1 ]; then
		USENOTIFIER=0
	else
		if [ -n "$2" ] && [ "$2" == "X" ]; then
			if [ -z "$NOTY" ]; then
				NOTY="$(command -v "notify-send")"
			fi
		fi

		if [ -n "$USENOTIFIER" ] && [ "$USENOTIFIER" -eq 1 ] && { [ -z "$2" ] || { [ -n "$2" ] && [ "$2" != "S" ]; };} || { [ -n "$2" ] && [ "$2" == "X" ]; }; then
			if [ -x "$(command -v "$NOTY")" ]; then
				if [ -z "${NOTYARGSARR[0]}" ]; then
					mapfile -d " " -t -O "${#NOTYARGSARR[@]}" NOTYARGSARR < <(printf '%s' "$NOTYARGS")
				fi
				"$NOTY" "${NOTYARGSARR[@]}" "$1"
			else
				writelog "INFO" "${FUNCNAME[0]} - Warning - '$NOTY' not found - disabling notifier"
				USENOTIFIER=0
			fi
		fi
		
		if [ -n "$2" ] && [ "$2" == "S" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Message '$1' should go to StatusWindow"
			echo "$1"
		fi
	fi
}

function strFix {
	STRIN="$1"
	if [ -z "$2" ]; then
		echo "$STRIN"
	else
		STRIN2="${STRIN//XXX/$2}"
		STRIN3="${STRIN2//YYY/$3}"
		STRIN4="${STRIN3//ZZZ/$4}"
		echo "${STRIN4//QQQ/$5}"
	fi
}

function getProtPathFromCSV {
	delEmptyFile "$PROTONCSV"
	if [ ! -f "$PROTONCSV" ]; then
		writelog "INFO" "${FUNCNAME[0]} - Creating '$PROTONCSV'"
		getAvailableProtonVersions "up" X
	fi

	if [ -f "$PROTONCSV" ]; then
		grep "^$1" "$PROTONCSV" | sort -nr | head -n1 | cut -d ';' -f2
	fi
}

function setRunWineServer {
	if [ "$ISGAME" -eq 2 ]; then
		writelog "INFO" "${FUNCNAME[0]} - Initiated from '$1'"

		if [ -n "$USEPROTON" ] && [ ! -f "$(getProtPathFromCSV "$USEPROTON")" ] && [ "$HAVEINPROTON" -eq 0 ]; then
			fixProtonVersionMismatch "USEPROTON" "$STLGAMECFG"
		fi

		if [ -z "$RUNPROTON" ] && [ "$HAVEINPROTON" -eq 1 ]; then
			RUNPROTON="${INPROTCMD[*]}"
		fi

		if [ -z "$RUNPROTON" ]; then
			setRunProtonFromUseProton
		fi

		CHECKWINED="$(dirname "$RUNPROTON")/$DBW"
		CHECKWINEF="$(dirname "$RUNPROTON")/$FBW"
		if [ -f "$CHECKWINED" ]; then
			RUNWINE="$CHECKWINED"
			RUNWINESERVER="${RUNWINE}server"
			writelog "INFO" "${FUNCNAME[0]} - Set the wine binary for proton in path '$RUNPROTON'"	
			writelog "INFO" "${FUNCNAME[0]} - to '$RUNWINE'"	
			writelog "INFO" "${FUNCNAME[0]} - and wineserver to '$RUNWINESERVER'"	
		elif [ -f "$CHECKWINEF" ]; then
			RUNWINE="$CHECKWINEF"
			RUNWINESERVER="${RUNWINE}server"
			writelog "INFO" "${FUNCNAME[0]} - Set the wine binary for proton in path '$RUNPROTON'"	
			writelog "INFO" "${FUNCNAME[0]} - to '$RUNWINE'"	
			writelog "INFO" "${FUNCNAME[0]} - and wineserver to '$RUNWINESERVER'"
		else
			writelog "WARN" "${FUNCNAME[0]} - Couldn't find the wine binary for the proton in path '$RUNPROTON' - falling back to 'wine' for plain RUNWINE and 'wineserver' for RUNWINESERVER"
		fi
	fi
}

function setNewProtVars {
	if [ "$ISGAME" -eq 2 ] && [ "$USEWINE" -eq 0 ]; then
		if [ "$HAVEINPROTON" -eq 1 ]; then
			if [ -z "$RUNWINESERVER" ]; then
				setRunWineServer "${FUNCNAME[0]}"
			fi
		else
			# arg1 is absolute proton path
			if [ "$HAVEINPROTON" -eq 0 ]; then
				writelog "INFO" "${FUNCNAME[0]} - Setting new Proton Variables based on '$1'"
				RUNPROTON="$1"
				CHECKWINED="$(dirname "$RUNPROTON")/$DBW"
				CHECKWINEF="$(dirname "$RUNPROTON")/$FBW"

				writelog "INFO" "${FUNCNAME[0]} - Continuing with RUNPROTON='$RUNPROTON'"

				PDTGZ="proton_dist.tar.gz"
				if [ ! -f "$CHECKWINED" ] && [ ! -f "$CHECKWINEF" ] && [ -f "$(dirname "$RUNPROTON")/$PDTGZ" ]; then
					writelog "INFO" "${FUNCNAME[0]} - Wine binary not found, but a proton archive '$PDTGZ' - extracting now"
					mkProjDir "$(dirname "$RUNPROTON")/dist"
					"$TAR" xf "$(dirname "$RUNPROTON")/$PDTGZ" -C "$(dirname "$RUNPROTON")/dist" 2>/dev/null
				fi
				
				PROTONVERSION="$(setProtonPathVersion "$RUNPROTON")"
				USEPROTON="$PROTONVERSION"

				setRunWineServer "${FUNCNAME[0]}"
			else
				writelog "SKIP" "${FUNCNAME[0]} - Using Steam Proton '$FIRSTUSEPROTON' instead of ${PROGNAME,,} Proton '$USEPROTON', because '$PROGCMD' was used as '$SLO'"
				notiShow "$(strFix "$NOTY_SETNEWPROTVARS" "$FIRSTUSEPROTON")"
			fi
		fi

		if [ "$USEWINEDEBUGPROTON" -eq 1 ]; then
			writelog "INFO" "${FUNCNAME[0]} - Using '$STLWINEDEBUG' as Proton 'WINEDEBUG' parameters, because 'USEWINEDEBUGPROTON' is enabled"
			export WINEDEBUG="$STLWINEDEBUG"
		fi

		if [ -n "$STLWINEDLLOVERRIDES" ] && [ "$STLWINEDLLOVERRIDES" != "$NON" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Using '$STLWINEDLLOVERRIDES' as 'WINEDLLOVERRIDES' parameter"
			export WINEDLLOVERRIDES="$WINEDLLOVERRIDES;$STLWINEDLLOVERRIDES"
		fi
	fi
}

# in case you wonder NOP='Newest Official Proton'
function getNOP {
	createProtonList
	NEWESTPROTRAW="$(printProtonArr | grep "^proton-[0-9]." | sort -nr | head -n1)"
	
	if [ "$1" == "p" ]; then
		cut -d ';' -f2 <<< "$NEWESTPROTRAW"
	elif [ "$1" == "v" ]; then
		cut -d ';' -f1 <<< "$NEWESTPROTRAW"
	fi
}

function setNOP {
	writelog "INFO" "${FUNCNAME[0]} - Selecting newest official Proton available"
	NOPPATH="$(getNOP "p")"
	if [ -n "$NOPPATH" ]; then
		writelog "INFO" "${FUNCNAME[0]} - Selected '$NOPPATH'"
		NEWPROPA="$( dirname "$NOPPATH" )"
		NEWPROPA="${NEWPROPA%*/}"
		NEWPROPA="${NEWPROPA##*/}"
		notiShow "$(strFix "$NOTY_WANTPROTON2" "$NEWPROPA" "$USEPROTON")"

		setNewProtVars "$NOPPATH"
	else
		writelog "SKIP" "${FUNCNAME[0]} - Haven't found anything"
	fi
}

function needNewProton {
	if [ "$HAVEINPROTON" -eq 0 ]; then
		getAvailableProtonVersions "up"
		export CURWIKI="$PPW/Proton-Versions"
		TITLE="${PROGNAME}-NeedNewProtonVersion"
		pollWinRes "$TITLE"
		writelog "INFO" "${FUNCNAME[0]} - No Proton Version was found - opening a requester to choose from one"
		createProtonList
		
		PICKPROTON="$("$YAD" --f1-action="$F1ACTION" --window-icon="$STLICON" --center $WINDECO --form --scroll --separator="\n" --quoted-output \
		--text="$(spanFont "$GUI_NEEDNEWPROTON" "H")" \
		--field="$GUI_NEEDNEWPROTON2":CB "$(cleanDropDown "${USEPROTON/#-/ -}" "$PROTYADLIST")" \
		--title="$TITLE" "$GEOM")"

		if [ -n "$PICKPROTON" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Selected Proton Version $PICKPROTON"
			setNewProtVars "$(getProtPathFromCSV "$PICKPROTON")"
		else
			writelog "INFO" "${FUNCNAME[0]} - No Proton Version was selected - try again"
			"${FUNCNAME[0]}"
		fi
	fi
}

function dlCustomProton {
	if [ "$CUPROTOCOMPAT" -eq 1 ]; then
		CUPROEXTDIR="$STEAMCOMPATOOLS"
	else
		CUPROEXTDIR="$CUSTPROTEXTDIR"
	fi

	CPURL="${1//\"/}"
	CPURLFILE="${CPURL##*/}"
	DSTDL="$CUSTPROTDLDIR/$CPURLFILE"
	if [ ! -f "$DSTDL" ]; then
		notiShow "$(strFix "$NOTY_DLCUSTOMPROTON" "$CPURL")" "S"
		DLCHK="X"
		INCHK="$NON"
		# only "-STL" and "GE" proton have a sha512sum
		if grep -q "\-GE" <<< "$CPURLFILE" || grep -q "GE-" <<< "$CPURLFILE" || grep -q "\-STL" <<< "$CPURLFILE"; then
			DLCHK="sha512sum"
			INCHK="$("$WGET" -q "${CPURL%%.tar*}.${DLCHK}" -O - 2> >(grep -v "SSL_INIT") | cut -d ' ' -f1)"
		fi
		dlCheck "$CPURL" "$DSTDL" "$DLCHK" "Downloading '$CPURL' to '$CUSTPROTDLDIR'" "$INCHK"
	else
		writelog "INFO" "${FUNCNAME[0]} - File '$DSTDL' already exists - nothing to download"
		if [ -z "$2" ]; then
			notiShow "$(strFix "$NOTY_DLCUSTOMPROTON4" "$CPURLFILE")"
		fi
	fi
	
	PROTNAMERAW="${CPURLFILE%%.tar*}"
	PROTNAME="${PROTNAMERAW//.zip/}"
	if [ -d "$CUPROEXTDIR/$PROTNAME" ]; then
		writelog "INFO" "${FUNCNAME[0]} - directory '$CUPROEXTDIR/$PROTNAME' already exists - nothing to extract"
	else
		# only "-STL" and "GE" proton have a sha512sum
		if grep -q "\-GE" <<< "$CPURLFILE" || grep -q "GE-" <<< "$CPURLFILE" || grep -q "\-STL" <<< "$CPURLFILE"; then
			DLCHK="sha512sum"
			writelog "INFO" "${FUNCNAME[0]} - checking if the checksum of the already downloaded file is correct '${CPURL%%.tar*}.${DLCHK}'"
			INCHK="$("$WGET" -q "${CPURL%%.tar*}.${DLCHK}" -O - 2> >(grep -v "SSL_INIT") | cut -d ' ' -f1)"
			dlCheck "$DLCHK" "$DSTDL" "C" "$INCHK"
		fi

		if grep -q "\.tar\." <<< "$DSTDL"; then
			notiShow "$(strFix "$NOTY_DLCUSTOMPROTON5" "$CPURLFILE")" "S"

			PROTRELPATH="$("$TAR" -tf "$DSTDL" 2>/dev/null | grep "proton$" 2>/dev/null )"
			if [ -n "$PROTRELPATH" ]; then
				if grep -q "^proton$" <<< "$PROTRELPATH"; then
					EXTDEST="$CUPROEXTDIR/$PROTNAME"
					PROTFULLPATH="$EXTDEST/$PROTRELPATH"
					writelog "INFO" "${FUNCNAME[0]} - Archive is a tarbomb - creating parent directory '$EXTDEST' as extract dest dir"
					mkProjDir "$EXTDEST"
				else
					writelog "INFO" "${FUNCNAME[0]} - Archive contains proton in subdirectory '$PROTRELPATH'"
					PROTFULLPATH="$CUPROEXTDIR/$PROTRELPATH"
					EXTDEST="$CUPROEXTDIR"
				fi

				if [ -f "$PROTFULLPATH" ]; then
					writelog "SKIP" "${FUNCNAME[0]} - The destination path '$PROTFULLPATH' already exists - looks like '$DSTDL' was already extracted before"
				else
					notiShow "$(strFix "$NOTY_DLCUSTOMPROTON3" "$CPURL")" "S"
					"$TAR" xf "$DSTDL" -C "$EXTDEST" 2>/dev/null
					getAvailableProtonVersions "up"
					touch "$PROTBUMPTEMP"
				fi
			else
				notiShow "$(strFix "$NOTY_DLCUSTOMPROTON6" "$DSTDL")" "S"
				writelog "SKIP" "${FUNCNAME[0]} - Archive doesn't seem to contain a 'proton' file"
			fi
		elif grep -q "\.zip$" <<< "$DSTDL"; then
			if grep -q "proton$" <<< "$("$UNZIP" -l "$DSTDL" 2>/dev/null)"; then
				writelog "INFO" "${FUNCNAME[0]} - Archive contains proton"
				SUBDIR="$(basename "${DSTDL//.zip/}")"
				PROTRELPATH="$SUBDIR/proton"
				PROTFULLPATH="$CUPROEXTDIR/$PROTRELPATH"
				if [ -f "$PROTFULLPATH" ]; then
					writelog "SKIP" "${FUNCNAME[0]} - The destination path '$PROTFULLPATH' already exists - looks like '$DSTDL' was already extracted before"
				else
					notiShow "$(strFix "$NOTY_DLCUSTOMPROTON3" "$CPURL")" "S"
					"$UNZIP" "$DSTDL" -d "$CUPROEXTDIR/$SUBDIR" 2>/dev/null
					getAvailableProtonVersions "up"
					touch "$PROTBUMPTEMP"
					notiShow "$GUI_DONE" "S"
				fi
			else
				notiShow "$(strFix "$NOTY_DLCUSTOMPROTON6" "$CPURL")" "S"
				writelog "SKIP" "${FUNCNAME[0]} - Archive doesn't seem to contain a 'proton' file"
			fi
		else
			writelog "SKIP" "${FUNCNAME[0]} - Don't know how to extract "
		fi
	fi

	rm "$PROTONCSV" 2>/dev/null

	if [ -f "$PROTFULLPATH" ]; then
		addCustomProtonToList "$PROTFULLPATH"
	fi
}

function createDLProtList {
	if [ ! -x "$(command -v "$JQ")" ]; then
		writelog "WARN" "${FUNCNAME[0]} - 'jq' is not installed - Can't generate list of online Proton versions"
	else
		writelog "INFO" "${FUNCNAME[0]} - Generating list of online available custom Proton builds"

		PROTDLLIST="$STLSHM/ProtonDL.txt"
		MAXAGE=360

		if [ ! -f "$PROTDLLIST" ] || test "$(find "$PROTDLLIST" -mmin +"$MAXAGE")"; then
			rm "$PROTDLLIST" 2>/dev/null
			while read -r CPURL; do
				if grep -q "$GHURL" <<< "${!CPURL}"; then
					SRCURL="${!CPURL}"
					SRCURL="${SRCURL//\/releases}"
					SRCURL="${SRCURL//$GHURL/$AGHURL\/repos}"
					SRCURL="${SRCURL}/releases"

					"$WGET" -q "$SRCURL" -O - | "$JQ" -r '.[].assets[].browser_download_url' | grep "tar.gz\|tar.xz" | grep -v "Yad\|7.x" >> "$PROTDLLIST"
				fi
			done <<< "$(grep "^CP_" "$STLURLCFG" | cut -d '=' -f1)"
		fi
	fi

	delEmptyFile "$PROTDLLIST"

	if [ ! -f "$PROTDLLIST" ]; then
		writelog "ERROR" "${FUNCNAME[0]} - Could not generating list of online available custom Proton builds - Probably $GHURL changed something"
	else
		unset ProtonDLList
		unset ProtonDLDispList

		while read -r CPVERS; do
			mapfile -t -O "${#ProtonDLList[@]}" ProtonDLList <<< "$CPVERS"
			mapfile -t -O "${#ProtonDLDispList[@]}" ProtonDLDispList <<< "${CPVERS##*/}"
		done < "$PROTDLLIST"
	fi
}

function dlCustomProtonGUI {
	createDLProtList

	writelog "INFO" "${FUNCNAME[0]} - Opening dialog to choose a download"

	DLPROTLIST="$(printf "!%s\n" "${ProtonDLDispList[@]//\"/}" | tr -d '\n' | sed "s:^!::" | sed "s:!$::")"
	export CURWIKI="$PPW/Download-Custom-Proton"
	TITLE="${PROGNAME}-DownloadCustomProton"
	pollWinRes "$TITLE"

	if [ -z "$DLPROTON" ]; then
		DLPROTON="${ProtonDLDispList[0]}"
	fi

	DLDISPCUSTPROT="$("$YAD" --f1-action="$F1ACTION" --window-icon="$STLICON" --form --center --on-top $WINDECO \
	--title="$TITLE" \
	--text="$(spanFont "$GUI_DLCUSTPROTTEXT" "H")" \
	--field=" ":LBL " " --separator="" \
	--field="$GUI_DLCUSTPROTTEXT2!$GUI_DLCUSTPROTTEXT":CBE "$(cleanDropDown "${DLPROTON/#-/ -}" "$DLPROTLIST")" \
	"$GEOM"
	)"
	
	if [ -n "${DLDISPCUSTPROT}" ]; then
		if grep -q "^http" <<< "${DLDISPCUSTPROT}"; then
			writelog "INFO" "${FUNCNAME[0]} - The URL '$DLDISPCUSTPROT' was entered manually - downloading directly"
			StatusWindow "$GUI_DLCUSTPROT" "dlCustomProton ${DLDISPCUSTPROT}" "DownloadCustomProtonStatus"
		else
			DLURL="$(printf "%s\n" "${ProtonDLList[@]}" | grep -m1 "${DLDISPCUSTPROT}")"
			writelog "INFO" "${FUNCNAME[0]} - '${DLDISPCUSTPROT}' was selected - downloading '$DLURL'"
			StatusWindow "$GUI_DLCUSTPROT" "dlCustomProton ${DLURL}" "DownloadCustomProtonStatus"
		fi

		createProtonList
	fi
}

function openSteamGridDir {
	writelog "INFO" "${FUNCNAME[0]} - Opening Steam Grid directory"
	"$XDGO" "$STUIDPATH/config/grid"
}

# Set artwork for Steam game by copying/linking/moving passed artwork to steam grid folder
function setGameArt {
	function applyGameArt {
		GAMEARTAPPID="$1"
		GAMEARTSOURCE="$2"  # e.g. /home/gaben/GamesArt/cs2_hero.png
		GAMEARTSUFFIX="$3"  # e.g. "_hero" etc
		GAMEARTCMD="$4"

		SGGRIDDIR="$STUIDPATH/config/grid"
		GAMEARTBASE="$( basename "$GAMEARTSOURCE" )"
		GAMEARTDEST="${SGGRIDDIR}/${GAMEARTAPPID}${GAMEARTSUFFIX}.${GAMEARTBASE#*.}"  # path to filename in grid e.g. turns "/home/gaben/GamesArt/cs2_hero.png" into "~/.local/share/Steam/userdata/1234567/config/grid/4440654_hero.png"

		if [ -n "$GAMEARTSOURCE" ]; then
			if [ -f "$GAMEARTDEST" ]; then
				writelog "WARN" "${FUNCNAME[0]} - Existing art already exists at '$GAMEARTDEST' - Removing file..."
				rm "$GAMEARTDEST"
			fi

			if [ -f "$GAMEARTSOURCE" ]; then
				$GAMEARTCMD "$GAMEARTSOURCE" "$GAMEARTDEST"
				writelog "INFO" "${FUNCNAME[0]} - Successfully set game art for '$GAMEARTSOURCE' at '$GAMEARTDEST'"
			else
				writelog "WARN" "${FUNCNAME[0]} - Given game art '$GAMEARTSOURCE' does not exist, skipping..."
			fi
		fi
	}

	GAME_APPID="$1"  # We don't validate AppID as it would drastically slow down the process for large libraries

	SETARTCMD="cp"  # Default command will copy art
	for i in "$@"; do
		case $i in
			-hr=*|--hero=*)
				SGHERO="${i#*=}"  # <appid>_hero.png -- Banner used on game screen, logo goes on top of this 
				shift ;;
			-lg=*|--logo=*)
				SGLOGO="${i#*=}"  # <appid>_logo.png -- Logo used e.g. on game screen
				shift ;;
			-ba=*|--boxart=*)
				SGBOXART="${i#*=}"  # <appid>p.png -- Used in library
				shift ;;
			-tf=*|--tenfoot=*)
				SGTENFOOT="${i#*=}"  # <appid>.png -- Used as small boxart for e.g. most recently played banner
				shift ;;
			--copy)
				SETARTCMD="cp"  # Copy file to grid folder -- Default
				shift ;;
			--link)
				SETARTCMD="ln -s"  # Symlink file to grid folder
				shift ;;
			--move)
				SETARTCMD="mv"  # Move file to grid folder
				shift ;;
		esac
	done

	applyGameArt "$GAME_APPID" "$SGHERO" "_hero" "$SETARTCMD"
	applyGameArt "$GAME_APPID" "$SGLOGO" "_logo" "$SETARTCMD"
	applyGameArt "$GAME_APPID" "$SGBOXART" "p" "$SETARTCMD"
	applyGameArt "$GAME_APPID" "$SGTENFOOT" "" "$SETARTCMD"

	writelog "INFO" "${FUNCNAME[0]} - Finished setting game art for '$GAME_APPID'. Restart Steam for the changes to take effect."
	echo "Finished setting game art for '$GAME_APPID'. Restart Steam for the changes to take effect."
}

# Shows the Yad GUI for selecting artwork to pass to setGameArt
function setGameArtGui {
	writelog "INFO" "${FUNCNAME[0]} - Starting the GUI for setting game artwork"

	if [ -z "$SUSDA" ] || [ -z "$STUIDPATH" ]; then
		setSteamPaths
	fi

	export CURWIKI="$PPW/Custom-Game-Artwork"
	TITLE="${PROGNAME}-$SGA"
	pollWinRes "$TITLE"

	SGAGAMENAME="Unknown Game"
	if [ -n "$1" ]; then
		SGAGAMENAME="$( getTitleFromID "$1" )"
		if [ -z "$AID" ] || [ "$AID" -eq "$PLACEHOLDERAID" ]; then
			AID="$1"
		fi
	fi

	setShowPic

	SGASETACTIONS="copy!link!move"
	SGASET="$("$YAD" --f1-action="$F1ACTION" --window-icon="$STLICON" --form --center --on-top "$WINDECO" \
	--title="$TITLE" --separator="|" --image="$SHOWPIC" \
	--text="$(spanFont "$( strFix "$GUI_SGATITLE" "$SGAGAMENAME" "$1" )" "H")\n$GUI_SGATEXT" \
	--field=" ":LBL " " \
	--field="$GUI_SGAHERO!$DESC_SGAHERO ('SGAHERO')":FL "${SGAHERO/#-/ -}" \
	--field="$GUI_SGALOGO!$DESC_SGALOGO ('SGALOGO')":FL "${SGALOGO/#-/ -}" \
	--field="$GUI_SGABOXART!$DESC_SGABOXART ('SGABOXART')":FL "${SGABOXART/#-/ -}" \
	--field="$GUI_SGATENFOOT!$DESC_SGATENFOOT ('SGATENFOOT')":FL "${SGATENFOOT/#-/ -}" \
	--field="$GUI_SGASETACTION!$DESC_SGASETACTION ('SGASETACTION')":CB "$( cleanDropDown "copy" "$SGASETACTIONS" )" \
	--button="$BUT_CAN":0 --button="$BUT_DONE":2 "$GEOM" )"

	case $? in
		0)  writelog "INFO" "${FUNCNAME[0]} - Selected '$BUT_CAN'" ;;
		2)  writelog "INFO" "${FUNCNAME[0]} - Selected '$BUT_DONE'"
			mapfile -d "|" -t -O "${#SGASETARR[@]}" SGASETARR < <(printf '%s' "$SGASET")
			SGAHERO="${SGASETARR[1]}"
			SGALOGO="${SGASETARR[2]}"
			SGABOXART="${SGASETARR[3]}"
			SGATENFOOT="${SGASETARR[4]}"
			SGACOPYMETHOD="${SGASETARR[5]}"

			if [ "$SGACOPYMETHOD" = "link" ]; then
				setGameArt "$1" --hero="$SGAHERO" --logo="$SGALOGO" --boxart="$SGABOXART" --tenfoot="$SGATENFOOT" --link
			elif [ "$SGACOPYMETHOD" = "move" ]; then
				setGameArt "$1" --hero="$SGAHERO" --logo="$SGALOGO" --boxart="$SGABOXART" --tenfoot="$SGATENFOOT" --move
			else  # Default to copy
				setGameArt "$1" --hero="$SGAHERO" --logo="$SGALOGO" --boxart="$SGABOXART" --tenfoot="$SGATENFOOT" --copy
			fi
	esac
}

function CustomFallbackPicture {
	if [ "$USECUSTOMFALLBACKPIC" -eq 1 ]; then
		writelog "INFO" "${FUNCNAME[0]} - Using custom fallback picture if possible and required"

		if [ ! -f "$CUSTOMFALLBACKPIC" ]; then
			if [ -n "$GITHUBUSER" ] && [ "$GITHUBUSER" != "$NON" ]; then
				dlCheck "$GHURL/${GITHUBUSER}.png" "$CUSTOMFALLBACKPIC" "X" "Downloading github avatar for user '$GITHUBUSER' to use as custom fallback picture"
			fi
		fi

		if [ -f "$CUSTOMFALLBACKPIC" ]; then
			SHOWPIC="$CUSTOMFALLBACKPIC"
			writelog "INFO" "${FUNCNAME[0]} - Using '$SHOWPIC' as custom fallback picture"
		else
			writelog "INFO" "${FUNCNAME[0]} - No custom fallback picture found - using internal picture instead"
		fi
	fi	
}

# This could use a bit of a rewrite
function setShowPic {
	GRIDBANNER="$( find "$STUIDPATH/config/grid" -iname "${AID}_hero.*" -type f -exec realpath {} \; | head -n1  )"

	if [ "$STLPLAY" -eq 1 ] && [ -f "$STLGPNG/${AID}.png" ]; then
		SHOWPIC="$STLGPNG/${AID}.png"
	elif [ -n "$GRIDBANNER" ]; then
		# Find custom image in grid folder and store resized image at '$STLGHEADD/<org_image_name_with_extension>'
		writelog "INFO" "${FUNCNAME[0]} - Using hero image found in Steam Grid folder - '$GRIDBANNER'"
		CUSTPIC="$GRIDBANNER"
		"$CONVERT" "$CUSTPIC" -resize "460x215!" "$STLGHEADD/${AID}.png"
		SHOWPIC="$STLGHEADD/${AID}.png"
	elif [ "$USEGAMEPICS" -eq 1 ]; then
		writelog "INFO" "${FUNCNAME[0]} - Determining game picture"
		if [ -s "$STLGHEADD/$AID.jpg" ]; then
			SHOWPIC="$STLGHEADD/$AID.jpg"
			writelog "INFO" "${FUNCNAME[0]} - Using '$SHOWPIC' as game picture"
		else
			SHOWPIC="$STLICON"
			CustomFallbackPicture

			if [ ! -f "$STLGHEADD/$AID.jpg" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Using '$SHOWPIC' as fallback picture, because '$STLGHEADD/$AID.jpg' doesn't exist"
			elif [ -f "$STLGHEADD/$AID.jpg" ] && [ ! -s "$STLGHEADD/$AID.jpg" ]; then
				# Attempt to redownload header picture if we failed last time (e.g., if we were offline)
				writelog "INFO" "${FUNCNAME[0]} - Game header picture exists at '$STLGHEADD/$AID.jpg' but has zero bytes. Attempting one redownload"
				getGameData "$AID"

				if [ -s "$STLGHEADD/$AID.jpg" ]; then
					writelog "INFO" "${FUNCNAME[0]} - Successfully redownloaded header picture for '$AID' to '$STLGHEADD/$AID.jpg', using that."
					SHOWPIC="$STLGHEADD/$AID.jpg"  # Actually use the new picture
				else
					writelog "INFO" "${FUNCNAME[0]} - Could not redownload header picture, defaulting '$SHOWPIC' to STL icon '$STLICON' (Maybe we're offline?)"
				fi
			elif [ ! -s "$STLGHEADD/$AID.jpg" ]; then
				if [ -z "$SUSDA" ] || [ -z "$STUIDPATH" ]; then
					setSteamPaths
				fi
				CUSTPIC="$STUIDPATH/config/grid/${AID}_hero.png"
				if [ -f "$CUSTPIC" ]; then
					writelog "INFO" "${FUNCNAME[0]} - Found custom game picture under '$CUSTPIC'"
					if [ -x "$(command -v "$CONVERT" 2>/dev/null)" ]; then
						writelog "INFO" "${FUNCNAME[0]} - Replacing the empty '$STLGHEADD/$AID.jpg' file with a scaled down version and using that"
						"$CONVERT" "$CUSTPIC" -resize "460x215!" "$STLGHEADD/$AID.jpg"
						SHOWPIC="$STLGHEADD/$AID.jpg"
					else
						writelog "SKIP" "${FUNCNAME[0]} - Command '$CONVERT' not found, so scaling the custom game picture is not possible - skipping"
					fi
				else
					writelog "INFO" "${FUNCNAME[0]} - Using '$SHOWPIC' as fallback picture, because '$STLGHEADD/$AID.jpg' has zero bytes"
					writelog "INFO" "${FUNCNAME[0]} - Leaving '$STLGHEADD/$AID.jpg' as is to avoid another download attempt"
					writelog "INFO" "${FUNCNAME[0]} - Feel free to replace it with a custom picture"
				fi
			fi
		fi
	else
		SHOWPIC="$NOICON"
		writelog "INFO" "${FUNCNAME[0]} - Using '$SHOWPIC' as invisible picture"
	fi	
}

function addCustomProtonToList {
	if [ -f "$1" ]; then
		writelog "INFO" "${FUNCNAME[0]} - Received directly the file as argument"
		if [ -n "$2" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Received '$2' as Proton Version"
			OUTNEWCUSTPROT="$2;$1"
		else
			OUTNEWCUSTPROT="$1"
		fi
	else
		NEWCUSTPROT="$1"

		if grep -q "||" <<< "$NEWCUSTPROT"; then
			if grep -q "|http" <<< "$NEWCUSTPROT"; then
				CPURLWIP="$(tr '|' '"' <<< "$NEWCUSTPROT" | sed "s:\"http:\";\"http:g")"
				CPURL="$(cut -d ';' -f2 <<< "$CPURLWIP")"
				StatusWindow "$GUI_DLCUSTPROT" "dlCustomProton ${CPURL}" "DownloadCustomProtonStatus"
			else
				CPWIP="$(tr -s '|' <<< "$NEWCUSTPROT" | tr '|' '"')"
				if [ -f "${CPWIP//\"/}" ]; then
					OUTNEWCUSTPROT="$CPWIP"
				fi
			fi
		else
			if grep -q "|http" <<< "$NEWCUSTPROT"; then
				CPURLWIP="$(tr '|' '"' <<< "$NEWCUSTPROT" | sed "s:\"http:\";\"http:g")"
				CPURL="$(cut -d ';' -f2 <<< "$CPURLWIP")"
				StatusWindow "$GUI_DLCUSTPROT" "dlCustomProton ${CPURL}" "DownloadCustomProtonStatus"
			else
				CPWIP="$(tr '|' '"' <<< "$NEWCUSTPROT" | sed "s:\"/:\";\"/:g")"
				CPWIPF="$(cut -d ';' -f2 <<< "$CPWIP")"
				if [ -f "${CPWIPF//\"/}" ]; then
					OUTNEWCUSTPROT="$CPWIP"
				fi
			fi
		fi
	fi

	if [ -n "$OUTNEWCUSTPROT" ] ; then
		writelog "INFO" "${FUNCNAME[0]} - Adding '$OUTNEWCUSTPROT' to '$CUSTOMPROTONLIST'"
		echo "$OUTNEWCUSTPROT" >> "$CUSTOMPROTONLIST"
		writelog "INFO" "${FUNCNAME[0]} - (Re-)creating the internal List of available Proton-Versions"
		getAvailableProtonVersions "up" X
	fi
}

function dlLatestGE {
	createDLProtList
	
	if [ -n "${ProtonDLList[0]}" ]; then
		if [ "$1" == "latestge" ] || [ "$1" == "lge" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Downloading latest Proton GE"
		else
			writelog "INFO" "${FUNCNAME[0]} - Downloading latest custom Proton ${ProtonDLDispList[0]//\"/}"
		fi
		StatusWindow "$GUI_DLCUSTPROT" "dlCustomProton ${ProtonDLList[0]//\"/} $2" "DownloadCustomProtonStatus"
	else
		writelog "ERROR" "${FUNCNAME[0]} - Could not create list of downloadable Proton-Versions"
	fi
}

function dlCustomProtonGate {
	if [ -z "$1" ]; then
		dlCustomProtonGUI
	else
		if grep -q "^http" <<< "$1"; then
			writelog "INFO" "${FUNCNAME[0]} - '$1' is an URL - sending directly to dlCustomProton"
			StatusWindow "$GUI_DLCUSTPROT" "dlCustomProton $1" "DownloadCustomProtonStatus"
		else
			if [ "$1" == "latest" ] || [ "$1" == "l" ] || [ "$1" == "latestge" ] || [ "$1" == "lge" ]; then
				dlLatestGE "$1"
			elif [ "$1" == "latesttkg" ] || [ "$1" == "ltkg" ]; then
				createDLProtList
				writelog "INFO" "${FUNCNAME[0]} - Downloading latest Proton TKG"
				StatusWindow "$GUI_DLCUSTPROT" "dlCustomProton $(printf "%s\n" "${ProtonDLList[@]}" | grep -im1 "tkg")" "DownloadCustomProtonStatus"
			else
				writelog "SKIP" "${FUNCNAME[0]} - Don't know what to do with argument '$1'"
			fi
		fi
	fi
}

function addCustomProton {
	if [ -z "$1" ]; then
		if [ ! -f "$CUSTOMPROTONLIST" ]; then 
			{
			echo "# List of custom proton paths, which are not stored in the usual default locations (see README)"
			echo "# (optionally with identifying name (f.e. proton version) as field one)"
			echo "# Files can be added by using the '$PROGCMD' command line or the GUI (or manually of course)"
			echo "# Two valid examples:"
			echo "# \"Proton-47.11-FWX-3\";\"/random/path/to/a/custom/binary/proton\""
			echo "# \"/random/path/to/a/custom/binary/proton\""
			echo "# (In the first example \"Proton-47.11-FWX-3\" will be used as identifying proton version"
			echo "# in the second example the identifying proton version will be searched in '$CTVDF'"
			echo "# and 'version' files in the besides the given proton binary."
			echo "# When no proton version could be found, the selected file will be marked as invalid and removed at once)"
			echo "################################################"
			} > "$CUSTOMPROTONLIST"
		fi
		export CURWIKI="$PPW/Custom-Proton-Autoupdate"
		TITLE="${PROGNAME}-AddCustomProton"
		pollWinRes "$TITLE"

		NEWCUSTPROT="$("$YAD" --f1-action="$F1ACTION" --window-icon="$STLICON" --form --center --on-top $WINDECO \
		--title="$TITLE" \
		--text="$(spanFont "$GUI_ADDCUSTOMBINARY" "H")" \
		--field=" ":LBL " " \
		--field="$GUI_PROTONVERSIONNAME!$DESC_PROTONVERSIONNAME" "Proton-" \
		--field="$GUI_CUSTOMPROTONBINARY":FL "proton" --file-filter="$GUI_PROTONFILES (proton)| proton" \
		"$GEOM"
		)"

		addCustomProtonToList "$NEWCUSTPROT"
	else
		if grep -q "proton$" <<< "$1"; then
			if [ -f "$1" ]; then
				writelog "INFO" "${FUNCNAME[0]} - '$1' is a path to an existing 'proton' file - adding to the Custom Proton List"
				addCustomProtonToList "$@"
			else
			writelog "SKIP" "${FUNCNAME[0]} - File '$1' does not exist - skipping"
			fi
		fi
	fi
}

function saveMenuEntries {
	SAVMENUCAT="$1"
	writelog "INFO" "${FUNCNAME[0]} - Saving changed Settings"
	writelog "INFO" "${FUNCNAME[0]} - Clearing Results array with '${#Results[@]}' elements"
	writelog "INFO" "${FUNCNAME[0]} - Pulling values from tempfile '$MKCFG'"
	unset Results
	mapfile -t -O "${#Results[@]}" Results < "$MKCFG"

	for i in "${!Results[@]}"; do
		ONUM="$((i +1))"
		VAL="${Results[$i]}"

		RAWENT="$(sed "${ONUM}q;d" "${SAVMENUCAT}-${TMPL}")"
		VAR="$(grep -oP "\('\K[^\')]+" <<< "$RAWENT")"

		if [ -n "$VAL" ]; then
			if grep -q "MENU_GAME" <<< "$RAWENT"; then
				if [ "$SAVMENUCAT" == "$GAMETEMPMENU" ]; then
					SAVECFG="$STLDEFGAMECFG"
				else
					SAVECFG="$STLGAMECFG"
				fi
			elif grep -q "MENU_URL" <<< "$RAWENT"; then
				SAVECFG="$STLURLCFG"
			elif grep -q "MENU_GLOBAL" <<< "$RAWENT"; then
				SAVECFG="$STLDEFGLOBALCFG"
			else
				writelog "SKIP" "${FUNCNAME[0]} - No valid configfile determined for VAR='$VAR' WRITEVAL='$WRITEVAL' - this is an error!"
			fi
			VALUNQ="${VAL//\'/}"
			WRITEVAL="${VALUNQ/# -/-}"
			
			if [ -n "$VAR" ] && [ -z "$WRITEVAL" ] && [ -n "$SAVECFG" ]; then
				WRITEVAL="$NON"
				writelog "INFO" "${FUNCNAME[0]} - Value for '$VAR' is empty - automatically setting '$NON'"
			fi
			
			if [ -n "$VAR" ] && [ -n "$WRITEVAL" ] && [ -n "$SAVECFG" ]; then
				updateConfigEntry "$VAR" "$WRITEVAL" "$SAVECFG"
			fi
		fi
	done
	writelog "INFO" "${FUNCNAME[0]} - Done with Saving changed Settings"
}

function saveNewRes {
	if [ "$SAVESETSIZE" -eq 1 ] && [ -n "$3" ]; then
		SNEWW="$1"
		SNEWH="$2"
		CFG="$3"
		touch "$CFG"
		updateConfigEntry "WINX" "$SNEWW" "$CFG"
		updateConfigEntry "WINY" "$SNEWH" "$CFG"
		writelog "INFO" "${FUNCNAME[0]} - Saved new resolution '${SNEWW}x${SNEWH}' in '$CFG'" "$WINRESLOG"
	fi
}

function updateThisWinTemplate {
	if [ -f "$UPWINTMPL" ] && [ -f "$2" ]; then
		cp "$2" "$STLGUIDIR/$SCREENRES/${TEMPL}/${1}.conf"
		rm "$UPWINTMPL"
		writelog "INFO" "${FUNCNAME[0]} - Updated Window Template '$STLGUIDIR/$SCREENRES/${TEMPL}/${1}.conf' with '$2'" "$WINRESLOG"
		notiShow "$(strFix "$NOTY_TEMPLUP" "$1")"
	fi
}

function updateWinRes {
	if [ -z "$SAVESETSIZE" ] || [ "$ONSTEAMDECK" -eq 1 ]; then
		SAVESETSIZE=0
	fi
	
	if [ "$SAVESETSIZE" -eq 1 ]; then
		WNAM="$1"
		CFG="$2"
		TEMPLGUICFG="$3"

		writelog "INFO" "${FUNCNAME[0]} - Starting resolution-poll for '$GAMEGUICFG' with incoming '${WINX}x${WINY}'" "$WINRESLOG"

		ORGW="${WINX}"
		ORGH="${WINY}"	
		NEWW="${WINX}"
		NEWH="${WINY}"

		MAXWAIT=3
		COUNTER=0

		while ! "$XWININFO" -name "$WNAM" -stats >/dev/null 2>/dev/null; do
			if [ -f "$CLOSETMP" ]; then
				writelog "WAIT" "${FUNCNAME[0]} - ${PROGNAME,,} is just closing - leaving loop" "$WINRESLOG"
				break
			fi
			if [[ "$COUNTER" -ge "$MAXWAIT" ]]; then
				writelog "SKIP" "${FUNCNAME[0]} - Timeout waiting for Window '$WNAM'" "$WINRESLOG"
				return 
			fi

			writelog "INFO" "${FUNCNAME[0]} - Waiting for Window '$WNAM'" "$WINRESLOG"
			COUNTER=$((COUNTER+1))
			sleep 1
		done

		writelog "INFO" "${FUNCNAME[0]} - Window '$WNAM' is running - polling the resolution" "$WINRESLOG"

		while true; do
			SRES="$("$XWININFO" -name "$WNAM" -stats 2>/dev/null | awk '$1=="-geometry" {print $2}' | cut -d '+' -f1)"
			if grep -q "x" <<< "$SRES"; then
				PREVW="$NEWW"
				PREVH="$NEWH"
			
				TNEWW1="${SRES%x*}"
				TNEWW="${TNEWW1%%-*}"

				TNEWH1="${SRES#*x}"
				TNEWH="${TNEWH1%%-*}"

				if [ "$TNEWW" -ne "$ORGW" ] || [ "$TNEWH" -ne "$ORGH" ]; then
					if [ "$TNEWW" != "$PREVW" ] || [ "$TNEWH" != "$PREVH" ]; then
						if [ -n "${TNEWW##*[!0-9]*}" ] && [ -n "${TNEWH##*[!0-9]*}" ]; then
							NEWW="$TNEWW"
							NEWH="$TNEWH"
							writelog "INFO" "${FUNCNAME[0]} - Found new Window Resolution '${NEWW}x${NEWH}' for Window '$WNAM'" "$WINRESLOG"
						else
							writelog "SKIP" "${FUNCNAME[0]} - Skipping found false-positive size '${NEWW}x${NEWH}'"	"$WINRESLOG"
						fi
					fi
				fi
				sleep 1
			else
				if [ "$NEWW" -ne "$ORGW" ] || [ "$NEWH" -ne "$ORGH" ]; then
					writelog "INFO" "${FUNCNAME[0]} - The Window '$WNAM' was closed - saving the last seen resolution '${NEWW}x${NEWH}' into config '$CFG'" "$WINRESLOG"
					saveNewRes "$NEWW" "$NEWH" "$CFG"
					if [ ! -f "$TEMPLGUICFG" ]; then
						writelog "INFO" "${FUNCNAME[0]} - Creating template '$TEMPLGUICFG' with the same resolution '${NEWW}x${NEWH}'" "$WINRESLOG"
						cp "$CFG" "$TEMPLGUICFG"
					fi
				else
					writelog "INFO" "${FUNCNAME[0]} - The Window '$WNAM' was closed - the resolution didn't change - nothing to do" "$WINRESLOG"
				fi

				updateThisWinTemplate "$TITLE" "$CFG"
				
				return
			fi
		done
	fi	
}

function updateEditor {
	CFG="$1"

	loadCfg "$CFG" X
	if grep -q "$XDGO" <<< "$STLEDITOR" || [ ! -f "$STLEDITOR" ] ; then
		writelog "WARN" "${FUNCNAME[0]} - '$XDGO' selected as editor or configured editor not found - trying to find an installed editor installed"
		if [ -x "$(command -v "$XDGMIME" 2>/dev/null)" ]; then
			XDGED="$(command -v "$("$XDGMIME" query default text/plain | cut -d '.' -f1)" 2>/dev/null)"
			if [ -x "$XDGED" ]; then
				writelog "INFO" "${FUNCNAME[0]} - $XDGMIME points to '$XDGED', which also exists"
				FOUNDEDITOR="$XDGED"
			fi
		fi

		if [ -z "$FOUNDEDITOR" ]; then
			if [ -x "$(command -v "geany")" ]; then
				FOUNDEDITOR="$(command -v "geany")"
			elif [ -x "$(command -v "gedit")" ]; then
				FOUNDEDITOR="$(command -v "gedit")"
			elif [ -x "$(command -v "leafpad")" ]; then
				FOUNDEDITOR="$(command -v "leafpad")"
			elif [ -x "$(command -v "kwrite")" ]; then
				FOUNDEDITOR="$(command -v "kwrite")"
			fi
		fi

		if [ -n "$FOUNDEDITOR" ]; then
			writelog "INFO" "${FUNCNAME[0]} - changing STLEDITOR to '$FOUNDEDITOR' in '$CFG'"
			updateConfigEntry "STLEDITOR" "$FOUNDEDITOR" "$CFG"
			loadCfg "$CFG"
		else
			writelog "INFO" "${FUNCNAME[0]} - No valid editor found - will fall back to '$XDGO'."
		fi
	fi
}

function setGPfxFromAppMa {
	if [ -n "$2" ] && [ -f "$2" ]; then
		echo "${2%/*}/$CODA/$1/pfx"
	else
		if [ -z "$GPFX" ]; then
			APPMAFE="$(listAppManifests | grep -m1 "${1}.acf")"
			if [ -n "$APPMAFE" ]; then
				if [ ! -d "$APPMAFE" ]; then
					writelog "ERROR" "${FUNCNAME[0]} - '$APPMAFE' is no valid directory - probably function 'listAppManifests' requires a fix here!"
				else
					AMF="${APPMAFE##*/}"
					GPFX="${APPMAFE%/*}/$CODA/$1/pfx"
					writelog "INFO" "${FUNCNAME[0]} - Found WINEPREFIX '$GPFX' in '$AMF'"
				fi
			fi
		fi
	fi
	if [ -z "$GPFX" ] && [ -n "$AMF" ] && [ -z "$2" ]; then
		writelog "SKIP" "${FUNCNAME[0]} - Could not retrieve WINEPREFIX from '$AMF'"
	fi
}

function getGameTextFiles {
	setGPfxFromAppMa "$AID"
	unset GameTxtFiles

	if [ -d "$GPFX/$DRCU/$STUS" ]; then
		# an option to parse user-contributed per game config lists with the actual config files instead of searching for any textfile would be easy
		EXID="$HIDEDIR/hide-${AID}.txt"
		touch "$EXID"
		SKIPGTF=0
		
		if [ -n "$1" ]; then	
			writelog "INFO" "${FUNCNAME[0]} - Searching for at least one editable textfile in '$GPFX/$DRCU/$STUS'"
			find "$GPFX/$DRCU/$STUS" -type f -exec grep -Iq . {} \; -print -quit >/dev/null
		else
			while read -r gtxtfile; do
				while read -r skip; do
					if grep -q "$skip" <<< "$gtxtfile"; then
						SKIPGTF=1
					fi
				done < "$EXID"
						
				if [ "$SKIPGTF" -eq 0 ]; then
					GameTxtFiles+=("$gtxtfile")
				else
					SKIPGTF=0
				fi
			done <<< "$(find "$GPFX/$DRCU/$STUS" -type f -exec grep -Iq . {} \; -print)"	
		fi
	fi
}

function getAvailableCfgs {
	unset CfgFiles
	while read -r cfgfile; do
		if [ -f "${!cfgfile}" ]; then
			CfgFiles+=("${!cfgfile}")
		fi
	done <<< "$(sed -n "/^#STARTEDITORCFGLIST/,/^#ENDEDITORCFGLIST/p;/^#ENDEDITORCFGLIST/q" "$0" | grep -v "^#" | grep -v "LOGFILE" | grep "=" | cut -d '=' -f1)"	

	getGameTextFiles "X"
}

function confirmReq {
	QUESTION="$2"
	TITLE="${PROGNAME}-$1"
	pollWinRes "$TITLE"
	setShowPic
	
	"$YAD" --image "$SHOWPIC" --image-on-top --window-icon="$STLICON" --center --on-top "$WINDECO" --title="$TITLE" --text="$(spanFont "$QUESTION" "H")" "$GEOM"
	echo "$?"
}

function EditorDialog {
	writelog "INFO" "${FUNCNAME[0]} - Opening Editor Dialog"

	resetAID "$1"
	loadCfg "$STLGAMECFG" X
	getAvailableCfgs
	
	if [ "$BACKUPSTEAMUSER" -eq 1 ]; then
		EXID="$BACKEX/exclude-${AID}.txt"
		if [ -f "$EXID" ]; then
			CfgFiles+=("$EXID")
		fi
	fi

	HIDEID="$HIDEDIR/hide-${AID}.txt"
	if [ -f "$HIDEID" ]; then
		CfgFiles+=("$HIDEID")
	fi

	if [ -f "$MAHUTMPL" ]; then
		CfgFiles+=("$MAHUTMPL")
	fi

	MHIC="$MAHUCID/${AID}.conf"
	if [ -f "$MHIC" ]; then
		CfgFiles+=("$MHIC")
	fi
	
	getGameTextFiles
	CfgFiles+=("${GameTxtFiles[@]}")

	if [ -f "$LOGFILE" ]; then
		CfgFiles+=("$LOGFILE")
	fi

	REVALSC="$EVMETAID/${EVALSC}_${AID}.vdf"
	CEVALSC="$EVMETACUSTOMID/${EVALSC}_${AID}.vdf"
	AEVALSC="$EVMETAADDONID/${EVALSC}_${AID}.vdf"
	
	if [ -f "$REVALSC" ]; then
		CfgFiles+=("$REVALSC")
	fi

	if [ -f "$CEVALSC" ]; then
		CfgFiles+=("$CEVALSC")
	fi
	
	if [ "$UUUSEIGCS" -eq 1 ] || [ "$USEIGCS" -eq 1 ]; then
		IGCSINI="$EFD/${IGCS}.ini"
		if	 [ -f "$IGCSINI" ]; then
			CfgFiles+=("$IGCSINI")
		fi
	fi
	
	if [ "$UUUSEPATCH" -eq 1 ] || [ "$UUUSEVR" -eq 1 ]; then
		UUUPATCHFILE="$(find "$MEGAMEDIR" -name "$UUUPATCH")"
		if	[ -f "$UUUPATCHFILE" ]; then
			CfgFiles+=("$UUUPATCHFILE")
		fi
	fi

	if [ "$USERESHADE" -eq 1 ] || [ "$USESPECIALK" -eq 1 ]; then
		setFullGameExePath "FGEP"
		while read -r inifile; do
			if [ -f "$inifile" ]; then
				CfgFiles+=("$inifile")
			fi
		done <<< "$(find "$FGEP" -mindepth 1 -maxdepth 1 -type f -name "*.ini")"
	fi

	if [ "$USEOPENVRFSR" -eq 1 ]; then
		OVRFP="$EFD/${OVFS}-${SHOSTL}-enabled.txt"
		if [ -f "$OVRFP" ]; then
			OVRMODF="$EFD/$(grep "$OVRMOD" "$OVRFP")"
			if [ -f "$OVRMODF" ]; then
				CfgFiles+=("$OVRMODF")
			fi
		fi
	fi
	
	if [ -f "$AEVALSC" ]; then
		CfgFiles+=("$AEVALSC")
	fi
	
	if [ -f "$STLPROTONIDLOGDIR/steam-${AID}.log" ]; then
		CfgFiles+=("$STLPROTONIDLOGDIR/steam-${AID}.log")
	fi

	if [ -f "$STLDXVKLOGDIR/${GE}_d3d11.log" ]; then
		CfgFiles+=("$STLDXVKLOGDIR/${GE}_d3d11.log")
	fi

	if [ -f "$STLDXVKLOGDIR/${GE}_dxgi.log" ]; then
		CfgFiles+=("$STLDXVKLOGDIR/${GE}_dxgi.log")
	fi

	writelog "INFO" "${FUNCNAME[0]} - Found ${#CfgFiles[@]} available Config Files - opening Checklist"
	export CURWIKI="$PPW/Editor-Menu"
	TITLE="${PROGNAME}-Editor"
	pollWinRes "$TITLE"

	setShowPic

	EDFILES="$(while read -r f; do	echo "FALSE"; echo "$f"; done <<< "$(printf "%s\n" "${CfgFiles[@]}" | sort -u)" | \
	"$YAD" --f1-action="$F1ACTION" --image "$SHOWPIC" --image-on-top --window-icon="$STLICON" --center $WINDECO --list --checklist --column=Edit --column=ConfigFile --separator="\n" --print-column="2" \
	--text="$(spanFont "$(strFix "$GUI_EDITORDIALOG" "$SGNAID")" "H")" --title="$TITLE" --button="$BUT_EDIT":0 --button="$BUT_HIDE":2 --button="$BUT_OD":4 --button="$BUT_DEL":6 --button="$BUT_CAN":8 "$GEOM")"
	case $? in
		0)  {
				if [ -n "$EDFILES" ]; then
					if [ -n "$HELPURL" ] && [ "$HELPURL" != "$NON" ]; then 
						writelog "INFO" "${FUNCNAME[0]} - Opening the url '$HELPURL' in the browser"
						checkHelpUrl "$HELPURL"
					fi

					if [ -z "$STLEDITOR" ] || [ "$STLEDITOR" -eq "$NON" ]; then
						writelog "INFO" "${FUNCNAME[0]} - No editor found or selected. Falling back to '$XDGO'"
						writelog "WARN" "${FUNCNAME[0]} - If you find games fail to close try setting an editor manually"
						STLEDITOR=$XDGO
					fi
	
					writelog "INFO" "${FUNCNAME[0]} - Opening Editor '$STLEDITOR' with selected Config Files"
					mapfile -t -O "${#EdArr[@]}" EdArr <<< "$EDFILES"
					"$STLEDITOR" "${EdArr[@]}"
					unset EdArr
					# kill browser if it was opened with the editor:
					if [ -n "$KILLBROWSER" ]; then
						if [ "$KILLBROWSER" -eq 1 ]; then
							"$PKILL" -f "$BROWSER"
						fi
					fi
				fi
			}
		;;
		2)  {
		writelog "INFO" "${FUNCNAME[0]} - Selected HIDE 1"
				if [ -n "$EDFILES" ]; then
					HIDELIST="$HIDEDIR/hide-${AID}.txt"
					writelog "INFO" "${FUNCNAME[0]} - Selected HIDE - Hiding all selected files from the EditorList by adding them to the Exclude list '$HIDELIST'"
					echo "$EDFILES"	 >> "$HIDELIST"
					sort -u"$HIDELIST" -o "$HIDELIST"
					sed "/^ *$/d" -i "$HIDELIST"
				fi
			}
		;;
		4)  
			if [ -x "$(command -v "$XDGO" 2>/dev/null)" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Selected Open Directory - Opening the directory containing the first selected file using '$XDGO'"
				mapfile -t -O "${#EdArr[@]}" EdArr <<< "$EDFILES"
				"$XDGO" "$(dirname "${EdArr[0]}")"
				unset EdArr
			else
				writelog "SKIP" "${FUNCNAME[0]} - '$XDGO' not found - can't open the directory"
			fi
		;;
		6)  writelog "INFO" "${FUNCNAME[0]} - Selected Delete"
			RSEL="$(confirmReq "Ask_Delete_Selected_Files" "$GUI_DELSEL")"
			if [ "$RSEL" -eq 0 ]; then
			{
				writelog "INFO" "${FUNCNAME[0]} - Confirmed deletion of all selected files"
				mapfile -t -O "${#EdArr[@]}" EdArr <<< "$EDFILES"
				rm "${EdArr[@]}" 2>/dev/null
				unset EdArr
			}
			else
				writelog "INFO" "${FUNCNAME[0]} - Selected CANCEL - Not deleting the files"
			fi
		;;
		8)  writelog "INFO" "${FUNCNAME[0]} - Selected CANCEL"
		;;
	esac

	goBackToPrevFunction "${FUNCNAME[0]}" "$2"
}

function goBackToPrevFunction {
	IAM="$1"
	PREV="$2"
	
	if [ "$IAM" != "$PREV" ]; then
		if [ -z "$3" ]; then
			MYGOBACK=1
		else
			MYGOBACK="$3"
		fi

		if [ -z "$PREV" ]; then
			writelog "INFO" "${FUNCNAME[0]} - '$IAM' closed"
		else
			if [ "$PREV" != "$NON" ] && [ "$MYGOBACK" -eq 1 ]; then
				writelog "INFO" "${FUNCNAME[0]} - '$IAM' closed - Going back to the '$PREV'"
				"$PREV" "$AID" "$IAM"
			else
				writelog "INFO" "${FUNCNAME[0]} - '$IAM' closed"
			fi
		fi
	else
		writelog "SKIP" "${FUNCNAME[0]} - Took a wrong road somewhere - '$IAM' and '$PREV' - leaving"
	fi
}

function closeTrayIcon {
	notiShow "$(strFix "$NOTY_CLOSETRAY" "$YADTRAYPID")"
	writelog "INFO" "${FUNCNAME[0]} - Closing TrayIcon '$YADTRAYPID'"
	kill "$YADTRAYPID" 2>/dev/null
}

function cleanYadLeftOvers {
	closeTrayIcon
}

function GETALTEXEPATH {
	if [ -n "$ALTEXEPATH" ] && [ "$ALTEXEPATH" != "/tmp" ]; then
		if [ -d "$ALTEXEPATH" ]; then
			echo "$ALTEXEPATH"
		elif [ -d "$EFD/$ALTEXEPATH" ]; then
			echo "$EFD/$ALTEXEPATH"
		fi
	fi
}

#STARTIEX
function TrayIconExports {
	export XWI="$XWININFO"
	export XDO="$XDO"
	export PROGCMD="$PROGCMD"

	export -f writelog
	export AID="$AID"

	export GPFX="$GPFX"
	export KILLSWITCH="$KILLSWITCH"
	export -f killProtonGame
	export -f PauseGame
	export EFD="$EFD"
	export GAMEWINDOW="$GAMEWINDOW"
	export UPWINTMPL="$UPWINTMPL"
	export TRAYCUSC="$TRAYCUSC"

	if [ -n "$(GETALTEXEPATH)" ]; then
		SHADDESTDIR="$(GETALTEXEPATH)"
	fi

	export SHADDESTDIR="$SHADDESTDIR"

	KPFX="$GPFX"
	if [ "$USEWINE" -eq 1 ]; then
		setWineVars
		KPFX="$GWFX"
	fi

	if [ ! -f "$RUNWINE" ]; then
		setRunWineServer "${FUNCNAME[0]}"
	fi

	export RUNWINESERVER="$RUNWINESERVER"

	if [ -n "$KPFX" ]; then
		echo "WINEPREFIX=\"$KPFX\" \"$RUNWINESERVER\" -k" > "$KILLSWITCH"
		if [ "$USEMANGOAPP" -eq 1 ]; then
			echo "$PKILL -f \"$MANGOAPP\"" >> "$KILLSWITCH"
		fi
		echo "touch $CLOSETMP" >> "$KILLSWITCH"
		chmod +x "$KILLSWITCH"
	fi

	export SHADDESTDIR="$SHADDESTDIR"
	export -f TrayShaderMenu
	export -f TrayVR
	export -f TrayPickWin
	export -f TraySRC
	export -f TrayUWT
	export -f TrayLCS
	export -f TrayGameFiles
	export -f TrayMO2
	export -f TrayProtonList
	export -f TrayOpenIssue
}
#ENDIEX

function openTrayIcon {
	setShadDestDir

	if [ -z "$1" ]; then
		# loading gameconfig here, as some vars might have to be exported
		writelog "INFO" "${FUNCNAME[0]} - LoadCfg: $STLGAMECFG"
		loadCfg "$STLGAMECFG"
	fi

	if [ "$ONSTEAMDECK" -eq 1 ] && [ "$FIXGAMESCOPE" -eq 1 ]; then
		writelog "SKIP" "${FUNCNAME[0]} - Skipping TrayIcon on SteamDeck Game Mode" "X"
	else
		if [ -z "$YADTRAYPID" ] && [ "$USETRAYICON" -eq 1 ]; then
			writelog "INFO" "${FUNCNAME[0]} - Opening trayIcon:" "X"

			# variables and functions used by exported functions below

			# functions for the trayIcon Menu
			function killProtonGame {
				"$KILLSWITCH"
			}

			function PauseGame {
				PAUSEPID="$(sleep 5 && "$XDO" getactivewindow getwindowpid)"
				# idea taken with friendly permission from $GHURL/Ilazki:
				GAMESTATE="$(ps -q "$PAUSEPID" -o state --no-headers)"
				GAMESIG="-STOP"

				if [ "$GAMESTATE" = "T" ] ; then
					GAMESIG="-CONT"
				fi

				kill "$GAMESIG" "$PAUSEPID"
			}

			function TrayShaderMenu {
				"$PROGCMD" update gameshaders "$SHADDESTDIR"
			}

			function TrayVR {
				if [ -z "$GAMEWINDOW" ]; then
					GAMEWINDOW="$(sleep 2 && "$XWI" -stats | grep ^"$XWI" | tail -n1 | cut -d '"' -f2)";
				fi

				if [ -n "$GAMEWINDOW" ]; then
					writelog "INFO" "${FUNCNAME[0]} - TrayIcon: picked '$PICKWINDOWNAME'"
					"$PROGCMD" "vr" "$PICKWINDOWNAME" "$AID" "s"
				else
					writelog "SKIP" "${FUNCNAME[0]} - TrayIcon: Didn't find a game window name to open in vr"
				fi
			}
				
			function TrayPickWin {
				writelog "INFO" "${FUNCNAME[0]} - TrayIcon: Executing Window Pick command for game '$GN '$AID'"
				"$PROGCMD" "pw" "$AID" "$GN"
			}	

			function TraySRC {
				writelog "INFO" "${FUNCNAME[0]} - TrayIcon: Executing command '$STEAM ${STEAM}://${RECO}'"
				"$PROGCMD" "src"
			}

			function TrayUWT {
				writelog "INFO" "${FUNCNAME[0]} - TrayIcon: Triggering Window Template Update"
				touch "$UPWINTMPL"
			}

			function TrayLCS {
				writelog "INFO" "${FUNCNAME[0]} - TrayIcon: Triggering Launch custom script"
				"$TRAYCUSC"
			}

			function TrayGameFiles {
				writelog "INFO" "${FUNCNAME[0]} - TrayIcon: Executing Game Files command for game '$GN '$AID'"
				"$PROGCMD" "gf" "$AID"
			}	
			
			function TrayMO2 {
				writelog "INFO" "${FUNCNAME[0]} - TrayIcon: Starting standalone $MO instance"
				"$PROGCMD" "mo2" "start"
			}	

			function TrayProtonList {
				writelog "INFO" "${FUNCNAME[0]} - TrayIcon: Updating list of available Proton versions"
				"$PROGCMD" "proton" "list"
			}

			function TrayOpenIssue {
				writelog "INFO" "${FUNCNAME[0]} - TrayIcon: Open Issue Tracker with User's Default Browser"
				"$PROGCMD" "openissue"
			}

			TrayIconExports
			
			# actually open the actual trayIcon	
			GDK_BACKEND=x11 "$YAD" --image="$STLICON" --notification --item-separator=","\
			--menu="$TRAY_KILLSWITCH,bash -c killProtonGame \
			|$TRAY_PAUSE,bash -c PauseGame \
			|$TRAY_SHADER,bash -c TrayShaderMenu \
			|$TRAY_VR,bash -c TrayVR \
			|$TRAY_PICKWINDOW,bash -c TrayPickWin \
			|$TRAY_SRC,bash -c TraySRC \
			|$TRAY_UWT,bash -c TrayUWT \
			|$TRAY_LCS,bash -c TrayLCS \
			|$GUI_GAFI,bash -c TrayGameFiles \
			|$TRAY_UPL,bash -c TrayProtonList \
			|$FBUT_GUISET_MO,bash -c TrayMO2 \ 
			|$TRAY_OPENISSUE,bash -c TrayOpenIssue" \
			--text="$TRAY_TOOLTIP" >/dev/null 2>/dev/null &
			YADTRAYPID="$!"
		fi
	fi
}

function createProtonList {
	delEmptyFile "$PROTONCSV"
	if [ ! -f "$PROTONCSV" ]; then
		writelog "INFO" "${FUNCNAME[0]} - Looking for available Proton versions"
		getAvailableProtonVersions "up" X
	fi

	if [ "$ISGAME" -eq 2 ] || [ -n "$1" ] ; then
		PROTYADLIST="$(printf "!%s\n" "${ProtonCSV[@]//\"/}" | sort -u | cut -d ';' -f1 | tr -d '\n' | sed "s:^!::" | sed "s:!$::")"
	fi
}

function createDropdownLists {
	createProtonList
	createWineList
	createLanguageList
}

function favoritesMenuEntries {
	if [ -f "$STLFAVMENUCFG" ]; then
		unset FavSel
		mapfile -t -O "${#FavSel[@]}" FavSel < "$STLFAVMENUCFG"
	else
		FAVMENUCFG="$GLOBALMISCDIR/$FACO"

		if [ -f "$FAVMENUCFG" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Using global favorites preset for preselecting some entries"
			mapfile -t -O "${#FavSel[@]}" FavSel < "$FAVMENUCFG"
		else
			writelog "INFO" "${FUNCNAME[0]} - Global favorites preset '$FAVMENUCFG' not found - starting with zero preselection"
			declare -a FavSel
		fi
	fi
	
	while read -r ENTRY; do
		GE="GUI_${ENTRY}"
		DE="DESC_${ENTRY}"
		if [ -z "${!GE}" ]; then
			GEOUT="no description"
		else
			GEOUT="${!GE}"
		fi

		if [ -z "${!DE}" ]; then
			DEOUT="no description"
		else
			DEOUT="${!DE}"
		fi

		if grep -q "^$ENTRY$" <<< "$(printf "%s\n" "${FavSel[@]}")"; then 
			echo TRUE
			echo "$GEOUT"
			echo "$ENTRY"
			echo "$DEOUT"
		else
			echo FALSE
			echo "$GEOUT"
			echo "$ENTRY"
			echo "$DEOUT"
		fi
	done <<< "$(sort "$STLSETENTRIES")"
}

function favoritesMenu {
	if [ -z "$2" ]; then
		BACKFUNC="$NON"
	else
		if [ "$2" == "setGuiFavoritesSelection" ]; then
			BACKFUNC="MainMenu"
		else
			BACKFUNC="$2"
		fi
	fi

	if [ -f "${FAVMENU}-${TMPL}" ]; then
		writelog "INFO" "${FUNCNAME[0]} - Found an autoconfigured favorites menu template '${FAVMENU}-${TMPL}' - using it directly"
		openCustMenu "$1" "$BACKFUNC" "Favorites" "$FAVMENU" "$LFM"
	else
		if [ ! -f "$STLFAVMENUCFG" ]; then
			writelog "INFO" "${FUNCNAME[0]} - No Favorites defined yet - opening Favorites Selection"
			rm "${FAVMENU}-${TMPL}" 2>/dev/null
			setGuiFavoritesSelection "$AID" "${FUNCNAME[0]}"
		fi

		if [ -f "$STLFAVMENUCFG" ]; then
			TEMPF="${FAVMENU}-${TMPL}_w1"
			touch "$TEMPF"
			while read -r savfav; do
				SAVCAT="CAT_$(grep "'$savfav'" "$STLRAWENTRIES" | grep -oP '#CAT_\K[^`]+')"
				FAVHEADL="$(grep "#HEAD" "$STLRAWENTRIES" | grep "$SAVCAT")"
				FAVHEAD="HEAD_$(grep -oP '#HEAD_\K[^`]+' <<< "$FAVHEADL")"
				if ! grep -q "$FAVHEAD" "$TEMPF" && [ "$SAVCAT" != "CAT_" ]; then
					echo "$FAVHEADL" >> "$TEMPF"
				fi

				grep "'$savfav'" "$STLRAWENTRIES" >> "$TEMPF"
			done < "$STLFAVMENUCFG"

			getFilteredEntries "$TEMPF" >> "${FAVMENU}-${TMPL}"

			rm "$TEMPF" 2>/dev/null

			writelog "INFO" "${FUNCNAME[0]} - Found '$(wc -l < "${FAVMENU}-${TMPL}")' selected Favorites - opening the Menu now"
			openCustMenu "$1" "$BACKFUNC" "Favorites" "$FAVMENU" "$LFM"
		else
			writelog "SKIP" "${FUNCNAME[0]} - Still no Favorites defined - skipping"
		fi
	fi
}

function listAllSettingsEntries {
	if [ -f "$STLSETENTRIES" ]; then
		writelog "INFO" "${FUNCNAME[0]} - '$STLSETENTRIES' already exists - nothing to do"
	else
		writelog "INFO" "${FUNCNAME[0]} - Creating '$STLSETENTRIES'"
		while read -r ENTRY; do
			echo "$ENTRY" | tee -a "$STLRAWENTRIES" >/dev/null
			grep -oP "\('\K[^\')]+" <<< "$ENTRY" | tee -a "$STLSETENTRIES" >/dev/null
		done <<< "$(sed -n "/^#STARTSETENTRIES/,/^#ENDSETENTRIES/p;/^#ENDSETENTRIES/q" "$0" | grep "\--field")"
	fi
}

function spanFont {
	STRIN="$1"

	if [ "$2" == "H" ]; then
		FOSI="$HEADLINEFONT"
		FOWE="bold"
	fi

	SPIN="<span font_size='$FOSI' font_weight='$FOWE'>"
	SPOUT="</span>"
	echo "$SPIN$STRIN$SPOUT"
}

function AllSettingsEntriesDummyFunction {
#STARTSETENTRIES
	echo \
--field="$(spanFont "$GUI_OPTSGUI" "H")":LBL "SKIP" `#CAT_Gui` `#HEAD_Gui` `#MENU_GAME` `#MENU_GLOBAL` \
--field="     $GUI_STLLANG!$DESC_STLLANG ('STLLANG')":CB "$(cleanDropDown "${STLLANG/#-/ -}" "$LANGYADLIST")" `#CAT_Gui` `#MENU_GLOBAL` \
--field="     $GUI_STARTMENU!$DESC_STARTMENU ('STARTMENU')":CB "$(cleanDropDown "${STARTMENU/#-/ -}" "Editor!Favorites!Game!Menu")" `#CAT_Gui` `#MENU_GLOBAL` \
--field="     $GUI_WAITEDITOR!$DESC_WAITEDITOR ('WAITEDITOR')":NUM "${WAITEDITOR/#-/ -}" `#CAT_Gui` `#MENU_GAME` \
--field="     $GUI_MAXASK!$DESC_MAXASK ('MAXASK')":NUM "${MAXASK/#-/ -}" `#CAT_Gui` `#MENU_GLOBAL` \
--field="     $GUI_SAVESETSIZE!$DESC_SAVESETSIZE ('SAVESETSIZE')":CHK "${SAVESETSIZE/#-/ -}" `#CAT_Gui` `#SUB_Checkbox` `#MENU_GLOBAL` \
--field="     $GUI_TOGGLEWINDOWS!$DESC_TOGGLEWINDOWS ('TOGGLEWINDOWS')":CHK "${TOGGLEWINDOWS/#-/ -}" `#CAT_Gui` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_USETRAYICON!$DESC_USETRAYICON ('USETRAYICON')":CHK "${USETRAYICON/#-/ -}" `#CAT_Gui` `#SUB_Checkbox` `#MENU_GLOBAL` \
--field="     $GUI_USENOTIFIER!$DESC_USENOTIFIER ('USENOTIFIER')":CHK "${USENOTIFIER/#-/ -}" `#CAT_Gui` `#SUB_Checkbox` `#MENU_GLOBAL` \
--field="     $GUI_HEADLINEFONT!$DESC_HEADLINEFONT ('HEADLINEFONT')":CB "$(cleanDropDown "${HEADLINEFONT/#-/ -}" "$FONTSIZES")" `#CAT_Gui` `#MENU_GLOBAL` \
--field="     $GUI_USEWINDECO!$DESC_USEWINDECO ('USEWINDECO')":CHK "${USEWINDECO/#-/ -}" `#CAT_Gui` `#SUB_Checkbox` `#MENU_GLOBAL` \
--field="     $GUI_DLGAMEDATA!$DESC_DLGAMEDATA ('DLGAMEDATA')":CHK "${DLGAMEDATA/#-/ -}" `#CAT_Gui` `#SUB_Checkbox` `#MENU_GLOBAL` \
--field="     $GUI_USEGAMEPICS!$DESC_USEGAMEPICS ('USEGAMEPICS')":CHK "${USEGAMEPICS/#-/ -}" `#CAT_Gui` `#SUB_Checkbox` `#MENU_GLOBAL` \
--field="     $GUI_USECUSTOMFALLBACKPIC!$DESC_USECUSTOMFALLBACKPIC ('USECUSTOMFALLBACKPIC')":CHK "${USECUSTOMFALLBACKPIC/#-/ -}" `#CAT_Gui` `#SUB_Checkbox` `#MENU_GLOBAL` \
--field="     $GUI_GITHUBUSER!$DESC_GITHUBUSER ('GITHUBUSER')":CBE "${GITHUBUSER/#-/ -}" `#CAT_Gui` `#MENU_GLOBAL` \
--field="     $GUI_CHECKCOLLECTIONS!$DESC_CHECKCOLLECTIONS ('CHECKCOLLECTIONS')":CHK "${CHECKCOLLECTIONS/#-/ -}" `#CAT_Gui` `#SUB_Checkbox` `#MENU_GAME` \
--field="$(spanFont "$GUI_OPTSGRID" "H")":LBL "SKIP" `#CAT_SteamGridDB` `#HEAD_SteamGridDB` `#MENU_GLOBAL` \
--field="     $GUI_SGDBDLTOSTEAM!$DESC_SGDBDLTOSTEAM ('SGDBDLTOSTEAM')":CHK "${SGDBDLTOSTEAM/#-/ -}" `#CAT_SteamGridDB` `#SUB_Checkbox` `#MENU_GLOBAL` \
--field="     $GUI_SGDBAPIKEY!$DESC_SGDBAPIKEY ('SGDBAPIKEY')":CBE "${SGDBAPIKEY/#-/ -}" `#CAT_SteamGridDB` `#MENU_GLOBAL` \
--field="     $GUI_SGDBHASFILE!$DESC_SGDBHASFILE ('SGDBHASFILE')":CB "$(cleanDropDown "${SGDBHASFILE/#-/ -}" "skip!backup!replace")" `#CAT_SteamGridDB` `#MENU_GLOBAL` \
--field="     $GUI_SGDBAUTODL!$DESC_SGDBAUTODL ('SGDBAUTODL')":CB "$(cleanDropDown  "${SGDBAUTODL/#-/ -}" "$NON!after_game!before_game!no_meta")" `#CAT_SteamGridDB` `#MENU_GLOBAL` \
--field="     $GUI_SGDBSTYLES!$DESC_SGDBSTYLES ('SGDBSTYLES')":CBE "$(cleanDropDown "${SGDBSTYLES/#-/ -}" "${SGDBSTYOPTS//,/\!}")" `#CAT_SteamGridDB` `#MENU_GLOBAL` \
--field="     $GUI_SGDBDIMS!$DESC_SGDBDIMS ('SGDBDIMS')":CBE "$(cleanDropDown "${SGDBDIMS/#-/ -}" "${SGDBDIMOPTS//,/\!}")" `#CAT_SteamGridDB` `#MENU_GLOBAL` \
--field="     $GUI_SGDBTYPES!$DESC_SGDBTYPES ('SGDBTYPES')":CBE "$(cleanDropDown "${SGDBTYPES/#-/ -}" "animated!static!animated,static!static,animated")" `#CAT_SteamGridDB` `#MENU_GLOBAL` \
--field="     $GUI_SGDBNSFW!$DESC_SGDBNSFW ('SGDBNSFW')":CBE "$(cleanDropDown "${SGDBNSFW/#-/ -}" "any!false!true")" `#CAT_SteamGridDB` `#MENU_GLOBAL` \
--field="     $GUI_SGDBHUMOR!$DESC_SGDBHUMOR ('SGDBHUMOR')":CBE "$(cleanDropDown "${SGDBHUMOR/#-/ -}" "any!false!true")" `#CAT_SteamGridDB` `#MENU_GLOBAL` \
--field="$(spanFont "$GUI_OPTSHMM" "H")":LBL "SKIP" `#CAT_HMM` `#HEAD_HMM` `#MENU_GLOBAL` \
--field="     $GUI_HMMDLVER!$DESC_HMMDLVER ('HMMDLVER')":CB "$(cleanDropDown "${HMMDLVER/#-/ -}" "$HMMSTABLE!$HMMDEV")" `#CAT_HMM` `#MENU_GLOBAL` \
--field="     $GUI_HMMCOMPDATA!$DESC_HMMCOMPDATA ('HMMCOMPDATA')":DIR "${HMMCOMPDATA/#-/ -}" `#CAT_HMM` `#SUB_Directories` `#MENU_GLOBAL` \
--field="     $GUI_USEHMMPROTON!$DESC_USEHMMPROTON ('USEHMMPROTON')":CB "$(cleanDropDown "${USEHMMPROTON/#-/ -}" "$PROTYADLIST")" `#CAT_HMM` `#MENU_GLOBAL` \
--field="$(spanFont "$GUI_OPTSMISC" "H")":LBL "SKIP" `#CAT_Misc` `#HEAD_Misc` `#MENU_GAME` `#MENU_GLOBAL`  \
--field="     $GUI_KEEPSTLOPEN!$DESC_KEEPSTLOPEN ('KEEPSTLOPEN')":CHK "${KEEPSTLOPEN/#-/ -}" `#CAT_Misc` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_USECUSTOMCMD!$DESC_USECUSTOMCMD ('USECUSTOMCMD')":CHK "${USECUSTOMCMD/#-/ -}" `#CAT_Misc` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_CUSTOMCMD!$DESC_CUSTOMCMD $GUI_ECHOPLAC ('CUSTOMCMD')":FL "${OPCUSTPATH/#-/ -}" `#CAT_Misc` `#MENU_GAME` \
--field="     $GUI_CUSTOMCMD_ARGS!$DESC_CUSTOMCMD_ARGS ('CUSTOMCMD_ARGS')" "${CUSTOMCMD_ARGS/#-/ -}" `#CAT_Misc` `#MENU_GAME` \
--field="     $GUI_FORK_CUSTOMCMD!$DESC_FORK_CUSTOMCMD ('FORK_CUSTOMCMD')":CHK "${FORK_CUSTOMCMD/#-/ -}" `#CAT_Misc` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_EXTPROGS_CUSTOMCMD!$DESC_EXTPROGS_CUSTOMCMD ('EXTPROGS_CUSTOMCMD')":CHK "${EXTPROGS_CUSTOMCMD/#-/ -}" `#CAT_Misc` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_ONLY_CUSTOMCMD!$DESC_ONLY_CUSTOMCMD ('ONLY_CUSTOMCMD')":CHK "${ONLY_CUSTOMCMD/#-/ -}" `#CAT_Misc` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_CUSTOMCMD_FORCEWIN!$DESC_CUSTOMCMD_FORCEWIN ('CUSTOMCMDFORCEWIN')":CHK "${CUSTOMCMDFORCEWIN/#-/ -}" `#CAT_Misc` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_WAITFORCUSTOMCMD!$DESC_WAITFORCUSTOMCMD ('WAITFORCUSTOMCMD')":NUM "${WAITFORCUSTOMCMD/#-/ -}" `#CAT_Misc` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_INJECT_CUSTOMCMD!$DESC_INJECT_CUSTOMCMD ('INJECT_CUSTOMCMD')":CHK "${INJECT_CUSTOMCMD/#-/ -}" `#CAT_Misc` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_INJECTWAIT!$DESC_INJECTWAIT ('INJECTWAIT')":NUM "${INJECTWAIT/#-/ -}" `#CAT_Misc` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_USEIGCS!$DESC_USEIGCS ('USEIGCS')":CHK "${USEIGCS/#-/ -}" `#CAT_Misc` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_UUUSEIGCS!$DESC_UUUSEIGCS ('UUUSEIGCS')":CHK "${UUUSEIGCS/#-/ -}" `#CAT_Misc` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_IGCSWAIT!$DESC_IGCSWAIT ('IGCSWAIT')":NUM "${IGCSWAIT/#-/ -}" `#CAT_Misc` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_UUUSEPATCH!$DESC_UUUSEPATCH ('UUUSEPATCH')":CHK "${UUUSEPATCH/#-/ -}" `#CAT_Misc` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_UUUPATCHWAIT!$DESC_UUUPATCHWAIT ('UUUPATCHWAIT')":NUM "${UUUPATCHWAIT/#-/ -}" `#CAT_Misc` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_USERSTART!$DESC_USERSTART $GUI_ECHOPLAC ('USERSTART')":FL "${USERSTART/#-/ -}" `#CAT_Misc` `#MENU_GAME` \
--field="     $GUI_USERSTOP!$DESC_USERSTOP $GUI_ECHOPLAC ('USERSTOP')":FL "${USERSTOP/#-/ -}" `#CAT_Misc` `#MENU_GAME` \
--field="     $GUI_GAMEARGS!$DESC_GAMEARGS ('GAMEARGS')" "${GAMEARGS/#-/ -}" `#CAT_Misc` `#MENU_GAME` \
--field="     $GUI_SORTGARGS!$DESC_SORTGARGS ('SORTGARGS')":CHK "${SORTGARGS/#-/ -}" `#CAT_Misc` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_HARDARGS!$DESC_HARDARGS ('HARDARGS')":CBE "$(cleanDropDown "${HARDARGS/#-/ -}" "$ARGUMENTS")" `#CAT_Misc` `#MENU_GAME` \
--field="     $GUI_SLOARGS!$DESC_SLOARGS ('SLOARGS')":RO "${SLOARGS/#-/ -}" `#CAT_Misc` `#MENU_GAME` \
--field="     $GUI_CHANGE_PULSE_LATENCY!$DESC_CHANGE_PULSE_LATENCY ('CHANGE_PULSE_LATENCY')":CHK "${CHANGE_PULSE_LATENCY/#-/ -}" `#CAT_Misc` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_STL_PULSE_LATENCY_MSEC!$DESC_STL_PULSE_LATENCY_MSEC ('STL_PULSE_LATENCY_MSEC')":NUM "${STL_PULSE_LATENCY_MSEC/#-/ -}" `#CAT_Misc` `#MENU_GAME` \
--field="     $GUI_LOGLEVEL!$DESC_LOGLEVEL ('LOGLEVEL')":CB "$(cleanDropDown "${LOGLEVEL/#-/ -}" "0!1!2")" `#CAT_Misc` `#MENU_GLOBAL` \
--field="     $GUI_RESETLOG!$DESC_RESETLOG ('RESETLOG')":CHK "${RESETLOG/#-/ -}" `#CAT_Misc` `#SUB_Checkbox` `#MENU_GLOBAL` \
--field="     $GUI_STEAMAPPIDFILE!$DESC_STEAMAPPIDFILE ('STEAMAPPIDFILE')":CHK "${STEAMAPPIDFILE/#-/ -}" `#CAT_Misc` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_SKIPINTDEPCHECK!$DESC_SKIPINTDEPCHECK ('SKIPINTDEPCHECK')":CHK "${SKIPINTDEPCHECK/#-/ -}" `#CAT_Misc` `#SUB_Checkbox` `#MENU_GLOBAL` \
--field="     $GUI_NOSTEAMSTLDEF!$DESC_NOSTEAMSTLDEF ('NOSTEAMSTLDEF')":CHK "${NOSTEAMSTLDEF/#-/ -}" `#CAT_Misc` `#SUB_Checkbox` `#MENU_GLOBAL` \
--field="     $GUI_STORECOMPDATTITLE!$DESC_STORECOMPDATTITLE ('STORECOMPDATTITLE')":CHK "${STORECOMPDATTITLE/#-/ -}" `#CAT_Misc` `#SUB_Checkbox` `#MENU_GLOBAL` \
--field="     $GUI_LOGPLAYTIME!$DESC_LOGPLAYTIME ('LOGPLAYTIME')":CHK "${LOGPLAYTIME/#-/ -}" `#CAT_Misc` `#SUB_Checkbox` `#MENU_GLOBAL` \
--field="     $GUI_CRASHGUESS!$DESC_CRASHGUESS ('CRASHGUESS')":NUM "${CRASHGUESS/#-/ -}" `#CAT_Misc` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_HELPURL!$DESC_HELPURL ('HELPURL')":CB "$(cleanDropDown "${HELPURL}" "${HUYLIST}${NON}")" `#CAT_Misc` `#MENU_GAME` \
--field="     $GUI_CREATEDESKTOPICON!$DESC_CREATEDESKTOPICON ('CREATEDESKTOPICON')":NUM "${CREATEDESKTOPICON}!0..3" `#CAT_Misc` `#MENU_GAME` \
--field="     $GUI_GAMESCREENRES!$DESC_GAMESCREENRES ('GAMESCREENRES')":CBE "$(cleanDropDown "${GAMESCREENRES/#-/ -}" "$(printf "%s\n" "$(listScreenRes | tr '\n' '!')")$NON")" `#CAT_Misc` `#MENU_GAME` \
--field="     $GUI_TOGSTEAMWEBHELPER!$DESC_TOGSTEAMWEBHELPER ('TOGSTEAMWEBHELPER')":CHK "${TOGSTEAMWEBHELPER/#-/ -}" `#CAT_Misc` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_USEGEOELF!$DESC_USEGEOELF ('USEGEOELF')":CHK "${USEGEOELF/#-/ -}" `#CAT_Misc` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_AUTOGEOELF!$DESC_AUTOGEOELF ('AUTOGEOELF')":CHK "${AUTOGEOELF/#-/ -}" `#CAT_Misc` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_USESPECIALK!$DESC_USESPECIALK ('USESPECIALK')":CHK "${USESPECIALK/#-/ -}" `#CAT_Misc` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_SPEKVERS!$DESC_SPEKVERS ('SPEKVERS')":CB "$(cleanDropDown "${SPEKVERS/#-/ -}" "default!$SPEKYADLIST")" `#CAT_Misc` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_AUTOSPEK!$DESC_AUTOSPEK ('AUTOSPEK')":CHK "${AUTOSPEK/#-/ -}" `#CAT_Misc` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_USEFWS!$DESC_USEFWS ('USEFWS')":CHK "${USEFWS/#-/ -}" `#CAT_Misc` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_USETERM!$DESC_USETERM ('USETERM')":FL "${USETERM/#-/ -}" `#CAT_Misc` `#SUB_Checkbox` `#MENU_GLOBAL` \
--field="     $GUI_TERMARGS!$DESC_TERMARGS ('TERMARGS')" "${TERMARGS/#-/ -}" `#CAT_Misc` `#SUB_Checkbox` `#MENU_GLOBAL` \
--field="     $GUI_RUNSBS!$DESC_RUNSBS ('RUNSBS')":CHK "${RUNSBS/#-/ -}" `#CAT_Misc` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_SDLUSEWAYLAND!$DESC_SDLUSEWAYLAND ('SDLUSEWAYLAND')":CHK "${SDLUSEWAYLAND/#-/ -}" `#CAT_Misc` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_STLRAD_PFTST!$DESC_STLRAD_PFTST ('STLRAD_PFTST')":CBE "$(cleanDropDown "${STLRAD_PFTST/#-/ -}" "none!gpl!sam!rt!emulate_rt!rtwave64!video_decode")"  `#CAT_Misc` `#MENU_GAME` \
--field="$(spanFont "$GUI_OPTSPROTON" "H")":LBL "SKIP" `#CAT_Proton` `#HEAD_Proton` `#MENU_GAME` `#MENU_GLOBAL` \
--field="     $GUI_USEPROTON!$DESC_USEPROTON ('USEPROTON')":CB "$(cleanDropDown  "${USEPROTON/#-/ -}" "$PROTYADLIST")" `#CAT_Proton` `#MENU_GAME` \
--field="     $GUI_USESLR!$DESC_USESLR ('USESLR')":CHK "${USESLR/#-/ -}" `#CAT_Proton` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_FORCESLR!$DESC_FORCESLR ('FORCESLR')":CHK "${FORCESLR/#-/ -}" `#CAT_Proton` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_USEREAP!$DESC_USEREAP ('USEREAP')":CHK "${USEREAP/#-/ -}" `#CAT_Proton` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_FORCEREAP!$DESC_FORCEREAP ('FORCEREAP')":CHK "${FORCEREAP/#-/ -}" `#CAT_Proton` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_AUTOLASTPROTON!$DESC_AUTOLASTPROTON ('AUTOLASTPROTON')":CHK "${AUTOLASTPROTON/#-/ -}" `#CAT_Proton` `#SUB_Checkbox` `#MENU_GLOBAL` \
--field="     $GUI_REDIRCOMPDATA!$DESC_REDIRCOMPDATA ('REDIRCOMPDATA')":CB "$(cleanDropDown "${REDIRCOMPDATA/#-/ -}" "disabled!single-proton!global-proton")" `#CAT_Proton` `#MENU_GAME` \
--field="     $GUI_REDIRSTEAMUSER!$DESC_REDIRSTEAMUSER ('REDIRSTEAMUSER')":CB "$(cleanDropDown "${REDIRSTEAMUSER/#-/ -}" "disabled!symlink!restore-backup")" `#CAT_Proton` `#MENU_GAME` \
--field="     $GUI_AUTOBUMPGE!$DESC_AUTOBUMPGE ('AUTOBUMPGE')":CHK "${AUTOBUMPGE/#-/ -}" `#CAT_Proton` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_AUTOBUMPPROTON!$DESC_AUTOBUMPPROTON ('AUTOBUMPPROTON')":CHK "${AUTOBUMPPROTON/#-/ -}" `#CAT_Proton` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_PROTON_LOG!$DESC_PROTON_LOG $HOME/steam-$AID.log ('PROTON_LOG')":CHK "${PROTON_LOG/#-/ -}" `#CAT_Proton` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_PROTON_LOG_DIR!$DESC_PROTON_LOG_DIR ('PROTON_LOG_DIR')":DIR "${PROTON_LOG_DIR/#-/ -}" `#CAT_Proton` `#SUB_Directories` `#MENU_GAME` \
--field="     $GUI_USEWINEDEBUGPROTON!$DESC_USEWINEDEBUGPROTON ('USEWINEDEBUGPROTON')":CHK "${USEWINEDEBUGPROTON/#-/ -}" `#CAT_Proton` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_PROTON_NO_D3D10!$DESC_PROTON_NO_D3D10 ('PROTON_NO_D3D10')":CHK "${PROTON_NO_D3D10/#-/ -}" `#CAT_Proton` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_PROTON_NO_D3D11!$DESC_PROTON_NO_D3D11 ('PROTON_NO_D3D11')":CHK "${PROTON_NO_D3D11/#-/ -}" `#CAT_Proton` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_PROTON_NO_ESYNC!$DESC_PROTON_NO_ESYNC ('PROTON_NO_ESYNC')":CHK "${PROTON_NO_ESYNC/#-/ -}" `#CAT_Proton` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_PROTON_NO_FSYNC!$DESC_PROTON_NO_FSYNC ('PROTON_NO_FSYNC')":CHK "${PROTON_NO_FSYNC/#-/ -}" `#CAT_Proton` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_ENABLE_WINESYNC!$DESC_ENABLE_WINESYNC ('ENABLE_WINESYNC')":CHK "${ENABLE_WINESYNC/#-/ -}" `#CAT_Proton` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_PROTON_ENABLE_NVAPI!$DESC_PROTON_ENABLE_NVAPI ('PROTON_ENABLE_NVAPI')":CHK "${PROTON_ENABLE_NVAPI/#-/ -}" `#CAT_Proton` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_PROTON_HIDE_NVIDIA_GPU!$DESC_PROTON_HIDE_NVIDIA_GPU ('PROTON_HIDE_NVIDIA_GPU')":CHK "${PROTON_HIDE_NVIDIA_GPU/#-/ -}" `#CAT_Proton` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_USEDLSS!$DESC_USEDLSS ('USEDLSS')":CHK "${USEDLSS/#-/ -}" `#CAT_Proton` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_PROTON_USE_WINED3D!$DESC_PROTON_USE_WINED3D ('PROTON_USE_WINED3D')":CHK "${PROTON_USE_WINED3D/#-/ -}" `#CAT_Proton` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_PROTON_DEBUG_DIR!$DESC_PROTON_DEBUG_DIR ('PROTON_DEBUG_DIR')":DIR "${PROTON_DEBUG_DIR/#-/ -}" `#CAT_Proton` `#SUB_Directories` `#MENU_GAME` \
--field="     $GUI_PROTON_DUMP_DEBUG_COMMANDS!$DESC_PROTON_DUMP_DEBUG_COMMANDS ('PROTON_DUMP_DEBUG_COMMANDS')":CHK "${PROTON_DUMP_DEBUG_COMMANDS/#-/ -}" `#CAT_Proton` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_PROTON_FORCE_LARGE_ADDRESS_AWARE!$DESC_PROTON_FORCE_LARGE_ADDRESS_AWARE ('PROTON_FORCE_LARGE_ADDRESS_AWARE')":CHK "${PROTON_FORCE_LARGE_ADDRESS_AWARE/#-/ -}" `#CAT_Proton` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_USE_STLDXVKCFG!$DESC_USE_STLDXVKCFG ('USE_STLDXVKCFG')":CHK "${USE_STLDXVKCFG/#-/ -}" `#CAT_Proton` `#SUB_Dxvk` `#MENU_GAME` \
--field="     $GUI_DXVK_HUD!$DESC_DXVK_HUD ('DXVK_HUD')":CBE "$(cleanDropDown "${DXVK_HUD/#-/ -}" "0!1")" `#CAT_Proton` `#SUB_Dxvk` `#MENU_GAME` \
--field="     $GUI_DXVK_LOG_LEVEL!$DESC_DXVK_LOG_LEVEL ('DXVK_LOG_LEVEL')":CB "$(cleanDropDown "${DXVK_LOG_LEVEL/#-/ -}" "none!error!warn!info!debug")" `#CAT_Proton` `#SUB_Dxvk` `#MENU_GAME` \
--field="     $GUI_DXVK_LOG_PATH!$DESC_DXVK_LOG_PATH ('DXVK_LOG_PATH')":DIR "${DXVK_LOG_PATH/#-/ -}" `#CAT_Proton` `#SUB_Directories` `#MENU_GAME` \
--field="     $GUI_DXVK_SCALE!$DESC_DXVK_SCALE ('DXVK_SCALE')" "${DXVK_SCALE/#-/ -}" `#CAT_Proton` `#MENU_GAME` \
--field="     $GUI_DXVK_FPSLIMIT!$DESC_DXVK_FPSLIMIT ('DXVK_FPSLIMIT')":CBE "$(cleanDropDown "${DXVK_FPSLIMIT/#-/ -}" "none!30!60!75!90!120!144!165!240")"  `#CAT_Proton` `#MENU_GAME` \
--field="     $GUI_DXVK_ASYNC!$DESC_DXVK_ASYNC ('DXVK_ASYNC')":CHK "${DXVK_ASYNC/#-/ -}" `#CAT_Proton` `#SUB_Dxvk` `#MENU_GAME` \
--field="     $GUI_DXVK_HDR!$DESC_DXVK_HDR ('DXVK_HDR')":CHK "${DXVK_HDR/#-/ -}" `#CAT_Proton` `#SUB_Dxvk` `#MENU_GAME` \
--field="     $GUI_CUSTPROTDLDIR!$DESC_CUSTPROTDLDIR ('CUSTPROTDLDIR')":DIR "${CUSTPROTDLDIR/#-/ -}" `#CAT_Proton` `#SUB_Directories` `#MENU_GLOBAL` \
--field="     $GUI_CUSTPROTEXTDIR!$DESC_CUSTPROTEXTDIR ('CUSTPROTEXTDIR')":DIR "${CUSTPROTEXTDIR/#-/ -}" `#CAT_Proton` `#SUB_Directories` `#MENU_GLOBAL` \
--field="     $GUI_CUPROTOCOMPAT!$DESC_CUPROTOCOMPAT ('CUPROTOCOMPAT')":CHK "${CUPROTOCOMPAT/#-/ -}" `#CAT_Proton` `#SUB_Checkbox` `#MENU_GLOBAL` \
--field="     $GUI_USESUSYM!$DESC_USESUSYM ('USESUSYM')":CHK "${USESUSYM/#-/ -}" `#CAT_Proton` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_USEGLOBSUSYM!$DESC_USEGLOBSUSYM ('USEGLOBSUSYM')":CHK "${USEGLOBSUSYM/#-/ -}" `#CAT_Proton` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_FIXSYMLINKS!$DESC_FIXSYMLINKS ('FIXSYMLINKS')":CHK "${FIXSYMLINKS/#-/ -}" `#CAT_Proton` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_UNSYMLINK!$DESC_UNSYMLINK ('UNSYMLINK')":CHK "${UNSYMLINK/#-/ -}" `#CAT_Proton` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_DELPFX!$DESC_DELPFX ('DELPFX')":CHK "${DELPFX/#-/ -}" `#CAT_Proton` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_BACKUPSTEAMUSER!$DESC_BACKUPSTEAMUSER ('BACKUPSTEAMUSER')":CHK "${BACKUPSTEAMUSER/#-/ -}" `#CAT_Proton` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_RESTORESTEAMUSER!$DESC_RESTORESTEAMUSER ('RESTORESTEAMUSER')":CB "$(cleanDropDown "${RESTORESTEAMUSER/#-/ -}" "$NON!ask-always!ask-if-dst-has-no-backup-timestamp!ask-if-unsure!restore-always!restore-if-backup-timestamp-is-newer!restore-if-dst-has-no-backup-timestamp!restore-if-dst-is-empty")" `#CAT_Proton` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_CLEANPROTONTEMP!$DESC_CLEANPROTONTEMP ('CLEANPROTONTEMP')":CHK "${CLEANPROTONTEMP/#-/ -}" `#CAT_Proton` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_USEPDBRATING!$DESC_USEPDBRATING ('USEPDBRATING')":CHK "${USEPDBRATING/#-/ -}" `#CAT_Proton` `#SUB_Checkbox` `#MENU_GLOBAL` \
--field="     $GUI_PDBRATINGCACHE!$DESC_PDBRATINGCACHE ('PDBRATINGCACHE')":NUM "${PDBRATINGCACHE/#-/ -}" `#CAT_Proton` `#SUB_Checkbox` `#MENU_GLOBAL` \
--field="$(spanFont "$GUI_OPTSVKD3D" "H")":LBL "SKIP" `#CAT_VKD3D` `#HEAD_VKD3D` `#MENU_GAME` \
--field="     $GUI_USERAYTRACING!$DESC_USERAYTRACING ('USERAYTRACING')":CHK "${USERAYTRACING/#-/ -}" `#CAT_VKD3D` `#MENU_GAME` \
--field="     $GUI_STL_VKD3D_CONFIG!$DESC_STL_VKD3D_CONFIG ('STL_VKD3D_CONFIG')":CB "$(cleanDropDown "${STL_VKD3D_CONFIG/#-/ -}" "$NON!vk_debug!skip_application_workarounds!dxr!dxr11!force_static_cbv!single_queue!no_upload_hvv!force_host_cached!no_invariant_position")" `#CAT_VKD3D` `#MENU_GAME` \
--field="     $GUI_STL_VKD3D_DEBUG!$DESC_STL_VKD3D_DEBUG ('STL_VKD3D_DEBUG')":CB "$(cleanDropDown "${STL_VKD3D_DEBUG/#-/ -}" "$NON!err!info!fixme!warn!trace")" `#CAT_VKD3D` `#MENU_GAME` \
--field="     $GUI_STL_VKD3D_SHADER_DEBUG!$DESC_STL_VKD3D_SHADER_DEBUG ('STL_VKD3D_SHADER_DEBUG')":CB "$(cleanDropDown "${STL_VKD3D_SHADER_DEBUG/#-/ -}" "$NON!err!info!fixme!warn!trace")" `#CAT_VKD3D` `#MENU_GAME` \
--field="     $GUI_STL_VKD3D_LOG_FILE!$DESC_STL_VKD3D_LOG_FILE ('STL_VKD3D_LOG_FILE')":CBE "$(cleanDropDown "${STL_VKD3D_LOG_FILE/#-/ -}" "$NON!$STLVKD3DLOGDIR")" `#CAT_VKD3D` `#MENU_GAME` \
--field="     $GUI_STL_VKD3D_VULKAN_DEVICE!$DESC_STL_VKD3D_VULKAN_DEVICE ('STL_VKD3D_VULKAN_DEVICE')":CBE "$(cleanDropDown "${STL_VKD3D_VULKAN_DEVICE/#-/ -}")" `#CAT_VKD3D` `#MENU_GAME` \
--field="     $GUI_STL_VKD3D_FILTER_DEVICE_NAME!$DESC_STL_VKD3D_FILTER_DEVICE_NAME ('STL_VKD3D_FILTER_DEVICE_NAME')":CBE "$(cleanDropDown "${STL_VKD3D_FILTER_DEVICE_NAME/#-/ -}")" `#CAT_VKD3D` `#MENU_GLOBAL` \
--field="     $GUI_STL_VKD3D_DISABLE_EXTENSIONS!$DESC_STL_VKD3D_DISABLE_EXTENSIONS ('STL_VKD3D_DISABLE_EXTENSIONS')":CBE "$(cleanDropDown "${STL_VKD3D_DISABLE_EXTENSIONS/#-/ -}")" `#CAT_VKD3D` `#MENU_GAME` \
--field="     $GUI_STL_VKD3D_TEST_DEBUG!$DESC_STL_VKD3D_TEST_DEBUG ('STL_VKD3D_TEST_DEBUG')":NUM "${STL_VKD3D_TEST_DEBUG}!0..2" `#CAT_VKD3D` `#MENU_GAME` \
--field="     $GUI_STL_VKD3D_TEST_FILTER!$DESC_STL_VKD3D_TEST_FILTER ('STL_VKD3D_TEST_FILTER')":CB "$(cleanDropDown "${STL_VKD3D_TEST_FILTER/#-/ -}" "$NON!clear_render_target")" `#CAT_VKD3D` `#MENU_GAME` \
--field="     $GUI_STL_VKD3D_TEST_EXCLUDE!$DESC_STL_VKD3D_TEST_EXCLUDE ('STL_VKD3D_TEST_EXCLUDE')":CB "$(cleanDropDown "${STL_VKD3D_TEST_EXCLUDE/#-/ -}" "$NON!test_root_signature_priority,test_conservative_rasterization_dxil")" `#CAT_VKD3D` `#MENU_GAME` \
--field="     $GUI_STL_VKD3D_TEST_PLATFORM!$DESC_STL_VKD3D_TEST_PLATFORM ('STL_VKD3D_TEST_PLATFORM')":CB "$(cleanDropDown "${STL_VKD3D_TEST_PLATFORM/#-/ -}" "$NON!wine!windows!other")" `#CAT_VKD3D` `#MENU_GAME` \
--field="     $GUI_STL_VKD3D_TEST_BUG!$DESC_STL_VKD3D_TEST_BUG ('STL_VKD3D_TEST_BUG')":CBE "$(cleanDropDown "${STL_VKD3D_TEST_BUG/#-/ -}" "$NON!0")" `#CAT_VKD3D` `#MENU_GAME` \
--field="     $GUI_STL_VKD3D_PROFILE_PATH!$DESC_STL_VKD3D_PROFILE_PATH ('STL_VKD3D_PROFILE_PATH')":DIR "${STL_VKD3D_PROFILE_PATH/#-/ -}" `#CAT_VKD3D` `#MENU_GAME` \
--field="$(spanFont "$GUI_OPTSSHADER" "H")":LBL "SKIP" `#CAT_Shader` `#HEAD_Shader` `#MENU_GAME` `#MENU_GLOBAL` \
--field="     $GUI_USERESHADE!$DESC_USERESHADE ('USERESHADE')":CHK "${USERESHADE/#-/ -}" `#CAT_Shader` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_CUSTOMCMDRESHADE!$DESC_CUSTOMCMDRESHADE ('CUSTOMCMDRESHADE')":CHK "${CUSTOMCMDRESHADE/#-/ -}" `#CAT_Shader` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_DOWNLOAD_RESHADE!$DESC_DOWNLOAD_RESHADE ('DOWNLOAD_RESHADE')":CHK "${DOWNLOAD_RESHADE/#-/ -}" `#CAT_Shader` `#SUB_ReShade` `#SUB_Checkbox` `#MENU_GLOBAL` \
--field="     $GUI_INSTALL_RESHADE!$DESC_INSTALL_RESHADE ('INSTALL_RESHADE')":CHK "${INSTALL_RESHADE/#-/ -}" `#CAT_Shader` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_RESHADEUPDATE!$DESC_RESHADEUPDATE ('RESHADEUPDATE')":CHK "${RESHADEUPDATE/#-/ -}" `#CAT_Shader` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_RESHADEOVERRIDETOGGLE!$DESC_RESHADEOVERRIDETOGGLE ('RSOVRD')":CHK "${RSOVRD/#-/ -}" `#CAT_Shader` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_RSVERS!$DESC_RSVERS ('RSVERS')" "${RSVERS/#-/ -}" `#CAT_Shader` `#SUB_ReShade` `#MENU_GLOBAL` \
--field="     $GUI_AUTOBUMPRESHADE!$DESC_AUTOBUMPRESHADE ('AUTOBUMPRESHADE')":CHK "${AUTOBUMPRESHADE/#-/ -}" `#CAT_Shader` `#SUB_ReShade` `#MENU_GLOBAL` \
--field="     $GUI_RS_32!$DESC_RS_32 ('RS_32')" "${RS_32/#-/ -}" `#CAT_Shader` `#SUB_ReShade` `#MENU_GLOBAL` \
--field="     $GUI_RS_64!$DESC_RS_64 ('RS_64')" "${RS_64/#-/ -}" `#CAT_Shader` `#SUB_ReShade` `#MENU_GLOBAL` \
--field="     $GUI_RS_32_VK!$DESC_RS_32_VK ('RS_32_VK')" "${RS_32_VK/#-/ -}" `#CAT_Shader` `#SUB_ReShade` `#MENU_GLOBAL` \
--field="     $GUI_RS_64_VK!$DESC_RS_64_VK ('RS_64_VK')" "${RS_64_VK/#-/ -}" `#CAT_Shader` `#SUB_ReShade` `#MENU_GLOBAL` \
--field="     $GUI_D3D47_32!$DESC_D3D47_32 ('D3D47_32')" "${D3D47_32/#-/ -}" `#CAT_Shader` `#SUB_ReShade` `#MENU_GLOBAL` \
--field="     $GUI_D3D47_64!$DESC_D3D47_64 ('D3D47_64')" "${D3D47_64/#-/ -}" `#CAT_Shader` `#SUB_ReShade` `#MENU_GLOBAL` \
--field="     $GUI_RESHADEOVERRIDEVERSION!$DESC_RESHADEOVERRIDEVERSION ('RSOVRVERS')":CBE "$(cleanDropDown "${RSOVRVERS/#-/ -}" "$RESHADEVERSIONS")" `#CAT_Shader` `#SUB_ReShade` `#MENU_GAME` \
--field="     $GUI_ARCHALTEXE!$DESC_ARCHALTEXE ('ARCHALTEXE')":FL "${ARCHALTEXE/#-/ -}" `#CAT_Shader` `#SUB_ReShade` `#MENU_GAME` \
--field="     $GUI_ALTEXEPATH!$DESC_ALTEXEPATH ('ALTEXEPATH')":DIR "${ALTEXEPATH/#-/ -}" `#CAT_Shader` `#SUB_Directories` `#MENU_GAME` \
--field="     $GUI_RESHADESRCDIR!$DESC_RESHADESRCDIR ('RESHADESRCDIR')":DIR "${RESHADESRCDIR/#-/ -}" `#CAT_Shader` `#SUB_ReShade` `#SUB_Directories` `#MENU_GLOBAL` \
--field="     $GUI_RESHADE_DEPTH3D!$DESC_RESHADE_DEPTH3D ('RESHADE_DEPTH3D')":CHK "${RESHADE_DEPTH3D/#-/ -}" `#CAT_Shader` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_DLSHADER!$DESC_DLSHADER ('DLSHADER')":CHK "${DLSHADER/#-/ -}" `#CAT_Shader` `#SUB_Checkbox` `#MENU_GLOBAL`  \
--field="     $GUI_CHOOSESHADERS!$DESC_CHOOSESHADERS ('CHOOSESHADERS')":CHK "${CHOOSESHADERS/#-/ -}" `#CAT_Shader` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_ENABLE_VKBASALT!$DESC_ENABLE_VKBASALT ('ENABLE_VKBASALT')":CHK "${ENABLE_VKBASALT/#-/ -}" `#CAT_Shader` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_SBSRS!$DESC_SBSRS ('SBSRS')":CHK "${SBSRS/#-/ -}" `#CAT_Shader` `#SUB_Checkbox` `#SUB_ReShade` `#MENU_GAME` \
--field="$(spanFont "$PROGNAME $GUI_PATHS" "H")":LBL "SKIP" `#CAT_Paths` `#HEAD_Stl` `#MENU_GLOBAL`  \
--field="     $GUI_GLOBALCOLLECTIONDIR!$DESC_GLOBALCOLLECTIONDIR ('GLOBALCOLLECTIONDIR')":DIR "${GLOBALCOLLECTIONDIR/#-/ -}" `#CAT_Paths` `#SUB_Directories` `#MENU_GLOBAL` \
--field="     $GUI_GLOBALMISCDIR!$DESC_GLOBALMISCDIR ('GLOBALMISCDIR')":DIR "${GLOBALMISCDIR/#-/ -}" `#CAT_Paths` `#SUB_Directories` `#MENU_GLOBAL` \
--field="     $GUI_GLOBALSBSTWEAKS!$DESC_GLOBALSBSTWEAKS ('GLOBALSBSTWEAKS')":DIR "${GLOBALSBSTWEAKS/#-/ -}" `#CAT_Paths` `#SUB_Directories` `#MENU_GLOBAL` \
--field="     $GUI_GLOBALTWEAKS!$DESC_GLOBALTWEAKS ('GLOBALTWEAKS')":DIR "${GLOBALTWEAKS/#-/ -}" `#CAT_Paths` `#SUB_Directories` `#MENU_GLOBAL` \
--field="     $GUI_GLOBALSTLLANGDIR!$DESC_GLOBALSTLLANGDIR ('GLOBALSTLLANGDIR')":DIR "${GLOBALSTLLANGDIR/#-/ -}" `#CAT_Paths` `#SUB_Directories` `#MENU_GLOBAL` \
--field="     $GUI_GLOBALEVALDIR!$DESC_GLOBALEVALDIR ('GLOBALEVALDIR')":DIR "${GLOBALEVALDIR/#-/ -}" `#CAT_Paths` `#SUB_Directories` `#MENU_GLOBAL` \
--field="     $GUI_GLOBALSTLGUIDIR!$DESC_GLOBALSTLGUIDIR ('GLOBALSTLGUIDIR')":DIR "${GLOBALSTLGUIDIR/#-/ -}" `#CAT_Paths` `#SUB_Directories` `#MENU_GLOBAL` \
--field="     $PROGNAME $GUI_LOGDIR!$(strFix "$DESC_LOGDIR" "$PROGNAME") ('LOGDIR')":DIR "${LOGDIR/#-/ -}" `#CAT_Paths` `#SUB_Directories` `#MENU_GLOBAL` \
--field="$(spanFont "$GUI_OPTSTOOLS" "H")":LBL "SKIP" `#CAT_Tools` `#HEAD_Tools` `#MENU_GAME` `#MENU_GLOBAL`  \
--field="     $GUI_USEGAMEMODERUN!$DESC_USEGAMEMODERUN ('USEGAMEMODERUN')":CHK "${USEGAMEMODERUN/#-/ -}" `#CAT_Tools` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_USEMANGOHUD!$DESC_USEMANGOHUD ('USEMANGOHUD')":CHK "${USEMANGOHUD/#-/ -}" `#CAT_Tools` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_USEMANGOAPP!$DESC_USEMANGOAPP ('USEMANGOAPP')":CHK "${USEMANGOAPP/#-/ -}" `#CAT_Tools` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_MAHUVAR!$DESC_MAHUVAR ('MAHUVAR')":CHK "${MAHUVAR/#-/ -}" `#CAT_Tools` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_MAHUBIN!$DESC_MAHUBIN ('MAHUBIN')":FL "${MAHUBIN/#-/ -}" `#CAT_Tools` `#MENU_GAME` \
--field="     $GUI_MAHUARGS!$DESC_MAHUARGS ('MAHUARGS')":CBE "${MAHUARGS/#-/ -}!--dlsym" `#CAT_Tools` `#MENU_GAME` \
--field="     $GUI_LDPMAHU!$DESC_LDPMAHU ('LDPMAHU')":CHK "${LDPMAHU/#-/ -}" `#CAT_Tools` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_USEMANGOHUDSTLCFG!$DESC_USEMANGOHUDSTLCFG ('USEMANGOHUDSTLCFG')":CHK "${USEMANGOHUDSTLCFG/#-/ -}" `#CAT_Tools` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_USEGAMESCOPE!$DESC_USEGAMESCOPE ('USEGAMESCOPE')":CHK "${USEGAMESCOPE/#-/ -}" `#CAT_Tools` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_GAMESCOPE_ARGS!$DESC_GAMESCOPE_ARGS ('GAMESCOPE_ARGS')" "${GAMESCOPE_ARGS/#-/ -}" `#CAT_Tools` `#MENU_GAME` \
--field="     $GUI_USEOBSCAP!$DESC_USEOBSCAP ('USEOBSCAP')":CHK "${USEOBSCAP/#-/ -}" `#CAT_Tools` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_USEZINK!$DESC_USEZINK ('USEZINK')":CHK "${USEZINK/#-/ -}" `#CAT_Tools` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_USEPRIMERUN!$DESC_USEPRIMERUN ('USEPRIMERUN')":CHK "${USEPRIMERUN/#-/ -}" `#CAT_Tools` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_RUN_NYRNA!$DESC_RUN_NYRNA ('RUN_NYRNA')":CHK "${RUN_NYRNA/#-/ -}" `#CAT_Tools` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_RUN_REPLAY!$DESC_RUN_REPLAY ('RUN_REPLAY')":CHK "${RUN_REPLAY/#-/ -}" `#CAT_Tools` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_USEBOXTRON!$DESC_USEBOXTRON ('USEBOXTRON')":CHK "${USEBOXTRON/#-/ -}" `#CAT_Tools` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_BOXTRONCMD!$DESC_BOXTRONCMD ('BOXTRONCMD')":FL "${BOXTRONCMD/#-/ -}" `#CAT_Tools` `#MENU_GLOBAL` \
--field="     $GUI_BOXTRONARGS!$DESC_BOXTRONARGS ('BOXTRONARGS')" "${BOXTRONARGS/#-/ -}" `#CAT_Tools` `#MENU_GLOBAL` \
--field="     $GUI_USEROBERTA!$DESC_USEROBERTA ('USEROBERTA')":CHK "${USEROBERTA/#-/ -}" `#CAT_Tools` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_ROBERTACMD!$DESC_ROBERTACMD ('ROBERTACMD')":FL "${ROBERTACMD/#-/ -}" `#CAT_Tools` `#MENU_GLOBAL` \
--field="     $GUI_ROBERTAARGS!$DESC_ROBERTAARGS ('ROBERTAARGS')" "${ROBERTAARGS/#-/ -}" `#CAT_Tools` `#MENU_GLOBAL` \
--field="     $GUI_USELUXTORPEDA!$DESC_USELUXTORPEDA ('USELUXTORPEDA')":CHK "${USELUXTORPEDA/#-/ -}" `#CAT_Tools` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_LUXTORPEDACMD!$DESC_LUXTORPEDACMD ('LUXTORPEDACMD')":FL "${LUXTORPEDACMD/#-/ -}" `#CAT_Tools` `#MENU_GLOBAL` \
--field="     $GUI_LUXTORPEDAARGS!$DESC_LUXTORPEDAARGS ('LUXTORPEDAARGS')" "${LUXTORPEDAARGS/#-/ -}" `#CAT_Tools` `#MENU_GLOBAL` \
--field="     $GUI_STLEDITOR!$DESC_STLEDITOR ('STLEDITOR')":FL "${STLEDITOR/#-/ -}" `#CAT_Tools` `#MENU_GLOBAL` \
--field="     $GUI_BROWSER!$DESC_BROWSER ('BROWSER')":FL "${BROWSER/#-/ -}" `#CAT_Tools` `#MENU_GLOBAL` \
--field="     $GUI_NOTY!$DESC_NOTY ('NOTY')":FL "${NOTY/#-/ -}" `#CAT_Tools` `#MENU_GLOBAL` \
--field="     $GUI_NOTYARGS!$DESC_NOTYARGS ('NOTYARGS')" "${NOTYARGS/#-/ -}" `#CAT_Tools` `#MENU_GLOBAL` \
--field="     $GUI_USENETMON!$DESC_USENETMON ('USENETMON')":CHK "${USENETMON/#-/ -}" `#CAT_Tools` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_NETMON!$DESC_NETMON ('NETMON')":FL "${NETMON/#-/ -}" `#CAT_Tools` `#MENU_GLOBAL` \
--field="     $GUI_NETOPTS!$DESC_NETOPTS ('NETOPTS')" "${NETOPTS/#-/ -}" `#CAT_Tools` `#MENU_GLOBAL` \
--field="     $GUI_NETMONDIR!$DESC_NETMONDIR ('NETMONDIR')":DIR "${NETMONDIR/#-/ -}" `#CAT_Tools` `#SUB_Directories` `#MENU_GLOBAL` \
--field="     $GUI_BLOCKINTERNET!$DESC_BLOCKINTERNET ('BLOCKINTERNET')":CHK "${BLOCKINTERNET/#-/ -}" `#CAT_Tools` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_STRACERUN!$DESC_STRACERUN ('STRACERUN')":CHK "${STRACERUN/#-/ -}" `#CAT_Tools` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_STRACEDIR!$DESC_STRACEDIR ('STRACEDIR')":DIR "${STRACEDIR/#-/ -}" `#CAT_Tools` `#SUB_Directories` `#MENU_GLOBAL` \
--field="     $GUI_STRACEOPTS!$DESC_STRACEOPTS ('STRACEOPTS')" "${STRACEOPTS/#-/ -}" `#CAT_Tools` `#MENU_GAME` \
--field="     $GUI_AUTOCONTY!$DESC_AUTOCONTY ('AUTOCONTY')":CHK "${AUTOCONTY/#-/ -}" `#CAT_Tools` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_USECONTY!$DESC_USECONTY ('USECONTY')":CHK "${USECONTY/#-/ -}" `#CAT_Tools` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_CUSTCONTY!$DESC_CUSTCONTY ('CUSTCONTY')":FL "${CUSTCONTY/#-/ -}" `#CAT_Tools` `#MENU_GLOBAL` \
--field="     $GUI_UPDATECONTY!$DESC_UPDATECONTY ('UPDATECONTY')":CHK "${UPDATECONTY/#-/ -}" `#CAT_Tools` `#SUB_Checkbox` `#MENU_GLOBAL` \
--field="     $GUI_RUN_X64DBG!$DESC_RUN_X64DBG ('RUN_X64DBG')":CHK "${RUN_X64DBG/#-/ -}" `#CAT_Tools` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_RUN_GDB!$DESC_RUN_GDB ('RUN_GDB')":CHK "${RUN_GDB/#-/ -}" `#CAT_Tools` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_USE_WDIB!$DESC_USE_WDIB ('USE_WDIB')":CHK "${USE_WDIB/#-/ -}" `#CAT_Tools` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_DPRSCOMPDATA!$DESC_DPRSCOMPDATA ('DPRSCOMPDATA')":DIR "${DPRSCOMPDATA/#-/ -}" `#CAT_Tools` `#SUB_Directories` `#MENU_GLOBAL` \
--field="     $GUI_USEDPRSPROTON!$DESC_USEDPRSPROTON ('USEDPRSPROTON')":CB "$(cleanDropDown "${USEDPRSPROTON/#-/ -}" "$PROTYADLIST")" `#CAT_Tools` `#MENU_GLOBAL` \
--field="     $GUI_DPRSUSEVDFSYMLINKS!$DESC_DPRSUSEVDFSYMLINKS ('DPRSUSEVDFSYMLINKS')":CHK "${DPRSUSEVDFSYMLINKS/#-/ -}" `#CAT_Tools` `#SUB_Checkbox` `#MENU_GLOBAL` \
--field="     $GUI_DPRSPAUTOUP!$DESC_DPRSPAUTOUP ('DPRSPAUTOUP')":CHK "${DPRSPAUTOUP/#-/ -}" `#CAT_Tools` `#SUB_Checkbox` `#MENU_GLOBAL` \
--field="     $GUI_RUN_DEPS!$DESC_RUN_DEPS ('RUN_DEPS')":CHK "${RUN_DEPS/#-/ -}" `#CAT_Tools` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_DEPSAUTOUP!$DESC_DEPSAUTOUP ('DEPSAUTOUP')":CHK "${DEPSAUTOUP/#-/ -}" `#CAT_Tools` `#SUB_Checkbox` `#MENU_GLOBAL` \
--field="     $GUI_USEPEV_PELDD!$DESC_USEPEV_PELDD ('USEPEV_PELDD')":CHK "${USEPEV_PELDD/#-/ -}" `#CAT_Tools` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_USEPEV_PEPACK!$DESC_USEPEV_PEPACK ('USEPEV_PEPACK')":CHK "${USEPEV_PEPACK/#-/ -}" `#CAT_Tools` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_USEPEV_PERES!$DESC_USEPEV_PERES ('USEPEV_PERES')":CHK "${USEPEV_PERES/#-/ -}" `#CAT_Tools` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_USEPEV_PESCAN!$DESC_USEPEV_PESCAN ('USEPEV_PESCAN')":CHK "${USEPEV_PESCAN/#-/ -}" `#CAT_Tools` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_USEPEV_PESEC!$DESC_USEPEV_PESEC ('USEPEV_PESEC')":CHK "${USEPEV_PESEC/#-/ -}" `#CAT_Tools` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_USEPEV_PESTR!$DESC_USEPEV_PESTR ('USEPEV_PESTR')":CHK "${USEPEV_PESTR/#-/ -}" `#CAT_Tools` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_USEPEV_READPE!$DESC_USEPEV_READPE ('USEPEV_READPE')":CHK "${USEPEV_READPE/#-/ -}" `#CAT_Tools` `#SUB_Checkbox` `#MENU_GAME` \
--field="$(spanFont "$GUI_OPTSURLS" "H")":LBL "SKIP" `#CAT_Urls` `#HEAD_Urls` `#MENU_URL` \
--field="     $GUI_PROJECTPAGE!$(strFix "$DESC_PROJECTPAGE" "$PROGNAME") ('PROJECTPAGE')" "${PROJECTPAGE/#-/ -}" `#CAT_Urls` `#MENU_URL` \
--field="     $GUI_CP_PROTONTKG!$DESC_CP_PROTONTKG ('CP_PROTONTKG')" "${CP_PROTONTKG/#-/ -}" `#CAT_Urls` `#MENU_URL` \
--field="     $GUI_CP_PROTONGE!$DESC_CP_PROTONGE ('CP_PROTONGE')" "${CP_PROTONGE/#-/ -}" `#CAT_Urls` `#MENU_URL` \
--field="     $GUI_CP_PROTONSTL!$DESC_CP_PROTONSTL ('CP_PROTONSTL')" "${CP_PROTONSTL/#-/ -}" `#CAT_Urls` `#MENU_URL` \
--field="     $GUI_CW_KRON4EK!$DESC_CW_KRON4EK ('CW_KRON4EK')" "${CW_KRON4EK/#-/ -}" `#CAT_Urls` `#MENU_URL` \
--field="     $GUI_DL_D3D47_64!$DESC_DL_D3D47_64 ('DL_D3D47_64')" "${DL_D3D47_64/#-/ -}" `#CAT_Urls` `#MENU_URL` \
--field="     $GUI_DL_D3D47_32!$DESC_DL_D3D47_32 ('DL_D3D47_32')" "${DL_D3D47_32/#-/ -}" `#CAT_Urls` `#MENU_URL` \
--field="     $GUI_RESHADEDLURL!$DESC_RESHADEDLURL ('RESHADEDLURL')" "${RESHADEDLURL/#-/ -}" `#CAT_Urls` `#MENU_URL` \
--field="     $GUI_VORTEXRELURL!$DESC_VORTEXRELURL ('VORTEXPROJURL')" "${VORTEXPROJURL/#-/ -}" `#CAT_Urls` `#MENU_URL` \
--field="     $GUI_DXVKURL!$DESC_DXVKURL ('DXVKURL')" "${DXVKURL/#-/ -}" `#CAT_Urls` `#MENU_URL` \
--field="     $GUI_XLIVEURL!$DESC_XLIVEURL ('XLIVEURL')" "${XLIVEURL/#-/ -}" `#CAT_Urls` `#MENU_URL` \
--field="     $GUI_STASSURL!$DESC_STASSURL ('STASSURL')" "${STASSURL/#-/ -}" `#CAT_Urls` `#MENU_URL` \
--field="     $GUI_WINETRICKSURL!$DESC_WINETRICKSURL ('WINETRICKSURL')" "${WINETRICKSURL/#-/ -}" `#CAT_Urls` `#MENU_URL` \
--field="     $GUI_X64DBGURL!$DESC_X64DBGURL ('X64DBGURL')" "${X64DBGURL/#-/ -}" `#CAT_Urls` `#MENU_URL` \
--field="     $GUI_STEAMGRIDDBAPI!$DESC_STEAMGRIDDBAPI ('STEAMGRIDDBAPI')" "${STEAMGRIDDBAPI/#-/ -}" `#CAT_Urls` `#MENU_URL` \
--field="     $GUI_CONTYRELURL!$DESC_CONTYRELURL ('CONTYRELURL')" "${CONTYRELURL/#-/ -}" `#CAT_Urls` `#MENU_URL` \
--field="     $GUI_MO2DLURL!$DESC_MO2DLURL ('MO2PROJURL')" "${MO2PROJURL/#-/ -}" `#CAT_Urls` `#MENU_URL` \
--field="     $GUI_HMMDLURL!$DESC_HMMDLURL ('HMMPROJURL')" "${HMMPROJURL/#-/ -}" `#CAT_Urls` `#MENU_URL` \
--field="     $GUI_DPRSRELURL!$DESC_DPRSRELURL ('DPRSRELURL')" "${DPRSRELURL/#-/ -}" `#CAT_Urls` `#MENU_URL` \
--field="     $GUI_DEPURL!$DESC_DEPURL ('DEPURL')" "${DEPURL/#-/ -}" `#CAT_Urls` `#MENU_URL` \
--field="$(spanFont "$GUI_OPTSVR" "H")":LBL "SKIP" `#CAT_VR` `#HEAD_VR` `#MENU_GAME` `#MENU_GLOBAL`  \
--field="     $GUI_SBSVRGEOELF!$DESC_SBSVRGEOELF ('SBSVRGEOELF')":CHK "${SBSVRGEOELF/#-/ -}" `#CAT_VR` `#SUB_Checkbox` `#SUB_ReShade` `#MENU_GAME` \
--field="     $GUI_SBSVRRS!$DESC_SBSVRRS ('SBSVRRS')":CHK "${SBSVRRS/#-/ -}" `#CAT_VR` `#SUB_Checkbox` `#SUB_ReShade` `#MENU_GAME` \
--field="     $GUI_RUNSBSVR!$DESC_RUNSBSVR ('RUNSBSVR')":CHK "${RUNSBSVR/#-/ -}" `#CAT_VR` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_SBSZOOM!$DESC_SBSZOOM ('SBSZOOM')" "${SBSZOOM/#-/ -}" `#CAT_VR` `#MENU_GAME` \
--field="     $GUI_MINVRWINH!$DESC_MINVRWINH ('MINVRWINH')":NUM "${MINVRWINH/#-/ -}" `#CAT_VR` `#MENU_GAME` \
--field="     $GUI_VRVIDEOPLAYER!$DESC_VRVIDEOPLAYER ('VRVIDEOPLAYER')":FL "${VRVIDEOPLAYER/#-/ -}" `#CAT_VR` `#MENU_GLOBAL` \
--field="     $GUI_VRVIDEOPLAYERARGS!$DESC_VRVIDEOPLAYERARGS ('VRVIDEOPLAYERARGS')" "${VRVIDEOPLAYERARGS/#-/ -}" `#CAT_VR` `#MENU_GAME` \
--field="     $GUI_WAITFORTHISPID!$DESC_WAITFORTHISPID ('WAITFORTHISPID')" "${WAITFORTHISPID/#-/ -}" `#CAT_VR` `#MENU_GAME` \
--field="     $GUI_UUUSEVR!$DESC_UUUSEVR ('UUUSEVR')":CHK "${UUUSEVR/#-/ -}" `#CAT_VR` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_USEOPENVRFSR!$DESC_USEOPENVRFSR ('USEOPENVRFSR')":CHK "${USEOPENVRFSR/#-/ -}" `#CAT_VR` `#SUB_Checkbox` `#MENU_GAME` \
--field="$(spanFont "$GUI_OPTSVORTEX" "H")":LBL "SKIP" `#CAT_Vortex` `#HEAD_Vortex` `#MENU_GAME` `#MENU_GLOBAL` \
--field="     $GUI_USEVORTEX!$DESC_USEVORTEX ('USEVORTEX')":CHK "${USEVORTEX/#-/ -}" `#CAT_Vortex` `#MENU_GAME` \
--field="     $GUI_WAITVORTEX!$DESC_WAITVORTEX ('WAITVORTEX')":NUM "${WAITVORTEX/#-/ -}" `#CAT_Vortex` `#MENU_GAME` \
--field="     $GUI_RUN_VORTEX_WINETRICKS!$DESC_RUN_VORTEX_WINETRICKS ('RUN_VORTEX_WINETRICKS')":CHK "${RUN_VORTEX_WINETRICKS/#-/ -}" `#CAT_Vortex` `#MENU_GAME` \
--field="     $GUI_RUN_VORTEX_WINECFG!$DESC_RUN_VORTEX_WINECFG ('RUN_VORTEX_WINECFG')":CHK "${RUN_VORTEX_WINECFG/#-/ -}" `#CAT_Vortex` `#MENU_GAME` \
--field="     $GUI_USEVORTEXPRERELEASE!$DESCUSEVORTEXPRERELEASE ('USEVORTEXPRERELEASE')":CHK "${USEVORTEXPRERELEASE/#-/ -}" `#CAT_Vortex` `#SUB_Checkbox` `#MENU_GLOBAL`  \
--field="     $GUI_VORTEXDOWNLOADPATH!$DESC_VORTEXDOWNLOADPATH ('VORTEXDOWNLOADPATH')":DIR "${VORTEXDOWNLOADPATH/#-/ -}" `#CAT_Vortex` `#SUB_Directories` `#MENU_GLOBAL` \
--field="     $GUI_VORTEXCOMPDATA!$DESC_VORTEXCOMPDATA ('VORTEXCOMPDATA')":DIR "${VORTEXCOMPDATA/#-/ -}" `#CAT_Vortex` `#SUB_Directories` `#MENU_GLOBAL` \
--field="     $GUI_USEVORTEXPROTON!$DESC_USEVORTEXPROTON ('USEVORTEXPROTON')":CB "$(cleanDropDown "${USEVORTEXPROTON/#-/ -}" "$PROTYADLIST")" `#CAT_Vortex` `#MENU_GLOBAL` \
--field="     $GUI_DISABLE_AUTOSTAGES!$(strFix "$DESC_DISABLE_AUTOSTAGES" "$PROGNAME") ('DISABLE_AUTOSTAGES')":CHK "${DISABLE_AUTOSTAGES/#-/ -}" `#CAT_Vortex` `#SUB_Checkbox` `#MENU_GLOBAL` \
--field="$(spanFont "$GUI_OPTSWINE" "H")":LBL "SKIP" `#CAT_Wine` `#HEAD_Wine` `#MENU_GAME` `#MENU_GLOBAL` \
--field="     $GUI_USEWINE!$DESC_USEWINE ('USEWINE')":CHK "${USEWINE/#-/ -}" `#CAT_Wine` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_WINEVERSION!$DESC_WINEVERSION ('WINEVERSION')":CBE "$(cleanDropDown "${WINEVERSION/#-/ -}" "$WINEYADLIST")" `#CAT_Wine` `#MENU_GAME` \
--field="     $GUI_WINEDEFAULT!$DESC_WINEDEFAULT ('WINEDEFAULT')":CBE "$(cleanDropDown "${WINEDEFAULT/#-/ -}" "$WINEYADLIST")" `#CAT_Wine` `#MENU_GAME` \
--field="     $GUI_RUN_WINETRICKS!$DESC_RUN_WINETRICKS ('RUN_WINETRICKS')":CHK "${RUN_WINETRICKS/#-/ -}" `#CAT_Wine` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_DLWINETRICKS!$DESC_DLWINETRICKS ('DLWINETRICKS')":CHK "${DLWINETRICKS/#-/ -}" `#CAT_Wine` `#SUB_Checkbox` `#MENU_GLOBAL` \
--field="     $GUI_WINETRICKSPAKS!$DESC_WINETRICKSPAKS ('WINETRICKSPAKS')":CBE "$(cleanDropDown "${WINETRICKSPAKS/#-/ -}" "$SOMEPOPULARWINEPAKS")" `#CAT_Wine` `#MENU_GAME` \
--field="     $GUI_RUN_WINECFG!$DESC_RUN_WINECFG ('RUN_WINECFG')":CHK "${RUN_WINECFG/#-/ -}" `#CAT_Wine` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_REGEDIT!$DESC_REGEDIT ('REGEDIT')":CHK "${REGEDIT/#-/ -}" `#CAT_Wine` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_VIRTUALDESKTOP!$DESC_VIRTUALDESKTOP ('VIRTUALDESKTOP')":CHK "${VIRTUALDESKTOP/#-/ -}" `#CAT_Wine` `#SUB_Checkbox` `#MENU_GAME`  \
--field="     $GUI_VDRES!$DESC_VDRES ('VDRES')":CBE "$(cleanDropDown "${VDRES/#-/ -}" "$(printf "%s\n" "$(listScreenRes | tr '\n' '!')")$NON")" `#CAT_Wine` `#MENU_GAME` \
--field="     $GUI_USEWICO!$DESC_USEWICO ('USEWICO')":CHK "${USEWICO/#-/ -}" `#CAT_Wine` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_STLWINEDEBUG!$DESC_STLWINEDEBUG ('STLWINEDEBUG')":CBE "$(cleanDropDown "${STLWINEDEBUG/#-/ -}" "$SOMEWINEDEBUGOPTIONS")" `#CAT_Wine` `#MENU_GAME` \
--field="     $GUI_STLWINEDLLOVERRIDES!$DESC_STLWINEDLLOVERRIDES ('STLWINEDLLOVERRIDES')":CBE "$(cleanDropDown "${STLWINEDLLOVERRIDES/#-/ -}" "$SOMEWINEDLLOVERRIDES")" `#CAT_Wine` `#MENU_GAME` \
--field="     $GUI_WINE_FULLSCREEN_INTEGER_SCALING!$DESC_WINE_FULLSCREEN_INTEGER_SCALING ('WINE_FULLSCREEN_INTEGER_SCALING')":CHK "${WINE_FULLSCREEN_INTEGER_SCALING/#-/ -}" `#CAT_Wine` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_WINE_FULLSCREEN_FSR!$DESC_WINE_FULLSCREEN_FSR ('WINE_FULLSCREEN_FSR')":CHK "${WINE_FULLSCREEN_FSR/#-/ -}" `#CAT_Wine` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_WINE_FULLSCREEN_FSR_STRENGTH!$DESC_WINE_FULLSCREEN_FSR_STRENGTH ('WINE_FULLSCREEN_FSR_STRENGTH')":NUM "${WINE_FULLSCREEN_FSR_STRENGTH/#-/ -}!0..5" `#CAT_Wine` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_WINE_FULLSCREEN_FSR_MODE!$DESC_WINE_FULLSCREEN_FSR_MODE ('WINE_FULLSCREEN_FSR_MODE')":CBE "$(cleanDropDown "${WINE_FULLSCREEN_FSR_MODE/#-/ -}" "none!performance!balanced!quality!ultra")" `#CAT_Wine` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_WINE_FULLSCREEN_FSR_CUSTOM_MODE!$DESC_WINE_FULLSCREEN_FSR_CUSTOM_MODE ('WINE_FULLSCREEN_FSR_CUSTOM_MODE')":CBE "$(cleanDropDown "${WINE_FULLSCREEN_FSR_CUSTOM_MODE/#-/ -}" "none!$(printf "%s!" "${WINE_FSR_CUSTOM_RESOLUTIONS[@]}" | sed 's/!$//')")" `#CAT_Wine` `#SUB_Checkbox` `#MENU_GAME` \
--field="     $GUI_WINEDLDIR!$DESC_WINEDLDIR ('WINEDLDIR')":DIR "${WINEDLDIR/#-/ -}" `#CAT_Wine` `#SUB_Directories` `#MENU_GLOBAL` \
--field="     $GUI_WINEEXTDIR!$DESC_WINEEXTDIR ('WINEEXTDIR')":DIR "${WINEEXTDIR/#-/ -}" `#CAT_Wine` `#SUB_Directories` `#MENU_GLOBAL` \
--field="     $GUI_WINE_LOG_DIR!$DESC_WINE_LOG_DIR ('WINE_LOG_DIR')":DIR "${WINE_LOG_DIR/#-/ -}" `#CAT_Wine` `#SUB_Directories` `#MENU_GAME` \
--field="     $GUI_ONLYWICO!$DESC_ONLYWICO ('ONLYWICO')":CHK "${ONLYWICO/#-/ -}" `#CAT_Wine` `#SUB_Checkbox` `#MENU_GAME` \
--field="$(spanFont "$GUI_OPTSMO2" "H")":LBL "SKIP" `#CAT_MO2` `#HEAD_Vortex` `#MENU_GAME` `#MENU_GLOBAL` \
--field="     $GUI_MO2COMPDATA!$DESC_MO2COMPDATA ('MO2COMPDATA')":DIR "${MO2COMPDATA/#-/ -}" `#CAT_MO2` `#SUB_Directories` `#MENU_GLOBAL` \
--field="     $GUI_USEMO2PROTON!$DESC_USEMO2PROTON ('USEMO2PROTON')":CB "$(cleanDropDown "${USEMO2PROTON/#-/ -}" "$PROTYADLIST")" `#CAT_MO2` `#MENU_GLOBAL` \
--field="     $GUI_MO2MODE!$DESC_MO2MODE ('MO2MODE')":CB "$(cleanDropDown "${MO2MODE/#-/ -}" "disabled!gui")" `#CAT_MO2` `#MENU_GAME` \
--field="     $GUI_WAITMO2!$DESC_WAITMO2 ('WAITMO2')":NUM "${WAITMO2/#-/ -}" `#CAT_MO2` `#MENU_GAME` \
#ENDSETENTRIES
}

function rmCfgTemp {
	if [ -n "$MKCFG" ]; then
		writelog "INFO" "${FUNCNAME[0]} - Deleting and resetting MKCFG '$MKCFG' - triggered from '$1'"
		rm "$MKCFG" 2>/dev/null
		unset "MKCFG"
	fi
}

function mkCfgTemp {
	rmCfgTemp "${FUNCNAME[0]}"
	MKCFG="$(mktemp "$STLSHM/menu.XXXXXXXX")"
}

function prepareMenu {
	writelog "INFO" "${FUNCNAME[0]} - Opening Menu"
	GOBACK=1

	loadCfg "$STLDEFGLOBALCFG"
	loadCfg "$STLGAMECFG"
	loadCfg "$STLURLCFG"

	resetAID "$1"
	createGameCfg
	setGN "$1"

	if [ -z "$GN" ]; then
		writelog "ERROR" "${FUNCNAME[0]} - No game name found for '$AID' - this should not happen"
		exit
	fi
	createDropdownLists
	getAvailableCfgs	
}

function openGameMenu {
	prepareMenu "$@"
	if [ -z "$2" ]; then
		FUNC="$NON"
	else
		FUNC="$2"
	fi
	PARGUI="${FUNCNAME[0]}"
	openMenu "$AID" "$FUNC" "$STLGAMECFG" "0" "$GAMEMENU" "$LGAM" "$SHOWPIC" "EMPTY" "EMPTY" "$(strFix "$GUI_SETHEAD1" "$SGNAID")" "MENU_GAME"
}

function openGameDefaultMenu {
	prepareMenu "$@"
	if [ -z "$2" ]; then
		FUNC="$NON"
	else
		FUNC="$2"
	fi
	PARGUI="${FUNCNAME[0]}"
	openMenu "$AID" "$FUNC" "$STLDEFGAMECFG" "0" "$GAMETEMPMENU" "$LGATM" "$NOICON" "EMPTY" "EMPTY" "$GUI_SETHEAD2" "MENU_GAME"
}

function openGlobalMenu {
	prepareMenu "$@"
	autoBumpReShade
	if [ -z "$2" ]; then
		FUNC="$NON"
	else
		FUNC="$2"
	fi
	PARGUI="${FUNCNAME[0]}"
	openMenu "$AID" "$FUNC" "$STLDEFGLOBALCFG" "0" "$GLOBALMENU" "$LGLM" "$NOICON" "EMPTY" "EMPTY" "$GUI_SETHEAD3" "MENU_GLOBAL"
}

function startSteamGame {
	if [ "$ISGAME" -ge 1 ]; then
		writelog "INFO" "${FUNCNAME[0]} - Starting game"
	else
		if [ "$ISGAME" -ne 1 ] && [ "$AID" != "$PLACEHOLDERAID" ]; then
			STEAMARGS=(-applaunch "$AID")
			writelog "INFO" "${FUNCNAME[0]} - -------- starting game $AID in steam --------" "E"
			FINALSTARTCMD=("$STEAM" "${STEAMARGS[@]}")
			startGame "${FINALSTARTCMD[@]}" 2>/dev/null >/dev/null &
		fi
	fi	
}

function openCustMenu {
	MYCAT="$3"
	MYMENU="$4"
	MYFUNC="$5"

	prepareMenu "$@"

	createGameCfg
	createDropdownLists

	TITLE="${PROGNAME}-${MYCAT}"
	pollWinRes "$TITLE" 1

	setShowPic
	cp "$SHOWPIC" "$FAVPIC"

	mkCfgTemp "${FUNCNAME[0]}"

	if [ "$2" == "$NON" ]; then
		BUT0="$BUT_EXIT"
		GOTO="Exit"
	else
		BUT0="$BUT_BACK"
		GOTO="$2"
	fi

	BUT2="$BUT_MAINMENU"
	BUT4="$BUT_RELOAD"
	BUT6="$BUT_SAVERELOAD"
	BUT8="$BUT_SAVEPLAY"
	BUT10="$BUT_PLAY"
	
	MYTMPL="${MYMENU}-${TMPL}"

	if [ "$MYCAT" == "Favorites" ]; then
		MYTEXT="$(strFix "$GUI_FAVORITESMENU" "$SGNAID")"
	else
		MYTEXT="$(strFix "$GUI_CATMENU" "$SGNAID" "$MYCAT")"
		if [ ! -f "$MYTMPL" ]; then
			grep "CAT_${MYCAT}" "$STLRAWENTRIES" > "$MYTMPL"
		fi
	fi

	# shellcheck disable=SC2028 # doesn't like the newline seperator, but it is valid
	{
		echo "function $MYFUNC {"
		echo "\"$YAD\" --columns=\"$COLCOUNT\" --f1-action=\"$F1ACTIONCG\" --text=\"$(spanFont "$MYTEXT" "H")\" \\"
		echo "--title=\"$TITLE\" --image \"$FAVPIC\" --image-on-top --window-icon=\"$STLICON\" --center $WINDECO --form --separator=\"\\n\" --quoted-output \\"
		echo "--button=\"$BUT0\":0 --button=\"$BUT2\":2 --button=\"$BUT4\":4 --button=\"$BUT6\":6 --button=\"$BUT8\":8 --button=\"$BUT10\":10 $GEOM \\"
		cat "$MYTMPL"
		echo "--scroll"
		echo "}"
	} >"$MYMENU"
	
	source "$MYMENU"
	
	if [ -z "$MYFUNC" ]; then
		writelog "SKIP" "${FUNCNAME[0]} - Seems like some arguments are missing - got '$*'"
	else
		"$MYFUNC" > "$MKCFG"
		case $? in
		0)  {
				clickInfo "${FUNCNAME[0]}" "$?" "$BUT0" "Category '$MYCAT' Menu" "$GOTO"
				if [ "$GOTO" == "Exit" ]; then
					GOBACK=0
					closeSTL " ######### STOP EARLY $PROGNAME $PROGVERS #########"
					exit
				else
					rmCfgTemp "${FUNCNAME[0]}"
				fi
			}
		;;
		2) 	{
				clickInfo "${FUNCNAME[0]}" "$?" "$BUT2" "Category '$MYCAT' Menu" "$SETMENU"
				MainMenu "$AID" "${FUNCNAME[0]}"
			}
		;;
		4) 	{
				clickInfo "${FUNCNAME[0]}" "$?" "$BUT4" "Category '$MYCAT' Menu" "restart Menu"
				GOBACK=0
				writelog "INFO" "${FUNCNAME[0]} - Reload Configs and restart Category '$MYCAT' Menu"
				if [ "$SAVESETSIZE" -eq 1 ] ; then	sleep 1;	fi
				"${FUNCNAME[0]}" "$@"
			}
		;;
		6) {
				clickInfo "${FUNCNAME[0]}" "$?" "$BUT6" "Category '$MYCAT' Menu" "restart Menu"
				GOBACK=0
				saveMenuEntries "$MYMENU"
				if [ "$SAVESETSIZE" -eq 1 ] ; then	sleep 1;	fi
				
				if [ "$MYCAT" == "$GCD" ];then
					setGameCfgDiffs
				fi
				"${FUNCNAME[0]}" "$@"
			}
		;;
		8) 	{
				clickInfo "${FUNCNAME[0]}" "$?" "$BUT8" "Category '$MYCAT' Menu" "Game Start"
				GOBACK=0
				saveMenuEntries "$MYMENU"
				startSteamGame
			}
		;;
		10)	{
				clickInfo "${FUNCNAME[0]}" "$?" "$BUT10" "Category '$MYCAT' Menu" "Game Start"
				GOBACK=0
				startSteamGame
			}
		;;
		esac
		rmCfgTemp "${FUNCNAME[0]}"
		goBackToPrevFunction "${FUNCNAME[0]}" "$2" "$GOBACK"
	fi
}

function setGuiSortOrder {
	if [ ! -f "$STLMENUSORTCFG" ]; then
		writelog "INFO" "${FUNCNAME[0]} - '$STLMENUSORTCFG' missing"
		getCatsFromCode > "$STLMENUSORTCFG" 2>/dev/null
	fi
	export CURWIKI="$PPW/Gui-Sort-Order"
	TITLE="${PROGNAME}-SortCategories"
	pollWinRes "$TITLE"

	NEWSORT="$("$YAD" --f1-action="$F1ACTION" --window-icon="$STLICON" --center --on-top "$WINDECO" \
		--list --editable --column "Category" --separator="" --print-all \
		--title="$TITLE" --text="$(spanFont "$GUI_SORTCAT" "H")" $GEOM < "$STLMENUSORTCFG")"
	case $? in
		0) 	{
				writelog "INFO" "${FUNCNAME[0]} - Clicked OK - Saving new sortorder into '$STLMENUSORTCFG'"
				echo "$NEWSORT" > "$STLMENUSORTCFG"
			}
		;;
		1)	{
				writelog "INFO" "${FUNCNAME[0]} - Clicked Cancel"
			}
		;;
	esac
}

function setGuiFavoritesSelection {
	export CURWIKI="$PPW/Favorites-Menu"
	TITLE="${PROGNAME}-FavoritesSelection"
	pollWinRes "$TITLE"

	setShowPic

	FAVENTRIES="$(favoritesMenuEntries | \
	"$YAD" --f1-action="$F1ACTION" --image "$SHOWPIC" --image-on-top --window-icon="$STLICON" --center $WINDECO --list --checklist \
	--column="$GUI_ADD" --column="$GUI_DESC" --column="$GUI_VAR" --column="LongDesc" --separator="\n" --print-column="3" --tooltip-column 4 --hide-column 4 \
	--text="$(spanFont "$GUI_FAVORITESSEL" "H")" --title="$TITLE" "$GEOM")"
	case $? in
		0)  {
				if [ -n "$FAVENTRIES" ]; then
					writelog "INFO" "${FUNCNAME[0]} - Updating '$STLFAVMENUCFG' with selected Favorites"
					echo "${FAVENTRIES[@]}" > "$STLFAVMENUCFG"
					sort -u "$STLFAVMENUCFG" -o "$STLFAVMENUCFG"
					rm "${FAVMENU}-${TMPL}" 2>/dev/null
				else
					writelog "INFO" "${FUNCNAME[0]} - Nothing selected"
				fi
			}
		;;
		1)  {
				writelog "INFO" "${FUNCNAME[0]} - Selected CANCEL - creating empty '$STLFAVMENUCFG' to skip asking again"
				touch "$STLFAVMENUCFG"
			}
		;;
	esac

	goBackToPrevFunction "${FUNCNAME[0]}" "$2"
}

function setGuiBlockSelection {
	export CURWIKI="$PPW/Gui-Hide-Categories"
	TITLE="${PROGNAME}-EntryBlockSelection"
	pollWinRes "$TITLE"

	BLENTRIES="$(createBlockYadList | \
	"$YAD" --f1-action="$F1ACTION" --window-icon="$STLICON" --center --list --checklist \
	--column="$GUI_HIDE" --column="$GUI_DESC" --separator=" " --print-column="2" \
	--text="$(spanFont "$GUI_BLOCKSEL" "H")" --title="$TITLE" "$GEOM")"
	case $? in
		0)  {
				writelog "INFO" "${FUNCNAME[0]} - Updating '$STLMENUBLOCKCFG' with selected blocks"
				while read -r blentry; do
					if grep -q "$blentry" <<< "$(printf '%s\n' "$BLENTRIES")"; then
						updateConfigEntry "$blentry" "TRUE" "$STLMENUBLOCKCFG"
					else
						updateConfigEntry "$blentry" "FALSE" "$STLMENUBLOCKCFG"
					fi
				done <<< "$(grep -v "^#" "$STLMENUBLOCKCFG" | cut -d '=' -f1)"

				checkEntryBlocklist
			}
		;;
		1)  writelog "INFO" "${FUNCNAME[0]} - Selected CANCEL"
		;;
	esac

	goBackToPrevFunction "${FUNCNAME[0]}" "$2"
}

function setGameCfgDiffs {
	writelog "INFO" "${FUNCNAME[0]} - Getting changes between game config and default"
	CHTEMP="$STLSHM/${AID}_cfgchanges.txt"
	comm -13 <(grep -v "^#" "$STLDEFGAMECFG" | grep "=" | sort -u) <(grep -v "^#" "$STLGAMECFG" | grep "=" | sort -u) > "$CHTEMP"
	rm "$MTEMP/$GCD" "$MTEMP/$GCD-${TMPL}" 2>/dev/null

	while read -r change; do
		GVAR="${change%=*}"
		TVAL="$(grep "^${GVAR}=" "$STLDEFGAMECFG" | cut -d '=' -f2)"
		TVALO="${TVAL//\"/}"
		if [ -n "$TVAL" ];then
			FRLI="$(sed -n "/^#STARTSETENTRIES/,/^#ENDSETENTRIES/p;/^#ENDSETENTRIES/q" "$0" | grep "'$GVAR'")"
			FRL1="${FRLI//\')/\') - $GUI_TEMPVAL $TVALO}"
			echo "$FRL1" >> "$MTEMP/$GCD-${TMPL}"
		fi
	done < "$CHTEMP"
	sed '/^$/d' -i "$MTEMP/$GCD-${TMPL}"
}

function setGuiCategoryMenuSel {
	export CURWIKI="$PPW/Category-Menus"
	TITLE="${PROGNAME}-CategorySelection"
	pollWinRes "$TITLE"

	setShowPic
	
	CATDD="$(cleanDropDown "${GCD}" "$(getCatsFromCode | tr '\n' '!' | sed "s:^!::" | sed "s:!$::")")"

	SELECTCAT="$("$YAD" --f1-action="$F1ACTION" --image "$SHOWPIC" --image-on-top --window-icon="$STLICON" --center $WINDECO --form --separator="\n" \
	--text="$(spanFont "$(strFix "$GUI_CATSEL" "$PROGNAME")" "H")" \
	--title="$TITLE" --field=" $GUI_CAT!$(strFix "$GUI_CATSEL" "$PROGNAME")":CB "$CATDD" "$GEOM")"
	case $? in
		0)  {
				if [ "$SELECTCAT" == "$GCD" ]; then
					setGameCfgDiffs
				fi

				writelog "INFO" "${FUNCNAME[0]} - Selected '$SELECTCAT' - Opening Category Menu"
				openCustMenu "$AID" "${FUNCNAME[0]}" "$SELECTCAT" "$MTEMP/$SELECTCAT" "$LCM"
			}
		;;
		1)  {
				writelog "INFO" "${FUNCNAME[0]} - Nothing selected - going to the $SETMENU"
				MainMenu "$AID" "${FUNCNAME[0]}"
			}
		;;
	esac
}

function clickInfo {
	writelog "INFO" "$1 - Clicked '$2' - '$3'"
	writelog "INFO" "$1 - exiting '$4' and opening '$5'"
}

function getLaPl {
	if [ -f "$PLAYTIMELOGDIR/$GN.log" ]; then
		echo "<b>$GUI_LASTPLAYED</b> $(tail -n1 "$PLAYTIMELOGDIR/${GN}.log")"
	fi	
}

function fixShowGnAid {
	local PRETTYGAMENAME

    # Temp workaround to fix some games not launching because of locale bugs, particularly on Steam Deck
    # Not limited to Steam Deck since this could prevent future bug reports
    # May cause other bugs so keep an eye on this, but probably this is broken because of KDE not correctly setting all locales? Seems to affect KDE on Arch primarily
    if [ -n "$LANG" ]; then
        export LC_ALL="$LANG"  # $LANG should always be defined, unless locales are VERY broken
    fi

	# Will use "real" game name if it exists, e.g. "NieR:Automata" instead of NieRAutomata
	PRETTYGAMENAME="$( getTitleFromID "$AID" )"
	if [ -n "$PRETTYGAMENAME" ]; then
		SGNAID="$PRETTYGAMENAME ($AID)"
		SGNAID="${SGNAID//&/+}"
	elif [ -n "$GN" ]; then
		SGNAID="$GN ($AID)"
		SGNAID="${SGNAID//&/+}"
	else
		SGNAID="$PLACEHOLDERGN ($PLACEHOLDERAID)"
	fi
}

function fixShow {
	echo "${1//&/+}"
}

function setShadDestDir {
	autoCollectionSettings
	
	if [ "$USESPECIALK" -eq 1 ] && [ "$USERESHADE" -eq 1 ]; then
		writelog "INFO" "${FUNCNAME[0]} - Both '$SPEK' and '$RESH' are enabled." "E"
		writelog "INFO" "${FUNCNAME[0]} - Unfortunately the game currently crashes using Proton when both are enabled"
		writelog "INFO" "${FUNCNAME[0]} - therefore $RESH path redirect to the $SPEK directory is disabled" "E"
#		SPEKRESHDIR="My Mods/${SPEK}/Plugins/ThirdParty/${RESH}"
#		SHADDESTDIR="$GPFX/$DRCU/$STUS/$DOCS/$SPEKRESHDIR"
#	else
	fi
		# setFullGameExePath "SHADDESTDIR"
#	fi
	setFullGameExePath "SHADDESTDIR"
}

function refreshProtList {
	if [ -f "$PROTBUMPTEMP" ]; then
		rm "$PROTONCSV" 2>/dev/null
		unset ProtonCSV
		rm "$PROTBUMPTEMP" 2>/dev/null
		createProtonList X
	fi	
}

function MainMenu {
	writelog "INFO" "${FUNCNAME[0]} - Preparing to load Main Menu"

	createDLSpekList
	createDLReShadeList
	prepareMenu "$@"

	setShowPic
	
	setHuyList
	setOPCustPath

	fixCustomMeta "$CUMETA/$AID.conf" # will be removed again later
	loadCfg "$CUMETA/$AID.conf" X
	loadCfg "$GEMETA/$AID.conf" X

	export CURWIKI="$PPW/Main-Menu"
	TITLE="${PROGNAME}-MainMenu"
	if [ "$ONSTEAMDECK" -eq 1 ]; then
		pollWinRes "$TITLE" 2
	else
		pollWinRes "$TITLE" 4
	fi
	fixShowGnAid

	if [ -z "$STEAMDECKCOMPATRATING" ]; then
		prepareSteamDeckCompatInfo  # Only fetches data once, we might already have it from askSettings so don't fetch again - Minor optimisation
	fi

	LAPL="$(getLaPl)"
	SETHEAD="$(spanFont "${PROGNAME} (${PROGNAME,,}) - ${PROGVERS} \n \n$SGNAID" "H")"

	TT_OPENURL="Help Url Gui"

	# Last played date/time with STL
	if [ -n "$LAPL" ]; then
		writelog "INFO" "${FUNCNAME[0]} - Game Info Gotten!"
		SETHEAD="${SETHEAD}\n<i>$LAPL</i>"
	fi

	# Game config file info
	# TODO hide if no gamecfgs - Maybe this check needs an overhaul?
	SETHEAD="${SETHEAD}\n<i>(${#CfgFiles[@]} $GUI_EDITABLECFGS)\n($GUI_EDITABLEGAMECFGS)</i>"

	# Show Steam Deck compatibility on Main Menu when in Steam Deck Desktop Mode
	if [ "$SMALLDESK" -eq 1 ]; then
		SETHEAD="$SETHEAD \n<b>${GUI_SDCR}:</b> $STEAMDECKCOMPATRATING"
	fi

	if [ "$SMALLDESK" -eq 0 ]; then
		if [ -n "$DEVELOPER" ]; then
			SETHEAD="$SETHEAD \n\n<b>${GUI_DEV}:</b> $DEVELOPER"
		fi

		if [ -n "$PUBLISHER" ]; then
			SETHEAD="$SETHEAD \n<b>${GUI_PUB}:</b> $PUBLISHER"
		fi
	
		prepareProtonDBRating
		getGameFiles "$AID"
		setGameFilesArray
		TT_GAFI="$( printf "<u>%s</u>" "${GUI_GAFI}" )"
		TT_GAFI="${TT_GAFI}$(for i in "${!GamFiles[@]}"; do printf "\n<b>%s</b>: %s" "${GamDesc[$i]}" "${GamFiles[$i]}"; done)"

		# Only shown on the Game Files tooltip
		if [ -n "$METACRITIC_SCORE" ] && ! grep -q "^${GUI_MCS}" "$PDBRAINFO"; then
			echo "<b>${GUI_MCS}:</b> $METACRITIC_SCORE" >> "$PDBRAINFO"
		fi
		
		if [ -n "$OSLIST" ] && ! grep -q "${GUI_OSL}" "$PDBRAINFO"; then
			echo "<b>${GUI_OSL}</b>: $OSLIST" >> "$PDBRAINFO"
		fi
		
		if [ -f "$PDBRAINFO" ] && grep -q "[0-9]" "$PDBRAINFO" ;then
			SETHEAD="$SETHEAD \n $(cat "$PDBRASINF")"
			TT_OPENURL="$(cat "$PDBRAINFO")"
		fi

		if [ -n "$STEAMDECKCOMPATRATING" ]; then
			SETHEAD="$SETHEAD \n<b>${GUI_SDCR}:</b> $STEAMDECKCOMPATRATING"
		fi

		if [ -L "$GPFX/$DRCU/$STUS" ]; then
			SETHEAD="$SETHEAD \n<b>${GUI_SSU}:</b> symlink to $(readlink "$GPFX/$DRCU/$STUS")"
		fi

		if [ "$ISORIGIN" -eq 1 ]; then
			SETHEAD="$SETHEAD \n<b>${GUI_SGW}:</b> Origin interfering"
		else
			if [ -n "$GAMEWINDOW" ] && [ "$GAMEWINDOW" != "$NON" ]; then
				SETHEAD="$SETHEAD \n<b>${GUI_SGW}:</b> $(fixShow "$GAMEWINDOW")"
			fi	
		fi
		
		if [ -n "$GAMEEXE" ]; then
			SETHEAD="$SETHEAD \n<b>${GUI_SGE}:</b> $GAMEEXE"
		fi

		if [ "$ISORIGIN" -eq 1 ]; then
			SETHEAD="$SETHEAD \n<b>${GUI_SGA}:</b> Origin $L2EA url"
		else
			if [ "${#ORGCMDARGS[@]}" -ge 1 ]; then
				SETHEAD="$SETHEAD \n<b>${GUI_SGA}:</b> ${ORGCMDARGS[*]}"
			fi
		fi
	fi
	# filter html incompatible chars here
	#SETHEAD="${SETHEAD//&/+}"
	
	createProtonList X

	"$YAD" --f1-action="$F1ACTION" --image "$SHOWPIC" --image-on-top --scroll --center --window-icon="$STLICON" --form --center "$WINDECO" --title="$TITLE" \
	--text="$SETHEAD" \
	--columns="$COLCOUNT" --f1-action="$F1ACTIONCG" --separator="" \
	--field="$FBUT_GUISET_DCP":FBTN "$(realpath "$0") dcp" \
	--field="$FBUT_GUISET_DW":FBTN "$(realpath "$0") dw" \
	--field="$FBUT_GUISET_RECREATEPFX":FBTN "$(realpath "$0") ccd \"$AID\" \"s\"" \
	--field="$FBUT_GUISET_WDC":FBTN "$(realpath "$0") wdc \"$AID\"" \
	--field="$FBUT_GUISET_WTSEL":FBTN "$(realpath "$0") wt \"$AID\"" \
	--field="$FBUT_GUISET_ADDNSGA":FBTN "$(realpath "$0") ansg" \
	--field="$FBUT_GUISET_CREATEEVALSC":FBTN "$(realpath "$0") cfi \"$AID\"" \
	--field="$FBUT_GUISET_OTR":FBTN "$(realpath "$0") otr \"$AID\"" \
	--field="$FBUT_GUISET_DXHSEL":FBTN "$(realpath "$0") dxh \"$AID\"" \
	--field="$FBUT_GUISET_SHADERREPOS":FBTN "$(realpath "$0") update shaders repos" \
	--field="$FBUT_GUISET_UPSHADER":FBTN "$(realpath "$0") update gameshaders \"$SHADDESTDIR\"" \
	--field="$FBUT_GUISET_FAVSEL":FBTN "$(realpath "$0") fav \"$AID\" set"\
	--field="$FBUT_GUISET_BLOCKCAT":FBTN "$(realpath "$0") block" \
	--field="$FBUT_GUISET_SORTCAT":FBTN "$(realpath "$0") sort" \
	--field="$FBUT_GUISET_OPURL!$TT_OPENURL":FBTN "$(realpath "$0") hu \"$AID\" X" \
	--field="$FBUT_GUISET_GASCO":FBTN "$(realpath "$0") gs \"$AID\" \"$GN\"" \
	--field="$FBUT_GUISET_VORTEX":FBTN "$(realpath "$0") vortex gui" \
	--field="$FBUT_GUISET_MO":FBTN "$(realpath "$0") mo2 start" \
	--field="$FBUT_GUISET_WIKI":FBTN "$(realpath "$0") wiki" \
	--field="$GUI_GAFI!$TT_GAFI":FBTN "$(realpath "$0") gf \"$AID\"" \
	--button="$BUT_EXIT":0 \
	--button="$BUT_GUISET_CATMENUSHORT":4 \
	--button="$BUT_GM":6 \
	--button="$BUT_DGM":8 \
	--button="$BUT_GLM":10 \
	--button="$BUT_FAV":12 \
	--button="$BUT_EDITORMENU":14 \
	--button="$BUT_PLAY":16 \
	"$GEOM"
	case $? in
	0)  {
			clickInfo "${FUNCNAME[0]}" "$?" "$BUT_EXIT" "$SETMENU" "Exit"
			GOBACK=0
			closeSTL " ######### STOP EARLY $PROGNAME $PROGVERS #########"
			exit
		}
	;;
	4) 	{
			clickInfo "${FUNCNAME[0]}" "$?" "$BUT_GUISET_CATMENUSHORT" "$SETMENU" "Category Menu Selection"
			refreshProtList
			setGuiCategoryMenuSel "$AID" "${FUNCNAME[0]}"
		}
	;;
	6) 	{
			clickInfo "${FUNCNAME[0]}" "$?" "$BUT_GM" "$SETMENU" "$GAMMENU"
			refreshProtList
			openGameMenu "$AID" "${FUNCNAME[0]}"
		}
	;;
	8) 	{
			clickInfo "${FUNCNAME[0]}" "$?" "$BUT_DGM" "$SETMENU" "Game Default Menu"
			refreshProtList
			openGameDefaultMenu "$AID" "${FUNCNAME[0]}"
		}
	;;
	10) 	{
			clickInfo "${FUNCNAME[0]}" "$?" "$BUT_GLM" "$SETMENU" "Global Menu"
			refreshProtList
			openGlobalMenu "$AID" "${FUNCNAME[0]}" "1"
		}
	;;
	12) 	{
			clickInfo "${FUNCNAME[0]}" "$?" "$BUT_FAV" "$SETMENU" "Favorites"
			refreshProtList
			favoritesMenu "$AID" "${FUNCNAME[0]}"
		}
	;;
	14) 	{
			clickInfo "${FUNCNAME[0]}" "$?" "$BUT_EDITORMENU" "$SETMENU" "EditorDialog"
			EditorDialog "$AID" "${FUNCNAME[0]}"
		}
	;;
	16) 	{
			clickInfo "${FUNCNAME[0]}" "$?" "$BUT_PLAY" "$SETMENU" "Game"
			GOBACK=0
			startSteamGame
		}
	;;
	esac 

	goBackToPrevFunction "${FUNCNAME[0]}" "$2" "$GOBACK"
}

function createBlockYadList {
	checkEntryBlocklist
	while read -r block; do
		BLCAT="${block%=*}"
		BLVALR="${block#*=}"
		BLVAL="${BLVALR//\"/}"
		if [ "$BLVAL" -eq 1 ] ; then
			echo TRUE
			echo "$BLCAT"
		else
			echo FALSE
			echo "$BLCAT"
		fi
	done <<< "$(grep -v "^#" "$STLMENUBLOCKCFG" | grep "=")"
}

function getCatsFromCode {
	sed "s:CAT_:\nCAT_:g" "$STLRAWENTRIES" | grep "^CAT_" | cut -d '`' -f1 | cut -d '_' -f2 | sort -u
}

function updateMenuSortFile {
	if [ -f "$STLMENUSORTCFG" ] && [ -s "$STLMENUSORTCFG" ]; then
		while read -r catent; do
			if ! grep -q "^$catent" "$STLMENUSORTCFG"; then
				writelog "INFO" "${FUNCNAME[0]} - Adding missing Category '$catent' to '$STLMENUSORTCFG'"
				echo "$catent" >> "$STLMENUSORTCFG"
			fi
		done <<< "$(getCatsFromCode)"
	fi
}

function checkEntryBlocklist {
	# create blocklist with disabled categories
	if [ ! -f "$STLMENUBLOCKCFG" ]; then
		echo "#All enabled categories will be hidden in the menus" >"$STLMENUBLOCKCFG"
		while read -r block; do
			echo "${block}=\"0\"" >> "$STLMENUBLOCKCFG"
		done <<< "$(getCatsFromCode)"
	fi

	if [ -f "$STLMENUBLOCKCFG" ]; then
		# autoadding new (commented out) categories
		while read -r block; do
			if ! grep -q "^${block}" "$STLMENUBLOCKCFG"; then
				echo "${block}=\"0\"" >> "$STLMENUBLOCKCFG"
			fi
		done <<< "$(getCatsFromCode)"
		
		# create validity check file
		if [ ! -f "$STLMENUVALBLOCKCFG" ]; then
			cp "$STLMENUBLOCKCFG" "$STLMENUVALBLOCKCFG"
		fi
		
		# if validity check file differs - remove temporary menu files
		if ! cmp -s "$STLMENUBLOCKCFG" "$STLMENUVALBLOCKCFG"; then
			writelog "INFO" "${FUNCNAME[0]} - Removing temp menufiles in '$STLSHM'"
			find "$MTEMP" -maxdepth 1 -type f -name "*menu*" -exec rm {} \;
			cp "$STLMENUBLOCKCFG" "$STLMENUVALBLOCKCFG"
		fi
	fi
}

function getFilteredEntries {
	if [ -z "$1" ]; then
		INLIST="$STLRAWENTRIES"
	else
		INLIST="$1"
	fi

	# first remove blocked entries
	if grep -q "=\"1\"" "$STLMENUBLOCKCFG"; then
		writelog "INFO" "${FUNCNAME[0]} - Excluding blocked elements from '$STLMENUBLOCKCFG'"
		unset BlockCats
		while read -r line; do
			mapfile -t -O "${#BlockCats[@]}" BlockCats <<< "CAT_${line}"
		done <<< "$(grep "=\"1\"" "$STLMENUBLOCKCFG" | cut -d '=' -f1)"

		while read -r outline; do
			INCAT="CAT_$(grep -oP '#CAT_\K[^`]+' <<< "${outline}")"
			if [[ ! "${BlockCats[*]}" =~ $INCAT ]]; then
				echo "$outline" >> "$STLNOBLOCKENTRIES"
			fi
		done < "$INLIST"
	else
		writelog "INFO" "${FUNCNAME[0]} - No blocked elements found in '$STLMENUBLOCKCFG' - working with '$INLIST'"
		cp "$INLIST" "$STLNOBLOCKENTRIES"
	fi

	# now the sort order
	if [ ! -f "$STLMENUSORTCFG" ]; then
		writelog "INFO" "${FUNCNAME[0]} - '$STLMENUSORTCFG' missing - creating a default one"
		getCatsFromCode > "$STLMENUSORTCFG" 2>/dev/null
	fi
	
	writelog "INFO" "${FUNCNAME[0]} - Sort config '$STLMENUSORTCFG' found - sorting"

	while read -r line; do
		if [ -n "$line" ]; then
			grep "\`#CAT_${line}\`" "$STLNOBLOCKENTRIES" >> "$STLCATSORTENTRIES"
		fi
	done < "$STLMENUSORTCFG"
	cat "$STLCATSORTENTRIES"
	rm "$STLNOBLOCKENTRIES" 2>/dev/null
	rm "$STLCATSORTENTRIES" 2>/dev/null
}

function splitMenu {
	ARGSPLIT="$1"
	MYTMPL="$2"
	if [ "$ARGSPLIT" -gt 0 ]; then
		FUCO="$(wc -l < "$MYTMPL")"
		CUTCO=$((FUCO / 2 ))
		RESTCO=$((FUCO - CUTCO))
		head -n "$CUTCO" "$MYTMPL" > "${MYTMPL}_${ARGSPLIT}"

		if [ "$ARGSPLIT" -eq 1 ]; then
			writelog "INFO" "${FUNCNAME[0]} - ARGSPLIT is set to '$ARGSPLIT' - so using first half of '$MYTMPL' for the menu"
			head -n "$CUTCO" "$MYTMPL" > "${MYTMPL}_${ARGSPLIT}"
			mv "${MYTMPL}_${ARGSPLIT}" "$MYTMPL"
		elif [ "$ARGSPLIT" -eq 2 ]; then
			writelog "INFO" "${FUNCNAME[0]} - ARGSPLIT is set to '$ARGSPLIT' - so using second half of '$MYTMPL' for the menu"
			head -n "$CUTCO" "$MYTMPL" | grep "#HEAD" | tail -n 1 > "${MYTMPL}_${ARGSPLIT}"
			tail -n "$RESTCO" "$MYTMPL" >> "${MYTMPL}_${ARGSPLIT}"
			mv "${MYTMPL}_${ARGSPLIT}" "$MYTMPL"
		else
			writelog "INFO" "${FUNCNAME[0]} - ARGSPLIT is set to '$ARGSPLIT' - so using the whole '$MYTMPL' for the menu"
		fi
	fi
}

function createMenu {
	ARGSPLIT="$1"
	ARGMENU="$2"
	ARGFUNC="$3"
	ARGPIC="$4"
	UNUSED="$5"
	ARGCOLS="$6"
	ARGTITLE="$7"
	ARGPCMD="$8"
	ARGSPAT="$9"

	NEEDARG="9"

	MYTMPL="${ARGMENU}-${TMPL}"

	if [ "$#" -ne "$NEEDARG" ]; then
		writelog "ERROR" "${FUNCNAME[0]} - Need $NEEDARG arguments and got '$#':"
		writelog "ERROR" "${FUNCNAME[0]} - '$*'"
	else
		writelog "INFO" "${FUNCNAME[0]} - got '$#' elements: '$*'"
	fi
	
	if [ ! -f "$MYTMPL" ] || [ ! -s "$MYTMPL" ]; then
		writelog "INFO" "${FUNCNAME[0]} - Creating menu template '$MYTMPL'"
		getFilteredEntries "$STLRAWENTRIES" | grep "$ARGSPAT" > "$MYTMPL"
		rmDupLines "$MYTMPL"
		splitMenu "$ARGSPLIT" "$MYTMPL"
	fi

	if [ "$ARGPCMD" == "$NON" ]; then
		QBUT0="$BUT_EXIT"
	else
		QBUT0="$BUT_BACK"
	fi

	TITLE="${PROGNAME}-$ARGFUNC"

	echo "" >"$ARGMENU"
	# shellcheck disable=SC2028 # doesn't like the newline seperator, but it is valid
	{
		echo "function $ARGFUNC {"
		echo "\"$YAD\" --columns=\"$COLCOUNT\" --f1-action=\"$F1ACTIONCG\" --text=\"$(spanFont "$ARGTITLE" "H")\" \\"
		echo "--title=\"$TITLE\" --image \"$ARGPIC\" --image-on-top --window-icon=\"$STLICON\" --center \"$WINDECO\" --form --separator=\"\\n\" --quoted-output \\"
		echo "--button=\"$QBUT0\":0 --button=\"$BUT_MAINMENU\":2 --button=\"$BUT_RELOAD\":4 --button=\"$BUT_SAVERELOAD\":6 --button=\"$BUT_SAVEPLAY\":8 --button=\"$BUT_PLAY\":10 $GEOM \\"
		cat "$MYTMPL"
		echo "--scroll"
		echo "}"
	} >>"$ARGMENU"
}

function openMenu {
	ARGID="$1"
	ARGPCMD="$2"		# "$9"
	ARGLOADCFG="$3"
	# most args for createMenu:
	ARGSPLIT="$4"
	ARGMENU="$5"
	ARGFUNC="$6"
	ARGPIC="$7"
	UNUSED="$8"
	ARGCOLS="$9"
	ARGTITLE="${10}"
	ARGSPAT="${11}"
	 
	resetAID "$ARGID"
	createGameCfg
	setGN "$ARGID"
	createDropdownLists

	mkCfgTemp "${FUNCNAME[0]}"
	
	if [ "$LOADCFG" == "$STLGAMECFG" ] ; then
		setShowPic
	fi

	loadCfg "$ARGLOADCFG" X

	TITLE="${PROGNAME}-$ARGFUNC"
	pollWinRes "$TITLE"
	
	writelog "INFO" "${FUNCNAME[0]} - Starting createMenu \"$ARGMENU\" \"$ARGFUNC\" \"$ARGPIC\" \"$UNUSED\" \"$ARGCOLS\" \"$ARGTITLE\" \"$ARGPCMD\" \"$ARGSPAT\""
	createMenu "$ARGSPLIT" "$ARGMENU" "$ARGFUNC" "$ARGPIC" "$UNUSED" "$ARGCOLS" "$ARGTITLE" "$ARGPCMD" "$ARGSPAT"

	source "$ARGMENU"
	writelog "INFO" "${FUNCNAME[0]} - Currently used tempfile is '$MKCFG'"
	"$ARGFUNC" > "$MKCFG"
	
	case $? in
	0) 	{
			if [ "$ARGPCMD" == "$NON" ]; then
				clickInfo "${FUNCNAME[0]}" "$?" "$QBUT0" "$GAMMENU" "Exit"
				GOBACK=0
				closeSTL " ######### STOP EARLY $PROGNAME $PROGVERS #########"
				exit
			else
				clickInfo "${FUNCNAME[0]}" "$?" "$QBUT0" "$GAMMENU" "$ARGPCMD"
				"$ARGPCMD" "$AID" "${FUNCNAME[0]}"
			fi
		}
	;;
	2)  {
			clickInfo "${FUNCNAME[0]}" "$?" "$BUT_MAINMENU" "$FAVOMENU" "$SETMENU"
			MainMenu "$AID" "${FUNCNAME[0]}"
		}
	;;
	4) 	{
			GOBACK=0
			clickInfo "${FUNCNAME[0]}" "$?" "$BUT_RELOAD" "$FAVOMENU" "$PARGUI"
			if [ "$SAVESETSIZE" -eq 1 ] ; then	sleep 1;	fi
			"$PARGUI" "$AID" "$ARGPCMD" "$ARGSPLIT"
		}
	;;
	6) 	{
			clickInfo "${FUNCNAME[0]}" "$?" "$BUT_SAVERELOAD" "$FAVOMENU" "$PARGUI"
			GOBACK=0
			writelog "INFO" "${FUNCNAME[0]} - Saving config '$ARGLOADCFG' and restart '$PARGUI' GUI"
			saveMenuEntries "$ARGMENU"
			if [ "$SAVESETSIZE" -eq 1 ] ; then	sleep 1;	fi
			"$PARGUI" "$AID" "$ARGPCMD" "$ARGSPLIT"
		}
	;;
	8)  {
			clickInfo "${FUNCNAME[0]}" "$?" "$BUT_SAVEPLAY" "$FAVOMENU" "Game Start"
			GOBACK=0
			writelog "INFO" "${FUNCNAME[0]} - Saving config '$ARGLOADCFG' and starting the game"
			saveMenuEntries "$ARGMENU"
			startSteamGame
		}
	;;
	10)	{
			clickInfo "${FUNCNAME[0]}" "$?" "$BUT_PLAY" "$FAVOMENU" "Game Start"
			GOBACK=0
			startSteamGame
		}
	;;
	esac
}

function writelog {
#DBGMS "IN - $2"
# LOGLEVEL=0: disable log

# LOGLEVEL=1: log only:
LOGONE="404,ERROR,SKIP,WARN,CREATE"

# LOGLEVEL=2: log also - including:
#LOGTWO="HACK,INFO,NEW,UPDATE,WAIT"

	if [ -n "$4" ] && [ "$3" == "X" ] && grep -q ".log" <<< "$4"; then
		echo "$(date) $1 - $2" | tee -a "$4" >/dev/null
	else
		if [ -z "$LOGLEVEL" ]; then
			LOGLEVEL=2
		fi

		if [ "$LOGLEVEL" -eq 1 ]; then
			if grep -q "$1" <<< "$LOGONE"; then
				if [ -z "$LOGFILE" ]; then
					echo "$(date) $1 - $2" | tee -a "$TEMPLOG" >/dev/null
				else
					echo "$(date) $1 - $2" | tee -a "$TEMPLOG" "$LOGFILE" >/dev/null
				fi
			fi
		fi

		if [ "$LOGLEVEL" -eq 2 ]; then
			if [ -z "$LOGFILE" ]; then
				echo "$(date) $1 - $2" | tee -a "$TEMPLOG" >/dev/null
			else
				echo "$(date) $1 - $2" | tee -a "$TEMPLOG" "$LOGFILE" >/dev/null
			fi
		fi

		if [ -n "$3" ]; then
			if [ "$3" == "E" ]; then
				echo "$(date) $1 - $2"
			elif [ "$3" == "P" ] && [ -f "$PRELOG" ]; then
				echo "$(date) $1 - $2" | tee -a "$PRELOG" >/dev/null
			elif grep -q ".log" <<< "$3"; then
				echo "$(date) $1 - $2" | tee -a "$3" >/dev/null
			fi
		fi
	fi
#DBGMS "OUT - $2"
}

# generic git clone/pull function
function gitUpdate {
	GITDIR="$1"
	GITURL="$2"
	if [ -d "$GITDIR/.git" ]; then
		writelog "INFO" "${FUNCNAME[0]} - Pulling '$GITURL' update in '$GITDIR'"

		if [ "$ONSTEAMDECK" -eq 1 ]; then
			LD_PRELOAD="/usr/lib/libcurl.so.4" "$GIT" --work-tree="$GITDIR" --git-dir="$GITDIR/.git" pull --rebase=false &> "$STLSHM/${FUNCNAME[0]}-SteamDeck-${GITDIR##*/}"
		else
			"$GIT" --work-tree="$GITDIR" --git-dir="$GITDIR/.git" pull --rebase=false &> "$STLSHM/${FUNCNAME[0]}-${GITDIR##*/}"
		fi
	else
		mkProjDir "$GITDIR"
		writelog "INFO" "${FUNCNAME[0]} - Cloning '$GITURL' in '$GITDIR'"

		if [ "$ONSTEAMDECK" -eq 1 ]; then
			LD_PRELOAD="/usr/lib/libcurl.so.4" "$GIT" clone "$GITURL" "$GITDIR" &> "$STLSHM/${FUNCNAME[0]}-SteamDeck-${GITDIR##*/}"
		else
			"$GIT" clone "$GITURL" "$GITDIR" &> "$STLSHM/${FUNCNAME[0]}-${GITDIR##*/}"
		fi
	fi
}
# Get the last N tagged releases from PROJURL taken from sonic2kk
function fetchGitHubTags {
    PROJURL="$1"
    N="$2"

    RELEASESURL="${PROJURL}/releases"
    TAGSURL="${PROJURL}/tags"

    TAGSGREP="${RELEASESURL#"$GHURL"}/tag"

    mapfile -t BASETAGS < <("$WGET" -q "${TAGSURL}" -O - 2> >(grep -v "SSL_INIT") | grep -oE "${TAGSGREP}[^\"]+" | sort -urV | grep -m "$N" "$TAGSGREP")
    for TAG in "${BASETAGS[@]}"; do
        basename "$TAG"
    done
}

# Just for fun ;)
function getSeasonalGreeting {
	CURRDATE="$( date +"%d-%m" )"
	if [ "$CURRDATE" = "25-12" ];then
		echo "Happy Holidays!"
	elif [ "$CURRDATE" = "31-12" ] || [ "$CURRDATE" = "01-01" ]; then
		echo "Happy New Year!"
	elif [ "$CURRDATE" = "31-10" ]; then
		TM="$( date +"%H:%M" )"
		if [ "$TM" = "00:00" ]; then
			echo "Happy Halloween, it's the witching hour!"
		else
			echo "Happy Halloween!"
		fi
	fi
}

function migrateCfgOption {
	# temporary function to update specific configuration options - will vary depending on the current steamtinkerlaunch version and mostly won't be used at all
	if [ "$1" == "$STLGAMECFG" ]; then
		# update dxvk config handling:
		if grep -q "^#STLDXVKCFG" "$STLGAMECFG" && ! grep -q "^STLDXVKCFG" "$STLGAMECFG"; then
			writelog "INFO" "${FUNCNAME[0]} - Commenting in STLDXVKCFG in '$STLGAMECFG' automatically"
			sed "s:^#STLDXVKCFG:STLDXVKCFG:g" -i "$STLGAMECFG"
		fi

		if [ -z "$STLDXVKCFG" ]; then
			STLDXVKLINE="$(grep "^STLDXVKCFG" "$STLGAMECFG")"
			STLDXVKLINE="${STLDXVKLINE//\"/}"
			STLDXVKLINE="${STLDXVKLINE//STLCFGDIR/$STLCFGDIR}"
			if [ -n "$STLDXVKLINE" ]; then
				export "${STLDXVKLINE?}"
			fi
		fi

		if [ -z "$STLDXVKCFG" ]; then
			writelog "SKIP" "${FUNCNAME[0]} - Variable 'STLDXVKCFG' could not be found - giving up"
		else
			if [ -z "$STLGAMECFG" ]; then
				setAIDCfgs
			fi

			if grep -q "^STLDXVKCFG" "$STLGAMECFG" && ! grep -q "^USE_STLDXVKCFG=\"1\"" "$STLGAMECFG"; then	
				if [ -f "$STLDXVKCFG" ]; then
					if [ "$(wc -l < "$STLDXVKCFG")" -eq 1 ] && grep "^NOTE" "$STLDXVKCFG"; then
						writelog "INFO" "${FUNCNAME[0]} - Empty placeholder config '$STLDXVKCFG' found - not enabling USE_STLDXVKCFG automatically"
					elif [ "$(wc -l < "$STLDXVKCFG")" -gt 1 ] || { [ "$(wc -l < "$STLDXVKCFG")" -eq 1 ] && ! grep "^NOTE" "$STLDXVKCFG"; }; then
						mkProjDir "$STLTEMPDIR"
						DXVKMIGLIST="$STLTEMPDIR/dxvkcfg.txt"
						touch "$DXVKMIGLIST"
						if grep -q "^$AID$" "$DXVKMIGLIST"; then
							writelog "SKIP" "${FUNCNAME[0]} - STLDXVKCFG was already updated for '$AID' before"
						else
							writelog "INFO" "${FUNCNAME[0]} - Found STLDXVKCFG in '$STLGAMECFG' being used, so automatically enabling USE_STLDXVKCFG"
							touch "$FUPDATE"
							USE_STLDXVKCFG=1
							updateConfigEntry "USE_STLDXVKCFG" "$USE_STLDXVKCFG" "$STLGAMECFG"
							echo "$AID" > "$DXVKMIGLIST"
						fi
					else
						writelog "INFO" "${FUNCNAME[0]} - Unknown constellation - shouldn't happen"
					fi
				else
					writelog "INFO" "${FUNCNAME[0]} - File '$STLDXVKCFG' does not exist - nothing to do"
				fi	
			fi
		fi

		# specialk replace "old" version
		if [ "$SPEKVERS" == "discord" ] || [ "$SPEKVERS" == "old" ] || [ "$SPEKVERS" == "stable" ] || [ "$SPEKVERS" == "test" ]; then
			SPEKVERS="default"
			touch "$FUPDATE"
			writelog "INFO" "${FUNCNAME[0]} - Automatically updating variable SPEKVERS from 'old' to '$SPEKVERS' in '$STLGAMECFG'"
			updateConfigEntry "SPEKVERS" "$SPEKVERS" "$STLGAMECFG"	
		fi
		
		# collections update
		if [ -n "$CHECKCATEGORIES" ] && [ "$CHECKCATEGORIES" -eq 1 ]; then
			CHECKCOLLECTIONS="$CHECKCATEGORIES"
			touch "$FUPDATE"
			writelog "INFO" "${FUNCNAME[0]} - Automatically updating variable CHECKCOLLECTIONS from old variable CHECKCATEGORIES"
			updateConfigEntry "CHECKCOLLECTIONS" "$CHECKCOLLECTIONS" "$STLGAMECFG"	
		fi

#486
function wip {
		writelog "INFO" "${FUNCNAME[0]} - Upcoming file migration. Some files in '$STLCFGDIR' will soon be migrated to '$STLDATADIR' or '$STLCACHEDIR' - see #486"

		if [ "$(df -P "$STLCFGDIR" | awk 'END{print $NF}')" == "$(df -P "$STLCACHEDIR" | awk 'END{print $NF}')" ];then
			writelog "INFO" "${FUNCNAME[0]} - '$STLCACHEDIR' is on the same partition like '$STLCFGDIR'"
		else
			writelog "INFO" "${FUNCNAME[0]} - '$STLCACHEDIR' is on a different partition like '$STLCFGDIR' - need to check if there's enough space for migrating"
			OLDSTLDLDIR="$STLCFGDIR/downloads"
			NEWSTLDLDIR="$STLCACHEDIR/downloads"
			OLDDLDIRSIZE="$(du -sb "$OLDSTLDLDIR" | awk 'END{print $1}')"
			DLDIRSIZE="$(df -k --output=avail "$NEWSTLDLDIR" | tail -n1)"
			writelog "INFO" "${FUNCNAME[0]} - OLDDLDIRSIZE is '$OLDDLDIRSIZE'; DLDIRSIZE is '$DLDIRSIZE'"
		fi
}
	fi
}

function loadCfg {
	CFGFILE="$1"

	if [ -f "$CFGFILE" ]; then

		# disable logging here when the program just started (cosmetics)
		if [ -z "$2" ]; then
			writelog "INFO" "${FUNCNAME[0]} - '$CFGFILE' START"
		fi

		if [ "$CFGFILE" == "$STLGAMECFG" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Loading game config '$CFGFILE'"
		fi

		while read -r line; do
			if [ -n "$line" ]; then
				EXPORTLINE="${line//\"/}"
				EXPORTLINE="${EXPORTLINE//STLCFGDIR/$STLCFGDIR}"
				export "${EXPORTLINE?}"
			fi
		done <<< "$(grep -v "^#\|^$" "$CFGFILE")"

		# config migration #XXXXXXXXXXXXXX
		migrateCfgOption "$CFGFILE"

		# disable logging here when the program just started (cosmetics)
		if [ -z "$2" ]; then
			writelog "INFO" "${FUNCNAME[0]} - '$CFGFILE' STOP"
		fi
	fi
}

function extWine64Run {
	if [ "$USEWINE" -eq 0 ]; then
		writelog "INFO" "${FUNCNAME[0]} - Command in Proton WINEPREFIX is: WINE=\"$RUNWINE\" WINEARCH=win64 WINEDEBUG=\"$STLWINEDEBUG\" WINEPREFIX=\"$GPFX\" $*"
		WINE="$RUNWINE" WINEARCH=win64 WINEDEBUG="$STLWINEDEBUG" WINEPREFIX="$GPFX" "$@" 2>&1 | tee "$STLSHM/${FUNCNAME[0]}.log"
	else
		writelog "INFO" "${FUNCNAME[0]} - Command in Wine WINEPREFIX is: WINE=\"$RUNWINE\" WINEARCH=\"$RUNWINEARCH\" WINEDEBUG=\"$STLWINEDEBUG\" WINEPREFIX=\"$GWFX\" $*"
		WINE="$RUNWINE" WINEARCH="$RUNWINEARCH" WINEDEBUG="$STLWINEDEBUG" WINEPREFIX="$GWFX" "$@" 2>&1 | tee "$STLSHM/${FUNCNAME[0]}.log"
	fi
}

# NOTE: This needs an update to support launch commands set with `buildCustomCmdLaunch` - e.g. ONLY_CUSTOMCMD
function extProtonRun {
	MODE="$1"
	PROGRAM="$2"
	PROGARGS="$3"
	EXTPROGRAMARGS="$4"  # e.g. args like GameScope/GameMode taken from `buildCustomCmdLaunch` for ONLY_CUSTOMCMD
	EXTWINERUN=0

	if [ "$USEWINE" -eq 1 ] && [[ ! "$WINEVERSION" =~ ${DUMMYBIN}$ ]] && [ "$WINEVERSION" != "$NON" ]; then
		EXTWINERUN=1
	fi

	setRunProtonFromUseProton

	# could help here:
	if [ ! -f "${RUNPROTON//\"/}" ]; then
		writelog "WARN" "${FUNCNAME[0]} - '$USEPROTON' seems outdated as the executable ${RUNPROTON//\"/} wasn't found"
		fixProtonVersionMismatch "USEPROTON" "$STLGAMECFG"
	fi

	writelog "INFO" "${FUNCNAME[0]} - Continuing with RUNPROTON='$RUNPROTON'"

	if [ ! -f "$RUNPROTON" ]; then
		writelog "ERROR" "${FUNCNAME[0]} - When this error occurs, probably the configured Proton (or a similar) version is no longer available."
		writelog "ERROR" "${FUNCNAME[0]} - Because the RUNPROTON '$RUNPROTON' isn't ready here yet - please open an issue when you made sure it is set to an existing one and the error persists"
	else
		if [ -z "$PROGARGS" ] || [ "$PROGARGS" == "$NON" ]; then
			RUNPROGARGS=""
		else
			mapfile -d " " -t -O "${#RUNPROGARGS[@]}" RUNPROGARGS < <(printf '%s' "$PROGARGS")
		fi

		FWAIT=2

		# mirrors above RUNPROGARGS 
		if [ -z "$EXTPROGRAMARGS" ]; then
			writelog "INFO" "${FUNCNAME[0]} - No external program args here it seems"
			RUNEXTPROGRAMARGS=( "" ) 
		else
			writelog "INFO" "${FUNCNAME[0]} - Looks like we got some external program args, '${EXTPROGRAMARGS}'"
			mapfile -d " " -t -O "${#RUNEXTPROGRAMARGS[@]}" RUNEXTPROGRAMARGS < <(printf '%s' "$EXTPROGRAMARGS")
		fi

		# TODO pass "$EXTPROGRAMARGS" to programs running with Wine as well(?)
		# TODO refactor a bit to be a little cleaner if possible
		CUSTPROGNAME="$( basename "$PROGRAM" )"
		if [ "$MODE" == "F" ]; then  # Forked Proton/Wine 'normal' custom program
			if [ -n "${RUNPROGARGS[0]}" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Starting '$PROGRAM' with arguments '${RUNPROGARGS[*]}' forked into the background"
				restoreOrgVars
				if [ "$EXTWINERUN" -eq 1 ]; then
					(sleep "$FWAIT"; notiShow "$( strFix "$NOTY_CUSTPROG_FORKED_ARGS_WINE" "$CUSTPROGNAME" )"; extWine64Run "$PROGRAM" "${RUNPROGARGS[@]}") &
				else
					if [ -n "${RUNEXTPROGRAMARGS[0]}" ]; then
						(sleep "$FWAIT"; notiShow "$( strFix "$NOTY_CUSTPROG_FORKED_ARGS" "$CUSTPROGNAME" )"; "${RUNEXTPROGRAMARGS[@]}" "$RUNPROTON" run "$PROGRAM" "${RUNPROGARGS[@]}" 2>&1 | tee "$STLSHM/${FUNCNAME[0]}.log") &
					else
						(sleep "$FWAIT"; notiShow "$( strFix "$NOTY_CUSTPROG_FORKED_ARGS" "$CUSTPROGNAME" )"; "$RUNPROTON" run "$PROGRAM" "${RUNPROGARGS[@]}" 2>&1 | tee "$STLSHM/${FUNCNAME[0]}.log") &
					fi
				fi
				emptyVars "O" "X"
			else
				writelog "INFO" "${FUNCNAME[0]} - Starting '$PROGRAM' forked into the background"
				restoreOrgVars
				if [ "$EXTWINERUN" -eq 1 ]; then
					(sleep "$FWAIT"; notiShow "$( strFix "$NOTY_CUSTPROG_FORKED_WINE" "$CUSTPROGNAME" )"; extWine64Run "$PROGRAM") &
				else
					if [ -n "${RUNEXTPROGRAMARGS[0]}" ]; then
						(sleep "$FWAIT"; notiShow "$( strFix "$NOTY_CUSTPROG_FORKED" "$CUSTPROGNAME" )"; "${RUNEXTPROGRAMARGS[@]}" "$RUNPROTON" run "$PROGRAM" 2>&1 | tee "$STLSHM/${FUNCNAME[0]}.log") &
					else
						(sleep "$FWAIT"; notiShow "$( strFix "$NOTY_CUSTPROG_FORKED" "$CUSTPROGNAME" )"; "$RUNPROTON" run "$PROGRAM" 2>&1 | tee "$STLSHM/${FUNCNAME[0]}.log") &
					fi
				fi
				emptyVars "O" "X"
			fi
		elif [ "$MODE" == "FC" ]; then  # Forked Proton/Wine 'command line' custom program
			if [ -n "${RUNPROGARGS[0]}" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Starting '$WICO $PROGRAM' with arguments '${RUNPROGARGS[*]}' forked into the background"
				restoreOrgVars
				if [ "$EXTWINERUN" -eq 1 ]; then
					(sleep "$FWAIT"; notiShow "$( strFix "$NOTY_CUSTPROG_FORKED_ARGS_WINE" "$CUSTPROGNAME" )"; extWine64Run "$RUNWICO" "$PROGRAM" "${RUNPROGARGS[@]}") &
				else
					if [ -n "${RUNEXTPROGRAMARGS[0]}" ]; then
						(sleep "$FWAIT"; notiShow "$( strFix "$NOTY_CUSTPROG_FORKED_ARGS" "$CUSTPROGNAME" )"; "${RUNEXTPROGRAMARGS[@]}" "$RUNPROTON" run "$WICO" "$PROGRAM" "${RUNPROGARGS[@]}" 2>&1 | tee "$STLSHM/${FUNCNAME[0]}.log") &
					else
						(sleep "$FWAIT"; notiShow "$( strFix "$NOTY_CUSTPROG_FORKED_ARGS" "$CUSTPROGNAME" )"; "$RUNPROTON" run "$WICO" "$PROGRAM" "${RUNPROGARGS[@]}" 2>&1 | tee "$STLSHM/${FUNCNAME[0]}.log") &
					fi
				fi
				emptyVars "O" "X"
			else
				writelog "INFO" "${FUNCNAME[0]} - Starting '$WICO $PROGRAM' forked into the background"
				restoreOrgVars
				if [ "$EXTWINERUN" -eq 1 ]; then
					(sleep "$FWAIT"; notiShow "$( strFix "$NOTY_CUSTPROG_FORKED_WINE" "$CUSTPROGNAME" )"; extWine64Run "$RUNWICO" "$PROGRAM") &
				else
					if [ -n "${RUNEXTPROGRAMARGS[0]}" ]; then
						(sleep "$FWAIT"; notiShow "$( strFix "$NOTY_CUSTPROG_FORKED" "$CUSTPROGNAME" )"; "${RUNEXTPROGRAMARGS[@]}" "$RUNPROTON" run "$WICO" "$PROGRAM" 2>&1 | tee "$STLSHM/${FUNCNAME[0]}.log") &
					else
						(sleep "$FWAIT"; notiShow "$( strFix "$NOTY_CUSTPROG_FORKED" "$CUSTPROGNAME" )"; "$RUNPROTON" run "$WICO" "$PROGRAM" 2>&1 | tee "$STLSHM/${FUNCNAME[0]}.log") &
					fi
				fi
				emptyVars "O" "X"
			fi
		elif [ "$MODE" == "R" ]; then  # Regular (no fork/wait/etc) Proton/Wine custom program
			if [ -n "${RUNPROGARGS[0]}" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Starting '$PROGRAM' with arguments '${RUNPROGARGS[*]}' regularly"
				restoreOrgVars
				if [ "$EXTWINERUN" -eq 1 ]; then
					notiShow "$( strFix "$NOTY_CUSTPROG_REG_ARGS_WINE" "$CUSTPROGNAME" )"
					extWine64Run "$PROGRAM" "${RUNPROGARGS[@]}"
				else
					notiShow "$( strFix "$NOTY_CUSTPROG_REG_ARGS" "$CUSTPROGNAME" )"
					if [ -n "${RUNEXTPROGRAMARGS[0]}" ]; then
						"${RUNEXTPROGRAMARGS[@]}" "$RUNPROTON" run "$PROGRAM" "${RUNPROGARGS[@]}" 2>&1 | tee "$STLSHM/${FUNCNAME[0]}.log"
					else
						"$RUNPROTON" run "$PROGRAM" "${RUNPROGARGS[@]}" 2>&1 | tee "$STLSHM/${FUNCNAME[0]}.log"
					fi
				fi
				emptyVars "O" "X"
			else
				writelog "INFO" "${FUNCNAME[0]} - Starting '$PROGRAM' regularly"
				restoreOrgVars
				if [ "$EXTWINERUN" -eq 1 ]; then
					notiShow "$( strFix "$NOTY_CUSTPROG_REG_WINE" "$CUSTPROGNAME" )"
					extWine64Run "$PROGRAM"
				else
					notiShow "$( strFix "$NOTY_CUSTPROG_REG" "$CUSTPROGNAME" )"
					if [ -n "${RUNEXTPROGRAMARGS[0]}" ]; then
						"${RUNEXTPROGRAMARGS[@]}" "$RUNPROTON" run "$PROGRAM" 2>&1 | tee "$STLSHM/${FUNCNAME[0]}.log"
					else
						"$RUNPROTON" run "$PROGRAM" 2>&1 | tee "$STLSHM/${FUNCNAME[0]}.log"
					fi
				fi
				emptyVars "O" "X"
			fi
		elif [ "$MODE" == "RC" ]; then  # Regular (no fork/wait/etc) Proton/Wine 'command line' custom program
			if [ -n "${RUNPROGARGS[0]}" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Starting '$WICO $PROGRAM' with arguments '${RUNPROGARGS[*]}' regularly"
				restoreOrgVars
				if [ "$EXTWINERUN" -eq 1 ]; then
					notiShow "$( strFix "$NOTY_CUSTPROG_REG_ARGS_WINE" "$CUSTPROGNAME" )"
					extWine64Run "$RUNWICO" "$PROGRAM" "${RUNPROGARGS[@]}"
				else
					notiShow "$( strFix "$NOTY_CUSTPROG_REG_ARGS" "$CUSTPROGNAME" )"
					if [ -n "${RUNEXTPROGRAMARGS[0]}" ]; then
						"${RUNEXTPROGRAMARGS[@]}" "$RUNPROTON" run "$WICO" "$PROGRAM" "${RUNPROGARGS[@]}" 2>&1 | tee "$STLSHM/${FUNCNAME[0]}.log"
					else
						"$RUNPROTON" run "$WICO" "$PROGRAM" "${RUNPROGARGS[@]}" 2>&1 | tee "$STLSHM/${FUNCNAME[0]}.log"
					fi
				fi
				emptyVars "O" "X"
			else
				writelog "INFO" "${FUNCNAME[0]} - Starting '$WICO $PROGRAM' regularly"
				restoreOrgVars
				if [ "$EXTWINERUN" -eq 1 ]; then
					notiShow "$( strFix "$NOTY_CUSTPROG_REG_WINE" "$CUSTPROGNAME" )"
					extWine64Run "$RUNWICO" "$PROGRAM"
				else
					notiShow "$( strFix "$NOTY_CUSTPROG_REG" "$CUSTPROGNAME" )"
					if [ -n "${RUNEXTPROGRAMARGS[0]}" ]; then
						"${RUNEXTPROGRAMARGS[@]}" "$RUNPROTON" run "$WICO" "$PROGRAM" 2>&1 | tee "$STLSHM/${FUNCNAME[0]}.log"
					else
						"$RUNPROTON" run "$WICO" "$PROGRAM" 2>&1 | tee "$STLSHM/${FUNCNAME[0]}.log"
					fi
				fi
				emptyVars "O" "X"
			fi
		fi
	fi
}

function getWindowHeight {
	WINID="$1"
	"$XWININFO" -id "$WINID" -stats | awk '$1=="-geometry" {print $2}' | cut -d '+' -f1 | cut -d 'x' -f2
}

function getLatestGeoElf {
	GEOELFDLURL="$("$WGET" -q "$GEOELFURL" -O - 2> >(grep -v "SSL_INIT") | sed $'s/<a href=/\\\n/g' | grep "^\"https" | grep "\.zip" | grep -oP '"\K[^"]+' | grep -m1 https)" # maybe make less fragile later :)
	GEOELFFILE="${GEOELFDLURL##*/}"
	CURGEOELF="${GEOELFDLURL##*+v}"
	CURGEOELF="${CURGEOELF%.*}";
	
	CURGEOELFDIR="$GEOELFDLDIR/$CURGEOELF"
	mkProjDir "$CURGEOELFDIR"
	
	GEODSTD="$CURGEOELFDIR"
	GEODSTF="$GEODSTD/$GEOELFFILE"
	
	if [ -f "$GEODSTF" ]; then
		writelog "SKIP" "${FUNCNAME[0]} - Already have '$GEODSTF' - skipping download"
	else
		writelog "INFO" "${FUNCNAME[0]} - Downloading '$GEOELFDLURL' to '$GEODSTF'"
		dlCheck "$GEOELFDLURL" "$GEODSTF" "X" "Downloading '$GEOELFFILE'"
		"$UNZIP" -q "$GEODSTF" -d "$GEODSTD" 2>/dev/null
		writelog "INFO" "${FUNCNAME[0]} - Extracted '$GEODSTF' to '$GEODSTD'"
		if [ -L "$LGEOELFSYM" ]; then
			rm "$LGEOELFSYM"
			writelog "INFO" "${FUNCNAME[0]} - Updating symlink '$LGEOELFSYM' pointing to '$CURGEOELFDIR'"
		else
			writelog "INFO" "${FUNCNAME[0]} - Creating symlink '$LGEOELFSYM' pointing to '$CURGEOELFDIR'"
		fi
		ln -s "$CURGEOELFDIR" "$LGEOELFSYM"
		cp "$(find "$GEODSTD" -name "*Version*")" "$GEODSTD/${GEOELF}-version.txt"
	fi
}

function configureGeoElf {
	function installGeo {
		function copyGeo {
			rm "$GEOELFENA" 2>/dev/null
			while read -r file; do
				cp "$file" "$GEOELFDDIR"
				echo "${file##*/}" >> "$GEOELFENA"
			done <<< "$(find "$LGEOELFSYM/$1" -mindepth 1 -maxdepth 1 -type f)"

			# not sure yet if (ShaderFixes) subdirectory is even required - maybe implement later TODO?
			#			while read -r dir; do
			#				mkdir "$GEOELFDDIR/${dir##*/}"
			#			done <<< "$(find "$LGEOELFSYM/$1" -mindepth 1 -type d)"
			# ...

			cp "$LGEOELFSYM/${GEOELF}-version.txt" "$GEOELFDDIR"
			echo "${GEOELF}-version.txt" >> "$GEOELFENA"
		}
		
		if [ ! -d "$LGEOELFSYM/$1" ] || [ "$AUTOGEOELF" -eq 1 ]; then
			getLatestGeoElf
		fi

		if [ -d "$LGEOELFSYM/$1" ]; then
			if [ -f "$GEOELFENA" ]; then
				if [ "$AUTOGEOELF" -eq 1 ]; then
					GEOELFVI="$(cat "$GEOELFDDIR/${GEOELF}-version.txt")"
					GEOELFVA="$(cat "$LGEOELFSYM/${GEOELF}-version.txt")"
					writelog "INFO" "${FUNCNAME[0]} - Installed $GEOELF version is '$GEOELFVI', latest downloaded version is '$GEOELFVA'"
					# no need to check the newer version directly, because latest is either equal or newer
					if [ "$GEOELFVI" != "$GEOELFVA" ]; then
						writelog "INFO" "${FUNCNAME[0]} - Installing new $GEOELF version '$GEOELFVA'"
						copyGeo "$1"
					else
						writelog "INFO" "${FUNCNAME[0]} - Installed $GEOELF version '$GEOELFVI' is identical to the latest downloaded version '$GEOELFVA' - nothing to do"
					fi
				else
					writelog "SKIP" "${FUNCNAME[0]} - $GEOELF is already installed in the game dir and autoupdate is disabled - nothing to do"
				fi
			else
				writelog "INFO" "${FUNCNAME[0]} - Installing geo-11 drivers from '$LGEOELFSYM/$1' to '$GEOELFDDIR'"
				copyGeo "$1"
			fi
		else
			writelog "SKIP" "${FUNCNAME[0]} - '$LGEOELFSYM' could not be found - can't enable $GEOELF"
			USEGEOELF=0
		fi
	}

	GEOELFDDIR="$EFD"
	setFullGameExePath "GEOELFDDIR"	
	GEOELFENA="$GEOELFDDIR/${GEOELF}_enabled.txt"

	if [ "$USEGEOELF" -eq 1 ]; then	
		if [ "$USECUSTOMCMD" -eq 1 ] && [ -f "$CUSTOMCMD" ]; then
			ARCHEXE="$CUSTOMCMD"
		else
			ARCHEXE="$GP"
		fi
		
		if [ "$(getArch "$ARCHEXE")" == "32" ]; then
			installGeo "x32"
		elif [ "$(getArch "$ARCHEXE")" == "64" ]; then
			installGeo "x64"
		else
			writelog "SKIP" "${FUNCNAME[0]} - Could not determine the architecture of '$GP' - not installing '$GEOELF'" "E"
		fi
	else
		if [ -f "$GEOELFENA" ]; then
			writelog "INFO" "${FUNCNAME[0]} - $GEOELF was previously enabled, so removing all its files from '$GEOELFDDIR'"
			while read -r file; do
				RMFILE="$GEOELFDDIR/$file"
				if [ -f "$RMFILE" ]; then
					writelog "INFO" "${FUNCNAME[0]} - Removing '$RMFILE'"
					rm "$GEOELFDDIR/$file"
				else
					writelog "SKIP" "${FUNCNAME[0]} - '$RMFILE' missing - nothing to do" "E"
				fi
			done < "$GEOELFENA"
			rm "$GEOELFENA"
		fi
	fi
}

function initSteamVR {
	if [ "$RUNSBSVR" -eq 1 ]; then
		SVRJUSTSTARTED=0
		STEAMVRARGS=(-applaunch 250820)

		if "$PGREP" -a "vrcompositor" >/dev/null ; then
			writelog "INFO" "${FUNCNAME[0]} - Looks like SteamVR is already running - skipping this function"
		else
			writelog "WARN" "${FUNCNAME[0]} - This function might be removed as it blocks exiting the launched game"

			if ! "$PGREP" -a "vrcompositor" >/dev/null ; then
				writelog "INFO" "${FUNCNAME[0]} - Vrcompositor not running, so starting SteamVR now:"
				if ! "$STEAM" "${STEAMVRARGS[@]}" 2>/dev/null >/dev/null ; then
					writelog "SKIP" "${FUNCNAME[0]} - Starting SteamVR FAILED - skipping SBS-VR"
					echo "RUNSBSVR=\"0\"" > "$VRINITLOCK"
				else
					writelog "INFO" "${FUNCNAME[0]} - Started SteamVR"
					SVRJUSTSTARTED=1
				fi
			fi

			if ! "$PGREP" -a "vrstartup" >/dev/null ; then
				writelog "INFO" "${FUNCNAME[0]} - No vrstartup process running"
			else
				if [ "$SVRJUSTSTARTED" -eq 1 ]; then
					writelog "INFO" "${FUNCNAME[0]} - SteamVR initializing"
					while true; do
						writelog "INFO" "${FUNCNAME[0]} - Waiting for end of vrstartup"
						if ! "$PGREP" -a "vrstartup" >/dev/null ; then
							break
						fi
						if [ -f "$CLOSETMP" ]; then
							writelog "WAIT" "${FUNCNAME[0]} - ${PROGNAME,,} is just closing - leaving loop"
							break
						fi
					done
				else
					writelog "SKIP" "${FUNCNAME[0]} - Vrstartup found, but we didn't start SteamVR before! - skipping SBS-VR - just in case"
					echo "RUNSBSVR=\"0\"" > "$VRINITLOCK"
				fi
			fi

			if [ "$SVRJUSTSTARTED" -eq 1 ]; then
				while true; do
					if ! "$PGREP" -a "vrstartup" >/dev/null ; then
						writelog "WAIT" "${FUNCNAME[0]} - No vrstartup instance running"
						break
					fi
					if [ -f "$CLOSETMP" ]; then
						writelog "WAIT" "${FUNCNAME[0]} - ${PROGNAME,,} is just closing - leaving loop"
						break
					fi
					writelog "WAIT" "${FUNCNAME[0]} - Waiting for end of vrstartup"
				done
			fi

			if [ "$SVRJUSTSTARTED" -eq 1 ]; then
			MAXWAIT=10
			COUNTER=0
				while ! "$PGREP" -a "vrcompositor" >/dev/null; do
					if [ -f "$CLOSETMP" ]; then
						writelog "WAIT" "${FUNCNAME[0]} - ${PROGNAME,,} is just closing - leaving loop"
						break
					fi
					if [[ "$COUNTER" -ge "$MAXWAIT" ]]; then
						writelog "SKIP" "${FUNCNAME[0]} - ERROR - timeout waiting for SteamVR - exit"
						"$PKILL" -f "$VRVIDEOPLAYER"
						echo "RUNSBSVR=\"0\"" > "$VRINITLOCK"
						exit 1
					fi
					writelog "WAIT" "${FUNCNAME[0]} - Sec $COUNTER/$MAXWAIT waiting for vrcompositor"
					COUNTER=$((COUNTER+1))
					sleep 1
				done
			else
				writelog "INFO" "${FUNCNAME[0]} - we didn't start SteamVR before so no need to wait for vrcompositor"
			fi

			if "$PGREP" -a "vrcompositor" >/dev/null ; then
				while true; do
					if ! "$PGREP" -a "vrstartup" >/dev/null ; then
						writelog "WAIT" "${FUNCNAME[0]} - No vrstartup instance running - looks good"
						break
					fi
					sleep 1
					writelog "WAIT" "${FUNCNAME[0]} - Waiting for end of vrstartup"
				done

				writelog "INFO" "${FUNCNAME[0]} - Success - SteamVR running"
				sleep 1 # better safe than sorry
				
			else
				writelog "SKIP" "${FUNCNAME[0]} - SteamVR start failed - vrcompositor still not running - skipping SBS-VR!"
				echo "RUNSBSVR=\"0\"" > "$VRINITLOCK"
			fi
		fi
	fi
}

function dlOvrFSR {
	function getLatestOVRFSR {
		basename "$("$WGET" -q "$OVRFSRURL" -O - 2> >(grep -v "SSL_INIT") | grep -E 'releases.*download.*zip' | cut -d '"' -f2 | head -n1)"
	}

	DLDST="$STLDLDIR/$OVFS"
	mkProjDir "$DLDST"
	OVRFSRZIP="$(getLatestOVRFSR)"
	FSR1="${OVRFSRZIP//openvr_}"
	FSRV="${FSR1%.*}"

	if [ ! -f "$DLDST/$OVRFSRZIP" ]; then
		notiShow "$(strFix "$NOTY_DLCUSTOMPROTON" "$OVRFSRZIP")" "S"
		dlCheck "${OVRFSRURL}/download/$FSRV/$OVRFSRZIP" "$DLDST/$OVRFSRZIP" "X" "Downloading '$OVRFSRZIP'"
		notiShow "$(strFix "$NOTY_DLCUSTOMPROTON2" "$OVRFSRZIP")" "S"
	fi

	if [ ! -s "$DLDST/$OVRFSRZIP" ]; then
		writelog "SKIP" "${FUNCNAME[0]} - Downloaded file '$DLDST/$OVRFSRZIP' is empty - removing"
		rm "$DLDST/$OVRFSRZIP" 2>/dev/null
	else
		notiShow "$(strFix "$NOTY_DLCUSTOMPROTON3" "$OVRFSRZIP")" "S"
		writelog "INFO" "${FUNCNAME[0]} - Download of '$OVRFSRZIP' to '$DLDST' was successful"
	 	OMSRC="$DLDST/$OVRMOD"
	 	if [ -f "$OMSRC" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Removing old '$OMSRC'"
			rm "$OMSRC" 2>/dev/null
	 	fi
	 	OASRC="$DLDST/$OVRA"
	 	if [ -f "$OASRC" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Removing old '$OASRC'"
			rm "$OASRC" 2>/dev/null
	 	fi
	 	
	 	"$UNZIP" -q "$DLDST/$OVRFSRZIP" -d "$DLDST" 2>/dev/null
		writelog "INFO" "${FUNCNAME[0]} - Extracted '$OVRFSRZIP' to '$DLDST'"
	fi
}

function checkOpenVRFSR {
	OVRFSENA="${OVFS}-${PROGNAME,,}-enabled.txt"
	OVRFP="$EFD/$OVRFSENA"
	OVRAO="openvr_api.orig.dll"

	if [ "$USEOPENVRFSR" -eq 1 ]; then
		OVRPATH="$(find "$EFD" -name "*$OVRA" | head -n1)"
		if [ -f "$OVRPATH" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Found '$OVRA' under '$OVRPATH'"
			OVRASRC="$STLDLDIR/$OVFS/$OVRA"
			if [ ! -f "$OVRASRC" ]; then
				writelog "INFO" "${FUNCNAME[0]} - No $OVFS source dll found under '$OVRASRC' - Trying automatic download"
				StatusWindow "$(strFix "$NOTY_DLCUSTOMPROTON" "$OVRFSRZIP")" "dlOvrFSR" "DownloadOvrFSRStatus"
			fi

			if [ ! -f "$OVRASRC" ]; then
				writelog "SKIP" "${FUNCNAME[0]} - Still no $OVFS source dll found under '$OVRASRC' - automatic download failed!"
			else	
				OVRDIR="${OVRPATH%/*}"
				writelog "INFO" "${FUNCNAME[0]} - Moving original '$OVRPATH' to $OVRDIR/$OVRAO"
				mv "$OVRPATH" "$OVRDIR/$OVRAO"
				writelog "INFO" "${FUNCNAME[0]} - Copying '$OVRASRC' to '$OVRPATH'"
				cp "$OVRASRC" "$OVRPATH"
				echo "${OVRPATH//$EFD/}" > "$OVRFP"
				
				OVRMODSRC="$STLDLDIR/$OVFS/$OVRMOD"
				if [ -f "$OVRMODSRC" ]; then
					if [ ! -f "$OVRFP" ]; then
						writelog "WARN" "${FUNCNAME[0]} - No install 'log' found - should not happen here!"
					else
						OVRMODDST="${OVRPATH%/*}/$OVRMOD"
						if [ -f "$OVRMODDST" ]; then
							writelog "INFO" "${FUNCNAME[0]} - Moving '$OVRMODDST' to '${OVRMODDST}_old'"
							mv "$OVRMODDST" "${OVRMODDST}_old"
						fi
						writelog "INFO" "${FUNCNAME[0]} - Copying '$OVRMODSRC' to '$OVRMODDST'"
						cp "$OVRMODSRC" "$OVRMODDST"
						echo "${OVRMODDST//$EFD/}" >> "$OVRFP"
					fi
				fi
				
				if [ -f "$OVRFP" ]; then
					writelog "INFO" "${FUNCNAME[0]} - '$OVFS' installation (hopefully) succeeded!"
				fi
			fi
		else
			writelog "SKIP" "${FUNCNAME[0]} - USEOPENVRFSR is enabled, but no OVRA found in '$EFD'"
		fi
	else
		if [ -f "$OVRFP" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Found old '$OVFS' installation in '$EFD' - Removing"
			while read -r line; do
				if grep -q "$OVRA" <<< "$line"; then
					OVRAOP="$EFD/${line//$OVRA/$OVRAO}"
				if [ -f "$OVRAOP" ]; then
						writelog "INFO" "${FUNCNAME[0]} - Restoring original $OVRA from '$OVRAOP'"
						mv "$OVRAOP" "$EFD/$line" 2>/dev/null
					else
						writelog "SKIP" "${FUNCNAME[0]} - No '$OVRAOP' found to restore"
					fi
				else
					writelog "INFO" "${FUNCNAME[0]} - Removing '$EFD/$line'"
					rm "$EDF/$line" 2>/dev/null
				fi
			done < "$OVRFP"
			rm "$OVRFP" 2>/dev/null
		fi
	fi
}

function getGamePidFromFile {
	if [ -z "$GAMEWINPID" ] && [ -f "$TEMPGPIDFILE" ]; then
		loadCfg "$TEMPGPIDFILE"
		rm "$TEMPGPIDFILE"
		writelog "INFO" "${FUNCNAME[0]} - Got GAMEWINPID '$GAMEWINPID' from temp file"
	fi
}

function getGamePidFromWindowName {
	if [ -n "$GAMEWINDOW" ] && [ "$GAMEWINDOW" != "$NON" ]; then
		# xdotool at least doesn't like '(' and ')', so cutting them out as a partial match should be enough
		#CHECKWINDOWNAME="${GAMEWINDOW//(*}"
		writelog "INFO" "${FUNCNAME[0]} - Trying to get the PID of the window '$GAMEWINDOW'"
		# TESTPID="$("$XDO" getwindowpid "$("$XDO" search --name "$CHECKWINDOWNAME")" 2>/dev/null)"
		TESTPID="$("$XWININFO" -name "${GAMEWINDOW//\"/}" -wm | grep "Process id:" | awk -F 'Process id: ' '{print $2}' | cut -d ' ' -f1)"
		if [ -n "$TESTPID" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Found the PID '$TESTPID' for the window '$GAMEWINDOW'"
			echo "$TESTPID"
		fi
	fi
}

function GAMEPID {
	if	[ "$USECUSTOMCMD" -eq 1 ] && [ "$ONLY_CUSTOMCMD" -eq 1 ]; then
#		"$PGREP" -a "$CUSTOMCMD" | cut -d ' ' -f1 | tail -n1
		"$PGREP" -a "" | grep "${CUSTOMCMD##*/}" | grep "Z:" | grep "\.exe" | grep -v "CrashHandler" | cut -d ' ' -f1 | tail -n1
	else
		if [ -n "$WAITFORTHISPID" ] && [ "$WAITFORTHISPID" != "$NON" ]; then
			GAMPI="$("$PIDOF" "$WAITFORTHISPID" | cut -d ' ' -f1)"
		else
			if [ -n "$GAMEWINDOW" ] && [ "$GAMEWINDOW" != "$NON" ]; then
				GAMPI="$("$XWININFO" -name "${GAMEWINDOW//\"/}" -wm | grep "Process id:" | awk -F 'Process id: ' '{print $2}' | cut -d ' ' -f1)"
				writelog "INFO" "${FUNCNAME[0]} - Found gamewindow '$GAMEWINDOW' PID $GAMPI"
			else
				# very likely this needs to be improved/changed
				GAMPI="$("$PGREP" -a "" | grep "$GE" | grep "Z:" | grep "\.exe" | grep -v "CrashHandler" | cut -d ' ' -f1 | tail -n1)"
			fi
		fi
		echo "$GAMPI"
	fi
}

function waitForGamePid {
	if [ -n "$WAITFORTHISPID" ] && [ "$WAITFORTHISPID" != "$NON" ]; then
		writelog "WAIT" "${FUNCNAME[0]} - Waiting for alternative process WAITFORTHISPID '$WAITFORTHISPID'"
	elif [ "$USECUSTOMCMD" -eq 1 ] && [ "$ONLY_CUSTOMCMD" -eq 1 ]; then
		writelog "WAIT" "${FUNCNAME[0]} - Waiting for custom process CUSTOMCMD '$CUSTOMCMD'"
	fi

	while [ -z "$(GAMEPID)" ]; do 
		writelog "WAIT" "${FUNCNAME[0]} - Waiting for game process $(GAMEPID)"
		sleep 1
	done
	writelog "INFO" "${FUNCNAME[0]} - Game process found at $(GAMEPID)"
}

function getGameWinXIDFromPid {
	GPID="$1"
	while read -r WINS; do
		if [ "$("$XPROP" -id "$(printf 0x%x'\n' "$WINS")" | grep "_NET_WM_STATE(ATOM)" -c)" -ge 1 ]; then
			writelog "INFO" "${FUNCNAME[0]} - Found a controllable windowid"
			WSIZ="$(getWindowHeight "$WINS")"
			if [ "$WSIZ" -lt "$MINVRWINH" ]; then
				writelog "SKIP" "${FUNCNAME[0]} - '$(printf 0x%x'\n' "$WINS")' height is less than $MINVRWINH - this is very likely not the game window - skipping"
			else
				writelog "INFO" "${FUNCNAME[0]} Found window id $(printf 0x%x'\n' "$WINS") for '$GE' running with PID '$GPID'"
				echo "$WINS"
				break
			fi
		fi
	done <<< "$("$XDO" search --pid "$GPID")"	
}

function getGameWinNameFromXid {
	"$XDO" getwindowname "$1"
}

function getGameWindowPID {
	if [ "$MO2MODE" == "gui" ]; then
		writelog "SKIP" "${FUNCNAME[0]} - Skipping check for window pid, because MO2MODE is '$MO2MODE'"
	else
		if [ -n "$GAMEWINPID" ]; then
			writelog "SKIP" "${FUNCNAME[0]} - Already have the GAMEWINPID '$GAMEWINPID'"
			echo "$GAMEWINPID"
		else
			MAXWAIT=20
			COUNTER=0
			TESTPID="$NON"
			WASCLOSED=0

			touch "$PIDLOCK"

			while [ "$COUNTER" -lt "$MAXWAIT" ]; do
				if [ -f "$CLOSETMP" ]; then
					writelog "WAIT" "${FUNCNAME[0]} - ${PROGNAME,,} is just closing - leaving loop"
					WASCLOSED=1
					break
				fi
				TESTPID="$("$XDO" getactivewindow getwindowpid)"
				SYMCWD="$(readlink "/proc/$TESTPID/cwd")"
				SYMEXE="$(readlink "/proc/$TESTPID/exe")"

				if [ -n "$TESTPID" ]; then
					if [ -n "$HAVPA" ]; then
						writelog "WAIT" "${FUNCNAME[0]} - Found PID '$TESTPID' for game 'HAVPA' '$HAVPA' - leaving loop"
						FOUNDWIN="$YES"
						break;
					elif [ -n "$EXECUTABLE" ] && [ "$EXECUTABLE" == "$(cat "/proc/$TESTPID/comm")" ]; then
						writelog "WAIT" "${FUNCNAME[0]} - Found PID '$TESTPID' for game 'EXECUTABLE' '$EXECUTABLE' - leaving loop"
						FOUNDWIN="$YES"
						break;
					elif [ -n "$GE" ] && [ "$GE" == "$(cut -d '.' -f1 < "/proc/$TESTPID/comm")" ]; then
						writelog "WAIT" "${FUNCNAME[0]} - Found PID '$TESTPID' for game executable 'GE' '$GE' - leaving loop"
						FOUNDWIN="$YES"
						break;
					else
						# might not even be required anymore - maybe remove later:
						if [[ "$SYMCWD" == "$EFD" ]] && [[ "$SYMEXE" != *"$YAD"* ]]; then
							writelog "WAIT" "${FUNCNAME[0]} - Found PID '$TESTPID' for CWD '$SYMCWD' with EXE '$SYMEXE' - leaving loop"
							FOUNDWIN="$YES"
							break;
						fi
						if [ -n "$STEAM_COMPAT_CLIENT_INSTALL_PATH" ] && [[ "$SYMCWD" == "$STEAM_COMPAT_CLIENT_INSTALL_PATH" ]] && [[ "$SYMEXE" != *"$YAD"* ]]; then
							writelog "WAIT" "${FUNCNAME[0]} - Found PID '$TESTPID' for STEAM_COMPAT_CLIENT_INSTALL_PATH '$SYMCWD' with EXE '$SYMEXE' - leaving loop"
							FOUNDWIN="$YES"
							break;
						fi
					fi
				fi
				writelog "WAIT" "${FUNCNAME[0]} - Sec $COUNTER/$MAXWAIT Game Window with pwd '$EFD' not yet in front"
				COUNTER=$((COUNTER+1))
				sleep 1
			done

			rm "$PIDLOCK" 2>/dev/null
			
			if [ "$FOUNDWIN" == "$YES" ]; then
				if [ "$TESTPID" == "$NON" ]; then
					writelog "SKIP" "${FUNCNAME[0]} - FAIL - Found PID returned but it is empty: '$TESTPID'"
				fi
				writelog "INFO" "${FUNCNAME[0]} - Found PID '$TESTPID' for running exe '$(readlink "/proc/$TESTPID/exe")'"
				echo "$TESTPID"
			else
				if [ "$WASCLOSED" -eq 0 ]; then
					writelog "SKIP" "${FUNCNAME[0]} - ERROR - timeout waiting for '$EFD' window"
					echo "$NON"
				fi
			fi
		fi
	fi
}

function storeGameWindowNameMeta {
	GAMEWINDOW="$1"
	if [ -n "$GAMEWINDOW" ] && [ "$GAMEWINDOW" != "$NON" ] && [ "$STLPLAY" -eq 0 ]; then
		writelog "INFO" "${FUNCNAME[0]} - Found game window name '$GAMEWINDOW' - saving into metadata file '$GEMETA/$AID.conf' for game '$MGNA ($AID)'"
		touch "$FUPDATE"
		touch "$GEMETA/$AID.conf"
		updateConfigEntry "GAMEWINDOW" "$GAMEWINDOW" "$GEMETA/$AID.conf"
	fi	
}

function pickGameWindowNameMeta {
	if [ -n "$1" ]; then
		AID="$1"
	fi
	if [ -n "$2" ]; then
		GN="$2"
	fi
	fixShowGnAid
	writelog "INFO" "${FUNCNAME[0]} - Picking 'GAMEWINDOW' for '$SGNAID'"

	GAMEWINXID="$(printf 0x%x'\n' "$("$XDO" selectwindow)")"
	GAMEWINDOW="$("$XDO" getwindowname "$GAMEWINXID")"
	storeGameWindowNameMeta "$GAMEWINDOW"
	if [ -n "$AID" ]; then
		notiShow "$(strFix "$NOTY_PICKWINS" "$GAMEWINDOW" "$GN" "$AID")"
		writelog "INFO" "${FUNCNAME[0]} - Picked 'GAMEWINDOW $GAMEWINDOW' for '$SGNAID'"
	else
		notiShow "$(strFix "$NOTY_PICKWINN" "$GAMEWINDOW")"
	fi
}

# General function for the "steamtinkerlaunch list <arg> function"
# Can take two types of commands:
# - `steamtinkerlaunch list owned/installed` - Returns "Game Name (AppID)"
# - `steamtinkerlaunch list owned/installed id/name/path/full` - Returns either AppID, Game Name, Game Paths, or all in the format "Game Name (AppID) -> /path/to/game"
function listSteamGames {
	function getGameCount {
		if [ "$LSFILTER" == "owned" ] || [ "$LSFILTER" == "o" ]; then
			printf "Total games owned: %s\n" "${#LISTAIDSARR[@]}"
		else
			printf "Total games installed: %s\n" "${#LISTAIDSARR[@]}"
		fi
	}

	LSFILTER="$1"  # e.g. "owned", "installed"
	LSTYPE="$2"  # e.g. "id", "name", "path", "count", "full"
	LISTAIDS=""

	if [ "$LSFILTER" == "owned" ] || [ "$LSFILTER" == "o" ]; then
		LISTAIDS="$( getOwnedAids )"
	elif [ "$LSFILTER" == "installed" ] || [ "$LSFILTER" == "i" ]; then
		if [ "$(listInstalledGameIDs | wc -l)" -eq 0 ]; then
			writelog "SKIP" "${FUNCNAME[0]} - No installed games found!" "E"
			echo "No installed games found!"

			exit
		else
			LISTAIDS="$( listInstalledGameIDs )"
		fi
	else
		echo "unknown argument passed to 'list' command - '$LSFILTER'"
	fi

	if [ -n "$LISTAIDS" ]; then
		readarray -t LISTAIDSARR <<<"$LISTAIDS"

		if [ "$LSTYPE" == "id" ]; then
			for AID in "${LISTAIDSARR[@]}"; do 
				echo "$AID"
			done
		elif [ "$LSTYPE" == "name" ]; then
			for AID in "${LISTAIDSARR[@]}"; do 
				getTitleFromID "${AID}"
			done
		elif [ "$LSTYPE" == "path" ]; then
			if [ "$LSFILTER" == "owned" ] || [ "$LSFILTER" == "o" ]; then
				echo "Cannot use 'path' option when returning 'owned' games, as not all owned games will have an installation path!"
				echo "Use another option instead, or leave blank to only return path for games which have an installation path."
			else
				for AID in "${LISTAIDSARR[@]}"; do
					getGameDir "$AID" "1"
				done
			fi
		elif [ "$LSTYPE" == "count" ]; then
			printf "\n%s" "$( getGameCount )"
		elif [ "$LSTYPE" == "full" ] || [ -z "$LSTYPE" ]; then  # This is the default if id/name/path/full is not passed
			for AID in "${LISTAIDSARR[@]}"; do
				GAMDIR="$( getGameDir "$AID" )"
				GAMDIREXISTS=$?

				# Only display game dir if the game is installed, i.e. if getGameDir does not return 1
				# This means we won't return an error if we're returning OWNED games, as some owned games may not have paths
				if [ $GAMDIREXISTS -eq 1 ]; then
					GAMNAM="$( getTitleFromID "$AID" )"
					GAMNAMEXISTS=$?
					if [ $GAMNAMEXISTS -eq 1 ]; then
						echo "$AID"  # Game name unknown, probably never installed before? Just return AppID in this case
					else
						echo "$GAMNAM ($AID)"
					fi
				else
					echo "$GAMDIR"
				fi
			done

			printf "\n%s" "$( getGameCount )"  # Show total for "full"
		fi
	fi
}

function getIDFromTitle {
	if [ -z "$1" ]; then
		echo "A Game Title (part of it might be enough) is required as argument"
	else
		# Search for all meta files with a partial match for their `NAME` field
		# Search on `NAME` primarily, fallback to `GAMENAME`
		mapfile -t MATCHES < <(grep -i "^NAME=.*.$1" "$GEMETA" -R)
		if [ -z "${MATCHES[*]}" ]; then
			mapfile -t MATCHES < <(grep -i "^GAMENAME=.*.$1" "$GEMETA" -R)
		fi

		# Echo all matches in format "AppID (Game Name)"
		if [ -n "${MATCHES[*]}"  ]; then
			for i in "${MATCHES[@]}"
			do
				MATCH_AID="$( echo "${i##*/}" | awk -F'.conf:' '{print $1}' )"
				MATCH_NAME="$( echo "${i##*/}" | awk -F'NAME="' '{print $2}' )"
				MATCH_NAME="$( echo "${MATCH_NAME::-1}" | xargs )"

				printf '%s\t\t(%s)\n' "$MATCH_AID" "$MATCH_NAME"
			done
		else
			echo "Could not find AppID for name '$1'."
		fi
	fi	
}

function getTitleFromID {
	if [ -z "$1" ]; then
		echo "A Game ID is required as argument"
	else
		if [ -f "$GEMETA/${1}.conf" ]; then
			if grep -q "^NAME" "$GEMETA/${1}.conf"; then
				grep "^NAME" "$GEMETA/${1}.conf" | cut -d '"' -f2
			else
				getAppInfoData "$1" "name"
			fi
		else
			# Try to get AppManifest based on passed ID if we don't have a data file
			GAMEMANIFEST="$( listAppManifests | grep -m1 "appmanifest_${1}.acf" )"

			if [ -n "$GAMEMANIFEST" ]; then
				getValueFromAppManifest "name" "$GAMEMANIFEST"
			else
				echo "No Title found for '$1'"

				return 1
			fi
		fi
	fi
}

function getExeFromID {
	if [ -z "$1" ]; then
		echo "A Game ID is required as argument"
	else
		if [ -f "$GEMETA/${1}.conf" ]; then
			# Some games might only have "EXECUTABLE" in their meta conf file
			EXE="$(grep "^EXECUTABLE" "$GEMETA/${1}.conf" | cut -d '"' -f2)"
			if [ -z "${EXE}" ]; then
				EXE="$(grep "^GAMEEXE" "$GEMETA/${1}.conf" | cut -d '"' -f2)"
			fi
			
			if [ -n "${EXE}" ]; then
				echo "$EXE"
				return
			fi
		fi

		echo "No Executable or SteamTinkerLaunch file found for '$1'"
	fi
}

function getCompatData {
	if [ -z "$1" ]; then
		echo "A Game ID or Game Title is required as argument"
	else
		if [ -d "$STLCOMPDAT" ]; then
			unset FCOMPDAT
			if [ "$1" -eq "$1" ] 2>/dev/null; then
				while read -r "complink"; do
				TEST="$(readlink "$complink" | grep "/$1$")"
				if [ -d "$TEST" ]; then
					FCOMPDAT="${complink##*/};$TEST"
				fi
				done <<< "$(find "$STLCOMPDAT")"
			else
				TEST="$(find "$STLCOMPDAT" -iname "*${1}*" | head -n1)"
				if [ -n "$TEST" ]; then
					FCOMPDAT="${TEST##*/};$(readlink "$TEST")"
				fi
			fi

			if [ -n "$FCOMPDAT" ]; then
				COMPATGAMENAME="$( echo "$FCOMPDAT" | cut -d ";" -f 1 )"
				COMPATGAMEPATH="$( echo "$FCOMPDAT" | cut -d ";" -f 2 )"
				COMPATGAMEAID="$( basename "$COMPATGAMEPATH" )"

				echo "${COMPATGAMENAME} (${COMPATGAMEAID}) -> ${COMPATGAMEPATH}"
			else
				echo "No $CODA dir found for '$1'"
			fi
		else
			echo "No $CODA dir found for '$1'"
		fi
	fi
}

# Credit to StackOverflow community wiki
function trimWhitespaces {
	INSTR="$*"
	# remove leading whitespace characters
	INSTR="${INSTR#"${INSTR%%[![:space:]]*}"}"
	# remove trailing whitespace characters
	INSTR="${INSTR%"${INSTR##*[![:space:]]}"}"
	echo "$INSTR"
}

# Extracts a value from a given App Manifest file path
function getValueFromAppManifest {
	KEY="$1"
	APPMA="$2"
	EXTVAL="$( grep -m1 "$KEY" "$APPMA" | sed "s-\t- -g;s-\"${KEY}\"--g;s-\"--g" )"  # xargs gets angry when names have single quotes, e.g. "Shantae and the Pirate's Curse"

	trimWhitespaces "$EXTVAL"
}

# Returns game install directory in the format "Game (AppID) -> /path/to/gamefolder"
function getGameDir {
	ONLYPATH="$2"

	if [ -z "$1" ]; then
		echo "A Game ID or Game Title is required as argument"
	else
		# First assume user entered AppID, then if no AppManifest found, try get AppID from name and search on that
		SEARCHMANIFEST="$( listAppManifests | grep -m1 "appmanifest_${1}.acf" )"
		if [ -z "$SEARCHMANIFEST" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Could not find App Manifest with entered argument '$1' - Assuming it is a game title and trying to find its AppID from title"
			SEARCHGETIDFROMTITLE="$( getIDFromTitle "$1" | head -n1 )"
			
			writelog "INFO" "${FUNCNAME[0]} - called 'getIDFromTitle' for argument '$1', it returned '$SEARCHGETIDFROMTITLE'"
			SEARCHAID="$( echo "$SEARCHGETIDFROMTITLE" | cut -d "(" -f 1 | xargs)"

			writelog "INFO" "${FUNCNAME[0]} - Extracted AppID from 'getIDFromTitle' result is '$SEARCHAID' - Searching for App Manifest with this AppID"

			SEARCHMANIFEST="$( listAppManifests | grep -m1 "appmanifest_${SEARCHAID}.acf" )"
			if [ -z "$SEARCHMANIFEST" ]; then
				writelog "ERROR" "${FUNCNAME[0]} - Could not find game directory for '$1' - Maybe it is not installed"
				echo "Could not find game directory for '$1'"
				return 1
			else
				writelog "INFO" "${FUNCNAME[0]} - Found matching App Manifest '$SEARCHMANIFEST'"
			fi
		else
			writelog "INFO" "${FUNCNAME[0]} - Found matching App Manifest file for presumed entered AppID '$1' - Manifest file is '$SEARCHMANIFEST'"
		fi

		APPMAINSTDIR="$( getValueFromAppManifest "installdir" "$SEARCHMANIFEST" )"
		APPMALIBFLDR="$( dirname "$SEARCHMANIFEST" )"
		GAMINSTDIR="$APPMALIBFLDR/common/$APPMAINSTDIR"
		MUSINSTDIR="$APPMALIBFLDR/music/$APPMAINSTDIR"  # Fixes a not found error for installed soundtracks
		if [ -d "$GAMINSTDIR" ] || [ -d "$MUSINSTDIR" ]; then
			APPMAGN="$( getValueFromAppManifest "name" "$SEARCHMANIFEST" )"
			APPMAAID="$( getValueFromAppManifest "appid" "$SEARCHMANIFEST" )"

			if [ -z "$ONLYPATH" ]; then
				printf "%s (%s) -> %s\n" "$APPMAGN" "$APPMAAID" "$GAMINSTDIR"
			else
				printf "%s\n" "$GAMINSTDIR"  # Only output path, used by "listSteamGames"
			fi
		else
			echo "Could not find install directory for '$1'"
		fi
	fi
}

function getGameWindowName {
	if [ -n "$GAMEWINDOW" ] && [ "$GAMEWINDOW" != "$NON" ]; then
		writelog "SKIP" "${FUNCNAME[0]} - Already have the gamewindow name: '$GAMEWINDOW' - skipping"
		rm "$PIDLOCK" 2>/dev/null
	else
		rm "$TEMPGPIDFILE" 2>/dev/null
		
		if [ -n "$GPFX" ]; then
			SYSREG="$GPFX/$SREG"
			if [ ! -f "$SYSREG" ] ; then
				writelog "WAIT" "${FUNCNAME[0]} - Waiting for the pfx '$GPFX' to be full created"
			fi

			while [ ! -f "$SYSREG" ]; do
				if [ -f "$CLOSETMP" ]; then
					break
				fi
				sleep 1
			done
		fi

		writelog "INFO" "${FUNCNAME[0]} - No gamewindow name stored in metadata '$GEMETA/$AID.conf' yet. Trying to find it now"
		FOUNDWIN="$NON"
		GAMEWINPID="$(getGameWindowPID)"
		if [ -n "$GAMEWINPID" ] ; then
			if [[ "$GAMEWINPID" == "$NON" ]] ; then
				writelog "SKIP" "${FUNCNAME[0]} - No valid game window PID found"
			else
				writelog "INFO" "${FUNCNAME[0]} - Found valid game window PID '$GAMEWINPID'"
				echo "GAMEWINPID=\"$GAMEWINPID\"" > "$TEMPGPIDFILE"

				GAMEWINXID="$(getGameWinXIDFromPid "$GAMEWINPID")"
				if [ -n "$GAMEWINXID" ]; then
					writelog "INFO" "${FUNCNAME[0]} - Found game window XID '$GAMEWINXID'"
					storeGameWindowNameMeta "$(getGameWinNameFromXid "$GAMEWINXID")"
				fi
			fi
		fi
	fi
}

function getCfgHeader {
	echo "#########"
	echo "#GAMENAME=\"$GAMENAME\""
	echo "#GAMEEXE=\"$GAMEEXE\""
	echo "#GAMEID=\"$AID\""
	echo "#PROTONVERSION=\"$PROTONVERSION\""
	echo "#########"	
}

function SBSrunVRVideoPlayer {
	SBSVRWINNAME="vr-video-player"

	if [ "$RUNSBSVR" -eq 1 ]; then
		if [ -z "$GAMEWINXID" ]; then
			writelog "SKIP" "${FUNCNAME[0]} - ERROR - GAMEWINXID is empty"
			writelog "SKIP" "${FUNCNAME[0]} - ERROR - forcefully killing game with $PKILL -9 '$GAMEWINPID' - should exit this script as well"
			getGamePidFromFile
			"$PKILL" -9 "$GAMEWINPID"
		else
			if [ -z "$VRVIDEOPLAYERARGS" ];	then
				writelog "SKIP" "${FUNCNAME[0]} - ERROR - no VRVIDEOPLAYERARGS '$VRVIDEOPLAYERARGS'"
			fi

			mapfile -d " " -t -O "${#RUNVRVIDEOPLAYERARGS[@]}" RUNVRVIDEOPLAYERARGS < <(printf '%s' "$VRVIDEOPLAYERARGS")

			writelog "INFO" "${FUNCNAME[0]} - Starting '$VRVIDEOPLAYER' with args '${RUNVRVIDEOPLAYERARGS[*]}' for windowid '$GAMEWINXID'"

			GWIDDEC="$(("$GAMEWINXID"))"
			echo "GWIDDEC=$GWIDDEC" > "$GWIDFILE"

			sleep 1	# ugly, but it might need a bit...
			
			if [ -z "$SBSZOOM" ]; then
				"$VRVIDEOPLAYER" "${RUNVRVIDEOPLAYERARGS[@]}" "$GAMEWINXID" 2>/dev/null &
			else
				"$VRVIDEOPLAYER" "${RUNVRVIDEOPLAYERARGS[@]}" --zoom "$SBSZOOM" "$GAMEWINXID" 2>/dev/null &
			fi

			writelog "INFO" "${FUNCNAME[0]} - Waiting for '$VRVIDEOPLAYER' window '$SBSVRWINNAME' for GAMEWINXID '$GAMEWINXID'"

			MAXWAIT=20
			COUNTER=0
			
			while ! "$XWININFO" -name "$SBSVRWINNAME" -stats >/dev/null 2>/dev/null; do
				if [ -f "$CLOSETMP" ]; then
					writelog "WAIT" "${FUNCNAME[0]} - ${PROGNAME,,} is just closing - leaving loop"
					break
				fi
				if [[ "$COUNTER" -ge "$MAXWAIT" ]]; then
					writelog "SKIP" "${FUNCNAME[0]} - ERROR - timeout waiting for '$VRVIDEOPLAYER' - exit"
					"$PKILL" -f "$VRVIDEOPLAYER"
					RUNSBSVR=0
					exit 1
				fi
				if ! "$PGREP" -f "$VRVIDEOPLAYER" ; then
					if [ "$COUNTER" -ge 3 ]; then
						writelog "SKIP" "${FUNCNAME[0]} - ERROR - '$VRVIDEOPLAYER' not running (crashed?) no need to wait for its window to appear - exit"
						RUNSBSVR=0
						exit 1
					else
						writelog "WARN" "${FUNCNAME[0]} - '$VRVIDEOPLAYER' not running yet - waiting a bit longer"
					fi
				fi

				writelog "WAIT" "${FUNCNAME[0]} - WAIT - '$COUNTER/$MAXWAIT' sec waiting for '$VRVIDEOPLAYER' window '$SBSVRWINNAME'"
				COUNTER=$((COUNTER+1))
				sleep 1
			done

			# player windowid:
			SBSVRWID=$("$XWININFO" -name "$SBSVRWINNAME" -stats | grep "^$XWININFO" | awk -F 'id: ' '{print $2}' | cut -d ' ' -f1)
				
			if [ -n "$SBSVRWID" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Pressing w in '$VRVIDEOPLAYER' window '$SBSVRWINNAME' to adjust view: '$XDO windowactivate --sync $SBSVRWID key w'"
				"$XDO" windowactivate --sync "$SBSVRWID" key w

				writelog "INFO" "${FUNCNAME[0]} - Activating game window with id '$GAMEWINXID' for input"
				"$XDO" windowactivate --sync "$GAMEWINXID" click 1
			else
				writelog "SKIP" "${FUNCNAME[0]} - WARN - SBSVRWID '$SBSVRWID' is empty!"
			fi
		fi
	else
		writelog "SKIP" "${FUNCNAME[0]} - Skipping because RUNSBSVR was set to 0"
	fi
}

function SBSinitVRVideoPlayer {
	if [ "$RUNSBSVR" -eq 1 ]; then
		if [ -n "$GAMEWINXID" ]; then
			if [ "$GAMEWINXID" == "0x0" ]; then
				writelog "SKIP" "${FUNCNAME[0]} GAMEWINXID '$GAMEWINXID' is invalid - skipping VR"
				RUNSBSVR=0
			else
				writelog "INFO" "${FUNCNAME[0]} Using the gamewindow id '$GAMEWINXID' for stereoscopic 3D VR"
				SBSrunVRVideoPlayer	"$GAMEWINXID" 2>/dev/null &
			fi
		fi
	else
		writelog "SKIP" "${FUNCNAME[0]} - Skipping because RUNSBSVR was set to 0"
	fi
}

function SBSstopVRVideoPlayer {
	if [ "$RUNSBSVR" -eq 1 ]; then

		MAXWAIT=20
		COUNTER=0
		while [ -z "$GAMEWINPID" ]; do
			if [ -f "$CLOSETMP" ]; then
				writelog "WAIT" "${FUNCNAME[0]} - ${PROGNAME,,} is just closing - leaving loop"
				break
			fi
			if [[ "$COUNTER" -ge "$MAXWAIT" ]]; then
				writelog "SKIP" "${FUNCNAME[0]} - ERROR - timeout waiting for Game process - exit"
				break
			fi

			writelog "INFO" "${FUNCNAME[0]} - Don't have a Game process GAMEWINPID yet - waiting"
			getGamePidFromFile
			GAMEWINPID="$(getGamePidFromWindowName)"
			COUNTER=$((COUNTER+1))
			sleep 1
		done
		
		writelog "INFO" "${FUNCNAME[0]} - Waiting for game process '$GAMEWINPID' to finish..."

		if ! "$PGREP" -a "vrcompositor" >/dev/null ; then
			writelog "SKIP" "${FUNCNAME[0]} - ERROR - vrcompositor not running but it should - bailing out DRYRUN"
		fi

		tail --pid="$GAMEWINPID" -f /dev/null
		writelog "INFO" "${FUNCNAME[0]} - Game process '$GAMEWINPID' finished - closing '$VRVIDEOPLAYER'"

		if [ -f "$GWIDFILE" ]; then
			source "$GWIDFILE"
			GWIDTXT="/tmp/${VRVIDEOPLAYER##*/}_${GWIDDEC}"

			if [ -f "$GWIDTXT" ]; then
				writelog "INFO" "${FUNCNAME[0]} - '$GWIDTXT' found"
				updateConfigEntry "SBSZOOM" "$(cat "$GWIDTXT")" "$SBSTWEAKCFG"
				rm "$GWIDTXT" >/dev/null 2>/dev/null
			else
				writelog "SKIP" "${FUNCNAME[0]} - GWIDTXT '$GWIDTXT' not found - skipping"
			fi
			rm "$GWIDFILE" >/dev/null 2>/dev/null
		else
			writelog "SKIP" "${FUNCNAME[0]} - GWIDFILE '$GWIDFILE' not found - skipping"
		fi

		"$PKILL" -f "$VRVIDEOPLAYER"

		writelog "INFO" "${FUNCNAME[0]} - -------- finished SBS-VR --------"
	else
		writelog "SKIP" "${FUNCNAME[0]} - Skipping because RUNSBSVR was set to 0"
	fi
}

function waitForGameWindowName {
	if [ -n "$GAMEWINDOW" ] && [ "$GAMEWINDOW" != "$NON" ]; then
		writelog "INFO" "${FUNCNAME[0]} - Already have a Game Window '$GAMEWINDOW'"
	else
		MAXWAIT=20
		COUNTER=0
		writelog "INFO" "${FUNCNAME[0]} - Waiting for parallel process to find the Game Window"

		while [ -f "$PIDLOCK" ]; do
			if [ -f "$CLOSETMP" ] || [[ "$COUNTER" -ge "$MAXWAIT" ]]; then
				break
			fi
			COUNTER=$((COUNTER+1))
			sleep 1
		done

		COUNTER=0

		while ! grep -q "^GAMEWINDOW" "$GEMETA/$AID.conf"; do
			if [ -f "$CLOSETMP" ]; then
				writelog "WAIT" "${FUNCNAME[0]} - ${PROGNAME,,} is just closing - leaving loop"
				break
			fi
			if [[ "$COUNTER" -ge "$MAXWAIT" ]]; then
				writelog "SKIP" "${FUNCNAME[0]} - Giving up waiting for GAMEWINDOW to appear in the game metadata '$GEMETA/$AID.conf'"
				break
			fi

			writelog "WAIT" "${FUNCNAME[0]} - WAIT - '$COUNTER/$MAXWAIT' sec waiting for GAMEWINDOW to appear in game metadata '$GEMETA/$AID.conf'"
			COUNTER=$((COUNTER+1))
			sleep 1
		done
		loadCfg "$GEMETA/$AID.conf" X

		if [ -n "$GAMEWINDOW" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Parallel process found Game Window '$GAMEWINDOW'"
		else
			writelog "SKIP" "${FUNCNAME[0]} - Parallel process didn't find a Game Window GAMEWINDOW"
		fi
	fi
}

function getGameWindowXID {
	if [ -n "$GAMEWINXID" ]; then
		writelog "INFO" "${FUNCNAME[0]} - Already have the windowid '$GAMEWINXID'"
	else	
		if [ -n "$GAMEWINDOW" ] && [ "$GAMEWINDOW" != "$NON" ]; then
			GAMEWINXID="$("$XWININFO" -name "${GAMEWINDOW//\"/}" -stats | grep "^$XWININFO" | awk -F 'id: ' '{print $2}' | cut -d ' ' -f1)"
			if [ -n "$GAMEWINXID" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Found windowid '$GAMEWINXID' for the windowname '$GAMEWINDOW'"
			fi
		fi
		if [ -z "$GAMEWINXID" ]; then
			if [ -n "$GAMEWINPID" ]; then
				GAMEWINXID="$(getGameWinXIDFromPid "$GAMEWINPID")"
			else
				writelog "SKIP" "${FUNCNAME[0]} - Don't have a game pid '$GAMEWINPID' to detect the windowid GAMEWINXID"
			fi
			if [ -n "$GAMEWINXID" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Found windowid '$GAMEWINXID' for the game pid '$GAMEWINPID'"
			fi
		fi
	fi
	if [ -n "$GAMEWINPID" ]; then
		echo "$GAMEWINPID"
	else
		writelog "SKIP" "${FUNCNAME[0]} - Failed to detect the windowid GAMEWINXID"
	fi
}

function waitForGameWindowXid {
	if [ -n "$GAMEWINXID" ]; then
		writelog "INFO" "${FUNCNAME[0]} - Already have the game window XID '$GAMEWINXID'"
	else
		if [ -n "$GAMEWINDOW" ] && [ "$GAMEWINDOW" != "$NON" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Waiting for a window GAMEWINXID of the game window '$GAMEWINDOW'"
			MAXWAIT=20
			COUNTER=0
			while ! "$XWININFO" -name "${GAMEWINDOW//\"/}"; do
				if [ -f "$CLOSETMP" ]; then
					writelog "WAIT" "${FUNCNAME[0]} - ${PROGNAME,,} is just closing - leaving loop"
					break
				fi
				if [[ "$COUNTER" -ge "$MAXWAIT" ]]; then
					writelog "SKIP" "${FUNCNAME[0]} - Giving up waiting for GAMEWINXID"
					break
				fi

				writelog "WAIT" "${FUNCNAME[0]} - WAIT '$COUNTER/$MAXWAIT'"
				sleep 1
				COUNTER=$((COUNTER+1))
			done
		elif [ -n "$GAMEWINPID" ]; then
			GAMEWINXID="$(getGameWinXIDFromPid "$GAMEWINPID")"
		else
			writelog "SKIP" "${FUNCNAME[0]} - Can't wait for the windowid GAMEWINXID without either a valid GAMEWINDOW or GAMEWINPID"
		fi

		GAMEWINXID="$("$XWININFO" -name "${GAMEWINDOW//\"/}" -stats | grep "^$XWININFO" | awk -F 'id: ' '{print $2}' | cut -d ' ' -f1)"

		if [ -n "$GAMEWINXID" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Found the game window id '$GAMEWINXID'"
		else
			writelog "SKIP" "${FUNCNAME[0]} - Didn't find a game window id GAMEWINXID"
		fi
	fi
}

function initSBSVR {
	if [ "$RUNSBSVR" -eq 1 ]; then
		writelog "INFO" "${FUNCNAME[0]} - Checking if VR is available"
		touch "$VRINITLOCK"
		checkHMDPresent
		initSteamVR
		mv "$VRINITLOCK" "$VRINITRESULT"
	fi
}

function startSBSVR {
	if [ "$RUNSBSVR" -eq 1 ]; then
		MAXWAIT=20
		COUNTER=0
		
		writelog "INFO" "${FUNCNAME[0]} - Waiting for parallel process to detect VR HMD presence"

		while [ -f "$VRINITLOCK" ]; do
			if [ -f "$CLOSETMP" ] || [[ "$COUNTER" -ge "$MAXWAIT" ]]; then
				break
			fi
			COUNTER=$((COUNTER+1))
			sleep 1
		done
		
		loadCfg "$VRINITRESULT"
		rm "$VRINITRESULT"
		
		if [ "$RUNSBSVR" -eq 1 ]; then
			if [ -f "$SBSTWEAKCFG" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Loading SBS configfile '$SBSTWEAKCFG' to get current values"
				loadCfg "$SBSTWEAKCFG"
			fi
			writelog "INFO" "${FUNCNAME[0]} - Preparing VR launch for '$AID'"
			waitForGameWindowName
			waitForGameWindowXid
			SBSinitVRVideoPlayer
			SBSstopVRVideoPlayer
		else
			writelog "SKIP" "${FUNCNAME[0]} - VR mode was cancelled, because the parallel process could not initialize VR"
		fi
	fi
}

function checkHMDPresent {
	if "$PGREP" -a "vrcompositor" >/dev/null ; then
		writelog "INFO" "${FUNCNAME[0]} - Looks like SteamVR is already running - skipping this function"
	else
		if [ "$CHECKHMD" -eq 1 ]; then
			UUDEV="/lib/udev/rules.d"
			EUDEV="/etc/udev/rules.d"
			SVR="steam-vr"
			NOVRP="1142"
			FOUNDHMD=0

			SVRRULE="$(find "$UUDEV" -name "*$SVR*")"
			if [ -z "$SVRRULE" ]; then
				SVRRULE="$(find "$EUDEV" -name "*$SVR*")"
			fi

			if [ -n "$SVRRULE" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Found $SVR udev rule - trying to find one of the VR devices before starting SteamVR"

				while read -r line; do
					IDV="$(cut -d ',' -f3 <<< "$line" | grep -oP '"\K[^"]+')"
					IDP="$(cut -d ',' -f4 <<< "$line" | grep -v "$NOVRP" | grep -oP '"\K[^"]+')"
					if [ -n "$IDV" ] && [ -n "$IDP" ]; then
						IDVP="$IDV:$IDP"
						if "$LSUSB" | grep -q "$IDVP"; then
							FOUNDHMD=1
						fi
					fi
				done < "$SVRRULE"
			else
				echo "no $SVR udev rule found"
				writelog "WARN" "${FUNCNAME[0]} - No $SVR udev rule found. As it might be stored under a different name, this is just a warning"
			fi

			if [ "$FOUNDHMD" -eq 1 ]; then
				writelog "INFO" "${FUNCNAME[0]} - Found $SVR hardware using '$LSUSB' - continuing"
			else
				writelog "SKIP" "${FUNCNAME[0]} - No $SVR hardware found using '$LSUSB' - cancelling the SteamVR start"
				RUNSBSVR=0
				echo "RUNSBSVR=\"0\"" > "$VRINITLOCK"
			fi
		else
			writelog "SKIP" "${FUNCNAME[0]} - Skipping, as '$LSUSB' was not found"
		fi
	fi
}

# start game in side-by-side VR:
function checkSBSVRLaunch {
	if [ "$1" != "$NON" ]; then
		writelog "INFO" "${FUNCNAME[0]} - Incoming gamewindow name is '$1'"
		RUNSBSVR=1
	fi

	if [ -n "$RUNSBSVR" ]; then
		if [ "$RUNSBSVR" -eq 1 ]; then
		# override game configs with a sbs-tweak config if available:
		
		# first look for a global tweak:
			if [ -f "$GLOBALSBSTWEAKCFG" ]; then
				writelog "INFO" "${FUNCNAME[0]} - VR using overrides found in '$GLOBALSBSTWEAKCFG'"
				loadCfg "$GLOBALSBSTWEAKCFG"
			fi

		# then for a user tweak - (overriding the global one):
			if [ -f "$SBSTWEAKCFG" ]; then
				writelog "INFO" "${FUNCNAME[0]} - VR using overrides found in '$SBSTWEAKCFG'"
				loadCfg "$SBSTWEAKCFG"
			fi

		# start the whole side-by-side process:
			if [ "$1" != "$NON" ]; then
				writelog "INFO" "${FUNCNAME[0]} - ${FUNCNAME[0]} - Using argument 1 as GAMEWINDOW '$GAMEWINDOW'"
				export GAMEWINDOW="$1"
			fi

			writelog "INFO" "${FUNCNAME[0]} - ${FUNCNAME[0]} - Starting VRlaunch for '$AID'"
			if [ "$RUNSBSVR" -eq 1 ]; then
				initSBSVR &
			else
				writelog "SKIP" "${FUNCNAME[0]} - ERROR - RUNSBSVR is '$RUNSBSVR' which is invalid - setting to 0"
				RUNSBSVR=0
			fi
		fi
	fi
}

function checkSBSLaunch {
	if [ "$RUNSBS" -eq 1 ]; then
	# first look for a global tweak:
		if [ -f "$GLOBALSBSTWEAKCFG" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Using SBS overrides found in '$GLOBALSBSTWEAKCFG'"
			loadCfg "$GLOBALSBSTWEAKCFG"
		fi

	# then for a user tweak - (overriding the global one):
		if [ -f "$SBSTWEAKCFG" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Using SBS overrides found in '$SBSTWEAKCFG'"
			loadCfg "$SBSTWEAKCFG"
		fi
	fi
}

function dld3d47 {
	function dld3d4732 {
		dlCheck "$DL_D3D47_32" "$D3D47DLDIR/${D3D47//.dll/.zip}" "X" "Downloading '$D3D47_32' into '$D3D47DLDIR'"
		find "$DLDST" -size 0 -delete
		"$UNZIP" "$DLDST" -d "$D3D47DLDIR" 2>/dev/null
		mv "$D3D47DLDIR/$D3D47" "$D3D47DLDIR/$D3D47_32" 2>/dev/null
	}
	
	function dld3d4764 {
		if [ ! -f "$D3D47DLDIR/$D3D47_64" ]; then
			dlCheck "$DL_D3D47_64" "$D3D47DLDIR/$D3D47_64" "X" "Downloading '$D3D47_64' into '$D3D47DLDIR'"
			find "$D3D47DLDIR/$D3D47_64" -size 0 -delete
		fi
	}
	mkProjDir "$D3D47DLDIR"
	dld3d47"$1"
}

function installd3d47dll {
	if [ ! -f "$2/$D3D47" ]; then
		if [ ! -f "$D3D47DLDIR/$1" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Sourcefile '$D3D47DLDIR/$1' missing - trying to download" 
			dld3d47 "32"
			dld3d47 "64"
		fi
	
		if [ ! -f "$D3D47DLDIR/$1" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Sourcefile '$D3D47DLDIR/$1' still missing - skipping this file" 	
		else
			cp "$D3D47DLDIR/$1" "$2/$D3D47" >/dev/null 2>/dev/null
			writelog "INFO" "${FUNCNAME[0]} - Copied '$D3D47DLDIR/$1' to '$2/$D3D47'"
			if [ "$USESPECIALK" -eq 1 ]; then
				echo "$2/$D3D47" >> "$SPEKENA"
			else
				echo "$D3D47" >> "$2/$RSTXT"
				sort "$2/$RSTXT" -u -o "$2/$RSTXT"
			fi
		fi
	else
		writelog "SKIP" "${FUNCNAME[0]} - Destfile '$2/$D3D47' already exists - skipping this file" 
	fi
}

function autoBumpReShade {
	RSVERSLATEST="$( fetchGitHubTags "$RESHADEPROJURL" "1" )"
	RSVERSLATEST="${RSVERSLATEST//v/}"
	if [ "$AUTOBUMPRESHADE" -eq 1 ] && [[ "$RSVERS" < "$RSVERSLATEST" ]]; then
		writelog "INFO" "${FUNCNAME[0]} - Found newer version of '$RESH' - Updating '$RSVERS' to '$RSVERSLATEST"
		touch "$FUPDATE" 
		updateConfigEntry "RSVERS" "$RSVERSLATEST" "$STLDEFGLOBALCFG"
	else
		writelog "SKIP" "${FUNCNAME[0]} - '$RSVERS' is the latest version of '$RESH' - not updating"
	fi
}

function createDLReShadeList {
	if ! ping -q -c1 github.com &>/dev/null; then
		writelog "INFO" "${FUNCNAME[0]} - Can't reach GitHub, so not attempting to fetch ReShade versions list"
 		RESHADEVERSIONS="none"
	else
		RSVERSONLINE="$( fetchGitHubTags "$RESHADEPROJURL" "3" )"
		RSVERSONLINE="${RSVERSONLINE//$'\n'/!}"
		RSVERSONLINE="${RSVERSONLINE//$!/}"
		RSVERSONLINE="${RSVERSONLINE//v/}"
		writelog "INFO" "${FUNCNAME[0]} - Found the following '$RESH' versions online '$RSVERSONLINE'"
		RESHADEVERSIONS="$RSOVRVERS!$RSVERSONLINE!4.91!3.4.1" 
	fi
}

function dlReShade {
	if [ -z "$1" ]; then
		DLVERS="$RSVERS"
	else
		DLVERS="$1"
	fi

	DLDST="${RESHADESRCDIR}/${RSSU}_${DLVERS}.exe"

	RSSETUP="${RESHADEDLURL}/${RSSU}_${DLVERS}.exe"

	dlCheck "$RSSETUP" "$DLDST" "X" "Downloading $RSSU"
	
	echo "$DLVERS" > "${DLDST//.exe/.log}"

	if [ ! -s "$DLDST" ]; then
		writelog "SKIP" "${FUNCNAME[0]} - Downloaded file '$DLDST' is empty - removing"
		rm "$DLDST" 2>/dev/null
	else
		"$UNZIP" -qo "$DLDST" -d "$RESHADESRCDIR/${DLVERS}" 2>/dev/null
		writelog "INFO" "${FUNCNAME[0]} - Downloaded and extracted ${RESH}-v${DLVERS} file '$DLDST'"
	fi
}

function overrideReShadeVersion {
	if [ "$RSOVRD" -eq 1 ]; then  # This is meant to be the checkbox var
		if [[ ! "$RSOVRVERS" = "$RSVERS" ]]; then
			writelog "INFO" "${FUNCNAME[0]} - Overriding global '$RESH' version '$RSVERS' with '$RSOVRVERS'"
       		RSVERS="$RSOVRVERS"
   		else
       		writelog "SKIP" "${FUNCNAME[0]} - '$RESH' Override version and '$RESH' global version match - Not overriding"
   	fi
	else
    	writelog "SKIP" "${FUNCNAME[0]} - '$RESH' override is disabled - Skipping"
	fi
}

# prepare reshade files if not found:
function prepareReshadeFiles {
	overrideReShadeVersion
	if [ "$DOWNLOAD_RESHADE" -eq 1 ]; then
	writelog "INFO" "${FUNCNAME[0]} - DOWNLOAD_RESHADE enabled"
		if [ ! -f "$D3D47DLDIR/$D3D47_32" ]; then dd
			writelog "404" "${FUNCNAME[0]} - '$D3D47DLDIR/$D3D47_32' missing - downloading"

			if [ ! -d "$RESHADESRCDIR" ]; then
				writelog "404" "${FUNCNAME[0]} - '$RESHADESRCDIR' does not exist - trying to create it" 
				mkProjDir "$RESHADESRCDIR"
			fi
		fi
		dld3d47 "32"
		dld3d47 "64"

		#Check if ReShade file are missing
		if [ ! -f "$RESHADESRCDIR/$RSVERS/$RS_64" ] || [ ! -f "$RESHADESRCDIR/$RSVERS/$RS_32" ]; then
			writelog "404" "${FUNCNAME[0]} - '$RESHADESRCDIR/$RSVERS/$RS_64' and/or '$RS_32' missing - downloading"
			dlReShade
		fi

		if [ ! -f "$RESHADESRCDIR/$RSVERS/$RS_64_VK" ] || [ ! -f "$RESHADESRCDIR/$RSVERS/$RS_32_VK" ]; then
			writelog "404" "${FUNCNAME[0]} - '$RESHADESRCDIR/$RSVERS/$RS_64_VK' and/or '$RS_32_VK' missing - downloading"
			dlReShade
		fi

		#Check if ReShade file is zero bytes
		if [ ! -s "$RESHADESRCDIR/$RSVERS/$RS_64" ] || [ ! -s "$RESHADESRCDIR/$RSVERS/$RS_32" ]; then
			writelog "404" "${FUNCNAME[0]} - '$RESHADESRCDIR/$RSVERS/$RS_64' and/or '$RS_32' corrupted - downloading"
			dlReShade
		fi
		if [ ! -s "$RESHADESRCDIR/$RSVERS/$RS_64_VK" ] || [ ! -s "$RESHADESRCDIR/$RSVERS/$RS_32_VK" ]; then
			writelog "404" "${FUNCNAME[0]} - '$RESHADESRCDIR/$RSVERS/$RS_64_VK' and/or '$RS_32_VK' corrupted - downloading"
			dlReShade
		fi

		if [ "$RESHADEUPDATE" -eq 1 ]; then
			if [ -f "${RESHADESRCDIR}/${RSSU}.log" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Found ${RESH} download log '${RESHADESRCDIR}/${RSSU}.log'"
				if [ "$RSVERS" != "$(cat "${RESHADESRCDIR}/${RSSU}.log")" ]; then
					writelog "INFO" "${FUNCNAME[0]} - Last downloaded is ${RESH} version '$(cat "${RESHADESRCDIR}/${RSSU}.log")' is not equal to the latest available ${RESH} version '$RSVERS' - updating"
					dlReShade
				fi
			fi
		fi
	fi
	
	# make sure Depth3D is even wanted
	if [ "$RESHADE_DEPTH3D" -eq 1 ]; then
		writelog "INFO" "${FUNCNAME[0]} - RESHADE_DEPTH3D enabled"
		StatusWindow "$GUI_DLSHADER" "dlShaders depth3d" "DownloadShadersStatus"
	fi	
}

function SHADSRC {
	echo "$STLSHADDIR/${1,,}"
}

function createShaderRepoList {
	SHADREPOURL="https://www.pcgamingwiki.com/wiki/${RESH}"
	MAXAGE=1440

	if [ ! -f "$SHADREPOLIST" ] || test "$(find "$SHADREPOLIST" -mmin +"$MAXAGE")"; then	
		# if this breaks, we'll use bundled static url list instead
		"$WGET" -q "$SHADREPOURL" -O - 2> >(grep -v "SSL_INIT") | sed -n '/Repository</,/table>/p' | grep "^<td>" | awk 'ORS=NR%3?FS:RS' | grep -v "https://blues" | sed "s:<td><a rel=\"nofollow\" class=\"external text\" href=::; s:</a></td> <td>:;:; s:</td> <td>:;:; s:\">:\";:; s:<br />: :; s: ;:;:; s:/tree/master::; s:/reshade/Shaders::" > "$SHADREPOLIST"
	fi

	RCL="repocustomlist.txt"
	SHADREPOCUSTOMLIST="$STLSHADDIR/$RCL"

	if [ ! -f "$SHADREPOCUSTOMLIST" ]; then
		cp "$GLOBALMISCDIR/$RCL" "$SHADREPOCUSTOMLIST"
	fi

	if [ -f "$SHADREPOCUSTOMLIST" ]; then
		cat "$SHADREPOCUSTOMLIST" >> "$SHADREPOLIST"
		sort -u "$SHADREPOLIST" -o "$SHADREPOLIST"
	fi
	
	sed '/^$/d' -i "$SHADREPOLIST"
}

function unblockrssub {
	if grep -q "^${RSSUB}$" "$SHADERREPOBLOCKLIST"; then
		writelog "INFO" "${FUNCNAME[0]} - Removing essential '${RSSUB}' from the shader blocklist '$SHADERREPOBLOCKLIST'"
		grep -v "^${RSSUB}$" "$SHADERREPOBLOCKLIST" > "$STLSHM/SHADERREPOBLOCKLIST_tmp.txt"
		mv "$STLSHM/SHADERREPOBLOCKLIST_tmp.txt" "$SHADERREPOBLOCKLIST"					
	fi
}

function dlShaders {
	createShaderRepoList
	touch "$SHADERREPOBLOCKLIST"
	unblockrssub

	if [ -z "$1" ]; then
		if [ "$DLSHADER" -eq 1 ]; then
			while read -r SHADLINE; do
				SHADURL="$(cut -d ';' -f1 <<< "$SHADLINE")"
				SHADNAM="$(cut -d ';' -f2 <<< "$SHADLINE")"
				if ! grep -qi "^${SHADNAM}$" "$SHADERREPOBLOCKLIST"; then
					writelog "INFO" "${FUNCNAME[0]} - Updating $SHADNAM" 
					notiShow "$(strFix "$NOTY_DLSHADERS" "$SHADNAM")" "S"
					gitUpdate "$(SHADSRC "$SHADNAM")" "${SHADURL//\"/}"
				else
					writelog "SKIP" "${FUNCNAME[0]} - Skipping $SHADNAM"
				fi
			done < "$SHADREPOLIST"
			notiShow "$GUI_DONE" "S"
		fi
	else
		if [ "$1" == "list" ]; then
			while read -r SHADLINE; do
				SHADNAM="$(cut -d ';' -f2 <<< "$SHADLINE")"
				echo "\"${SHADNAM,,}\""
			done < "$SHADREPOLIST" | sort
		elif [ "$1" == "repos" ]; then
			ShaderRepoDialog
		else
			SHADURL="$(grep -i ";$1;" "$SHADREPOLIST" | cut -d ';' -f1)"
			if [ -n "$SHADURL" ]; then
				gitUpdate "$(SHADSRC "$1")" "${SHADURL//\"/}"
			else
				writelog "SKIP" "${FUNCNAME[0]} - Invalid shader $1"
			fi
		fi
	fi
}

function ShaderRepoDialog {
	createShaderRepoList
	unblockrssub
	fixShowGnAid
	export CURWIKI="$PPW/Shader-Repositories"
	TITLE="${PROGNAME}-${FUNCNAME[0]}"
	pollWinRes "$TITLE"

	setShowPic

	REPOPICKS="$(
	while read -r SHADLINE; do
		SHADURL="$(cut -d ';' -f1 <<< "$SHADLINE")"
		SHADNAM="$(cut -d ';' -f2 <<< "$SHADLINE")"
		SHADAUT="$(cut -d ';' -f3 <<< "$SHADLINE")"
		SHADDES="$(cut -d ';' -f4 <<< "$SHADLINE")"

		if grep -qi "^${SHADNAM}$" "$SHADERREPOBLOCKLIST"; then
			echo FALSE
		else
			echo TRUE
		fi

		echo "$SHADURL"
		echo "$SHADNAM"
		echo "$SHADAUT"
		echo "$SHADDES"
	done < "$SHADREPOLIST" | \
	"$YAD" --f1-action="$F1ACTION" --image "$SHOWPIC" --image-on-top --window-icon="$STLICON" --center "$WINDECO" --list --checklist --column="$GUI_USE" --column="$GUI_URL" --column="$GUI_NAME" --column="$GUI_AUTH" --column="$GUI_DESC" --separator="" --print-column="3" \
	--text="$(spanFont "$(strFix "$GUI_SHADREPDIALOG" "$SGNAID")" "H")" --title="$TITLE" --button="$BUT_CAN:0" --button="$BUT_SELECT:2" "$GEOM")"
	case $? in
		0)	{
				writelog "INFO" "${FUNCNAME[0]} - Selected '$BUT_CAN' - Cancelling selection"
			}
		;;
		2)	{
				writelog "INFO" "${FUNCNAME[0]} - Selected '$BUT_SELECT' - Saving Selection"

				if [ -z "$REPOPICKS" ]; then
					writelog "INFO" "${FUNCNAME[0]} - Nothing selected"
					REPOPICKS=""
				else
					rm "$SHADERREPOBLOCKLIST" 2>/dev/null
					while read -r SHADLINE; do
						SHADNAM="$(cut -d ';' -f2 <<< "$SHADLINE")"
						if ! grep -q "$SHADNAM" <<< "$REPOPICKS"; then
							echo "${SHADNAM,,}" >> "$SHADERREPOBLOCKLIST"
						fi
					done < "$SHADREPOLIST"
					touch "$SHADERREPOBLOCKLIST"
					sort -u "$SHADERREPOBLOCKLIST" -o "$SHADERREPOBLOCKLIST"
					unblockrssub
				fi
			}
		;;
	esac
}

function setFullGameExePath {
	if [[ ( "$USECUSTOMCMD" -eq 1 && -f "$CUSTOMCMD" && "$CUSTOMCMDRESHADE" -eq 1 ) || "$ONLY_CUSTOMCMD" -eq 1 ]]; then
		FGEP="${CUSTOMCMD%/*}"

		writelog "INFO" "${FUNCNAME[0]} - Using the directory '$FGEP' of the used custom command as absolute game exe path"

		if [ "$CUSTOMCMDRESHADE" -eq 1 ]; then
			writelog "INFO" "${FUNCNAME[0]} - User enabled 'CUSTOMCMDRESHADE' - Using custom command directory with exe as ReShade installation directory"
		fi

		export "$1"="$FGEP"
	else
		if [ "$USECUSTOMCMD" -eq 1 ] && [ ! -f "$CUSTOMCMD" ]; then
			writelog "WARN" "${FUNCNAME[0]} - User enabled Custom Command, but custom command at '$CUSTOMCMD' is not a file!"
		fi

		if [ "$CUSTOMCMDRESHADE" -eq 0 ]; then
			writelog "INFO" "${FUNCNAME[0]} - User did not enable 'CUSTOMCMDRESHADE' - Using the game's exe directroy as the ReShade installation directory"
		fi
		setShaderDest
		if [ -n "$SHADDESTDIR" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Using SHADDESTDIR '$SHADDESTDIR' for '$1'"
			export "$1"="$SHADDESTDIR"
		elif [ -n "$EFD" ]; then
			loadCfg "$GEMETA/$AID.conf" X
			if [ -z "$EXECUTABLE" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Using the base game directory '$EFD' as absolute game exe path - probably never reached?"
				export "$1"="$EFD"
			else
				if [ "$ISORIGIN" -eq 1 ] && grep -q "$L2EA" <<< "$EXECUTABLE" ; then
					MYMETA="$EVMETAID/${EVALSC}_${AID}.vdf"
					if [ -f "$MYMETA" ]; then
						writelog "INFO" "${FUNCNAME[0]} - Origin game detected - looking for the real executable name instead of the used command '$EXECUTABLE'"
						touch "$FUPDATE"
						updateConfigEntry "ORIGINEXE" "$EXECUTABLE" "$GEMETA/${AID}.conf" # unused, but who knows what it is good for later
						# shellcheck disable=SC1003
						EXECUTABLE="$(grep "Uninstall" "$MYMETA" -A10 | grep "DisplayIcon" | awk -F '\\' '{print $NF}')"
						EXECUTABLE="${EXECUTABLE//\"}"
						touch "$FUPDATE"
						updateConfigEntry "EXECUTABLE" "$EXECUTABLE" "$GEMETA/${AID}.conf"
						GAMEEXE="${EXECUTABLE//.exe}"
						touch "$FUPDATE"
						updateConfigEntry "GAMEEXE" "$GAMEEXE" "$GEMETA/${AID}.conf"		
					else
						writelog "WARN" "${FUNCNAME[0]} - Origin game detected - but $EVALSC file $MYMETA not found - can't look for original game name"
					fi
				else
					writelog "WARN" "${FUNCNAME[0]} - Using some weird old function to determine the absolute exe path - please report, this should never be reached"
				fi

				if grep -q "\\\\" <<< "$EXECUTABLE"; then
					RELEX="${EXECUTABLE//\\//}"
					FGEP="${EFD}/${RELEX%/*}"
					if [ ! -d "$FGEP" ] && [ -d "$EFD" ]; then
						if grep -q "/" <<< "${RELEX%/*}"; then
							FGEP="${EFD}"
							while read -r subdir; do
								FGEP="$(find "$FGEP" -iname "$subdir")"
							done <<< "$(tr '/' '\n' <<< "${RELEX%/*}")"
						else
							FGEP="$(find "${EFD}" -iname "${RELEX%/*}")"
						fi
					fi
					
					if [ -d "$FGEP" ]; then
						writelog "INFO" "${FUNCNAME[0]} - Using '$FGEP' as absolute game exe path"
						export "$1"="$FGEP"	
					fi
				fi
			fi
		fi
	fi
}

function setShaderDest {
	
	if [ -z "$SHADLOGGED" ]; then
		SHADLOGGED=0	
	fi

	if [ -n "$(GETALTEXEPATH)" ]; then
		SHADDESTDIR="$(GETALTEXEPATH)"
		writelog "INFO" "${FUNCNAME[0]} - Overriding SHADDESTDIR to '$SHADDESTDIR' because ALTEXEPATH is set to '$ALTEXEPATH'"
	fi

	if [ -z "$SHADDESTDIR" ]; then
		writelog "INFO" "${FUNCNAME[0]} - Determining Shader destination directory SHADDESTDIR"
		if [ -z "$1" ] || [ "$1" == "last" ]; then		
			if [ "$ABSGAMEEXEPATH" != "$NON" ]; then
				SHADDESTDIR="${ABSGAMEEXEPATH%/*}"
				writelog "INFO" "${FUNCNAME[0]} - Using variable ABSGAMEEXEPATH for Shader destination directory '$SHADDESTDIR'"
			else
				resetAID "last"
				if [ -f "$LASTRUN" ] && grep -q "$AID" "$LASTRUN"; then
					ABSGAMEEXEPATH="$(grep "^PREVABSGAMEEXEPATH" "$LASTRUN" | cut -d '=' -f2)"
					ABSGAMEEXEPATHDIR="${ABSGAMEEXEPATH%/*}"
					if [ -d "${ABSGAMEEXEPATHDIR//\"/}" ]; then
						SHADDESTDIR="${ABSGAMEEXEPATHDIR//\"/}"
						writelog "INFO" "${FUNCNAME[0]} - Using last PREVABSGAMEEXEPATH variable from '$LASTRUN' for Shader destination directory '$SHADDESTDIR'"
					else
						writelog "WARN" "${FUNCNAME[0]} - Found PREVABSGAMEEXEPATH variable in '$LASTRUN' but its directory does not exist"
					fi
				else
					notiShow "$NOTY_NOAIDNOPREV"
				fi
			fi
		else
			writelog "INFO" "${FUNCNAME[0]} - Using argument '$1' for Shader destination directory '$SHADDESTDIR'"
			if [ -f "$1" ]; then
				SHADDESTDIR="$(dirname "$1")"
			else 
				SHADDESTDIR="$1"
			fi
		fi

		if [ -n "$SHADDESTDIR" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Using Shader destination directory '$SHADDESTDIR'"
		fi
	fi	

	if [ -n "$SHADDESTDIR" ] && [ "$SHADLOGGED" -eq 0 ] ; then
		writelog "INFO" "${FUNCNAME[0]} - Shader destination directory is '$SHADDESTDIR'"
		SHADLOGGED=1
	fi
}

function disableThisGameShaderRepo {
	RMREP="$1"
	if [ -n "$2" ]; then
		SHADDESTDIR="$2"
	else
		setShaderDest
	fi

	if [ -z "$RSDSTS" ]; then
		RSDST="$SHADDESTDIR/$RSSUB"
		RSDSTS="$RSDST/Shaders"
		RSDSTT="$RSDST/Textures"
		RSDSTE="$RSDST/enabled"
	fi

	if [ -n "$RMREP" ] && [ -f "$RSDSTE/$RMREP" ]; then
		notiShow "$(strFix "$NOTY_SHADDIS" "$RMREP")"

		# removed disabled shaders
		if [ -d "$RSDSTS" ]; then
			while read -r syml; do
				if [[ "$(readlink "$syml")" =~ $RMREP ]]; then
					writelog "INFO" "${FUNCNAME[0]} - Removing shader symlink '$syml' from deactivated repo '$RMREP'" "X" "$SHADLOG"
					rm "$syml"
				fi
			done <<< "$(find -L "$RSDSTS")"
		fi
		# removed disabled textures
		if [ -d "$RSDSTT" ]; then
			while read -r syml; do
				if [[ "$(readlink "$syml")" =~ $RMREP ]]; then
					writelog "INFO" "${FUNCNAME[0]} - Removing texture symlink '$syml' from deactivated repo '$RMREP'" "X" "$SHADLOG"
					rm "$syml"
				fi
			done <<< "$(find -L "$RSDSTT")"
		fi
		rm "$RSDSTE/$RMREP" 
	fi
}

function enableThisGameShaderRepo {
	SELREPO="$1"
	REPDIR="$STLSHADDIR/$SELREPO"

	if grep -q "^${SELREPO}$" "$SHADERREPOBLOCKLIST"; then
		writelog "SKIP" "${FUNCNAME[0]} - The selected repo '$SELREPO' is in the block list '$SHADERREPOBLOCKLIST'" "X" "$SHADLOG"
	else
		if [ -n "$2" ]; then
			SHADDESTDIR="$2"
		else
			setShaderDest
		fi

		if [ ! -d "$REPDIR" ]; then
			writelog "SKIP" "${FUNCNAME[0]} - The directory '$REPDIR' for the selected repo '$SELREPO' does not exist" "X" "$SHADLOG"
		else
			if [ -z "$RSDSTS" ]; then
				RSDST="$SHADDESTDIR/$RSSUB"
				RSDSTS="$RSDST/Shaders"
				RSDSTT="$RSDST/Textures"
				RSDSTE="$RSDST/enabled"

				mkProjDir "$RSDSTS"
				mkProjDir "$RSDSTT"
				mkProjDir "$RSDSTE"
			fi

			if [ -f "$RSDSTE/$SELREPO" ]; then
				writelog "SKIP" "${FUNCNAME[0]} - Repo '$SELREPO' is already activated for the game" "X" "$SHADLOG"
			else
				notiShow "$(strFix "$NOTY_SHADENA" "$SELREPO")"
				# updating shaders
				writelog "INFO" "${FUNCNAME[0]} - Updating shaders for activated repo '$SELREPO'" "X" "$SHADLOG"
				SHADERSRC="$(find "$REPDIR" -type d -iname "Shaders")"
				if [ -n "$SHADERSRC" ]; then
					while read -r shaderfile; do
						writelog "INFO" "${FUNCNAME[0]} - Creating symlink '$RSDSTS/${shaderfile##*/}' for shader '$shaderfile'" "X" "$SHADLOG"
						ln -s "$shaderfile" "$RSDSTS/${shaderfile##*/}" 2>/dev/null
					done <<< "$(find "$SHADERSRC" -mindepth 1 -maxdepth 1)"
					touch "$RSDSTE/$SELREPO"
				fi

				# updating textures
				writelog "INFO" "${FUNCNAME[0]} - Updating textures for activated repo '$SELREPO'" "X" "$SHADLOG"
				TEXTURESRC="$(find "$REPDIR" -type d -iname "Textures")"			
				if [ -n "$TEXTURESRC" ]; then
					while read -r texfile; do
						writelog "INFO" "${FUNCNAME[0]} - Creating symlink '$RSDSTT/${texfile##*/}' for texture '$texfile'" "X" "$SHADLOG"
						ln -s "$texfile" "$RSDSTT/${texfile##*/}" 2>/dev/null
					done <<< "$(find "$TEXTURESRC" -mindepth 1 -maxdepth 1)"		
				fi
			fi
		fi
	fi
}

function GameShaderDialog {
	touch "$SHADERREPOBLOCKLIST"

	setShaderDest "$1"

	RSDST="$SHADDESTDIR/$RSSUB"
	RSDSTS="$RSDST/Shaders"
	RSDSTT="$RSDST/Textures"
	RSDSTE="$RSDST/enabled"

	if [ -f "$SHADLOG" ]; then
		rm "$SHADLOG" 2>/dev/null
	fi

	if [ "$SHADDESTDIR" != "$NON" ]; then
		mkProjDir "$RSDSTS"
		mkProjDir "$RSDSTT"
		mkProjDir "$RSDSTE"
	fi

	if [ -d "$RSDST" ]; then
		writelog "INFO" "${FUNCNAME[0]} - Opening Shader Selection Dialog for dir '$RSDST'"

		SHADDLLAST="$STLSHADDIR/lastdl.txt"
		MAXAGE=1440

		if [ ! -f "$SHADDLLAST" ] || test "$(find "$SHADDLLAST" -mmin +"$MAXAGE")"; then
			StatusWindow "$GUI_DLSHADER" "dlShaders" "DownloadShadersStatus"
			echo "$(date) - ${FUNCNAME[0]}" > "$SHADDLLAST"
		fi

		export CURWIKI="$PPW/Shader-Management"
		TITLE="${PROGNAME}-Shader"
		pollWinRes "$TITLE"

		setShowPic

		unset AVAILREPOS
		unset SELREPOS
		unset UNSELREPOS

		# appending a ';' to the reponames to prevent cutting the wrong, similar filename
		mapfile -d "|" -t -O "${#AVAILREPOS[@]}" AVAILREPOS <<< "$(find "$STLSHADDIR" -mindepth 1 -maxdepth 1 -not -empty -type d -printf "%p;\n")"

		SELREPOS="$(while read -r repo; do REPONAME="${repo##*/}"; if [ -f "$RSDSTE/${REPONAME//;}" ]; then	echo TRUE ; echo "${REPONAME//;}"; else echo FALSE ; echo "${REPONAME//;}" ;fi ; done <<< "$(printf "%s\n" "${AVAILREPOS[@]}")" | \
		"$YAD" --f1-action="$F1ACTION" --image "$SHOWPIC" --image-on-top --window-icon="$STLICON" --center "$WINDECO" --list --checklist --column="$GUI_ADD" --column=Shader-Repo --separator=" " --print-column="2" \
		--text="$(spanFont "$(strFix "$GUI_SHADERDIALOG" "${RSDST##*/}")" "H")" --title="$TITLE" "$GEOM")"
		case $? in
			0)  {
					UNSELREPO=( "${AVAILREPOS[@]}" )
									
					if [ -n "${SELREPOS[0]}" ]; then
						writelog "INFO" "${FUNCNAME[0]} - At least one repo was enabled, so automatically enabling required repo '$RSSUB'" "X" "$SHADLOG"
						SELREPOS=( "${SELREPOS[@]}" "$RSSUB" )

						writelog "INFO" "${FUNCNAME[0]} - Activating shaders for enabled repos" "X" "$SHADLOG"

						while read -r SELREPO; do
							writelog "INFO" "${FUNCNAME[0]} - Enabled: $SELREPO" "X" "$SHADLOG"
							unset REPDIR
							enableThisGameShaderRepo "$SELREPO"
							REPDIR="$STLSHADDIR/${SELREPO};"
							UNSELREPO=( "${UNSELREPO[@]/$REPDIR}" )

						done <<< "$(printf "%s\n" "${SELREPOS[@]}")"
					fi

					writelog "INFO" "${FUNCNAME[0]} - Deactivating shaders for disabled repos" "X" "$SHADLOG"

					while read -r UNSEL; do
						if [ -n "$UNSEL" ] && [ "$UNSEL" != ";" ]; then
							unset RMREP
							RMREP="${UNSEL//;}"
							RMREP="${RMREP##*/}"
							if [ "$RMREP" != "$RSSUB" ]; then
								writelog "INFO" "${FUNCNAME[0]} - Disabled: $RMREP" "X" "$SHADLOG"
								disableThisGameShaderRepo "$RMREP"
							fi
						fi
					done <<< "$(printf "%s\n" "${UNSELREPO[@]}")"

					if [ -z "${SELREPOS[0]}" ] && [ -f "$RSDSTE/$RSSUB" ]; then
						writelog "INFO" "${FUNCNAME[0]} - No repo was enabled, so also disabling the repo '$RSSUB'" "X" "$SHADLOG"
						disableThisGameShaderRepo "$RSSUB"
					fi

					writelog "INFO" "${FUNCNAME[0]} - Deactivating shaders for blocked repos" "X" "$SHADLOG"
					while read -r BLOCKREP; do
						disableThisGameShaderRepo "$BLOCKREP"
					done < "$SHADERREPOBLOCKLIST"
				}
			;;
			1)  writelog "INFO" "${FUNCNAME[0]} - Selected CANCEL"
			;;
		esac
	else
		writelog "SKIP" "${FUNCNAME[0]} - Dest Dir '$SHADDESTDIR' does not exist and could not be created - skipping"
		if [ -z "$SHADDESTDIR" ]; then
			SHADDESTDIR="$NON"
		fi 
		notiShow "$(strFix "$NOTY_MISSDIR" "$SHADDESTDIR")"
	fi

	if [ -n "$2" ];	then "$2";	fi
}

function getArch {
	# maybe remove reduntant lines later
	if [ "$(file "$1" | grep -c "PE32 ")" -eq 1 ]; then
		writelog "INFO" "${FUNCNAME[0]} - Architecture for '$1' is 32bit"
		echo "32"
	elif [ "$(file "$1" | grep -c "PE32+ ")" -eq 1 ]; then
		writelog "INFO" "${FUNCNAME[0]} - Architecture for '$1' is 64bit"
		echo "64"
	else
		if [ "$(find "$(dirname "$1")" -name "*.exe" | wc -l)" -ge 0 ]; then
			TESTEXE="$(find "$(dirname "$1")" -name "*.exe" | head -n1)"
			if [ "$(file "$TESTEXE" | grep -c "PE32 ")" -eq 1 ]; then
				writelog "INFO" "${FUNCNAME[0]} - Architecture for bundled '$TESTEXE' for '$1' is 32bit"
				echo "32"
			elif [ "$(file "$TESTEXE" | grep -c "PE32+ ")" -eq 1 ]; then
				writelog "INFO" "${FUNCNAME[0]} - Architecture for bundled '$TESTEXE' for '$1' is 64bit"
				echo "64"
			fi
		elif [ "$(find "$(dirname "$1")" -name "*.dll" | wc -l)" -ge 0 ]; then
			TESTDLL="$(find "$(dirname "$1")" -name "*.dll" | head -n1)"
			if [ "$(file "$TESTDLL" | grep -c "PE32 ")" -eq 1 ]; then
				writelog "INFO" "${FUNCNAME[0]} - Architecture for bundled '$TESTDLL' for '$1' is 32bit"
				echo "32"
			elif [ "$(file "$TESTDLL" | grep -c "PE32+ ")" -eq 1 ]; then
				writelog "INFO" "${FUNCNAME[0]} - Architecture for bundled '$TESTDLL' for '$1' is 64bit"
				echo "64"
			fi
		else
			writelog "SKIP" "${FUNCNAME[0]} - Could not detect architecture for '$1' directly or indirectly"
		fi
	fi
}

function chooseShaders {
	if [ "$CHOOSESHADERS" -eq 1 ]; then
		setShadDestDir
		writelog "INFO" "${FUNCNAME[0]} - Opening Shader Menu - shader destination path is '$SHADDESTDIR'"
		GameShaderDialog "$SHADDESTDIR"
	fi
}

function installRSdll {
	if [ ! -f "$INSTDESTDIR/$1" ] || [ "$1" == "F" ]; then
		if [ -n "$2" ] && [ "$2" -eq 1 ]; then
			writelog "SKIP" "${FUNCNAME[0]} - Skipping installation of $1 because 'NOD3D9' is enabled"
		else
			if [ ! -f "$RESHADESRCDIR/$RSVERS/$3" ]; then
				writelog "SKIP" "${FUNCNAME[0]} - Sourcefile '$RESHADESRCDIR/$RSVERS/$3' missing - skipping this file" 
			else
				cp "$RESHADESRCDIR/$RSVERS/$3" "$INSTDESTDIR/$1" >/dev/null 2>/dev/null
				echo "$1" >> "$INSTDESTDIR/$RSTXT"
				sort "$INSTDESTDIR/$RSTXT" -u -o "$INSTDESTDIR/$RSTXT"
				writelog "INFO" "${FUNCNAME[0]} - Copied '$RESHADESRCDIR/$RSVERS/$3' to '$INSTDESTDIR/$1'" 
			fi
		fi
	else
		if [ "$RESHADEUPDATE" -eq 0 ]; then
			writelog "SKIP" "${FUNCNAME[0]} - Destfile '$INSTDESTDIR/$1' already exists, but not checking the installed version, because RESHADEUPDATE is '$RESHADEUPDATE'" 
		else
			if grep -q "$RSVERS" <<< "$(strings "$INSTDESTDIR/$1" | grep "^Initializing")"; then
				writelog "SKIP" "${FUNCNAME[0]} - Destfile '$INSTDESTDIR/$1' already exists in the same version '$RSVERS' - skipping this file" 
			else
				writelog "INFO" "${FUNCNAME[0]} - Destfile '$INSTDESTDIR/$1' already exists, but has a different version - updating"
				cp "$RESHADESRCDIR/$RSVERS/$3" "$INSTDESTDIR/$1" >/dev/null 2>/dev/null
			fi
		fi
	fi
}

# install reshade:
function installReshade {
	if [ "$INSTALL_RESHADE" -eq 1 ]; then

		prepareReshadeFiles
		setShadDestDir

		INSTDESTDIR="$SHADDESTDIR"

		# checking for previous dll conficts between $RS_DX_DEST and $RS_D9_DEST
		# note: modern ReShade uses "ReShade_exenamehere.log", and old versions use "dxgi.log" (if ReShade dll is named dxgi.dll). we support both names.
		RESHADE_CONFLICTS=$(find "$INSTDESTDIR" -maxdepth 1 \( -name "${RS_DX_DEST//.dll/.log}" -or -name "ReShade_*.log" \) -print0 | xargs -0 -r grep -l "Another ReShade instance was already loaded from" | wc -l)
		if [ "$RESHADE_CONFLICTS" -ge 1 ]; then
			writelog "INFO" "${FUNCNAME[0]} - Found $RS_DX_DEST conflict with $RS_D9_DEST"
			if [ -f "$INSTDESTDIR/$RS_D9_DEST" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Removing $RS_D9_DEST"
				rm "$INSTDESTDIR/$RS_D9_DEST"
			else
				writelog "SKIP" "${FUNCNAME[0]} - $RS_D9_DEST not found"
			fi

			if [ -z "$NOD3D9" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Blocking re-installation of '$RS_D9_DEST' by setting NOD3D9=1 in '$STLGAMECFG'"
				updateConfigEntry "NOD3D9" "1" "$STLGAMECFG"
				export NOD3D9=1
			fi
		else
			writelog "INFO" "${FUNCNAME[0]} - No conflict found in old logfiles"
		fi

		if [ -n "$ARCHALTEXE" ] && [[ ! "$ARCHALTEXE" =~ ${DUMMYBIN}$ ]]; then
			CHARCH="$ARCHALTEXE"
		else
			CHARCH="$GP"
		fi

		if [ -d "$INSTDESTDIR" ]; then
			#32bit:
			if [ "$(getArch "$CHARCH")" == "32" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Installing 32bit ${RESH} as '$CHARCH' is 32bit" 
				#d3d47
				installd3d47dll "$D3D47_32" "$INSTDESTDIR"
				#dxgi:
				installRSdll "$RS_DX_DEST" "0" "$RS_32"
				#d3d9:
				installRSdll "$RS_D9_DEST" "$NOD3D9" "$RS_32"

			# 64bit:
			elif [ "$(getArch "$CHARCH")" == "64" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Installing 64bit ${RESH} as '$CHARCH' is 64bit" 
				#d3d47
				installd3d47dll "$D3D47_64" "$INSTDESTDIR"
				#dxgi:
				installRSdll "$RS_DX_DEST" "0" "$RS_64"
				#d3d9:
				installRSdll "$RS_D9_DEST" "$NOD3D9" "$RS_64"
			else
				writelog "SKIP" "${FUNCNAME[0]} - ERROR in ${RESH} installation - no file information detected for '$CHARCH' or any 'neighbor file' - setting USERESHADE=0 for this session"
				export USERESHADE=0
			fi
		else
			writelog "SKIP" "${FUNCNAME[0]} - INSTDESTDIR '$INSTDESTDIR' not found" 
		fi
	fi
}

function installDepth3DReshade {
	SHADERPOOL="depth3d"
	
	if [ "$RESHADE_DEPTH3D" -eq 1 ]; then
		StatusWindow "$GUI_DLSHADER" "dlShaders $SHADERPOOL" "DownloadCustomProtonStatus"
		setShadDestDir
		enableThisGameShaderRepo "$SHADERPOOL"
	fi
}

function checkReshade {
	setShadDestDir

	RSLIST="$SHADDESTDIR/$RSTXT"
	RSOLIST="${RSLIST}_off"
	FRSINI="$SHADDESTDIR/$RSINI"
	FRSOINI="$SHADDESTDIR/${RSINI}_off"

	# TODO remove later:
	RSENABLED="${RESH}-${PROGNAME,,}-enabled.txt"
	RSDISABLED="${RESH}-${PROGNAME,,}-disabled.txt"
	# this doesn't cover all migration constellations, but better than nothing
	if [ "$USERESHADE" -eq 1 ] && [ -f "$SHADDESTDIR/$RSENABLED" ]; then
		mv "$SHADDESTDIR/$RSENABLED" "$RSLIST"
		if [ -f "$SHADDESTDIR/$RS_DX_DEST" ] && grep -q "$RESH" "$SHADDESTDIR/$RS_DX_DEST"; then
			echo "$RS_DX_DEST" >> "$RSLIST"
		fi

		if [ -f "$SHADDESTDIR/$RS_D9_DEST" ] && grep -q "$RESH" "$SHADDESTDIR/$RS_D9_DEST"; then
			echo "$RS_D9_DEST" >> "$RSLIST"
		fi
		sort "$RSLIST" -u -o "$RSLIST"
	elif [ "$USERESHADE" -eq 1 ] && [ -f "$SHADDESTDIR/$RSDISABLED" ]; then
		mv "$SHADDESTDIR/$RSDISABLED" "$RSOLIST"
		if [ -f "$SHADDESTDIR/$RS_DX_DEST" ] && grep -q "$RESH" "$SHADDESTDIR/$RS_DX_DEST"; then
			echo "$RS_DX_DEST" >> "$RSOLIST"
		fi

		if [ -f "$SHADDESTDIR/$RS_D9_DEST" ] && grep -q "$RESH" "$SHADDESTDIR/$RS_D9_DEST"; then
			echo "$RS_D9_DEST" >> "$RSOLIST"
		fi
		sort "$RSOLIST" -u -o "$RSOLIST"
	fi
	#
	
	if [ "$USERESHADE" -eq 1 ]; then
		if [ -f "$FRSINI" ]; then
			if grep -q "EffectSearchPaths=.\$RSSUB\Shaders" "$FRSINI"; then
				writelog "SKIP" "${FUNCNAME[0]} - Already have '$FRSINI' with default paths pointing to '$RSSUB'"
			else
				writelog "SKIP" "${FUNCNAME[0]} - Found a '$FRSINI' without default paths pointing to '$RSSUB' - not touching it"
			fi
		else
			if [ -f "$FRSOINI" ] && grep -q "EffectSearchPaths=.*$RSSUB.*Shaders" "$FRSOINI"; then
				writelog "INFO" "${FUNCNAME[0]} - Re-enabling previously disabled '$FRSOINI'"
				mv "$FRSOINI" "$FRSINI"
			else
				writelog "INFO" "${FUNCNAME[0]} - Creating initial '$FRSINI' with default paths pointing to '$RSSUB'"
				{
					echo "[GENERAL]"
					echo "EffectSearchPaths=.\\$RSSUB\Shaders"
					echo "TextureSearchPaths=.\\$RSSUB\Textures"
					echo "PreprocessorDefinitions=RESHADE_DEPTH_LINEARIZATION_FAR_PLANE=1000.0,RESHADE_DEPTH_INPUT_IS_UPSIDE_DOWN=0,RESHADE_DEPTH_INPUT_IS_REVERSED=1,RESHADE_DEPTH_INPUT_IS_LOGARITHMIC=0"
				} > "$FRSINI"
			fi
		fi

#XXXXXXXXXXXXX
		if [ "$USESPECIALK" -eq 1 ]; then
			writelog "INFO" "${FUNCNAME[0]} - Both '$SPEK' and '$RESH' are enabled." "E"
			#writelog "INFO" "${FUNCNAME[0]} - Unfortunately the game currently crashes using Proton when both are enabled"
			writelog "INFO" "${FUNCNAME[0]} - During the last test long ago this crashed the game" "E"
			writelog "INFO" "${FUNCNAME[0]} - therefore the $RESH install to the $SPEK directory redirect is disabled" "E"
			writelog "INFO" "${FUNCNAME[0]} - Might work meanwhile, you're welcome to re-animate the functions" "E"
			# see also function prepareSpecialKReshade

#			writelog "INFO" "${FUNCNAME[0]} - Using ${RESH} and $SPEK together"
#			mkProjDir "$SHADDESTDIR"
#			if [ ! -f "$SHADDESTDIR/$RS_64" ]; then
#				writelog "INFO" "${FUNCNAME[0]} - Copying '$RESHADESRCDIR/$RS_64' and friends to '$SHADDESTDIR'"
#				cp "$RESHADESRCDIR/$RS_64" "$SHADDESTDIR"
#				cp "$RESHADESRCDIR/$RS_32" "$SHADDESTDIR"
#				cp "$RESHADESRCDIR/${RS_64//.dll/.json}" "$SHADDESTDIR"
#				cp "$RESHADESRCDIR/${RS_32//.dll/.json}" "$SHADDESTDIR"
#			else
#				writelog "SKIP" "${FUNCNAME[0]} - Already have '$RS_64' in '$SHADDESTDIR'"
#			fi
		fi

#		else
			if [ -f "$RSOLIST" ]; then
				writelog "INFO" "${FUNCNAME[0]} - ${RESH} has been disabled previously using '${PROGNAME,,}' - enabling it now"
				while read -r rsdll; do
					if [ -f "$SHADDESTDIR/${rsdll}_off" ]; then
						mv "$SHADDESTDIR/${rsdll}_off" "$SHADDESTDIR/$rsdll"
					else
						writelog "WARN" "${FUNCNAME[0]} - '$SHADDESTDIR/${rsdll}_off' was supposed to be reenabled, but the file is missing"
					fi
				done < "$SHADDESTDIR/${RSTXT}_off"
				mv "$RSOLIST" "$RSLIST"
			fi

			if [ ! -f "$SHADDESTDIR/$D3D47" ]; then
				writelog "INFO" "${FUNCNAME[0]} - USERESHADE is '$USERESHADE' - looks like ${RESH} is not yet installed in '$SHADDESTDIR' - installing because USERESHADE is enabled"
				INSTALL_RESHADE=1 installReshade
			fi

			if [ -f "$FRSINI" ] && [ ! -f "$RSLIST" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Looks like ${RESH} was installed previously using '${PROGNAME,,}' without creating '$RSLIST' - recreating it now"
				INSTALL_RESHADE=1 installReshade F
			fi

			writelog "INFO" "${FUNCNAME[0]} - Setting WINEDLLOVERRIDES for ${RESH}: dxgi=n,b;d3d9=n,b;${D3D47//.dll}=n,b"
			export WINEDLLOVERRIDES="$WINEDLLOVERRIDES;dxgi=n,b;d3d9=n,b;${D3D47//.dll}=n,b"
#		fi
	else	
		if [ -f "$FRSINI" ]; then
			writelog "INFO" "${FUNCNAME[0]} - ${RESH} has been disabled by the user, so renaming '$FRSINI' to '$FRSOINI'"
			mv "$FRSINI" "$FRSOINI"
		fi

		if [ -f "$RSLIST" ]; then
			writelog "INFO" "${FUNCNAME[0]} - ${RESH} has been installed previously with '${PROGNAME,,}' - disabling it now"
			while read -r rsdll; do
				if [ -f "$SHADDESTDIR/${rsdll}" ]; then
					mv "$SHADDESTDIR/$rsdll" "$SHADDESTDIR/${rsdll}_off"
				else
					writelog "WARN" "${FUNCNAME[0]} - '$SHADDESTDIR/${rsdll}' was supposed to be disabled, but the file is already missing"
				fi
			done < "$RSLIST"
			mv "$RSLIST" "$RSOLIST"
		fi
		
		if [ "$USESPECIALK" -eq 0 ]; then
			if [ -f "$SHADDESTDIR/$RS_DX_DEST" ] && grep -q "$RESH" "$SHADDESTDIR/$RS_DX_DEST"; then
				writelog "WARN" "${FUNCNAME[0]} - Found unknown '$RESH' dll '$RS_DX_DEST' in '$SHADDESTDIR'"
			fi

			if [ -f "$SHADDESTDIR/$RS_D9_DEST" ] && grep -q "$RESH" "$SHADDESTDIR/$RS_D9_DEST"; then
				writelog "WARN" "${FUNCNAME[0]} - Found unknown '$RESH' dll '$RS_D9_DEST' in '$SHADDESTDIR'"
			fi
		fi
	fi
}

function extSpek {
	SRCARCH="$1"
	SPEXT64="$SPEKDLDIR/$SPEKVERS/${SPEK}64.dll"

	if [ -f "$SPEXT64" ]; then
		writelog "SKIP" "${FUNCNAME[0]} - Already have '$SPEXT64' - skipping extraction" "E"
	else
		if [ ! -f "$SRCARCH" ]; then
			SRCARCH="${SRCARCH//lK/l_K}"
		fi
		if [ -f "$SRCARCH" ]; then
			if [ -x "$(command -v "$SEVZA")" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Extracting '$SRCARCH' to '$SPEKDLDIR/$SPEKVERS'" "E"
				"$SEVZA" x "$SRCARCH" -o"$SPEKDLDIR/$SPEKVERS" 2>/dev/null
			else
				writelog "SKIP" "${FUNCNAME[0]} - Can't extract '$SRCARCH', because '$SEVZA' wasn't found!" "E"
			fi
		fi
	fi
}

function dlSpecialK {
	if [ -n "$1" ]; then
		SPEKVERS="$1"
	fi

	SPEKARC="${SPEK}.7z"

	mkProjDir "$SPEKDLDIR/$SPEKVERS"

	SPEKDL="$SPEKDLDIR/$SPEKVERS/$SPEKARC"
	
	if [ "$SPEKVERS" == "default" ]; then
		SPEKDLURL="$SPEKURL/$SPEKARC"
	elif [ "$SPEKVERS" == "latest" ]; then
		SPEKDLURL="$SPEKGHURL/$SPEKVERS/download/$SPEKARC"
	else 
		SPEKDLURL="$SPEKGHURL/download/SK_${SPEKVERS//./_}/$SPEKARC"
	fi
	
	if [ ! -f "$SPEKDL" ]; then
		notiShow "$(strFix "$NOTY_DLCUSTOMPROTON" "$SPEK")"
		dlCheck "$SPEKDLURL" "$SPEKDL" "X" "Downloading '$SPEKDLURL' to '$SPEKDLDIR'"
		extSpek "$SPEKDL"
	elif [ "$AUTOSPEK" -eq 1 ] && { [ "$SPEKVERS" == "default" ] || [ "$SPEKVERS" == "latest" ];}; then
		writelog "INFO" "${FUNCNAME[0]} - AUTOSPEK is enabled and SPEKVERS is '$SPEKVERS' - so looking for $SPEK updates" "E"
		# XXXXXX todo remove previous download?
		notiShow "$(strFix "$NOTY_DLCUSTOMPROTON" "$SPEK")"
		dlCheck "$SPEKDLURL" "$SPEKDL" "X" "Downloading '$SPEKDLURL' to '$SPEKDLDIR'"
		extSpek "$SPEKDL"
	else
		writelog "INFO" "${FUNCNAME[0]} - Already have the archive '${SPEKDL}'" "E"
	fi
	
	SPEK32SRC="$SPEKDLDIR/$SPEKVERS/${SPEK}32.dll"
	SPEK64SRC="$SPEKDLDIR/$SPEKVERS/${SPEK}64.dll"

	if [ -f "$SPEK32SRC" ]; then
		writelog "INFO" "${FUNCNAME[0]} - '$SPEK32SRC' is ready" "E"
	else
		writelog "SKIP" "${FUNCNAME[0]} - '$SPEK32SRC' is missing!" "E"
	fi

	if [ -f "$SPEK64SRC" ]; then
		writelog "INFO" "${FUNCNAME[0]} - '$SPEK64SRC' is ready" "E"
	else
		writelog "SKIP" "${FUNCNAME[0]} - '$SPEK64SRC' is missing!" "E"
	fi
}

function getSpecialKGameRenderApi {
	SPEKCOMP="$SPEKDLDIR/${SPEK}_compat.html"
	MAXAGE=1440
	if [ ! -f "$SPEKCOMP" ] || test "$(find "$SPEKCOMP" -mmin +"$MAXAGE")"; then
		dlCheck "$SPEKCOMPURL" "$SPEKCOMP" "X" "Downloading '$SPEKCOMP'"
	fi
	writelog "INFO" "${FUNCNAME[0]} - Searching Render Api for '$GN' in '$SPEKCOMP'"
	RAPI="$(sed -n "/id=\"Compatibility_list\"/,$ p" "$SPEKCOMP" | grep -A1 "${GN// /\*.\*}" | tail -n1 | cut -d '>' -f2 | cut -d '<' -f1)"
	if [ -n "$RAPI" ]; then
		writelog "INFO" "${FUNCNAME[0]} - Found Render Api '$RAPI'"
		if [ "$RAPI" == "Direct3D 11" ]; then
			SPEKDST="$SPEKDDIR/$DXGI"
		elif [ "$RAPI" == "Direct3D 9" ]; then
			SPEKDST="$SPEKDDIR/$D3D9"
		elif [ "$RAPI" == "OpenGL" ]; then
			SPEKDST="$SPEKDDIR/$OGL32"
		else
			writelog "INFO" "${FUNCNAME[0]} - Unknown Render Api '$RAPI' - assuming 'Direct3D 11'"
			SPEKDST="$SPEKDDIR/$DXGI"
		fi
	else
		writelog "INFO" "${FUNCNAME[0]} - Could not find Render Api - assuming 'Direct3D 11'"
		SPEKDST="$SPEKDDIR/$DXGI"
	fi	
}

function prepareSpecialKReshade {
	if [ "$USERESHADE" -eq 1 ]; then
		writelog "INFO" "${FUNCNAME[0]} - Both '$SPEK' and '$RESH' are enabled." "E"
		#writelog "INFO" "${FUNCNAME[0]} - Unfortunately the game currently crashes using Proton when both are enabled"
		writelog "INFO" "${FUNCNAME[0]} - During the last test long ago this crashed the game" "E"
		writelog "INFO" "${FUNCNAME[0]} - therefore the $RESH install to the $SPEK directory redirect is disabled" "E"
		writelog "INFO" "${FUNCNAME[0]} - Might work meanwhile, you're welcome to re-animate the functions" "E"
		# see also function checkReshade
			
		# XXXXXXXXXXXXX
		# maybe later:
		# "[Import.ReShade64]"
		# "Architecture=x64"
		# "Role=ThirdParty"
		# "When=PlugIn"
		# "When=Early"
		# "Filename=C:\users\steamuser\Documents\My Mods\SpecialK\PlugIns\ThirdParty\ReShade\ReShade64.dll"
	fi
}

function prepareSpecialKIni {
	UWI="UsingWINE"
	UWIT="$UWI=true"

	if [ -f "$SPEKDDIR/$DXGI" ]; then
		FOUNDRAPI="$SPEKDDIR/$DXGI"
	elif [ -f "$SPEKDDIR/$D3D9" ]; then
		FOUNDRAPI="$SPEKDDIR/$D3D9"
	elif [ -f "$SPEKDDIR/$OGL32" ]; then
		FOUNDRAPI="$SPEKDDIR/$D3D9"
	else
		getSpecialKGameRenderApi
		FOUNDRAPI="$SPEKDST"
	fi

	if [ -z "$SPEKINI" ]; then
		SPEKINI="${FOUNDRAPI//.dll/.ini}"
	fi
	
	COGE="Compatibility.General"

	if [ -n "$SPEKINI" ]; then
		if [ -f "$SPEKINI" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Found the ini file '$SPEKINI' - enabling '$UWI' function" "E"
			if grep -q "$UWIT" "$SPEKINI"; then
				writelog "SKIP" "${FUNCNAME[0]} - nothing to do - '$UWI' is already enabled" "E"
			elif grep -q "$UWI=false" "$SPEKINI"; then
				writelog "INFO" "${FUNCNAME[0]} - Enabling '$UWI' in the config" "E"
				sed "s:$UWI=false:$UWIT:" -i "$SPEKINI"
			else
				writelog "INFO" "${FUNCNAME[0]} - Adding a new entry '$UWI' in the ini, because it is missing" "E"
				if grep -q "$COGE" "$SPEKINI"; then
					sed "/\[$COGE\]/a $UWIT" -i "$SPEKINI"
				else
					sed "1 i $UWIT" -i "$SPEKINI"
					sed "1 i \[$COGE\]" -i "$SPEKINI"
				fi
			fi

		else
			writelog "INFO" "${FUNCNAME[0]} - Creating a minimal ini file '$SPEKINI' with enabled '$UWI' function" "E"
			{
				echo "[$COGE]"
				echo "$UWIT"
			} >> "$SPEKINI"
		fi
	fi
}

function createDLSpekList {
	# maybe improve later

	if [ "$USESPECIALK" -eq 1 ]; then
		writelog "INFO" "${FUNCNAME[0]} - $SPEK is enabled, looking for available versions online"
		while read -r line; do
			mapfile -t -O "${#SKDLList[@]}" SKDLList <<< "$line"
		done <<< "$("$WGET" -q "$SPEKGHURL" -O - 2> >(grep -v "SSL_INIT") | grep "download*.*\.7z" | grep -oE '\"/[^\\"]+' | sed "s|^\"/${SPEK}O/${SPEK}/releases/download/SK_||g" | sed "s|/${SPEK}.7z||g" | sed "s|_|.|g")" # '
		SPEKYADLIST="latest!$(printf "!%s\n" "${SKDLList[@]//\"/}" | tr -d '\n' | sed "s:^!::" | sed "s:!$::")"
	else
		writelog "SKIP" "${FUNCNAME[0]} - Skipping looking for available SpecialK versions, because USESPECIALK is disabled"
		SPEKYADLIST="latest"
	fi
}

function useSpecialK {
	function installSpekDll {
		SPEKSRC="$1"
		if [ -f "$SPEKDST" ] && [ "$(stat -c %s "$SPEKSRC")" -eq "$(stat -c %s "$SPEKDST")" ]; then
			writelog "SKIP" "${FUNCNAME[0]} - Nothing to update - '$SPEKDST' corresponds to '$SPEKSRC'" "E"
		else
			writelog "INFO" "${FUNCNAME[0]} - Installing '${SPEKSRC##*/}' as '$GP' is $2-bit" "E"
			cp "$SPEKSRC" "$SPEKDST"
			if [ -f "${SPEKSRC//dll/pdb}" ]; then
				SPEKPDB="${SPEKSRC##*/}"
				SPEKPDB="${SPEKPDB//dll/pdb}"
				writelog "INFO" "${FUNCNAME[0]} - Also installing debugging '$SPEKPDB'" "E"
				cp "${SPEKSRC//dll/pdb}" "$SPEKDDIR"
				echo "$SPEKDDIR/$SPEKPDB" >> "$SPEKENA"
			fi
		fi

		IPAK="vcrun2019-$3"
		if [ -f "$GPFX/${IPAK}_installed.txt" ]; then
			writelog "SKIP" "${FUNCNAME[0]} - Skipping '$IPAK' - already installed" "E"
		else
			installSteWoShPak "$IPAK" "$GPFX" "$RUNWINE"
			echo "$IPAK" > "$GPFX/${IPAK}_installed.txt"
		fi
		installd3d47dll "$4" "$SPEKDDIR"
	}

	function installSpekArchDll {
		if [ "$USECUSTOMCMD" -eq 1 ] && [ -f "$CUSTOMCMD" ]; then
			ARCHEXE="$CUSTOMCMD"
		else
			ARCHEXE="$GP"
		fi
		
		if [ "$(getArch "$ARCHEXE")" == "32" ]; then
			installSpekDll "$SPEK32SRC" "32" "x86" "$D3D47_32"
		elif [ "$(getArch "$ARCHEXE")" == "64" ]; then
			installSpekDll "$SPEK64SRC" "64" "x64" "$D3D47_64"
		else
			writelog "SKIP" "${FUNCNAME[0]} - Could not determine the architecture of '$GP' - not installing '$SPEK'" "E"
		fi
	}
	
	SPEKDDIR="$EFD"
	setFullGameExePath "SPEKDDIR"	
	SPEKENA="$SPEKDDIR/${SPEK}_enabled.txt"

	if [ "$USESPECIALK" -eq 1 ]; then
		REQDLL="api-ms-win-crt-string-l1-1-0.dll"
		if [ -d "$GPFX/$DRCW" ] && [ ! -f "$GPFX/$DRCW/system32/$REQDLL" ]; then # the directory check exists for skipping the warning if the pfx does not exist yet _(not nice, but )_ - PR if you care
			writelog "SKIP" "${FUNCNAME[0]} - '$SPEK' requires '$REQDLL', which is not available in the WINEPREFIX currently running with '$USEPROTON'" "E"
			notiShow "$(strFix "$NOTY_MISSDLL" "$SPEK" "$REQDLL" "$USEPROTON")"
		else
			prepareSpecialKReshade
			prepareSpecialKIni
			UPSPEK=1
			
			if [ "$AUTOSPEK" -eq 1 ] && { [ "$SPEKVERS" == "default" ] || [ "$SPEKVERS" == "latest" ];}; then
				writelog "INFO" "${FUNCNAME[0]} - Updating $SPEK in the gamedir because AUTOSPEK is enabled"
				UPSPEK=1
			elif [ -f "$SPEKENA" ]; then
				writelog "SKIP" "${FUNCNAME[0]} - ${SPEK} is already configured - nothing to do"
				UPSPEK=0
			fi
			
			if [ "$UPSPEK" -eq 1 ]; then
				writelog "INFO" "${FUNCNAME[0]} - ${SPEK} is enabled - Installing dlls if required"
				dlSpecialK

				getSpecialKGameRenderApi
				
				writelog "INFO" "${FUNCNAME[0]} - Using '$SPEKDST' as $SPEK destination dll"

				if [ -f "$GPFX/$DRCW/DirectX.log" ]; then
					writelog "SKIP" "${FUNCNAME[0]} - Skipping 'dxsetup' - already installed" "E"
				else
					notiShow "$(strFix "$NOTY_INSTSTART" "dxsetup")"
					installSteWoShPak "dxsetup" "$GPFX" "$RUNWINE"
					notiShow "$(strFix "$NOTY_INSTSTOP" "dxsetup")"
				fi

				echo "$SPEKDST" > "$SPEKENA"

				if [ -f "$SPEKDST" ]; then
					if [ "$AUTOSPEK" -eq 1 ] && { [ "$SPEKVERS" == "default" ] || [ "$SPEKVERS" == "latest" ];}; then
						writelog "INFO" "${FUNCNAME[0]} - Updating $SPEK dlls because AUTOSPEK is enabled"
						installSpekArchDll
					else
						writelog "SKIP" "${FUNCNAME[0]} - Already have a '${SPEKDST##*/}' in '$SPEKDDIR' - not installing '$SPEK'" "E"
					fi
				else
					installSpekArchDll
				fi
			fi
		fi
	else
		if [ -f "$SPEKENA" ]; then
			writelog "INFO" "${FUNCNAME[0]} - ${SPEK} was enabled before, removing existing $SPEK dlls"
			while read -r spekdll; do
				rm "$spekdll" 2>/dev/null
			done < "$SPEKENA"
			rm "$SPEKENA" 2>/dev/null
		fi
	fi
}

function getUsedVars {
	while read -r line; do 
		if grep -q -v "^#" <<< "$line"; then
			awk -F '=' '{print $1}' <<< "$line" 
		fi
	done <"$1"
}

function getScreenRes {
	function widthList {
		"$XRANDR" --verbose | grep "\*" -A2 | grep -oP 'width\K[^start]+'
	}

	function heightList {
		"$XRANDR" --verbose | grep "\*" -A2 | grep -oP 'height\K[^start]+'	
	}

	function getRes {
		if grep -q "^[0-9]*$" <<< "$FOUNDW" && grep -q "^[0-9]*$" <<< "$FOUNDH"; then
			FOUNDRES="${FOUNDW}x${FOUNDH}"
			writelog "INFO" "${FUNCNAME[0]} - Detected screen resolution '$FOUNDRES'" "X"
			echo "$FOUNDRES"
		else
			writelog "INFO" "${FUNCNAME[0]} - Screen resolution for width '$FOUNDW' and height '$FOUNDH' is invalid" "X"
		fi		
	}

	HCNT="$(wc -l <<< "$(widthList)")"
	if [ "$HCNT" -eq 1 ] || [ "$HCNT" -gt 2 ]; then
		FOUNDW="$(widthList | head -n1 | tr -dc '0-9')"
		FOUNDH="$(heightList | head -n1 | tr -dc '0-9')"
	else
		XCUT="$("$XRANDR" --listactivemonitors | grep -Eo "\+[1-9][[:digit:]]*\+" | grep -Eo "[[:digit:]]*")"
		MPOS="$("$XDO" getmouselocation --shell | head -n1 | cut -d '=' -f2)"
		if [ "$MPOS" -gt "$XCUT" ]; then
			FOUNDW="$(widthList | tail -n1 | tr -dc '0-9')"
			FOUNDH="$(heightList | tail -n1 | tr -dc '0-9')"
		else
			FOUNDW="$(widthList | head -n1 | tr -dc '0-9')"
			FOUNDH="$(heightList | head -n1 | tr -dc '0-9')"
		fi
	fi

	if [ "$1" == "w" ]; then
		if grep -q "^[0-9]*$" <<< "$FOUNDW"; then
			writelog "INFO" "${FUNCNAME[0]} - Found screen width '$FOUNDW'" "X"
			echo "$FOUNDW"
		else
			writelog "INFO" "${FUNCNAME[0]} - Screen width '$FOUNDW' is invalid" "X"
		fi
	elif [ "$1" == "h" ]; then
		if grep -q "^[0-9]*$" <<< "$FOUNDH"; then
			writelog "INFO" "${FUNCNAME[0]} - Found screen height '$FOUNDH'" "X"
			echo "$FOUNDH"
		else
			writelog "INFO" "${FUNCNAME[0]} - Screen height '$FOUNDH' is invalid" "X"
		fi		
	else
		getRes
	fi
}

function listScreenRes {
	while read -r lres; do
		echo "${lres%*[[:blank:]]}" | cut -d ' ' -f1
	done <<< "$("$XRANDR" --verbose | grep "+VSync$")" | sort -nur
}

function setInitWinXY {
	DEFRESSHM="$STLSHM/defres.txt"
	if [ -f "$DEFRESSHM" ] ; then
		loadCfg "$DEFRESSHM" X
		writelog "INFO" "${FUNCNAME[0]} - Using '${WINX}x${WINY}' from config '$DEFRESSHM'"
	else
		if [ "$ONSTEAMDECK" -eq 1 ]; then
			WINX="1280"
			WINY="800"
		else
			SCRW="$(getScreenRes w)"
			SCRH="$(getScreenRes h)"
			WINX=$(( SCRW * 3 / 4))
			WINY=$(( SCRH * 3 / 4))
		fi

		{
		echo "WINX=\"$WINX\""
		echo "WINY=\"$WINY\""
		} >> "$DEFRESSHM"
		writelog "INFO" "${FUNCNAME[0]} - Using '${WINX}x${WINY}' as default resolution for all windows without a configured resolution"
	fi
}

function setNewRes {
	SCREENRES="$(getScreenRes r)"
	if [ "$GAMESCREENRES" != "$NON" ] && [ "$GAMESCREENRES" != "$SCREENRES" ]; then
		writelog "INFO" "${FUNCNAME[0]} - Setting screen resolution to '$GAMESCREENRES' using '$XRANDR'" "X"
		"$XRANDR" -s "$GAMESCREENRES"
	fi
}

function setPrevRes {
	if [ "$GAMESCREENRES" != "$NON" ]; then
		writelog "INFO" "${FUNCNAME[0]} - Returning to previous screen resolution via '$XRANDR -s 0'" "X"
		"$XRANDR" -s 0
	fi
}

function customUserScriptStart {
	if [ -n "$USERSTART" ] && [[ ! "$USERSTART" =~ ${DUMMYBIN}$ ]]; then
		if [ -x "$USERSTART" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Starting custom user startscript '$USERSTART'"
			if [ "$USEWINE" -eq 0 ]; then
				"$USERSTART" "1" "$AID" "$GP" "$GPFX" &
			else
				"$USERSTART" "1" "$AID" "$GP" "$GWFX" &
			fi
		else
			writelog "SKIP" "${FUNCNAME[0]} - Custom user startscript '$USERSTART' not found or not executable"
		fi
	fi
}

function customUserScriptStop {
	if [ -n "$USERSTOP" ] && [[ ! "$USERSTOP" =~ ${DUMMYBIN}$ ]]; then
		if [ -x "$USERSTOP" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Starting custom user stopscript '$USERSTOP'"
			if [ "$USEWINE" -eq 0 ]; then
				"$USERSTOP" "0" "$AID" "$GP" "$GPFX" &
			else
				"$USERSTOP" "0" "$AID" "$GP" "$GWFX" &
			fi
		else
			writelog "SKIP" "${FUNCNAME[0]} - Custom user stopscript '$USERSTOP' not found or not executable"
		fi
	fi
}

function editorSkipped {
	if [ -z "$MAXASK" ]; then
		writelog "INFO" "${FUNCNAME[0]} - Maximal editor requester count MAXASK not defined - skipping"
	else
		if ! grep -q "^ASKCNT" "$STLGAMECFG"; then
			SETASKCNT=1
			updateConfigEntry "ASKCNT" "$SETASKCNT" "$STLGAMECFG"
		else
			SETASKCNT=$(($(grep "ASKCNT" "$STLGAMECFG" | cut -d '=' -f2 | sed 's/\"//g') +1))
			updateConfigEntry "ASKCNT" "$SETASKCNT" "$STLGAMECFG"
		fi

		ASKCNT="$SETASKCNT"

		if [ "$ASKCNT" -ge "$MAXASK" ]; then
			notiShow "$(strFix "$NOTY_CANCELREQ1" "$MAXASK" "$GN" "$AID")"
			writelog "INFO" "${FUNCNAME[0]} - 'ASKCNT $ASKCNT' reached 'MAXASK $MAXASK' - disabling requester and resetting counter"
			updateConfigEntry "WAITEDITOR" "0" "$STLGAMECFG"
			updateConfigEntry "ASKCNT" "0" "$STLGAMECFG"
		elif [ "$ASKCNT" -lt "$MAXASK" ]; then
			notiShow "$(strFix "$NOTY_CANCELREQ2" "$ASKCNT" $((MAXASK - ASKCNT)) "$GN" "$AID")"
		fi
	fi
}

function checkWaitRequester {
	if [ -f "$EWRF" ] ; then
		if grep -q "^WAITEDITOR=\"0\"" "$STLGAMECFG"; then
			writelog "INFO" "${FUNCNAME[0]} - Re-enabling Wait Requester in '$STLGAMECFG', because '$EWRF' was found"
			updateConfigEntry "WAITEDITOR" "2" "$STLGAMECFG"
		fi
		rm "$EWRF"
	fi
	
	if [ -f "$UWRF" ] ; then
		if [ -f "$SWRF" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Stop skipping Wait Requester, because '$UWRF' was found"
			rm "$SWRF"
		fi
		rm "$UWRF"
	fi
}

function askSettings {
	if ! grep -q "^WAITEDITOR=\"0\"" "$STLGAMECFG"; then
		if [ -f "$SWRF" ]; then
			writelog "SKIP" "${FUNCNAME[0]} - Skipping Wait-Requester because skip file was found under '$SWRF'"
		else
			# open editor requester 
			if grep -q "^WAITEDITOR" "$STLGAMECFG"; then
				WEDGAME="$(grep "^WAITEDITOR" "$STLGAMECFG"| cut -d '=' -f2)"
				WAITEDITOR="${WEDGAME//\"/}"
				writelog "INFO" "${FUNCNAME[0]} - Using game specific requester timeout '$WAITEDITOR'"
			fi

			writeAllAIMeta "$AID" &

			if [ "$WAITEDITOR" -gt 0 ]; then
				writelog "INFO" "${FUNCNAME[0]} - Opening Requester with timeout '$WAITEDITOR'"

				getAvailableCfgs
				fixShowGnAid
				export CURWIKI="$PPW/Wait-Requester"
				TITLE="${PROGNAME}-OpenSettings"
				pollWinRes "$TITLE"

				setShowPic

				if [ "$STARTMENU" == "Editor" ]; then
					REQQEST="$GUI_ASKOPENED"
					REQBUT="$BUT_EDITORMENU"
					LAUNCHMENU="EditorDialog"
				elif [ "$STARTMENU" == "Favorites" ]; then
					REQQEST="$GUI_ASKOPENFAV"
					REQBUT="$BUT_FAV"
					LAUNCHMENU="favoritesMenu"
				elif [ "$STARTMENU" == "Game" ]; then
					REQQEST="$GUI_ASKOPENGAM"
					REQBUT="$BUT_GM"	
					LAUNCHMENU="openGameMenu"
				else
					REQQEST="$GUI_ASKOPENSET"
					REQBUT="$BUT_MAINMENU"
					LAUNCHMENU="MainMenu"
				fi
			
				ASKSETSTLVERS="<b>${PROGNAME} ${PROGVERS}</b>"

				LAPL="$(getLaPl)"

				PDBROUT=""
				prepareProtonDBRating
				if [ -f "$PDBRASINF" ];then
					PDBROUT="$(cat "$PDBRASINF")"
				fi

				# Tested and this should not break Non-Steam Games - Open an issue if it does!
				prepareSteamDeckCompatInfo
				STEAMDECKCOMPATOUT="<b>$GUI_SDCR:</b> ${STEAMDECKCOMPATRATING:$STEAMDECKCOMPAT_UNKNOWN}"
				if ! [ -f "$STLGDECKCOMPAT/${AID}-deckcompatrating.json" ]; then
					# If the Steam Deck compat rating json doesn't exist, assume something messed up e.g. offline or JQ is not installed
					writelog "INFO" "${FUNCNAME[0]} - Could not retrieve Steam Deck compatibility rating, defaulting to $STEAMDECKCOMPAT_UNKNOWN - Maybe '$JQ' is missing or we are offline?"
				fi

				writelog "INFO" "${FUNCNAME[0]} - Steam Deck compatibility rating string is '$STEAMDECKCOMPATOUT'"
				writelog "INFO" "${FUNCNAME[0]} - Preparing to show Wait Requester"

				"$YAD" --f1-action="$F1ACTION" --image "$SHOWPIC" --image-on-top --window-icon="$STLICON" --form --center --on-top "$WINDECO" \
				--title="$TITLE" \
				--text="$(spanFont "$ASKSETSTLVERS" "H")\n\n$(spanFont "$SGNAID - $REQQEST" "H")" \
				--field="<i>$PDBROUT</i>":LBL \
				--field="<i>$STEAMDECKCOMPATOUT</i>":LBL \
				--field="<i>$LAPL</i>":LBL \
				--field="<i>(${#CfgFiles[@]} $GUI_EDITABLECFGS)</i>":LBL \
				--field="<i>($GUI_EDITABLEGAMECFGS)</i>":LBL \
				--button="$REQBUT":0 \
				--button="$BUT_SKIP":1 \
				--timeout="$WAITEDITOR" \
				--timeout-indicator=top \
				"$GEOM"

				case $? in
					0)  {
						"$LAUNCHMENU" "$AID"
						}
					;;
					1)  writelog "INFO" "${FUNCNAME[0]} - Selected CANCEL - Starting game without opening the $SETMENU"
						editorSkipped ;;
					70) writelog "INFO" "${FUNCNAME[0]} - TIMEOUT - Starting game without opening the $SETMENU" ;;
				esac
			fi
		fi
	else
		writelog "SKIP" "${FUNCNAME[0]} - Skipping Wait-Requester because WAITEDITOR is 0 in '$STLGAMECFG'"
	fi
}

# create project dir $1 - no idea what the former arg2 was good for :)
function mkProjDir {
	mkdir -p "$1" 2>/dev/null >/dev/null
}

# create project dirs
function createProjectDirs {
	mkProjDir "$STLCFGDIR"
	mkProjDir "$STLLANGDIR"
	mkProjDir "$LOGDIRID"
	mkProjDir "$LOGDIRTI"
	mkProjDir "$STLPROTONIDLOGDIR"
	mkProjDir "$STLPROTONTILOGDIR"
	mkProjDir "$STLDXVKLOGDIR"
	mkProjDir "$STLWINELOGDIR"
	mkProjDir "$STLGLLOGDIRID"
	mkProjDir "$STLGLLOGDIRTI"
	mkProjDir "$STLGAMEDIRID"
	mkProjDir "$STLGAMEDIRTI"
	mkProjDir "$STLCOLLECTIONDIR"
	mkProjDir "$TWEAKDIR"
	mkProjDir "$USERTWEAKDIR"
	mkProjDir "$TWEAKCMDDIR"
	mkProjDir "$SBSTWEAKDIR"
	mkProjDir "$STLDLDIR"
	mkProjDir "$STLSHADDIR"
	mkProjDir "$STLVORTEXDIR"
	mkProjDir "${STLVORTEXDIR}/downloads"
	mkProjDir "$RESHADESRCDIR"
	mkProjDir "$CUSTPROTDLDIR"
	mkProjDir "$CUSTPROTEXTDIR"
	mkProjDir "$WINEDLDIR"
	mkProjDir "$WINEEXTDIR"
	mkProjDir "$STLGAMES"
	mkProjDir "$STLGDESKD"
	mkProjDir "$STLIDFD"
	mkProjDir "$STLGHEADD"
	mkProjDir "$STLGICO"
	mkProjDir "$STLGZIP"
	mkProjDir "$STLGPNG"
	mkProjDir "$STLAPPINFOIDDIR"
	mkProjDir "$HIDEDIR"
	mkProjDir "$VORTEXCOMPDATA"
	mkProjDir "$GEMETA"
	mkProjDir "$MO2COMPDATA"
	mkProjDir "$STLVKD3DLOGDIR"
	mkProjDir "$GEMETA"
	mkProjDir "$CUMETA"
	mkProjDir "$TIGEMETA"
	mkProjDir "$TICUMETA"
	mkProjDir "$STLCUSTVARSDIR"
	mkProjDir "$STLGDECKCOMPAT"
}

# add missing config entries to configfile $1 using seperator $2:
function updateConfigFile {

	if [ -z "$1" ]; then
		writelog "SKIP" "${FUNCNAME[0]} - Expected configfile as argument 1"
	else
		CFGFILE="$1"
		SEP="$2"

		# disable logging temporarily when the program just started (cosmetics)
		if [ -n "$3" ]; then
			ORGLOGLEVEL="$LOGLEVEL"
			LOGLEVEL=0
		fi

		if grep "$STLCFGDIR" "$CFGFILE" >/dev/null ; then
			writelog "UPDATE" "${FUNCNAME[0]} - Replacing '$STLCFGDIR' with 'STLCFGDIR' in '$CFGFILE'"
			sed "s:$STLCFGDIR:STLCFGDIR:g" -i "$CFGFILE"
		fi
		
		if grep -q "config Version: $PROGVERS" "$CFGFILE"; then
			writelog "SKIP" "${FUNCNAME[0]} - Config file '$CFGFILE' already at version '$PROGVERS'"
		else
			OLDVERS="$(grep "config Version" "$CFGFILE" | awk -F ': ' '{print $2}')"

			if [ -n "$OLDVERS" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Updating '$CFGFILE' from '$OLDVERS' to '$PROGVERS'"
				sed "s/config Version: $OLDVERS/config Version: $PROGVERS/" -i "$CFGFILE"
			else
				writelog "INFO" "${FUNCNAME[0]} - Updating '$CFGFILE' to '$PROGVERS'"
				sed "1s/^/##########################\n/" -i "$CFGFILE"
				sed "1s/^/## config Version: $PROGVERS\n/" -i "$CFGFILE"
			fi

			UPFROMTMPL=0
			if [ "$CFGFILE" == "$STLGAMECFG" ] && [ -f "$STLDEFGAMECFG" ]; then
				UPFROMTMPL=1
			fi

			while read -r RAWLINE; do
				LCAT="$(cut -d '=' -f1 <<< "$RAWLINE")"
				LVAL="$(cut -d '=' -f2 <<< "$RAWLINE")"
				if ! grep "^${LCAT}=" "$CFGFILE" >/dev/null ; then
					writelog "UPDATE" "${FUNCNAME[0]} - Entry '$LCAT' is missing in '$CFGFILE' - adding it now!"
					if [ "$UPFROMTMPL" -eq 1 ]; then
						OUTVAL="$(grep "^${LCAT}=" "$STLDEFGAMECFG" | cut -d '=' -f2)"
						OUTVAL="${OUTVAL//\"}"
					else
						if grep -q "\\$" <<< "$LVAL"; then
							if grep -q "WINX$\|WINY\|POSX\|POSY$" <<< "$LVAL"; then
								VARNAM=${LVAL//\$/DEF}
							else
								VARNAM=${LVAL//\$/}
							fi
							OUTVAL=${!VARNAM}
						else
							OUTVAL="$LVAL"
						fi
					fi
					OUTVAL="${OUTVAL//$STLCFGDIR/STLCFGDIR}"
					ADDLINE="$LCAT=\"$OUTVAL\""
					writelog "UPDATE" "${FUNCNAME[0]} - Adding line '$ADDLINE'"
					echo "$ADDLINE" >> "$CFGFILE"
				fi
			done <<< "$(sed -n "/#START$SEP/,/#END$SEP/p;/#END$SEP/q" "$0" | awk -F 'echo ' '{print $2}' | grep -v "\"##" | awk '{$1=$1};1' | sed '/^[[:space:]]*$/d'| sed 's/\"//g' | sed 's/=\\/=/g' | sed 's/\\$//g')"
		fi

		# re-enable logging
		if [ -n "$3" ]; then
			LOGLEVEL="$ORGLOGLEVEL"
		fi
	fi
}

function linkGameCfg {
	if [ -z "$GN" ]; then
		writelog "SKIP" "${FUNCNAME[0]} - Skipping symlinking config - no valid game name found"
	else
		createSymLink "${FUNCNAME[0]}" "$STLGAMECFG" "${STLGAMEDIRTI}/${GN}.conf"
	fi
}

# create game configs:
function createGameCfg {	

	if [ -f "$STLGAMECFG" ]; then
		# add missing config entries in the default global config:
		updateConfigFile "$STLGAMECFG" "saveCfgdefault_template"
	else
		updateConfigEntry "CUSTOMCMD" "$DUMMYBIN" "$STLDEFGAMECFG"
		getGameName "$AID"
		if [ -n "$GAMENAME" ] && [ "$GAMENAME" != "$NON" ]; then
		{
		echo "## config Version: $PROGVERS"
		echo "##########################"
		echo "#########"
		echo "#$PROGNAME $PROGVERS"
		echo "#########"
		getCfgHeader
		echo "## set the default config file for DXVK_CONFIG_FILE which is used when found - defaults to config found in $STLDXVKDIR"
		echo "STLDXVKCFG=\"$STLDXVKDIR/$AID.conf\""
		grep -v "config Version" "$STLDEFGAMECFG"
		} >> "$STLGAMECFG"
		else
			writelog "SKIP" "${FUNCNAME[0]} - No game name found for '$AID' - does the game exist?"
		fi
	fi
	linkGameCfg
}

# override game configs with a tweak config if available:
function checkTweakLaunch {
	if [ -z "$TWEAKCMD" ]; then
		TWEAKCMD=""
	fi

	if [ -f "$GLOBALTWEAKCFG" ]; then
		writelog "INFO" "${FUNCNAME[0]} - Using overrides found in '$GLOBALTWEAKCFG'"
		notiShow "$(strFix "$NOTY_GLOBALTWEAK" "$GLOBALTWEAKCFG")"
		loadCfg "$GLOBALTWEAKCFG"
	fi

	# then user config - (overriding the global one)
	if [ -f "$TWEAKCFG" ]; then
		writelog "INFO" "${FUNCNAME[0]} - Using overrides found in '$TWEAKCFG'"
		loadCfg "$TWEAKCFG"
	fi

	if [ -n "$TWEAKCMD" ]; then
		# tweak command defined
		if [ -f "$TWEAKCMD" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Found TWEAKCMD '$TWEAKCMD'"
			RUNTWEAK="$TWEAKCMD"
		elif [ -f "$TWEAKCMDDIR/$TWEAKCMD" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Found TWEAKCMD '$TWEAKCMD' in '$TWEAKCMDDIR'"
			RUNTWEAK="$TWEAKCMDDIR/$TWEAKCMD"
		elif [ -f "$GFD/$TWEAKCMD" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Found TWEAKCMD '$TWEAKCMD' in '$GFD'"
			RUNTWEAK="$GFD/$TWEAKCMD"
		fi
		# tweak command found

		if [ -n "$RUNTWEAK" ]; then

			if grep -q "^TWEAKFILE" "$RUNTWEAK"; then
				# dependency for tweak command defined
				writelog "INFO" "${FUNCNAME[0]} - TWEAKFILE configured in $RUNTWEAK as dependency - checking if the file exists in gamedir - relative to the gameexe"
				TWEAKFILE="$(grep "^TWEAKFILE" "$RUNTWEAK" | awk -F 'TWEAKFILE=' '{print $2}')"
				if [ -f "$EFD/$TWEAKFILE" ]; then
					# dependency for tweak command found
					writelog "INFO" "${FUNCNAME[0]} - Found tweakcmd dependency in $EFD/$TWEAKFILE - starting the tweakcmd now"
					# start tweak command
					"$RUNTWEAK"
					writelog "INFO" "${FUNCNAME[0]} - $RUNTWEAK finished"
				else
					# dependency for tweak command not found
					writelog "SKIP" "${FUNCNAME[0]} - Configured TWEAKFILE $TWEAKFILE not found - skipping launch of the tweakcmd $TWEAKCMD"
				fi
			else
				# start tweak command
				writelog "INFO" "${FUNCNAME[0]} - No TWEAKFILE configured in $RUNTWEAK as dependency - starting the tweakcmd regularly now"
				"$RUNTWEAK"
				writelog "INFO" "${FUNCNAME[0]} - $RUNTWEAK finished"
			fi
		else
			writelog "SKIP" "${FUNCNAME[0]} - Configured TWEAKCMD $TWEAKCMD not found - can't start it"
		fi
	fi
}

function genDefIcon {
	if [ ! -f "$STLICON" ]; then
		base64 -d <<< "iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAMAAACdt4HsAAAAZlBMVEUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcHByAgIAAAAD///8AAACfn5+AgIC/v78QEBDv7+9gYGBQUFCvr6/Pz88wMDAgICDf399wcHBAQECPj4/mYUh/AAAAEXRSTlMAYICf778gj3DfUEAwz48gEPfJjAsAAAKXSURBVFjDnZfpetsgFEQtW17jtGVAgNBi9/1fsiDz5dbBTKLMH286xwgBFzaSa7Pdbi+Hzc9y+NXikffmJ/wp4pM3xvQWOF9X8zugH1yIgqD0BDSreRucsUixxvloWMsP8wiMsQXpZdDrDMfIqwljp1K6CdaVhsv2VZaL3oBBqVvv1CPOT059NjR4nbf42xlGlckG4dO/qKF7yoh9asCkVM0gvLFWq0/xAK6xB26KGDKv1WCR7lLieowex80enWKGzC+A/SsKbeFdF+8BUIoaMh8TJlivuxjtLWyIXwFJQA3Cx+gROaN2SgTMsPCSOZiYMMe3WdDCEYNPfD0ObezEQFrAeRViJ57gOc/icdocgJnw80z4GTikudjXed6GHru0mLUwhCcGg/awzFRAV3li0MBFxnqVFwOfbZrwgGa8GEpeDJQXQ8mPoxgIL4ay/+RdjRdDwUPFQAwVXgzClwJowovhmYd3zkMMVV4MwuNmeizpzS0bCC+rvw5IWcb3HTH3ZdQuCZlnRVZHakm3cNnUAYsr8bsqnnuBtUAjpqF8TKUPpIcayseUT0H4L55iTjkOhOfjSAyFIPN8JEuKuSA8nUsSmY0Fz2ZzaSh4sp5UDMLzFa1mEL5muJB1V/j6qix1oYwWvlYXpDLR6kQq0wGg5W9OPKmNUp1JG2h13iOs4cv9QQvHec93KCv2SEXW7tK4gO8TieC7O9XX6bD/9l75ZW44frVb54YJ8Xz2DkN4ajDY5xPLc7t64alhAN4+zkwq3B+dOd9hhWeGweIopzZlgN4E0yN+4Kuu8Lv/z43KfNQSX1v3vZKED15OrtoYo52e6pVn0hkfemC3+ux8PQO2jxf5CWhPzz/+3p6/cXpv3vHIefsnf/UP3QHUzgWHsSYAAAAASUVORK5CYII=" > "$STLICON"
	fi

	if [ ! -f "$NOICON" ]; then
		base64 -d <<< "R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" > "$NOICON"
	fi
}

function createDefaultCfgs {
	writelog "INFO" "${FUNCNAME[0]} - START"

	createProjectDirs

	loadLanguage "$@"

	writelog "INFO" "${FUNCNAME[0]} - setSteamPaths:"
	setSteamPaths

	saveCfg "$STLDEFGLOBALCFG" X
	loadCfg "$STLDEFGLOBALCFG" X
	saveCfg "$STLURLCFG" X
	loadCfg "$STLURLCFG" X
	prepareGUI
	genDefIcon

	createProjectDirs
	getGameOS "$@"
	delEmptyFile "$PROTONCSV"

	if [ "$HAVEINPROTON" -eq 0 ]; then
		if [ "$ISGAME" -eq 2 ] || [ ! -f "$PROTONCSV" ]; then
			writelog "INFO" "${FUNCNAME[0]} - createProtonList:"
			createProtonList X
			writelog "INFO" "${FUNCNAME[0]} - createProtonList end"
		elif [ "$ISGAME" -ne 2 ] && [ -f "$PROTONCSV" ]; then
			mapfile -t -O "${#ProtonCSV[@]}" ProtonCSV < "$PROTONCSV"
		fi
	fi

	checkStartMode
	saveCfg "$STLDEFGAMECFG" X
	createProjectDirs
	setGlobalAIDCfgs
	listAllSettingsEntries
	checkEntryBlocklist
	updateMenuSortFile
	writelog "INFO" "${FUNCNAME[0]} - STOP"
}

# updates or creates option $1 with value $2 in configfile $3:
function updateConfigEntry {

	CFGCAT="$1"
	CFGVALUE="$2"
	CFGFILE="$3"
	
	if [ "$CFGCAT" == "CUSTOMCMD" ] && [ "$CFGFILE" == "$STLDEFGAMECFG" ]; then
		writelog "INFO" "${FUNCNAME[0]} - Emptying '$CFGCAT' for '$STLDEFGAMECFG'"
		CFGVALUE="$DUMMYBIN"
	fi

	if [ -z "$3" ]; then
		writelog "SKIP" "${FUNCNAME[0]} - Expected 3 arguments - only got $*"
	else
		if [ ! -f "$CFGFILE" ]; then
			writelog "SKIP" "${FUNCNAME[0]} - Configfile '$CFGFILE' does not exist - skipping config update"
		else
			if [ -n "$CFGVALUE" ]; then
				if [ "$CFGVALUE" == "TRUE" ]; then
					CFGVALUE="1"
				elif [ "$CFGVALUE" == "FALSE" ]; then
					CFGVALUE="0"
				fi	

				if [ "$CFGVALUE" == "DUMMY" ]; then
					CFGVALUE=""
				fi

				# only save value if it changed
				if { [ "${!CFGCAT}" != "$CFGVALUE" ] && [ "${!CFGCAT}" != "${CFGVALUE//$STLCFGDIR/STLCFGDIR}" ];} || [ -f "$FUPDATE" ]; then
					CFGVALUE="${CFGVALUE//$STLCFGDIR/STLCFGDIR}"
					if [ "$(grep -c "#${CFGCAT}=" "$CFGFILE")" -eq 1 ]; then
						writelog "INFO" "${FUNCNAME[0]} - Option '$CFGCAT' commented out in config '${CFGFILE##*/}' - activating it with the new value '$CFGVALUE'"
						sed -i "/^#${CFGCAT}=/c$CFGCAT=\"$CFGVALUE\"" "$CFGFILE"
					elif [ "$(grep -c "^${CFGCAT}=" "$CFGFILE")" -eq 0 ]; then
						writelog "INFO" "${FUNCNAME[0]} - '$CFGCAT' option missing in config '${CFGFILE##*/}' - adding a new line"
						echo "$CFGCAT=\"$CFGVALUE\"" >> "$CFGFILE"
					else
						writelog "INFO" "${FUNCNAME[0]} - Option '$CFGCAT' is updated with the new value '$CFGVALUE' in config '${CFGFILE##*/}'"
						sed -i "/^${CFGCAT}=/c$CFGCAT=\"$CFGVALUE\"" "$CFGFILE"
					fi
					rm "$FUPDATE" 2>/dev/null
				fi
			fi
		fi
	fi

	CFGCAT=""
	CFGVALUE=""
	CFGFILE=""
}

# autoapply configuration settings based on the steam collections the game is in:
function autoCollectionSettings {
	if [ "$CHECKCOLLECTIONS" -eq 1 ] && [ "$STLPLAY" -eq 0 ]; then
		if [ -z "$SUSDA" ] || [ -z "$STUIDPATH" ]; then
			setSteamPaths
		fi
		if [ -d "$SUSDA" ]; then
			SC="$STUIDPATH/$SRSCV"

			if [ ! -f "$SC" ]; then
				writelog "SKIP" "${FUNCNAME[0]} - File '${SC##*/}' not found in steam userid dir - skipping"
			else
				writelog "INFO" "${FUNCNAME[0]} - Searching collections for game '$AID' in '$SC'"

				while read -r SCAT; do
					GLOBALSCATCONF="$(find "$GLOBALCOLLECTIONDIR" -type f -iname "$SCAT.conf")"
					# GLOBALSCATCONFF="$GLOBALCOLLECTIONDIR/$SCAT.conf"

					# Should we break after a file to load is found? Is there benefit to loading another file?
					if [ -f "$GLOBALSCATCONF" ]; then
						writelog "INFO" "${FUNCNAME[0]} - Global Config '$GLOBALSCATCONF' found - loading its settings"
						loadCfg "$GLOBALSCATCONF"
					else
						writelog "SKIP" "${FUNCNAME[0]} - Global Config '$GLOBALSCATCONF' not found - skipping"
					fi

					SCATCONF="$(find "$STLCOLLECTIONDIR" -type f -iname "$SCAT.conf")"
					# SCATCONFF="$STLCOLLECTIONDIR/$SCAT.conf"

					if [ -f "$SCATCONF" ]; then
						writelog "INFO" "${FUNCNAME[0]} - Collections Directory Config '$SCATCONF' found - loading its settings"
						loadCfg "$SCATCONF"
					else
						writelog "SKIP" "${FUNCNAME[0]} - Collections Directory Config '$SCATCONF' not found - skipping"
					fi
					
					SCATCMD="$TWEAKCMDDIR/$SCAT.sh"
					if [ -f "$SCATCMD" ]; then
						writelog "INFO" "${FUNCNAME[0]} - Steam-Collection user command '$SCATCMD' found - executing"
						if [ "$USEWINE" -eq 0 ]; then
							"$SCATCMD" "$AID" "$EFD" "$GPFX"
						else
							"$SCATCMD" "$AID" "$EFD" "$GWFX"
						fi
					fi
				done <<< "$(sed -n "/\"$AID\"/,/}/p;" "$SC" | sed -n "/\"tags\"/,/}/p" | sed -n "/{/,/}/p" | grep -v '{\|}' | cut -d '"' -f4)"
			fi
		else
			writelog "SKIP" "${FUNCNAME[0]} - '$SUSDA' not found - this should not happen! - skipping"
		fi
	fi
}
	
function stracerun {
	writelog "INFO" "${FUNCNAME[0]} - Starting stracerun"
	waitForGamePid
	writelog "INFO" "${FUNCNAME[0]} - $STRACE -p $(GAMEPID) $STRACEOPTS -o $STRACEDIR/$AID.log"
	mapfile -d " " -t -O "${#RUNSTRACEOPTS[@]}" RUNSTRACEOPTS < <(printf '%s' "$STRACEOPTS")
	"$STRACE" -p "$(GAMEPID)" "${RUNSTRACEOPTS[@]}" -o "$STRACEDIR/$AID.log"
}

function checkStraceLaunch {
	if [ -n "$STRACERUN" ]; then
		if [ "$STRACERUN" -eq 1 ]; then
			stracerun &
		fi
	fi
}

function netrun {
	writelog "INFO" "${FUNCNAME[0]} - Starting network traffic monitor"

	waitForGamePid

	if [ -n "$NETMONDIR" ]; then
		if [ ! -d "$NETMONDIR" ]; then
			writelog "INFO" "${FUNCNAME[0]} - $NETMON dest directory $NETMONDIR does not exist - trying to create it"
			mkProjDir "$NETMONDIR"
		fi

		if [ -d "$NETMONDIR" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Writing network traffic for $AID int dest directory $NETMONDIR"
			if [ -f "$NETMONDIR/$AID-$NETMON.log" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Removing old $NETMONDIR/$AID-$NETMON.log"
				rm "$NETMONDIR/$AID-$NETMON.log"
			fi
			mapfile -d " " -t -O "${#RUNNETOPTS[@]}" RUNNETOPTS < <(printf '%s' "$NETOPTS")
			"$NETMON" "${RUNNETOPTS[@]}" | grep "wineserver" | grep -v "localhost\|0.0.0.0" >> "$NETMONDIR/$AID-$NETMON.log"
		else
			writelog "SKIP" "${FUNCNAME[0]} - $NETMON dest directory $NETMONDIR still does not exist - skipping"
		fi
	else
		writelog "SKIP" "${FUNCNAME[0]} - $NETMON dest directory variable NETMONDIR is empty"
	fi
}

function checkNetMonLaunch {
	if [ "$USENETMON" -eq 1 ]; then
		if [ -n "$NETMON" ]; then
			netrun &
		fi
	fi
}

function checkXliveless {
	if [ -n "$NOGFWL" ]; then
		if [ "$NOGFWL" -eq 1 ]; then
			rm -rf "$GPFX/$DRC/$PFX86/Microsoft Games for Windows - LIVE"
			rm -rf "$GPFX/$DRC/Program Files/Common Files/Microsoft Shared/Windows Live"
			# option for USEWINE probably not really required
			WLID="WLIDSvcM.exe"
			if "$PGREP" "$WLID" >/dev/null; then
				writelog "INFO" "${FUNCNAME[0]} - GFWL starts '$WLID' directly after installation and it never exists - killing it now"
				"$PKILL" -9 "$WLID"
			fi

			XLIVEDLL="xlive.dll"
			XLDL="$STLDLDIR/xlive/"
			XLDST="$XLDL/$XLIVEDLL"
			mkProjDir "$XLDL"

			writelog "INFO" "${FUNCNAME[0]} - Game '$SGNAID' needs '$XLIVEDLL' - checking"
			if [ -f "$EFD/$XLIVEDLL" ]; then
				writelog "SKIP" "${FUNCNAME[0]} - Found '$XLIVEDLL' in dir $EFD - nothing to do"
			else
				writelog "INFO" "${FUNCNAME[0]} - '$XLIVEDLL' not found in gamedir '$EFD'"
				if [ ! -f "$XLDST" ]; then
					dlCheck "$XLIVEURL" "$XLDST" "X" "'$XLDST' not found - downloading automatically from '$XLIVEURL'"
					"$UNZIP" "$XLDL/${DLURL##*/}" -d "$XLDL"
					if [ -f "$XLDL/dinput8.dll" ]; then
						mv "$XLDL/dinput8.dll" "$XLDST"
					fi
				fi
				if [ -f "$XLDST" ]; then
					writelog "INFO" "${FUNCNAME[0]} - Found '$XLIVEDLL' in '$XLDL' - copying into gamedir '$EFD'"
					cp "$XLDST" "$EFD"
				fi
			fi
		fi
	fi
}

function setGameScopeVars {
	function getGameScopeArg {
		ARGS="$1"  # e.g. "$GAMESCOPE_ARGS"
		UNESCAPED_FLAG="$2"
		FLAG="${2//-/\\-}"  # e.g. "--hdr-enabled" becomes "\-\-hdr\-enabled"
		VAR="$3"  # e.g. "$GSHDR"
		TRUEVAL="$4"  # e.g. "1"
		DEFVAL="$5"  # e.g. "0"
		ARGTYPE="${6,,}"  # e.g. "chk", "cb", etc (matches Yad widget types mostly)

		if [ -z "$VAR" ]; then
			if grep -qw "$FLAG" <<< "$ARGS"; then
				if [[ $ARGTYPE =~ "cb" ]] || [[ $ARGTYPE =~ "num" ]]; then
					# Get the value given to the argument as the enabled/selected value, e.g. get '2' from '-U 2' if we passed '-U'
					tr ' ' '\n' <<< "$ARGS" | grep -A1 "$FLAG" | tail -n1
				elif [[ $ARGTYPE =~ "path" ]] || [[ $ARGTYPE =~ "txt" ]]; then
					# Get value given to arguments with two dashes, like `--`
					echo "$ARGS" | sed 's:--:\n--:g' | grep -A1 "$FLAG" | sed "s:${UNESCAPED_FLAG}::g;s:-:\n-:g" | head -n1 | xargs
				else
					echo "$TRUEVAL"
				fi
			else
				echo "$DEFVAL"
			fi
		fi
	}

	function getGameScopeGeneralOpts {
		# GameScope Show Resolution (corresponds to -W, -H options, uppercase) -- Actual GameScope window size -- Dropdown
		if [ -z "$GSSHWRES" ]; then
			if ! grep -qw "\-w" <<< "$GAMESCOPE_ARGS" || ! grep -qw "\-h" <<< "$GAMESCOPE_ARGS"; then
				GSSHWRES="1280x720"
			else
				GSSHWRES="$(tr ' ' '\n' <<< "$GAMESCOPE_ARGS" | grep -wA1 "\-W" | tail -n1)x$(tr ' ' '\n' <<< "$GAMESCOPE_ARGS" | grep -wA1 "\-H" | tail -n1)"
			fi
		fi
		
		# GameScope Internal Resolution (corresponds to -w, -h options, lowercase) -- Resolution that games see -- Dropdown
		if [ -z "$GSINTRES" ]; then
			if ! grep -qw "\-w" <<< "$GAMESCOPE_ARGS" || ! grep -qw "\-h" <<< "$GAMESCOPE_ARGS"; then
				GSINTRES="1280x720"
			else
				GSINTRES="$(tr ' ' '\n' <<< "$GAMESCOPE_ARGS" | grep -wA1 "\-w" | tail -n1)x$(tr ' ' '\n' <<< "$GAMESCOPE_ARGS" | grep -wA1 "\-h" | tail -n1)"
			fi
		fi

		# Default internal resolution to $NON ('none') if blank -- Ensures we don't pass invalid resolution to GameScope
		if [ -z "$GSINTRES" ]; then  GSINTRES="$NON"; fi

		# Default show resolution to $NON ('none') if blank -- Ensures we don't pass invalid resolution to GameScope
		if [ -z "$GSSHWRES" ]; then  GSSHWRES="$NON"; fi

		# Focused Frame Rate Limit -- Dropdown
		GSFLR="$( getGameScopeArg "$GAMESCOPE_ARGS" "-r" "$GSFLR" "" "$UL" "cb")"

		# Unfocused Frame Rate Limit -- Dropdown
		GSFLU="$( getGameScopeArg "$GAMESCOPE_ARGS" "-o" "$GSFLU" "" "$UL" "cb")"

		# Fullscreen (-f) -- Checkbox
		GSFS="$( getGameScopeArg "$GAMESCOPE_ARGS" "-f" "$GSFS" "1" "0" )"

		# Borderless Window (-b) -- Checkbox
		GSBW="$( getGameScopeArg "$GAMESCOPE_ARGS" "-b" "$GSBW" "1" "0" )"

		# Steam Integration (-e) -- Can fix some strange bugs with some peripherals -- Checkbox
		GSSE="$( getGameScopeArg "$GAMESCOPE_ARGS" "-e" "$GSSE" "1" "0" )"

		# Force windows to be fullscreen inside the nested dislay (--force-windows-fullscreen) -- Checkbox 
		GSFWF="$( getGameScopeArg "$GAMESCOPE_ARGS" "--force-windows-fullscreen" "$GSFWF" "1" "0" )"

		# Force grab cursor -- Keeps cursor inside GameScope nested display -- Checkbox
		GSFGC="$( getGameScopeArg "$GAMESCOPE_ARGS" "--force-grab-cursor" "$GSFGC" "1" "0" )"

		# Orientation (--force-orientation) -- Can be either 'left', 'right', 'normal', 'upsidedown' (Defaults to 'normal') -- Dropdown
		# NOTE: Passing this normally to GameScope (e.g. `gamescope --force-orientation upsidedown -- supertuxkart`) doesn't seem to do anything?
		GSFOOR="$( getGameScopeArg "$GAMESCOPE_ARGS" "--force-orientation" "$GSFOOR" "" "$GSNORM" "cb")"

		# Custom cursor image (--cursor) -- File picker
		GSENABLECUSTCUR="0"
		GSCURSOR="$( getGameScopeArg "$GAMESCOPE_ARGS" "--cursor" "$GSCURSOR" "" "" "path" )"
		if [ -n "$GSCURSOR" ]; then  GSENABLECUSTCUR="1"; fi

		# There is a `--cursor-scale-height` option, but at time of writing (15/02/22) this doesn't seem to do anything - We can add it in future, but not now
	}

	function getGameScopeFilteringOpts {
		# AMD FidelityFX 1.0 / NVIDIA Image Sharpening upscaler value -- Spinner
		GSFSRS="$( getGameScopeArg "$GAMESCOPE_ARGS" "--fsr-sharpness" "$GSFSRS" "" "2" "num" )"

		# Integer scaling (-i) -- Checkbox
		GSIS="$( getGameScopeArg "$GAMESCOPE_ARGS" "-i" "$GSIS" "1" "0" )"

		# Nearest Neighbor (-n) -- Checkbox
		GSNN="$( getGameScopeArg "$GAMESCOPE_ARGS" "-n" "$GSNN" "1" "0" )"

		# FidelityFX 1.0 enabled (-U) -- Checkbox
		GSFSR="$( getGameScopeArg "$GAMESCOPE_ARGS" "-U" "$GSFSR" "1" "0" )"

		# NVIDIA Image Scaling v1.0.3 (-Y) -- Checkbox
		GSNIS="$( getGameScopeArg "$GAMESCOPE_ARGS" "-Y" "$GSNIS" "1" "0" )"

		# Max Scale Factor -- No idea how this option actually works, the documentation is a bit sparce but Steam Deck seems to default it to 2 (https://github.com/Plagman/gamescope/issues/588#issue-1338038588)
		GSMSF="$( getGameScopeArg "$GAMESCOPE_ARGS" "-m" "$GSMSF" "" "0" "num" )"
	}

	function getGameScopeHDROpts {
		# HDR (--hdr-enabled) -- Checkbox
		GSHDR="$( getGameScopeArg "$GAMESCOPE_ARGS" "--hdr-enabled" "$GSHDR" "1" "0" )"

		# HDR Wide Gammut for SDR (--hdr-wide-gammut-for-sdr) - Checkbox
		GSHDRWGFS="$( getGameScopeArg "$GAMESCOPE_ARGS" "--hdr-wide-gammut-for-sdr" "$GSHDRWGFS" "1" "0" )"

		# HDR SDR Content Nits (--hdr-sdr-content-nits) -- Defaults to 203 -- Numberbox
		GSHDRSCNITS="$( getGameScopeArg "$GAMESCOPE_ARGS" "--hdr-sdr-content-nits" "$GSHDRSCNITS" "1" "0" )"

		# HDR Inverse Tone Mapping Enabled (--hdr-itm-enable) -- Checkbox
		GSHDRITM="$( getGameScopeArg "$GAMESCOPE_ARGS" "--hdr-itm-enable" "$GSHDRITM" "1" "0" )"

		# HDR Inverse Tone Mapping SDR NITs (--hdr-itm-sdr-nits) -- Spinner
		# Default: 100 nits
		# Max: 1000 nits
		#
		# We default to 0 though in case a user doesn't want to use it, so we won't pass when this is 0
		GSHDRITMSDRNITS="$( getGameScopeArg "$GAMESCOPE_ARGS" "--hdr-itm-sdr-nits" "$GSHDRITMSDRNITS" "" "0" "num" )"

		# HDR Inverse Tone Mapping Target NITs (--hdr-itm-target-nits) -- Spinner
		# Default: 1000 nits
		# Max: 10000 nits
		#
		# Like `GSHDRITMSDRNITS`, we default to 0 because we don't want to always pass a value
		GSHDRITMTGTNITS="$( getGameScopeArg "$GAMESCOPE_ARGS" "--hdr-itm-target-nits" "$GSHDRITMTGTNITS" "" "0" "num" )"
	}

	function getGameScopeVROpts {
		# There are some other GameScope VR options:
		# * --vr-overlay-physical-width
		# * --vr-overlay-physical-curvature
		# * --vr-overlay-physical-pre-curve-pitch
		#
		# These options are probably very bespoke and not important to the average user, especially the physcial width option which takes a value in metres!
		# Usage on these options is also a bit unclear, probably documented in the GameScope source but not sure -We could add these in future if it is requested

		# Enable OpenVR (--openvr) -- Checkbox
		GSVR="$( getGameScopeArg "$GAMESCOPE_ARGS" "--openvr" "$GSVR" "1" "0" )"

		# SteamVR Explicit Name (--vr-overlay-explicit-name) -- Textbox
		GSVREXNA="$( getGameScopeArg "$GAMESCOPE_ARGS" "--vr-overlay-explicit-name" "$GSVREXNA" "" "" "txt" )"	

		# SteamVR Default Name when no window title available (--vr-overlay-default-name) -- Textbox
		GSVRDEFNAM="$( getGameScopeArg "$GAMESCOPE_ARGS" "--vr-overlay-default-name" "$GSVRDEFNAM" "" "" "txt" )"	

		# SteamVR Overlay Icon (--vr-overlay-icon) -- Similar to cursor picker -- File picker 
		GSVRICONENABLE="0"
		GSVRICON="$( getGameScopeArg "$GAMESCOPE_ARGS" "--vr-overlay-icon" "$GSVRICON" "" "" "path" )"
		if [ -n "$GSVRICON" ]; then  GSVRICONENABLE="1"; fi

		# Focus VR overlay immediately (--vr-overlay-show-immediately) -- Checkbox
		GSVRSHOIMM="$( getGameScopeArg "$GAMESCOPE_ARGS" "--vr-overlay-show-immediately" "$GSVRSHOIMM" "1" "0" )"

		# Enable SteamVR Control Bar (--vr-overlay-enable-control-bar) -- Checkbox
		GSVRCONTROLBAR="$( getGameScopeArg "$GAMESCOPE_ARGS" "--vr-overlay-enable-control-bar" "$GSVRCONTROLBAR" "1" "0" )"

		# Enable SteamVR Keyboard Button on Control Bar (--vr-overlay-enable-control-bar-keyboard) -- Checkbox
		GSVRCONTROLBARKEYBOARD="$( getGameScopeArg "$GAMESCOPE_ARGS" "--vr-overlay-enable-control-bar-keyboard" "$GSVRCONTROLBARKEYBOARD" "1" "0" )"

		# Enable SteamVR Close Button on Control Bar (--vr-overlay-enable-control-bar-close) -- Checkbox
		GSVRCONTROLBARCLOSE="$( getGameScopeArg "$GAMESCOPE_ARGS" "--vr-overlay-enable-control-bar-close" "$GSVRCONTROLBARCLOSE" "1" "0" )"

		# Show SteamVR Overlay as Modal (--vr-overlay-modal) -- Checkbox
		GSVRMODAL="$( getGameScopeArg "$GAMESCOPE_ARGS" "--vr-overlay-modal" "$GSVRMODAL" "1" "0" )"
	}

	function getGameScopeEmbeddedOpts {
		# Default action on touch (--default-touch-mode) -- Dropdown
		# --------------------
		# 0: hover
		# 1: leftclick
		# 2: rightclick
		# 3: middleclick
		# 4: passthrough
		# 
		# More information in the GameScope commit that added it: https://github.com/Plagman/gamescope/commit/39c9e93e0c0539d4c767e1be1c96e0d38778af12 
		GSDEFTOUCHMODE="$( getGameScopeArg "$GAMESCOPE_ARGS" "--default-touch-mode" "$GSDEFTOUCHMODE" "" "${GSDEF}" "cb" )"
		case $GSDEFTOUCHMODE in
			0) GSDEFTOUCHMODE="${GSHOVER}" ;;
			1) GSDEFTOUCHMODE="${GSLEFTCLICK}" ;;
			2) GSDEFTOUCHMODE="${GSRIGHTCLICK}" ;;
			3) GSDEFTOUCHMODE="${GSMIDDLECLICK}" ;;
			4) GSDEFTOUCHMODE="${GSPASSTHRU}" ;;
		esac

		# Enable Immediate Flips (--immediate-flips) -- Probably equivalent to the Steam Deck's "allow tearing" option -- Checkbox
		GSIMMEDIATEFLIPS="$( getGameScopeArg "$GAMESCOPE_ARGS" "--immediate-flips" "$GSIMMEDIATEFLIPS" "1" "0" )"

		# Enable Adaptive Sync / VRR (--adaptive-sync) -- Checkbox
		GSADAPTIVESYNC="$( getGameScopeArg "$GAMESCOPE_ARGS" "--adaptive-sync" "$GSADAPTIVESYNC" "1" "0" )"

		# Preferred GameScope Output in order of preference -- Not sure how exactly this should be passed and it can take N number of outputs - For this reason we just give the user a textbox and let them enter their displays manually
		GSPREFOUT="$( getGameScopeArg "$GAMESCOPE_ARGS" "-O" "$GSPREFOUT" "" "" "txt" )"	

		# GameScope DRM Mode Generation algorithm to use -- GameScope takes either "cvt" or "fixed", but we will have a "default" option in the dropdown which means we will ignore the flag altogether
		GSDRMMODE="$( getGameScopeArg "$GAMESCOPE_ARGS" "--generate-drm-mode" "$GSDRMMODE" "" "$GSDEF" "cb")"
	}

	function getGameScopeAdvancedOpts {
		# Path to write GameScope statistics to (--stats-path) -- File picker
		# '-T' option is also availsble, but we have to use '--stats-path' because of how 'getGameScopeArg' works
		GSSTATSPATHENABLE="0"
		GSSTATSPATH="$( getGameScopeArg "$GAMESCOPE_ARGS" "--stats-path" "$GSSTATSPATH" "" "" "path" )"
		if [ -n "$GSSTATSPATH" ]; then  GSSTATSPATHENABLE="1"; fi

		# Amount of time in milliseconds to wait before hiding the cursor (-C) -- Spinner
		GSHIDECURSORDELAY="$( getGameScopeArg "$GAMESCOPE_ARGS" "-C" "$GSHIDECURSORDELAY" "" "0" "num" )"

		# Disables direct scan-out (--force-composition) -- Checkbox
		GSFORCECOMP="$( getGameScopeArg "$GAMESCOPE_ARGS" "--force-composition" "$GSFORCECOMP" "1" "0" )"

		# Draw debug hud (--debug-hud) -- Checkbox
		GSDEBUGHUD="$( getGameScopeArg "$GAMESCOPE_ARGS" "--debug-hud" "$GSDEBUGHUD" "1" "0" )"

		# Force HDR support flag (--hdr-debug-force-support) -- Checkbox
		GSFORCEHDRSUPPORT="$( getGameScopeArg "$GAMESCOPE_ARGS" "--hdr-debug-force-support" "$GSFORCEHDRSUPPORT" "1" "0" )"

		# Force HDR output on display (--hdr-debug-force-output) -- Will look terrible if unsupported -- Checkbox
		GSFORCEHDROUTPUT="$( getGameScopeArg "$GAMESCOPE_ARGS" "--hdr-debug-force-output" "$GSFORCEHDROUTPUT" "1" "0" )"

		# Prefer Vulkan device for compositing (--prefer-vk-device) -- Checkbox
		GSPREFERVKDEVICE="$( getGameScopeArg "$GAMESCOPE_ARGS" "--prefer-vk-device" "$GSPREFERVKDEVICE" "1" "0" )"

		# Expose Wayland (--expose-wayland) -- Checkbox
		GSWAYLAND="$( getGameScopeArg "$GAMESCOPE_ARGS" "--expose-wayland" "$GSWAYLAND" "1" "0" )"

		# Realtime Scheduling (--rt) -- Checkbox
		GSRT="$( getGameScopeArg "$GAMESCOPE_ARGS" "--rt" "$GSRT" "1" "0" )"
	}

	# Set storage vars
	UL="unlimited"
	FSRS_STR="\-\-fsr\-sharpness"
	GSNORM="normal"
	GSFOOROPTS="left!right!${GSNORM}!upsidedown"
	GSDEF="default"
	GSHOVER="hover:0"
	GSLEFTCLICK="leftclick:1"
	GSRIGHTCLICK="rightclick:2"
	GSMIDDLECLICK="middleclick:3"
	GSPASSTHRU="passthrough:4"
	GSTOUCHMODES="${GSDEF}!${GSHOVER}!${GSLEFTCLICK}!${GSRIGHTCLICK}!${GSMIDDLECLICK}!${GSPASSTHRU}" # Corresponds to 0,1,2,3,4 respectively internally by GameScope -- Default is ingored and the flag is not passed to GameScope
	GSDRMMODES="${GSDEF}!cvt!fixed"

	# Get values for UI elements based on existing GameScope args 
	getGameScopeGeneralOpts
	getGameScopeFilteringOpts
	getGameScopeHDROpts
	getGameScopeVROpts
	getGameScopeEmbeddedOpts
	getGameScopeAdvancedOpts
}

function GameScopeGui {
	if [ -n "$1" ]; then
		AID="$1"
		setAIDCfgs
	fi
	
	if [ -n "$2" ]; then
		GN="$2"
		fixShowGnAid
	fi

	# Setup Yad UI stuff
	loadCfg "$STLGAMECFG"
	export CURWIKI="$PPW/GameScope"
	TITLE="${PROGNAME}-${FUNCNAME[0]}"
	pollWinRes "$TITLE"
	setShowPic
	setGameScopeVars  # Get values for UI elements below

	# GameScope Yad options form
	GASCOS="$("$YAD" --f1-action="$F1ACTION" --image "$SHOWPIC" --image-on-top --scroll --window-icon="$STLICON" --form --center --on-top $WINDECO \
			--title="$TITLE" --separator="|" \
			--text="$(spanFont "$(strFix "$GUI_GASCOSET" "$SGNAID")" "H")" \
			--field="$(spanFont "$GUI_GSGENERALSET" "H")":LBL "SKIP" \
			--field="$GUI_GSINTRES!$DESC_GSINTRES ('GSINTRES')":CBE "$(cleanDropDown "${GSINTRES//\"}" "$(printf "%s\n" "$("$XRANDR" --current | grep "[0-9]x" | awk '{print $1}' | grep "^[0-9]" | tr '\n' '!')")")" \
			--field="$GUI_GSSHWRES!$DESC_GSSHWRES ('GSSHWRES')":CBE "$(cleanDropDown "${GSSHWRES//\"}" "$(printf "%s\n" "$("$XRANDR" --current | grep "[0-9]x" | awk '{print $1}' | grep "^[0-9]" | tr '\n' '!')")")" \
			--field="$GUI_GSFLR!$DESC_GSFLR ('GSFLR')":CBE "$(cleanDropDown "${GSFLR//\"}" "30!60!90!120!$UL")" \
			--field="$GUI_GSFLU!$DESC_GSFLU ('GSFLU')":CBE "$(cleanDropDown "${GSFLU//\"}" "30!60!90!120!$UL")" \
			--field="$GUI_USEGAMESCOPE!$DESC_USEGAMESCOPE ('USEGAMESCOPE')":CHK "${USEGAMESCOPE/#-/ -}" \
			--field="$GUI_GSFS!$DESC_GSFS ('GSFS')":CHK "$GSFS" \
			--field="$GUI_GSBW!$DESC_GSBW ('GSBW')":CHK "$GSBW" \
			--field="$GUI_GSSE!$DESC_GSSE ('GSSE')":CHK "$GSSE" \
			--field="$GUI_GSFWF!$DESC_GSFWF ('GSFWF')":CHK "$GSFWF" \
			--field="$GUI_GSFGC!$DESC_GSFGC ('GSFGC')":CHK "$GSFGC" \
			--field="$GUI_GSFOOR!$DESC_GSFOOR ('GSFOOR')":CB "$(cleanDropDown "${GSFOOR}" "${GSFOOROPTS}")" \
			--field="$GUI_GSENABLECUSTCUR!$GUI_GSENABLECUSTCUR ('GSENABLECUSTCUR')":CHK "$GSENABLECUSTCUR" \
			--field="$GUI_GSCURSOR!$DESC_GSCURSOR ('GSCURSOR')":FL "${GSCURSOR/#-/ -}" \
			--field="$(spanFont "$GUI_GSFILTERINGSET" "H")":LBL "SKIP" \
			--field="$GUI_GSFSRS!$DESC_GSFSRS ('GSFSRS')":NUM "${GSFSRS/#-/ -}:!0..20" \
			--field="$GUI_GSIS!$DESC_GSIS ('GSIS')":CHK "$GSIS" \
			--field="$GUI_GSNN!$DESC_GSNN ('GSNN')":CHK "$GSNN" \
			--field="$GUI_GSFSR!$DESC_GSFSR ('GSFSR')":CHK "$GSFSR" \
			--field="$GUI_GSNIS!$DESC_GSNIS ('GSNIS')":CHK "$GSNIS" \
			--field="$GUI_GSMSF!$DESC_GSMSF ('GSMSF')":NUM "$GSMSF" \
			--field="$(spanFont "$GUI_GSHDRSET" "H")":LBL "SKIP" \
			--field="$GUI_GSHDR!$DESC_GSHDR ('GSHDR')":CHK "$GSHDR" \
			--field="$GUI_GSHDRWGFS!$DESC_GSHDRWGFS ('GSHDRWGFS')":CHK "$GSHDRWGFS" \
			--field="$GUI_GSHDRSCNITS!$DESC_GSHDRSCNITS ('GSHDRSCNITS')":NUM "${GSHDRSCNITS/#-/ -}" \
			--field="$GUI_GSHDRITM!$DESC_GSHDRITM ('GSHDRITM')":CHK "$GSHDRITM" \
			--field="$GUI_GSHDRITMSDRNITS!$DESC_GSHDRITMSDRNITS ('GSHDRITMSDRNITS')":NUM "${GSHDRITMSDRNITS/#-/ -}" \
			--field="$GUI_GSHDRITMTGTNITS!$DESC_GSHDRITMTGTNITS ('GSHDRITMTGTNITS')":NUM "${GSHDRITMTGTNITS/#-/ -}" \
			--field="$(spanFont "$GUI_GSVRSET" "H")":LBL "SKIP" \
			--field="$GUI_GSVR!$DESC_GSVR ('GSVR')":CHK "$GSVR" \
			--field="$GUI_GSVREXNA!$DESC_GSVREXNA ('GSVREXNA')" "$GSVREXNA" \
			--field="$GUI_GSVRDEFNAM!$DESC_GSVRDEFNAM ('GSVRDEFNAM')" "$GSVRDEFNAM" \
			--field="$GUI_GSVRICONENABLE!$DESC_GSVRICONENABLE ('GSVRICONENABLE')":CHK "$GSVRICONENABLE" \
			--field="$GUI_GSVRICON!$DESC_GSVRICON ('GSVRICON')":FL "${GSVRICON//\"}" \
			--field="$GUI_GSVRSHOIMM!$DESC_GSVRSHOIMM ('GSVRSHOIMM')":CHK "$GSVRSHOIMM" \
			--field="$GUI_GSVRCONTROLBAR!$DESC_GSVRCONTROLBAR ('GSVRCONTROLBAR')":CHK "$GSVRCONTROLBAR" \
			--field="$GUI_GSVRCONTROLBARKEYBOARD!$DESC_GSVRCONTROLBARKEYBOARD ('GSVRCONTROLBARKEYBOARD')":CHK "$GSVRCONTROLBARKEYBOARD" \
			--field="$GUI_GSVRCONTROLBARCLOSE!$DESC_GSVRCONTROLBARCLOSE ('GSVRCONTROLBARCLOSE')":CHK "$GSVRCONTROLBARCLOSE" \
			--field="$GUI_GSVRMODAL!$DESC_GSVRMODAL ('GSVRMODAL')":CHK "$GSVRMODAL" \
			--field="$(spanFont "$GUI_GSEMBEDDEDSET" "H")":LBL "SKIP" \
			--field="$GUI_GSDEFTOUCHMODE!$DESC_GSDEFTOUCHMODE ('GSDEFTOUCHMODE')":CB "$(cleanDropDown "${GSDEFTOUCHMODE}" "${GSTOUCHMODES}")" \
			--field="$GUI_GSIMMEDIATEFLIPS!$DESC_GSIMMEDIATEFLIPS ('GSIMMEDIATEFLIPS')":CHK "$GSIMMEDIATEFLIPS" \
			--field="$GUI_GSADAPTIVESYNC!$DESC_GSADAPTIVESYNC ('GSADAPTIVESYNC')":CHK "$GSADAPTIVESYNC" \
			--field="$GUI_GSPREFOUT!$DESC_GSPREFOUT ('GSPREFOUT')" "" \
			--field="$GUI_GSDRMMODE!$DESC_GSDRMMODE ('GSDRMMODE')":CB "$(cleanDropDown "${GSDRMMODE}" "${GSDRMMODES}")" \
			--field="$(spanFont "$GUI_GSADVOPTIONS" "H")":LBL "SKIP" \
			--field="$GUI_GSSTATSPATHENABLE!$DESC_GSSTATSPATHENABLE ('GSSTATSPATHENABLE')":CHK "$GSSTATSPATHENABLE" \
			--field="$GUI_GSSTATSPATH!$DESC_GSSTATSPATH ('GSSTATSPATH')":DIR "${GSSTATSPATH//\"}" \
			--field="$GUI_GSHIDECURSORDELAY!$DESC_GSHIDECURSORDELAY ('GSHIDECURSORDELAY')":NUM "${GSHIDECURSORDELAY/#-/ -}" \
			--field="$GUI_GSFORCECOMP!$DESC_GSFORCECOMP ('GSFORCECOMP')":CHK "$GSFORCECOMP" \
			--field="$GUI_GSDEBUGHUD!$DESC_GSDEBUGHUD ('GSDEBUGHUD')":CHK "$GSDEBUGHUD" \
			--field="$GUI_GSFORCEHDRSUPPORT!$DESC_GSFORCEHDRSUPPORT ('GSFORCEHDRSUPPORT')":CHK "$GSFORCEHDRSUPPORT" \
			--field="$GUI_GSFORCEHDROUTPUT!$DESC_GSFORCEHDROUTPUT ('GSFORCEHDROUTPUT')":CHK "$GSFORCEHDROUTPUT" \
			--field="$GUI_GSPREFERVKDEVICE!$DESC_GSPREFERVKDEVICE ('GSPREFERVKDEVICE')":CHK "$GSPREFERVKDEVICE" \
			--field="$GUI_GSWAYLAND!$DESC_GSWAYLAND ('GSWAYLAND')":CHK "$GSWAYLAND" \
			--field="$GUI_GSRT!$DESC_GSRT ('GSRT')":CHK "$GSRT" \
			--button="$BUT_CAN:0" --button="$BUT_DONE:2" "$GEOM"
			)"
			case $? in
				0)	{
						writelog "INFO" "${FUNCNAME[0]} - Selected '$BUT_CAN' - Exiting"
					}
				;;
				2)	{
						# TODO This section could still be simplified a bit further probably
						
						# Get selected GameScope options
						mapfile -d "|" -t -O "${#GSARR[@]}" GSARR < <(printf '%s' "$GASCOS")
						# GSARR[0] is the General heading
						GSINTRES="${GSARR[1]}"
						GSSHWRES="${GSARR[2]}"
						GSFLR="${GSARR[3]}"
						GSFLU="${GSARR[4]}"
						USEGAMESCOPE="${GSARR[5]}"
						GSFS="${GSARR[6]}"
						GSBW="${GSARR[7]}"
						GSSE="${GSARR[8]}"
						GSFWF="${GSARR[9]}"
						GSFGC="${GSARR[10]}"
						GSFOOR="${GSARR[11]}"
						GSENABLECUSTCUR="${GSARR[12]}"
						GSCURSOR="${GSARR[13]}"
						# GSARR[14] is the Filtering heading
						GSFSRS="${GSARR[15]}"
						GSIS="${GSARR[16]}"
						GSNN="${GSARR[17]}"
						GSFSR="${GSARR[18]}"
						GSNIS="${GSARR[19]}"
						GSMSF="${GSARR[20]}"
						# GSARR[21] is the HDR heading
						GSHDR="${GSARR[22]}"
						GSHDRWGFS="${GSARR[23]}"
						GSHDRSCNITS="${GSARR[24]}"
						GSHDRITM="${GSARR[25]}"
						GSHDRITMSDRNITS="${GSARR[26]}"
						GSHDRITMTGTNITS="${GSARR[27]}"
						# GSARR[28] is the VR heading
						GSVR="${GSARR[29]}"
						GSVREXNA="${GSARR[30]}"
						GSVRDEFNAM="${GSARR[31]}"
						GSVRICONENABLE="${GSARR[32]}"
						GSVRICON="${GSARR[33]}"
						GSVRSHOIMM="${GSARR[34]}"
						GSVRCONTROLBAR="${GSARR[35]}"
						GSVRCONTROLBARKEYBOARD="${GSARR[36]}"
						GSVRCONTROLBARCLOSE="${GSARR[37]}"
						GSVRMODAL="${GSARR[38]}"
						# GSARR[39] is the Embedded heading
						GSDEFTOUCHMODE="${GSARR[40]}"
						GSIMMEDIATEFLIPS="${GSARR[41]}"
						GSADAPTIVESYNC="${GSARR[42]}"
						GSPREFOUT="${GSARR[43]}"
						GSDRMMODE="${GSARR[44]}"
						# GSARR[45] is the Advanced heading
						GSSTATSPATHENABLE="${GSARR[46]}"
						GSSTATSPATH="${GSARR[47]}"
						GSHIDECURSORDELAY="${GSARR[48]}"
						GSFORCECOMP="${GSARR[49]}"
						GSDEBUGHUD="${GSARR[50]}"
						GSFORCEHDRSUPPORT="${GSARR[51]}"
						GSFORCEHDROUTPUT="${GSARR[52]}"
						GSPREFERVKDEVICE="${GSARR[53]}"
						GSWAYLAND="${GSARR[54]}"
						GSRT="${GSARR[55]}"

						# Build the GameScope arguments string
						unset GAMESCOPE_ARGS
						GSINTW1="${GSINTRES%x*}"
						GSINTW="${GSINTW1%%-*}"
						GSINTH1="${GSINTRES#*x}"
						GSINTH="${GSINTH1%%-*}"
						GAMESCOPE_ARGS="-w ${GSINTW} -h ${GSINTH}"

						GSSHWW1="${GSSHWRES%x*}"
						GSSHWW="${GSSHWW1%%-*}"
						GSSHWH1="${GSSHWRES#*x}"
						GSSHWH="${GSSHWH1%%-*}"
						GAMESCOPE_ARGS="${GAMESCOPE_ARGS} -W ${GSSHWW} -H ${GSSHWH}"

						### GENERAL OPTIONS ###
						if [ "$GSFLR" -eq "$GSFLR" ] 2>/dev/null                        ; then  GAMESCOPE_ARGS="${GAMESCOPE_ARGS} -r ${GSFLR}"; fi
						if [ "$GSFLU" -eq "$GSFLU" ] 2>/dev/null                        ; then  GAMESCOPE_ARGS="${GAMESCOPE_ARGS} -o ${GSFLU}"; fi
						if [ "$GSFS" == "TRUE" ]                                        ; then  GAMESCOPE_ARGS="${GAMESCOPE_ARGS} -f"; fi
						if [ "$GSBW" == "TRUE" ]                                        ; then  GAMESCOPE_ARGS="${GAMESCOPE_ARGS} -b"; fi
						if [ "$GSSE" == "TRUE" ]                                        ; then  GAMESCOPE_ARGS="${GAMESCOPE_ARGS} -e"; fi
						if [ "$GSFWF" == "TRUE" ]                                       ; then  GAMESCOPE_ARGS="${GAMESCOPE_ARGS} --force-windows-fullscreen"; fi
						if [ "$GSFGC" == "TRUE" ]                                       ; then  GAMESCOPE_ARGS="${GAMESCOPE_ARGS} --force-grab-cursor"; fi
						if [ -f "$GSCURSOR" ] && [ "$GSENABLECUSTCUR" == "TRUE" ]       ; then  GAMESCOPE_ARGS="${GAMESCOPE_ARGS} --cursor '${GSCURSOR}'"; fi
						if [ ! "$GSFOOR" == "$GSNORM" ]                                 ; then  GAMESCOPE_ARGS="${GAMESCOPE_ARGS} --force-orientation ${GSFOOR}"; fi  # Only force orientation if option other than default 'normal' is selected
						### GENERAL OPTIONS END ###

						### FILTERING OPTIONS ###
						if [ "$GSIS" == "TRUE" ]                                        ; then  GAMESCOPE_ARGS="${GAMESCOPE_ARGS} -i"; fi
						if [ "$GSNN" == "TRUE" ]                                        ; then  GAMESCOPE_ARGS="${GAMESCOPE_ARGS} -n"; fi 
						if [ "$GSFSR" == "TRUE" ]                                       ; then  GAMESCOPE_ARGS="${GAMESCOPE_ARGS} -U"; fi
						if [ "$GSNIS" == "TRUE" ]                                       ; then  GAMESCOPE_ARGS="${GAMESCOPE_ARGS} -Y"; fi
						if [ ! "$GSMSF" == "0" ]                                        ; then  GAMESCOPE_ARGS="${GAMESCOPE_ARGS} -m ${GSMSF}"; fi # Ignore Max Scale Factor if 0
						if [ "$GSFSRS" -eq "$GSFSRS" ] 2>/dev/null && [ "$GSFSR" == "TRUE" ] || [ "$GSNIS" == "TRUE" ]; then
							# Sharpness Value should only be passed if FSR or NIS is enabled
							writelog "INFO" "${FUNCNAME[0]} - Adding sharpness parameter to the gamescope arguments:"
							if grep -q "$FSRS_STR" <<< "$("$(command -v "$GAMESCOPE")" --help 2>&1)"; then
								writelog "INFO" "${FUNCNAME[0]} - using '--fsr-sharpness ${GSFSRS}'"
								GAMESCOPE_ARGS="${GAMESCOPE_ARGS} --fsr-sharpness ${GSFSRS}"
							else
								writelog "INFO" "${FUNCNAME[0]} - using '--sharpness ${GSFSRS}'"
								GAMESCOPE_ARGS="${GAMESCOPE_ARGS} --sharpness ${GSFSRS}"
							fi
						fi
						## FILTERING OPTIONS END ###

						### HDR OPTIONS ###
						if [ "$GSHDR" == "TRUE" ]                                       ; then  GAMESCOPE_ARGS="${GAMESCOPE_ARGS} --hdr-enabled"; fi  # Possible to check if any HDR displays available and warn if not?
						if [ "$GSHDRWGFS" == "TRUE" ]; then
							# Don't enable GSHDRWGFS if GSHDR is not enabled first
							if [ "$GSHDR" == "TRUE" ]; then 
								GAMESCOPE_ARGS="${GAMESCOPE_ARGS} --hdr-wide-gammut-for-sdr"
							else
								writelog "WARN" "${FUNCNAME[0]} - GSHDRWGFS (--hdr-wide-gammut-for-sdr) option for GameScope enabled but HDR was not enabled - Ignoring as this option would have no effect"
							fi
						fi
						if [ ! "$GSHDRSCNITS" == "203" ]; then
							# Only pass value if nits != 203 && HDR enabled
							if [ "$GSHDR" == "TRUE" ] && [ "$GSHDRWGFS" == "TRUE" ]; then
								GAMESCOPE_ARGS="${GAMESCOPE_ARGS} --hdr-sdr-content-nits ${GSHDRSCNITS}"
							else
								writelog "WARN" "${FUNCNAME[0]} - GSHDRSCNITS (--hdr-sdr-content-nits) option for GameScope was set but HDR and SDR were not enabled - Ignoring as this option would have no effect"
							fi
						else
							writelog "INFO" "${FUNCNAME[0]} - GSHDRSCNITS (--hdr-sdr-content-nits) option for GameScope was left at default 203 - GameScope should use this anyway - Ignoring as this option would have no effect"
						fi
						if [ "$GSHDRITM" == "TRUE" ]                                    ; then  GAMESCOPE_ARGS="${GAMESCOPE_ARGS} --hdr-itm-enable"; fi
						if [ ! "$GSHDRITMSDRNITS" == "0" ]                              ; then  GAMESCOPE_ARGS="${GAMESCOPE_ARGS} --hdr-itm-sdr-nits ${GSHDRITMSDRNITS}"; fi
						if [ ! "$GSHDRITMTGTNITS" == "0" ]                              ; then  GAMESCOPE_ARGS="${GAMESCOPE_ARGS} --hdr-itm-target-nits ${GSHDRITMTGTNITS}"; fi
						### HDR OPTIONS END ###

						### VR OPTIONS ###
						if [ "$GSVR" == "TRUE" ]                                        ; then  GAMESCOPE_ARGS="${GAMESCOPE_ARGS} --openvr"; fi
						if [ "${#GSVREXNA}" -gt 0 ]                                     ; then  GAMESCOPE_ARGS="${GAMESCOPE_ARGS} --vr-overlay-explicit-name '${GSVREXNA}'"; fi  # Don't set explicit name if it's blank
						if [ "${#GSVRDEFNAM}" -gt 0 ]                                   ; then  GAMESCOPE_ARGS="${GAMESCOPE_ARGS} --vr-overlay-default-name '${GSVRDEFNAM}'"; fi  # Don't set default name if it's blank
						if [ -f "$GSVRICON" ] && [ "$GSVRICONENABLE" == "TRUE" ]        ; then  GAMESCOPE_ARGS="${GAMESCOPE_ARGS} --vr-overlay-icon '${GSVRICON}'"; fi
						if [ "$GSVRSHOIMM" == "TRUE" ]                                  ; then  GAMESCOPE_ARGS="${GAMESCOPE_ARGS} --vr-overlay-show-immediately"; fi
						if [ "$GSVRCONTROLBAR" == "TRUE" ]                              ; then  GAMESCOPE_ARGS="${GAMESCOPE_ARGS} --vr-overlay-enable-control-bar"; fi
						if [ "$GSVRCONTROLBARKEYBOARD" == "TRUE" ]                      ; then  GAMESCOPE_ARGS="${GAMESCOPE_ARGS} --vr-overlay-enable-control-bar-keyboard"; fi
						if [ "$GSVRCONTROLBARCLOSE" == "TRUE" ]                         ; then  GAMESCOPE_ARGS="${GAMESCOPE_ARGS} --vr-overlay-enable-control-bar-close"; fi
						if [ "$GSVRMODAL" == "TRUE" ]                                   ; then  GAMESCOPE_ARGS="${GAMESCOPE_ARGS} --vr-overlay-modal"; fi
						### VR OPTIONS END

						### EMBEDDED OPTIONS ###
						# Don't pass default touch mode option if we left at default
						if [ ! "${GSDEFTOUCHMODE}" == "${GSDEF}" ]; then 
							# Get the corresponding number that should be passed to GameScope from the number in the dropdown string, e.g. gets "0" from "hover:0"
							SELECTEDTOUCHMODE="$( echo "$GSDEFTOUCHMODE" | cut -d ":" -f 2 )" 
							GAMESCOPE_ARGS="${GAMESCOPE_ARGS} --default-touch-mode ${SELECTEDTOUCHMODE}"
						fi
						if [ "$GSIMMEDIATEFLIPS" == "TRUE" ]                            ; then  GAMESCOPE_ARGS="${GAMESCOPE_ARGS} --immediate-flips"; fi
						if [ "$GSADAPTIVESYNC" == "TRUE" ]                              ; then  GAMESCOPE_ARGS="${GAMESCOPE_ARGS} --adaptive-sync"; fi
						if [ "${#GSPREFOUT}" -gt 0 ]                                    ; then  GAMESCOPE_ARGS="${GAMESCOPE_ARGS} -O ${GSPREFOUT}"; fi  # Don't pass preferred output(s) if the textbox is blank
						# EMBEDDED OPTIONS END

						## ADVANCED OPTIONS ###
						if [ ! "$GSDRMMODE" == "${GSDEF}" ]                             ; then  GAMESCOPE_ARGS="${GAMESCOPE_ARGS} --generate-drm-mode ${GSDRMMODE}"; fi  # Don't pass DRM mode if "default"
						if [ -d "$GSSTATSPATH" ] && [ "$GSSTATSPATHENABLE" == "TRUE" ]  ; then  GAMESCOPE_ARGS="${GAMESCOPE_ARGS} --stats-path '${GSSTATSPATH}'"; fi
						if [ ! "$GSHIDECURSORDELAY" == "0" ]                            ; then  GAMESCOPE_ARGS="${GAMESCOPE_ARGS} -C ${GSHIDECURSORDELAY}"; fi  # Ignore cursor delay if it's 0
						if [ "$GSFORCECOMP" == "TRUE" ]                                 ; then  GAMESCOPE_ARGS="${GAMESCOPE_ARGS} --force-composition"; fi
						if [ "$GSDEBUGHUD" == "TRUE" ]                                  ; then  GAMESCOPE_ARGS="${GAMESCOPE_ARGS} --debug-hud"; fi
						if [ "$GSFORCEHDRSUPPORT" == "TRUE" ]                           ; then  GAMESCOPE_ARGS="${GAMESCOPE_ARGS} --hdr-debug-force-support"; fi
						if [ "$GSFORCEHDROUTPUT" == "TRUE" ]                            ; then  GAMESCOPE_ARGS="${GAMESCOPE_ARGS} --hdr-debug-force-output"; fi
						if [ "$GSPREFERVKDEVICE" == "TRUE" ]                            ; then  GAMESCOPE_ARGS="${GAMESCOPE_ARGS} --prefer-vk-device"; fi
						if [ "$GSWAYLAND" == "TRUE" ]                                   ; then  GAMESCOPE_ARGS="${GAMESCOPE_ARGS} --expose-wayland"; fi
						if [ "$GSRT" == "TRUE" ]                                        ; then  GAMESCOPE_ARGS="${GAMESCOPE_ARGS} --rt"; fi
						### ADVANCED OPTIONS END ###
						
						GAMESCOPE_ARGS="${GAMESCOPE_ARGS} --"
			
						writelog "INFO" "${FUNCNAME[0]} - Saving configured GAMESCOPE_ARGS '$GAMESCOPE_ARGS' into '$STLGAMECFG'"
						touch "$FUPDATE"
						updateConfigEntry "GAMESCOPE_ARGS" "$GAMESCOPE_ARGS" "$STLGAMECFG"						
						touch "$FUPDATE"
						updateConfigEntry "USEGAMESCOPE" "$USEGAMESCOPE" "$STLGAMECFG"						
					}
				;;	
			esac
}

function StandaloneProtonGame {
	function SapRun {
		if [ "$SAPRUN" == "TRUE" ]; then
			RUNSAPPROTON="$(getProtPathFromCSV "$SAPPROTON")"
			if [ ! -f "$RUNSAPPROTON" ]; then
				RUNSAPPROTON="$(fixProtonVersionMismatch "SAPPROTON" "$STLGAMECFG" X)"
			fi

			if [ ! -f "$RUNSAPPROTON" ]; then
				writelog "SKIP" "${FUNCNAME[0]} - No executable for selected Proton '$SAPPROTON' found"
			elif [ ! -f "$SAPEXE" ]; then
				writelog "SKIP" "${FUNCNAME[0]} - No executable found"
			elif [ ! -d "$SAP_COMPAT_DATA_PATH" ]; then
				writelog "SKIP" "${FUNCNAME[0]} - No $CODA dir found"
			else
				if [ -z "$SAPARGS" ]; then
					RUNSAPARGS=""
				else
					mapfile -d " " -t -O "${#RUNSAPARGS[@]}" RUNSAPARGS < <(printf '%s' "$SAPARGS")
				fi
				
				writelog "INFO" "${FUNCNAME[0]} - Starting '$SAPEXE' with '$SAPPROTON' with STEAM_COMPAT_DATA_PATH '$SAP_COMPAT_DATA_PATH'"
				STEAM_COMPAT_DATA_PATH="$SAP_COMPAT_DATA_PATH" "$RUNSAPPROTON" run "$SAPEXE" "${RUNSAPARGS[@]}"
			fi
		fi
	}

	function SapGui {
		export CURWIKI="$PPW/Standalone-Proton"
		TITLE="${PROGNAME}-StandaloneProtonGame"
		pollWinRes "$TITLE"

		SAPGAMELIST="$(find "$STLGSAPD" -type f -exec basename {} .conf \; | tr '\n' '!')"

		if [ -z "$SAP_COMPAT_DATA_PATH" ]; then
			SAP_COMPAT_DATA_PATH="$STLGSACD/${PROGNAME,,}-$((10000 + RANDOM % 10000))"
			mkProjDir "$SAP_COMPAT_DATA_PATH"
			IN_SAP_COMPAT_DATA_PATH="$SAP_COMPAT_DATA_PATH"
		fi

		PROTPARTS="$("$YAD" --f1-action="$F1ACTION" --window-icon="$STLICON" --form --center --on-top $WINDECO \
		--title="$TITLE" \
		--text="$(spanFont "$GUI_SAPTEXT" "H")" \
		--field=" ":LBL " " --separator="|" \
		--field="$GUI_SAPGAME!$DESC_SAPGAME":CBE "$(cleanDropDown "${SAPGAME}" "$SAPGAMELIST")" \
		--field="$GUI_SAPPROTON!$DESC_SAPPROTON":CB "$(cleanDropDown "${SAPPROTON//\"}" "$PROTYADLIST")" \
		--field="$GUI_SAP_COMPAT_DATA_PATH!$DESC_SAP_COMPAT_DATA_PATH":DIR "${SAP_COMPAT_DATA_PATH//\"}" \
		--field="$GUI_SAPEXE!$DESC_SAPEXE":FL "${SAPEXE//\"}" \
		--field="$GUI_SAPARGS!$DESC_SAPARGS" "${SAPARGS//\"}"\
		--field="$GUI_SAPRUN!$DESC_SAPRUN":CHK "$SAPRUN" \
		--button="$BUT_CAN:0" --button="$BUT_LOAD:2" --button="$BUT_RUN:4" "$GEOM"
		)"
		case $? in
			0)	{
					writelog "INFO" "${FUNCNAME[0]} - Selected '$BUT_CAN' - Exiting"
					if [ -d "$IN_SAP_COMPAT_DATA_PATH" ]; then
						rmdir "$IN_SAP_COMPAT_DATA_PATH"
					fi
				}
			;;
			2)	{
					writelog "INFO" "${FUNCNAME[0]} - Selected '$BUT_LOAD'"
					mapfile -d "|" -t -O "${#SAPARR[@]}" SAPARR < <(printf '%s' "$PROTPARTS")
					SAPGAME="${SAPARR[1]}"
					writelog "INFO" "Loading '${STLGSAPD}/${SAPGAME}.conf' and starting the gui ${FUNCNAME[0]}"
					loadCfg "${STLGSAPD}/${SAPGAME}.conf"

					if [ "$IN_SAP_COMPAT_DATA_PATH" != "$SAP_COMPAT_DATA_PATH" ]; then
						if [ -d "$IN_SAP_COMPAT_DATA_PATH" ]; then
							writelog "INFO" "${FUNCNAME[0]} - User chose an own COMPAT_DATA_PATH, removing autocreated '$IN_SAP_COMPAT_DATA_PATH'"
							rmdir "$IN_SAP_COMPAT_DATA_PATH"
						fi
					fi

					"${FUNCNAME[0]}"
				}
			;;
			4)	{
					writelog "INFO" "${FUNCNAME[0]} - Selected '$BUT_RUN' - Exiting"
					unset SAPARR
					mapfile -d "|" -t -O "${#SAPARR[@]}" SAPARR < <(printf '%s' "$PROTPARTS")
					SAPGAME="${SAPARR[1]}"
					SAPPROTON="${SAPARR[2]}"
					SAP_COMPAT_DATA_PATH="${SAPARR[3]}"
					SAPEXE="${SAPARR[4]}"
					SAPARGS="${SAPARR[5]}"
					SAPRUN="${SAPARR[6]}"
					
					if [ "$IN_SAP_COMPAT_DATA_PATH" != "$SAP_COMPAT_DATA_PATH" ]; then
						if [ -d "$IN_SAP_COMPAT_DATA_PATH" ]; then
							writelog "INFO" "${FUNCNAME[0]} - User chose an own COMPAT_DATA_PATH, removing autocreated '$IN_SAP_COMPAT_DATA_PATH'"
							rmdir "$IN_SAP_COMPAT_DATA_PATH"
						fi
					fi

					if [ -n "$SAPGAME" ];then
						SAPCFG="${STLGSAPD}/${SAPGAME}.conf"
				
						touch "$FUPDATE" "$SAPCFG"
						updateConfigEntry "SAPGAME" "$SAPGAME" "$SAPCFG"

						if [ -n "$SAPPROTON" ];then
							touch "$FUPDATE"
							updateConfigEntry "SAPPROTON" "$SAPPROTON" "$SAPCFG"
						fi

						if [ -n "$SAP_COMPAT_DATA_PATH" ];then
							touch "$FUPDATE"
							updateConfigEntry "SAP_COMPAT_DATA_PATH" "$SAP_COMPAT_DATA_PATH" "$SAPCFG"
						fi

						if [ -n "$SAPEXE" ];then
							touch "$FUPDATE"
							updateConfigEntry "SAPEXE" "$SAPEXE" "$SAPCFG"
						fi

						if [ -n "$SAPARGS" ];then
							touch "$FUPDATE"
							updateConfigEntry "SAPARGS" "$SAPARGS" "$SAPCFG"
						fi

						if [ -n "$SAPRUN" ];then
							touch "$FUPDATE"
							updateConfigEntry "SAPARGS" "$SAPARGS" "$SAPCFG"
						fi
					fi
					SapRun
				}
			;;
		esac
	}

	createProtonList X

	mkProjDir "$STLGSAPD"
	SAPGUI=1
	SAPRUN="TRUE"

	if [ -n "$1" ] && [ -z "$2" ] && [ -f "${STLGSAPD}/${1}.conf" ]; then
		writelog "INFO" "${FUNCNAME[0]} - Loading '${STLGSAPD}/${1}.conf' silently"
		loadCfg "${STLGSAPD}/${1}.conf"
		SAPGUI=0
		SapRun
	elif [ -n "$1" ] && [ ! -f "${STLGSAPD}/${1}.conf" ]; then
		if [ "$1" == "list" ]; then
			find "$STLGSAPD" -type f -exec basename {} .conf \;
			SAPGUI=0
			SAPRUN="FALSE"
		else
			writelog "INFO" "${FUNCNAME[0]} - Using '$1' as game title"
			SAPGAME="$1"
		fi
	elif [ -n "$1" ] && [ -n "$2" ] && [ -f "${STLGSAPD}/${1}.conf" ]; then
		writelog "INFO" "${FUNCNAME[0]} - Loading '${STLGSAPD}/${1}.conf' and starting the gui"
		loadCfg "${STLGSAPD}/${1}.conf"
		SAPGUI=1
	elif [ -z "$1" ]; then
		writelog "INFO" "${FUNCNAME[0]} - Only starting plain gui"
	fi

	if [ "$SAPGUI" -eq 1 ]; then
		SapGui
	fi
}

function getWinecfgExecutable {
	# Check if we have a systemwide Winecfg
	if [ -x "$(command -v "$WINECFG")" ]; then
		writelog "INFO" "${FUNCNAME[0]} - Using Winecfg found at '$WINECFG'"
		OTWINECFGEXE="$WINECFG"
	else
		# Try to use winecfg with Proton executable
		writelog "INFO" "${FUNCNAME[0]} - Trying to use Winetricks with game Proton version"
		if [ -z "$RUNPROTON" ]; then
			writelog "WARN" "${FUNCNAME[0]} - RUNPROTON is empty - '$RUNPROTON' - Maybe this is not a Proton game?"
		else
			WINECFGBASEPATH="$(dirname "$RUNPROTON")"
			if [ -d "$WINECFGBASEPATH" ]; then
				OTWINECFGEXE="$( find "$WINECFGBASEPATH" -name "winecfg.exe" | head -n1 )"
				writelog "INFO" "${FUNCNAME[0]} - Using Winecfg found at '$OTWINECFGEXE'"
			else
				writelog "WARN" "${FUNCNAME[0]} - Could not find directory name for Proton version '$RUNPROTON' - This probably shouldn't happen! - Could not get Winecfg executable to run"
			fi
		fi
	fi
}

# Extracted from part of setModWine
# Does not handle Proton version mismatches but this should hopefully be handled before game launch -- a PR would be welcome for this until I get around to it :-)
function getWineBinFromProtPath {
	INPROTON="$1"

	CHECKDNWINED="$(dirname "$INPROTON")/$DBW"  # Valve Proton structure
	CHECKDNWINEF="$(dirname "$INPROTON")/$FBW"  # GE-Proton structure

	FWINEVAR=""
	if [ -f "$CHECKDNWINED" ]; then
		writelog "INFO" "${FUNCNAME[0]} - CHECKDNWINED is a file -- '${CHECKDNWINED}' -- Looks like we have a Valve Proton here"
		FWINEVAR="$CHECKDNWINED"
	elif [ -f "$CHECKDNWINEF" ]; then
		FWINEVAR="$CHECKDNWINEF"
		writelog "INFO" "${FUNCNAME[0]} - CHECKDNWINEF is a file -- '${CHECKDNWINEF}' -- Looks like we have a GE-Proton here"
	else
		writelog "ERROR" "${FUNCNAME[0]} - Could not find Wine binary for Proton '$INPROTON' - can't continue"
	fi

	echo "$FWINEVAR"
}

# These functions will always use the game Proton version instead of the Proton version in the dropdown
# I don't think there's a way for us to get the Proton version in this dropdown to use with the game
#
# Having these as primary menu buttons would mean the dialog would close and the user would have to re-open the one-time run menu to run their game
# The tradeoff for now is having them set the Proton version by changing the game version before going to the one-time menu, and then they can run Winetricks
#
# I think this is a better tradeoff than having the menu close, as the amount of users who would change the Proton version are probably minimal
# compared to the users who would be annoyed by the dialog closing



# These two winecfg and winetricks functions need to be updated to accomodate a passed in AppID from the command line
# - needs to be able to get game config / proton versions
# - handle cases where a Proton version is not set for a game that has never been launched with STL
# - abort for native games (may need to check executable for this?)
function oneTimeWinecfg {
	OTPROT="$( getProtPathFromCSV "$USEPROTON" )"
	OTWINE="$( getWineBinFromProtPath "$OTPROT" )" 

	if [ -z "$GPFX" ]; then
		getGameFiles "$AID"  # Potentially fix GPFX not being set in some situations
	fi

	writelog "INFO" "${FUNCNAME[0]} - Running OneTime Winecfg with Wine '$RUNWINE'"

	if [ -z "$RUNPROTON" ]; then 
		RUNPROTON="$OTPROT"  # Makes getWinecfgExecutable happy
	fi

	getWinecfgExecutable
	WINEDEBUG="-all" WINEPREFIX="$GPFX" "$OTWINE" "$OTWINECFGEXE" # GPFX is not defined on Steam Deck for some reason? Need to fix, then this should work
}

# Needs updated to accomodate a passed in AppID from the command line
function oneTimeWinetricks {
	writelog "INFO" "${FUNCNAME[0]} - Getting Winetricks binary"
	chooseWinetricks
	if [ ! -x "$(command -v "$WINETRICKS")" ]; then
		writelog "WARN" "${FUNCNAME[0]} - Could not run one-time Winetricks because Winetricks is not installed - Skipping"
	else
		OTPROT="$( getProtPathFromCSV "$USEPROTON" )"
		OTWINE="$( getWineBinFromProtPath "$OTPROT" )"

		if [ -z "$GPFX" ]; then
			getGameFiles "$AID"  # Potentially fix GPFX not being set in some situations
		fi

		writelog "INFO" "${FUNCNAME[0]} - Running OneTime Winetricks for prefix '$GPFX'"
		
		WINE="$OTWINE" WINEPREFIX="$GPFX" "$WINETRICKS"  # GPFX is not defined on Steam Deck for some reason? Need to fix, then this should work
	fi
}

function OneTimeRunGui {

	if [ -n "$1" ]; then
		AID="$1"
		setAIDCfgs
	fi
	loadCfg "$STLGAMECFG"

	if [ -z "$STEAM_COMPAT_DATA_PATH" ]; then
		METCFG="$CUMETA/${AID}.conf"
		if [ -f "$METCFG" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Loading Metadata '$METCFG'"
			fixCustomMeta "$METCFG" # will be removed again later
			loadCfg "$METCFG"
		fi
		if [ -n "$WINEPREFIX" ]; then
			STEAM_COMPAT_DATA_PATH="${WINEPREFIX%/*}"
			writelog "INFO" "${FUNCNAME[0]} - Found STEAM_COMPAT_DATA_PATH '$STEAM_COMPAT_DATA_PATH'"
		fi
	fi

	if [ -z "$STEAM_COMPAT_DATA_PATH" ]; then
		writelog "ERROR" "${FUNCNAME[0]} - STEAM_COMPAT_DATA_PATH could not be determined"
	else
		createProtonList X
		export CURWIKI="$PPW/One-Time-Run"
		TITLE="${PROGNAME}-${FUNCNAME[0]}"
		pollWinRes "$TITLE"
		setShowPic
		if [ -z "$OTPROTON" ]; then
			OTPROTON="$USEPROTON"
		fi

		OTCMDS="$("$YAD" --f1-action="$F1ACTION" --image "$SHOWPIC" --image-on-top --window-icon="$STLICON" --form --center --on-top $WINDECO \
			--title="$TITLE" --separator="|" \
			--columns="2" \
			--text="$(spanFont "$GUI_ONETIMERUN" "H")" \
			--field="$GUI_OTPROTON!$DESC_OTPROTON":CB "$(cleanDropDown "${OTPROTON//\"}" "$PROTYADLIST")" \
			--field="$GUI_OTEXE!$DESC_OTEXE":FL "${OTEXE//\"}" \
			--field="$GUI_OTARGS!$DESC_OTARGS" "${OTARGS//\"}"\
			--field="$BUT_RUNWINECFG!$DESC_RUNWINECFG":FBTN "$( realpath "$0" ) runwinecfg" \
			--field="$GUI_OTRCUSTWORKINGDIR!$DESC_OTRCUSTWORKINGDIR":DIR "" \
			--field="$GUI_OTRUSEEXEDIR!$DESC_OTRUSEEXEDIR":CHK "FALSE" \
			--field="$GUI_OTSAVE!$DESC_OTSAVE":CHK "FALSE" \
			--field="$BUT_RUNWINETRICKS!$DESC_RUNWINETRICKS":FBTN "$( realpath "$0" ) runwinetricks" \
			--button="$BUT_CAN:0" \
			--button="$BUT_RUNONETIMECMD:2" \
			"$GEOM"
			)"
			case $? in
				# Selected Cancel
				0)	{
						writelog "INFO" "${FUNCNAME[0]} - Selected '$BUT_CAN' - Exiting"
					}
				;;
				# Selected Run
				2)	{
						mapfile -d "|" -t -O "${#OTARR[@]}" OTARR < <(printf '%s' "$OTCMDS")
						OTPROTON="${OTARR[0]}"
						OTEXE="${OTARR[1]}"
						OTARGS="${OTARR[2]}"
						# OTARR[3] and OTARR[4] are the WINECFG and WINETRICKS buttons
						OTUSEEXEDIR="${OTARR[5]}"
						OTCUSTWORKDIR="${OTARR[6]}"
						OTSAVE="${OTARR[7]}"	

						RUNOTPROTON="$(getProtPathFromCSV "$OTPROTON")"
						if [ ! -f "$RUNOTPROTON" ]; then
							RUNOTPROTON="$(fixProtonVersionMismatch "OTPROTON" "$STLGAMECFG" X)"
						fi
		
						if [ ! -f "$RUNOTPROTON" ]; then
							writelog "SKIP" "${FUNCNAME[0]} - No executable for selected Proton '$OTPROTON' found"
						elif [ ! -f "$OTEXE" ]; then
							writelog "SKIP" "${FUNCNAME[0]} - No executable found"
						else
							# Set the custom arguments passed from the textbox for the exe
							if [ -z "$OTARGS" ]; then
								RUNOTARGS=""
							else
								mapfile -d " " -t -O "${#RUNOTARGS[@]}" RUNOTARGS < <(printf '%s' "$OTARGS")
							fi
							
							if [ "$OTSAVE" == "TRUE" ];then
								writelog "INFO" "${FUNCNAME[0]} - Saving One time run settings into '$STLGAMECFG'"
								touch "$FUPDATE"
								updateConfigEntry "OTPROTON" "$OTPROTON" "$STLGAMECFG"
								touch "$FUPDATE"
								updateConfigEntry "OTEXE" "$OTEXE" "$STLGAMECFG"
								touch "$FUPDATE"
								updateConfigEntry "OTARGS" "$OTARGS" "$STLGAMECFG"
							fi

							OTRUNDIR="$( pwd )"
							if [ "$OTUSEEXEDIR" == "TRUE" ]; then
								OTRUNDIR="$( dirname "$OTEXE" )"
								if [ -d "$OTRUNDIR" ]; then
									writelog "INFO" "${FUNCNAME[0]} - User enabled 'OTUSEEXEDIR' - Setting directory to run executable to same directory - '$OTRUNDIR'"
								else
									writelog "WARN" "${FUNCNAME[0]} - User enabled 'OTUSEEXEDIR' but its directory '$OTRUNDIR' did NOT exist - Ignoring and calling back to pwd - '$( pwd )'"
									OTRUNDIR="$( pwd )"
								fi
							elif [ -n "$OTCUSTWORKDIR" ]; then
								if [ -d "$OTCUSTWORKDIR" ]; then
									OTRUNDIR="$OTCUSTWORKDIR"
									writelog "INFO" "${FUNCNAME[0]} - User entered path for a custom working directory and it exists - Using '$OTCUSTWORKDIR' as directory to run executable from"
								else
									writelog "WARN" "${FUNCNAME[0]} - User entered path for a custom working directory but it does NOT exist - Ignoring and sticking with current script working directory based on 'pwd' - '$OTRUNDIR'"
								fi
							else
								writelog "INFO" "${FUNCNAME[0]} - User did not select any custom executable path options - Keeping as default based on current script directory with 'pwd' - '$OTRUNDIR'"
							fi

							# Run in subshell to avoid messing with current script paths
							# TODO - Allow running native Linux programs here too
							writelog "INFO" "${FUNCNAME[0]} - Starting '$OTEXE' with '$OTPROTON' with STEAM_COMPAT_DATA_PATH '$STEAM_COMPAT_DATA_PATH'"
							(cd "$OTRUNDIR" && STEAM_COMPAT_DATA_PATH="$STEAM_COMPAT_DATA_PATH" "$RUNOTPROTON" run "$OTEXE" "${RUNOTARGS[@]}")
						fi
					}
				;;	
			esac
	fi
}

function setOPCustPath {
	if [ -z "$CUSTOMCMD" ] || [[ "$CUSTOMCMD" =~ ${DUMMYBIN}$ ]]; then
		OPCUSTPATH="$GP"
	fi
	
	if [ -z "$OPCUSTPATH" ]; then
		OPCUSTPATH="$CUSTOMCMD"
	fi
	
	if [ -n "$OPCUSTPATH" ]; then
		export OPCUSTPATH="$OPCUSTPATH"
		writelog "INFO" "${FUNCNAME[0]} - Default path for custom exe file requester is '$OPCUSTPATH'"
	fi
}

function setCommandLaunchVars {
	if [ "$USEGAMEMODERUN" -eq 1 ]; then
		GMR="$(command -v "$GAMEMODERUN")"
	fi

	if [ "$USEOBSCAP" -eq 1 ]; then
		OBSC="$(command -v "$OBSCAP")"
	fi

	if [ "$USEGAMESCOPE" -eq 1 ]; then
		if [ "$USEMANGOAPP" -eq 1 ]; then
			if [ "$ONSTEAMDECK" -eq 1 ]; then
				if [ "$FIXGAMESCOPE" -eq 1 ]; then
					writelog "SKIP" "${FUNCNAME[0]} - Disabling USEMANGOAPP variable in Steam Deck Game Mode, because Steam Deck uses $MANGOAPP already by default"
					USEMANGOAPP=0
				else
					writelog "INFO" "${FUNCNAME[0]} - Allowing USEMANGOAPP variable in Steam Deck Desktop Mode"
					USEMANGOAPP=1
				fi
			else
				writelog "SKIP" "${FUNCNAME[0]} - Not adding $GAMESCOPE to the game launch command, because $MANGOAPP is enabled, which triggers it automatically"
				USEGAMESCOPE=0
			fi
		else
			GSC="$(command -v "$GAMESCOPE")"
			
			gameScopeArgs "$GAMESCOPE_ARGS"  # Create GameScope args array - Is called twice because we call `setCommandLaunchVars` above and in `buildCustomCmdLaunch` it seems
		fi
	fi

	if [ "$USEZINK" -eq 1 ]; then
		export __GLX_VENDOR_LIBRARY_NAME=mesa
		export MESA_LOADER_DRIVER_OVERRIDE=zink
		export GALLIUM_DRIVER=zink
	fi
	
	if [ "$ENABLE_WINESYNC" -eq 1 ]; then
		export WINEESYNC=0
		export WINEFSYNC=0
		export WINEFSYNC_FUTEX2=0
	fi

	if [ "$USEPRIMERUN" -eq 1 ]; then
		export __NV_PRIME_RENDER_OFFLOAD=1
		export __VK_LAYER_NV_optimus=NVIDIA_only
		export __GLX_VENDOR_LIBRARY_NAME=nvidia
	fi

	# This could be expanded in future as a general option to force Wayland for games/engines that support it, e.g. '-wayland' flag for unity
	if [ "$SDLUSEWAYLAND" -eq 1 ]; then
		export SDL_VIDEODRIVER=wayland
	fi

	if [ -n "$STLRAD_PFTST" ] && [ "$STLRAD_PFTST" != "none" ]; then
		writelog "INFO" "${FUNCNAME[0]} - STLRADV_PFTST is not empty or none - Exporting RADV_PERFTEST=$STLRAD_PFTST"
		export RADV_PERFTEST=$STLRAD_PFTST
	fi
}

# Used to create the launch command for games and custom commands so they can use various program functions i.e. GameScope
function buildCustomCmdLaunch {
	setCommandLaunchVars  # Checks for things like GameMode, GameScope, etc
	FINALOUTCMD=()

	# Lifted originally from `launchSteamGame`
	if [ -n "$GMR" ]; then
		if [ -n "${FINALOUTCMD[0]}" ]; then
			FINALOUTCMD=("${FINALOUTCMD[@]}" "$GMR")
		else
			FINALOUTCMD=("$GMR")
		fi
	fi

	# GameScope has to be appended before other commands
	if [ -n "$GSC" ]; then
		if [ -n "${FINALOUTCMD[0]}" ]; then
			FINALOUTCMD=("${FINALOUTCMD[@]}" "$GSC")
		else
			FINALOUTCMD=("$GSC")
		fi
		
		if [ -n "${FINALOUTCMD[0]}" ]; then
			FINALOUTCMD=("${FINALOUTCMD[@]}" "${GAMESCOPEARGSARR[@]}")
		fi
	fi

	# OBS capture has to go after GameScope
	if [ "$USEOBSCAP" -eq 1 ]; then
		writelog "INFO" "${FUNCNAME[0]} - USEOBSCAP is enabled - preparing $OBSCAP command"
		if [ -n "${FINALOUTCMD[0]}" ]; then
			FINALOUTCMD=("${FINALOUTCMD[@]}" "$OBSC")
		else
			FINALOUTCMD=("$OBSC")
		fi
	fi
	
	# MangoHud has to go inside GameScope
	if [ "$USEMANGOHUD" -eq 1 ]; then
		if [ "$MAHUARGS" != "$NON" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Exporting MANGOHUD_CONFIG with $MAHU arguments '$MAHUARGS'"
			export MANGOHUD_CONFIG="$MAHUARGS"
		else
			writelog "SKIP" "${FUNCNAME[0]} - Not exporting  MANGOHUD_CONFIG '$MAHUARGS'"
		fi

		if [ "$MAHUVAR" -eq 1 ]; then
			writelog "INFO" "${FUNCNAME[0]} - Exporting MANHOGUD variable and skipping all $MAHU binary settings, because MAHUVAR is '$MAHUVAR'"
			export MANGOHUD=1
		else
			if [ -f "$MAHUBIN" ]; then
				writelog "INFO" "${FUNCNAME[0]} - $MAHU is enabled"
				if [ "$LDPMAHU" -eq 1 ]; then
					writelog "INFO" "${FUNCNAME[0]} - Preloading $MAHU"
					export LD_PRELOAD="$LD_PRELOAD $MAHUBIN"
				else
					if [ -n "${FINALOUTCMD[0]}" ]; then
						FINALOUTCMD=("${FINALOUTCMD[@]}" "$MAHUBIN")
					else
						FINALOUTCMD=("$MAHUBIN")
					fi	
				fi
			else
				writelog "WARN" "${FUNCNAME[0]} - $MAHU binary not found - disabling"
				USEMANGOHUD=0
			fi
		fi
	fi
}

function launchCustomProg {
	if [ -n "$1" ]; then
		CUSTOMCMD="$WICO"
	fi
	
	if [ -z "$CUSTOMCMD" ] || [[ "$CUSTOMCMD" =~ ${DUMMYBIN}$ ]]; then

		writelog "INFO" "${FUNCNAME[0]} - CUSTOMCMD variable is empty - opening file requester"
		fixShowGnAid

		export CURWIKI="$PPW/Custom-Program"
		TITLE="${PROGNAME}-OpenCustomProgram"
		pollWinRes "$TITLE"

		ZCUST="$("$YAD" --f1-action="$F1ACTION" --window-icon="$STLICON" --form --center --on-top "$WINDECO" \
		--title="$TITLE" \
		--text="$(spanFont "$SGNAID - $GUI_SELECTCUSTOMEXE" "H")" \
		--field=" ":LBL " " \
		--field="$GUI_SELECTEXE":FL "${OPCUSTPATH/#-/ -}" "$GEOM")"

		if [ -n "$ZCUST" ]; then
			writelog "INFO" "${FUNCNAME[0]} - '${ZCUST//|/}' selected for CUSTOMCMD - updating configfile '$STLGAMECFG'"
			updateConfigEntry "CUSTOMCMD" "${ZCUST//|/}" "$STLGAMECFG"

			CUSTOMCMD="${ZCUST//|/}"
		else
			writelog "SKIP" "${FUNCNAME[0]} - Nothing selected for CUSTOMCMD - skipping"
			if [ "$ONLY_CUSTOMCMD" -eq 1 ]; then
				writelog "SKIP" "${FUNCNAME[0]} - ONLY_CUSTOMCMD is enabled - bailing out here"
				closeSTL " ######### STOP EARLY '$PROGNAME $PROGVERS' #########"
				exit
			else
				writelog "SKIP" "${FUNCNAME[0]} - Continuing with the main game"
				return
			fi
		fi
	fi
	
	if [ -z "$CUSTOMCMD" ]; then
		writelog "ERROR" "${FUNCNAME[0]} - CUSTOMCMD variable is empty - but it shouldn't be empty here!"
	fi
	
	CHCUSTDIR=0
	if [ -n "$1" ]; then
		writelog "INFO" "${FUNCNAME[0]} - Using '$WICO' as custom command"
		LACO="$WICO"
		CUSTCOM="$WICO"
	elif [ -x "$(command -v "$CUSTOMCMD")" ]; then
		writelog "INFO" "${FUNCNAME[0]} - '$CUSTOMCMD' found"
		LACO="$CUSTOMCMD"
		CUSTCOM="$(command -v "$CUSTOMCMD")"
		CHCUSTDIR=1
	else
		writelog "INFO" "${FUNCNAME[0]} - '$CUSTOMCMD' not found - searching in gamedir"

		if [ -f "$EFD/$CUSTOMCMD" ]; then
			writelog "INFO" "${FUNCNAME[0]} - '$CUSTOMCMD' was found in gamedir '$EFD'"
			LACO="$EFD/$CUSTOMCMD"
			CUSTCOM="$EFD/$CUSTOMCMD"
		else
			writelog "INFO" "${FUNCNAME[0]} - '$CUSTOMCMD' also not in '$EFD/$CUSTOMCMD' - checking if absolute path was provided"

			if [ -f "$CUSTOMCMD" ]; then
				writelog "INFO" "${FUNCNAME[0]} - '$CUSTOMCMD' is absolute path"
				LACO="$CUSTOMCMD"
				CUSTCOM="$CUSTOMCMD"
				CHCUSTDIR=1
			else
				writelog "INFO" "${FUNCNAME[0]} - CUSTOMCMD file '$CUSTOMCMD' not found - opening file requester"
				fixShowGnAid
				export CURWIKI="$PPW/Custom-Program"
				TITLE="${PROGNAME}-OpenCustomProgram"
				pollWinRes "$TITLE"
				
				ZCUST="$("$YAD" --f1-action="$F1ACTION" --window-icon="$STLICON" --form --center --on-top "$WINDECO" \
				--title="$TITLE" \
				--text="$(spanFont "$SGNAID - $GUI_SELECTCUSTOMEXE" "H")" \
				--field=" ":LBL " " \
				--field="$GUI_SELECTEXE":FL "${OPCUSTPATH/#-/ -}" "$GEOM")"		
				
				if [ -n "$ZCUST" ]; then
					writelog "INFO" "${FUNCNAME[0]} - '${ZCUST//|/}' selected for CUSTOMCMD - updating configfile '$STLGAMECFG'"
					updateConfigEntry "CUSTOMCMD" "${ZCUST//|/}" "$STLGAMECFG"
					LACO="${ZCUST//|/}"
					CUSTCOM="${ZCUST//|/}"
					CUSTOMCMD="${ZCUST//|/}"
					CHCUSTDIR=1
				else
					writelog "SKIP" "${FUNCNAME[0]} - Nothing selected for CUSTOMCMD - skipping"
					if [ "$ONLY_CUSTOMCMD" -eq 1 ]; then
						writelog "SKIP" "${FUNCNAME[0]} - ONLY_CUSTOMCMD is enabled - bailing out here"
						closeSTL " ######### STOP EARLY $PROGNAME $PROGVERS #########"
						exit
					else
						writelog "SKIP" "${FUNCNAME[0]} - Continuing with the main game"
						return
					fi
				fi
			fi
		fi
	fi

	if [ -z "$LACO" ]; then
		writelog "SKIP" "${FUNCNAME[0]} - ERROR - launch command empty- skipping launch"
	else
		startSBSVR &

		if [ "$CHCUSTDIR" -eq 1 ]; then
			CUSTDIR="$(dirname "$CUSTOMCMD")"
			cd "$CUSTDIR" >/dev/null || return
			writelog "INFO" "${FUNCNAME[0]} - Changed pwd into the custom directory '$PWD'"
		fi

		# Putting logic here means we have FINALOUTCMD for Wine/Proton *and* native games
		if [ "$EXTPROGS_CUSTOMCMD" -eq 1 ]; then 
			writelog "INFO" "${FUNCNAME[0]} - EXTPROGS_CUSTOMCMD was set to 1, so checking for custom arguments like MangoHUD and GameScope"
			buildCustomCmdLaunch  # Create FINALOUTCMD
			writelog "INFO" "${FUNCNAME[0]} - Generated arguments for custom command are now '${FINALOUTCMD[*]}'"
		fi

		# Cannot always rely on `file` to return `PE32` even for Windows executables -- See #710 (seems to be when exe files are built on Linux they are not PE32)
		if [ "$(file "$CUSTCOM" | grep -c "PE32")" -eq 1 ] || grep -q ".bat" <<< "$CUSTCOM" || [ "$CUSTOMCMDFORCEWIN" -eq 1 ]; then
			if [ "$CUSTOMCMDFORCEWIN" -eq 1 ]; then
				# Force custom command to use Wine/Proton, even if we do not detect it as a valid Windows binary
				writelog "INFO" "${FUNCNAME[0]} - CUSTOMCMDFORCEWIN is '$CUSTOMCMDFORCEWIN' - User wants to force this custom command as a Windows program"
				if [ "$(file "$CUSTCOM" | grep -c "PE32")" -eq 0 ]; then
					writelog "WARN" "${FUNCNAME[0]} - Custom command does not appear to be a Windows program by normal SteamTinkerLaunch checks, but CUSTOMCMDFORCEWIN was enabled, so using Proton anyway"
				else
					writelog "INFO" "${FUNCNAME[0]} - Custom command seems to be a Windows program anyway even though CUSTOMCMDFORCEWIN was enabled"
				fi
			else
				writelog "INFO" "${FUNCNAME[0]} - '$CUSTCOM' seems to be a MS Windows program - starting through proton"
			fi

			if [ "$USEWICO" -eq 1 ] && [ "$(file "$CUSTCOM" | grep -c "(console)")" -eq 1 ]; then  # Command line Wine/Proton custom program
				writelog "INFO" "${FUNCNAME[0]} - '$CUSTCOM' seems to be a MS console program - starting using '$WICO'"
				if [ "$FORK_CUSTOMCMD" -eq 1 ]; then	
					writelog "INFO" "${FUNCNAME[0]} - FORK_CUSTOMCMD is set to 1 - forking the custom program in background and continue"
					extProtonRun "FC" "$LACO" "$CUSTOMCMD_ARGS"
				elif [ "$ONLY_CUSTOMCMD" -eq 1 ] && [ -n "${FINALOUTCMD[*]}" ]; then
					writelog "INFO" "${FUNCNAME[0]} - ONLY_CUSTOMCMD is set to 1 and we have some arguments in FINALOUTCMD - passing to extProtonRun to build a valid start command"
					extProtonRun "R" "$LACO" "$CUSTOMCMD_ARGS" "$FINALOUTCMD"  # extProtonRun will handle adding the FINALOUTCMD args to 
				else
					extProtonRun "RC" "$LACO" "$CUSTOMCMD_ARGS"
				fi
			else  # GUI Wine/Proton program
				writelog "INFO" "${FUNCNAME[0]} - '$CUSTCOM' seems to be a MS gui program - starting regularly"

				if [ "$FORK_CUSTOMCMD" -eq 1 ]; then	
					writelog "INFO" "${FUNCNAME[0]} - FORK_CUSTOMCMD is set to 1 - forking the custom program in background and continue"
					extProtonRun "F" "$LACO" "$CUSTOMCMD_ARGS"
				elif [ "$ONLY_CUSTOMCMD" -eq 1 ] && [ -n "$FINALOUTCMD" ]; then
					writelog "INFO" "${FUNCNAME[0]} - ONLY_CUSTOMCMD is set to 1 and we have some arguments in FINALOUTCMD - passing to extProtonRun to build a valid start command"
					extProtonRun "R" "$LACO" "$CUSTOMCMD_ARGS" "${FINALOUTCMD[*]}"  # extProtonRun will handle adding the FINALOUTCMD args
				else
					extProtonRun "R" "$LACO" "$CUSTOMCMD_ARGS"
				fi
			fi
		else  # Native custom command 
			writelog "INFO" "${FUNCNAME[0]} - Seems like we may have a Linux executable here"

			# Arguments to append to executable
			if [ -z "$CUSTOMCMD_ARGS" ] || [ "$CUSTOMCMD_ARGS" == "$NON" ]; then
				RUNCUSTOMCMD_ARGS=""
			else
				writelog "INFO" "${FUNCNAME[0]} - Starting the custom program '$CUSTOMCMD' with args: '$CUSTOMCMD_ARGS'"
				mapfile -d " " -t -O "${#RUNCUSTOMCMD_ARGS[@]}" RUNCUSTOMCMD_ARGS < <(printf '%s' "$CUSTOMCMD_ARGS")
			fi

			# Custom program args to preceed executable (e.g. /usr/bin/gamemode /usr/bin/gamescope -- ./game.sh) 
			if [ -z "$FINALOUTCMD" ]; then
				writelog "INFO" "${FUNCNAME[0]} - No external program args here it seems"
				RUNEXTPROGRAMARGS=( "" )  # Initialise to array with empty string so we don't have to do checks in each if block
			else
				writelog "INFO" "${FUNCNAME[0]} - Looks like we got some external program args, '${FINALOUTCMD[*]}'"
				mapfile -d " " -t -O "${#RUNEXTPROGRAMARGS[@]}" RUNEXTPROGRAMARGS < <(printf '%s' "${FINALOUTCMD[*]}")
			fi

			FWAIT=2

			# Launch native custom command
			NATIVEPROGNAME="$( basename "$LACO" )"
			if [ -n "$1" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Starting only the '$WICO' with command: '$LACO'"
				"${RUNEXTPROGRAMARGS[@]}" "$LACO"
				writelog "STOP" "######### CLEANUP #########"
				closeSTL "######### DONE - $PROGNAME $PROGVERS #########"
				exit
			else
				writelog "INFO" "${FUNCNAME[0]} - '$CUSTCOM' doesn't seem to be a MS Windows exe - regular start (without further analysing)"
				if [ "$FORK_CUSTOMCMD" -eq 1 ]; then  # Forked native custom program
					writelog "INFO" "${FUNCNAME[0]} - FORK_CUSTOMCMD is set to 1 - forking the custom program in background and continue"
					if [ -n "${RUNEXTPROGRAMARGS[0]}" ]; then
						(sleep "$FWAIT"; notiShow "$( strFix "$NOTY_CUSTPROG_FORKED_NATIVE" "$NATIVEPROGNAME" )"; "${RUNEXTPROGRAMARGS[@]}" "$LACO" "${RUNCUSTOMCMD_ARGS[@]}") &
					else
						(sleep "$FWAIT"; notiShow "$( strFix "$NOTY_CUSTPROG_FORKED_NATIVE" "$NATIVEPROGNAME" )"; "$LACO" "${RUNCUSTOMCMD_ARGS[@]}") &
					fi
				else  # Regular native executable
					writelog "INFO" "${FUNCNAME[0]} - Starting native custom command regularly"
					notiShow "$( strFix "$NOTY_CUSTPROG_REG_NATIVE" "$NATIVEPROGNAME" )"
					if [ -n "${RUNEXTPROGRAMARGS[0]}" ]; then
						"${RUNEXTPROGRAMARGS[@]}" "$LACO" "${RUNCUSTOMCMD_ARGS[@]}"
					else
						"$LACO" "${RUNCUSTOMCMD_ARGS[@]}"
					fi
				fi
			fi
		fi

		if [ "$CHCUSTDIR" -eq 1 ]; then
			writelog "INFO" "${FUNCNAME[0]} - Changing pwd into previous directory"
			cd - >/dev/null || return
		fi
	fi
}

function getGameFiles {
	AID="$1"

	if [ -z "$APPMAFE" ]; then
		APPMAFE="$(listAppManifests | grep -m1 "${AID}.acf")"
	fi

	if [ -f "$APPMAFE" ]; then
		if [ -z "$GPFX" ]; then
			GPFX="$(dirname "$APPMAFE")/$CODA/$1/pfx"
		fi

		if [ -z "$EFD" ]; then
			EFD="$(getGameDirFromAM "$APPMAFE")"
		fi

		if [ -z "$STECOSHAPA" ]; then
			STECOSHAPA="${APPMAFE%/*}/shadercache/$AID"
		fi
	fi
}

function createCustomCfgs {
	if [ ! -f "$GAMECUSTVARS" ]; then
		writelog "INFO" "${FUNCNAME[0]} - Creating emtpy game-specific config '$GAMECUSTVARS' for user defined custom variables"
		touch "$GAMECUSTVARS"
	fi

	if [ ! -f "$GLOBCUSTVARS" ]; then
		writelog "INFO" "${FUNCNAME[0]} - Creating emtpy global config '$GLOBCUSTVARS' for user defined custom variables"
		touch "$GLOBCUSTVARS"
	fi

}

function loadCustomVars {
	if [ -s "$GLOBCUSTVARS" ]; then
		writelog "INFO" "${FUNCNAME[0]} - Loading user defined custom variables from global config '$GLOBCUSTVARS'"
		loadCfg "$GLOBCUSTVARS"
	else
		writelog "INFO" "${FUNCNAME[0]} - Empty global config '$GLOBCUSTVARS' for user defined custom variables not loaded"
	fi
	
	if [ -s "$GAMECUSTVARS" ]; then
		writelog "INFO" "${FUNCNAME[0]} - Loading user defined custom variables from game-specific config '$GAMECUSTVARS'"
		loadCfg "$GAMECUSTVARS"
	else
		writelog "INFO" "${FUNCNAME[0]} - Empty game-specific config '$GAMECUSTVARS' for user defined custom variables not loaded"
	fi	
}

function setGameFilesArray {
	unset GamDesc
	unset GamFiles
	if [ "$EFD" != "." ] && [ -d "$EFD" ]; then
		GamDesc+=("$GUI_GD")
		GamFiles+=("$EFD")
	fi

	if [ -d "$GPFX" ]; then
		GamDesc+=("$GUI_WP")
		GamFiles+=("$GPFX")
	fi

	if [ -f "$APPMAFE" ]; then
		GamDesc+=("$GUI_AM")
		GamFiles+=("$APPMAFE")
	fi

	if [ -d "$STECOSHAPA" ]; then
		GamDesc+=("$GUI_SP")
		GamFiles+=("$STECOSHAPA")
	fi

	if [ -n "$STLDXVKCFG" ]; then
		GamDesc+=("$GUI_DXVKCFG")
		GamFiles+=("$STLDXVKCFG")
	fi

	if [ -f "$MAHUCID/${AID}.conf" ]; then
		GamDesc+=("$GUI_MANGOHUDGAMECFG")
		GamFiles+=("$MAHUCID/${AID}.conf")
	fi

	createCustomCfgs

	GamDesc+=("$GUI_STLCVFILE")
	GamFiles+=("$GAMECUSTVARS")
 
	GamDesc+=("$GUI_STLGLBCVFILE")
	GamFiles+=("$GLOBCUSTVARS")
}

function GameFilesMenu {
	if [ -n "$1" ]; then
		getGameFiles "$1"
	else
		setGameVars
	fi

	fixShowGnAid

	setGameFilesArray
		
	if [ "${#GamFiles[@]}" -ge 1 ]; then	
		writelog "INFO" "${FUNCNAME[0]} - Found ${#GamFiles[@]} available game files and directories - opening menu"
		export CURWIKI="$PPW/Game-Files"
		TITLE="${PROGNAME}-Game-Files"
		pollWinRes "$TITLE"

		setShowPic
		OPFILES="$(for i in "${!GamFiles[@]}"; do printf "FALSE\n%s\n%s\n" "${GamDesc[$i]}" "${GamFiles[$i]}"; done | \
		"$YAD" --f1-action="$F1ACTION" --image "$SHOWPIC" --image-on-top --window-icon="$STLICON" --center $WINDECO --list --checklist --column=Open --column=Description --column=Path --separator="\n" --print-column="3" \
		--text="$(spanFont "$(strFix "$GUI_GAFIDIALOG" "$SGNAID")" "H")" --title="$TITLE" --button="$BUT_CAN:0" --button="$BUT_SELECT:2" "$GEOM")"
		case $? in
			0) writelog "INFO" "${FUNCNAME[0]} - Selected '$BUT_CAN' - Cancelling selection"
			;;
			2) 
				if [ -x "$(command -v "$XDGO" 2>/dev/null)" ]; then
					writelog "INFO" "${FUNCNAME[0]} - Selected Open - Opening selected files and directories using '$XDGO'"
					mapfile -t -O "${#OpArr[@]}" OpArr <<< "$OPFILES"
					if [ "${#OpArr[@]}" -ge 1 ]; then
						while read -r gafi; do
							if [ -n "$gafi" ]; then
								if [ "$gafi" == "$STLDXVKCFG" ] && [ ! -f "$STLDXVKCFG" ]; then
									writelog "INFO" "${FUNCNAME[0]} - Creating blank game-specific DXVK config in '$STLDXVKCFG' for user-defined DXVK configuration options"
									echo "## $(strFix "$STLDXVKCFG_WARNING" "$DXVKURL")" > "$STLDXVKCFG"
									if [ "$USE_STLDXVKCFG" -eq 0 ]; then
										writelog "INFO" "${FUNCNAME[0]} - Enabling USE_STLDXVKCFG automatically, because the user selected to open the config file '$STLDXVKCFG'"
										USE_STLDXVKCFG=1
										touch "$FUPDATE"
										updateConfigEntry "USE_STLDXVKCFG" "$USE_STLDXVKCFG" "$STLGAMECFG"
									fi
								fi
								"$XDGO" "$gafi"
							fi
						done <<< "$(printf "%s\n" "${OpArr[@]}")"
						unset OpArr
					else
						writelog "SKIP" "${FUNCNAME[0]} - Nothing selected"
					fi
				else
					writelog "SKIP" "${FUNCNAME[0]} - '$XDGO' not found - can't open the directory"
				fi
			;;
		esac
	else
		writelog "SKIP" "${FUNCNAME[0]} - Could not find any game files"
	fi
}

function DxvkHudPick {
	if [ -n "$1" ]; then
		AID="$1"
		setAIDCfgs
	fi

	if [ ! -f "$STLGAMECFG" ]; then
		writelog "ERROR" "${FUNCNAME[0]} - Game config '$STLGAMECFG' not found - exiting"
	else
		DXVKHUDLIST="1,devinfo,fps,frametimes,submissions,drawcalls,pipelines,memory,gpuload,version,api,compiler,samplers,full"

		writelog "INFO" "${FUNCNAME[0]} - LoadCfg: $STLGAMECFG"
		loadCfg "$STLGAMECFG"

		unset CURDXH

		if [ "$DXVK_HUD" == "0" ]; then
			declare -a CURDXH
		else
			mapfile -d " " -t -O "${#CURDXH[@]}" CURDXH <<< "$(printf '%s\n' "$DXVK_HUD")"
		fi
		fixShowGnAid
		export CURWIKI="$PPW/Dxvk-Hud-Options"
		TITLE="${PROGNAME}-DXVK-Hud-Options"
		pollWinRes "$TITLE"

		setShowPic

		DXHUDOPTS="$(
		while read -r dxline; do
			if [[ "${CURDXH[*]}" =~ $dxline ]]; then
				echo TRUE
			else
				echo FALSE
			fi
			echo "$dxline"
		done <<< "$(tr ',' '\n' <<< "$DXVKHUDLIST")"	 | \
		"$YAD" --f1-action="$F1ACTION" --image "$SHOWPIC" --image-on-top --window-icon="$STLICON" --center "$WINDECO" --list --checklist --column="$GUI_ADD" --column="$GUI_DXH" --separator="" --print-column="2" \
		--text="$(spanFont "$(strFix "$GUI_DXHDIALOG" "$SGNAID")" "H")" --title="$TITLE" "$GEOM")"

		if [ -n "$DXHUDOPTS" ]; then
			unset DXVK_HUD
			while read -r line; do
				DXVK_HUD="${DXVK_HUD},$line"
			done <<< "$DXHUDOPTS"
			DXVK_HUD="${DXVK_HUD#*[[:blank:]]}"
			DXVK_HUD="${DXVK_HUD#*,}"
			DXVK_HUD="${DXVK_HUD%*[[:blank:]]}"
			touch "$FUPDATE"
			updateConfigEntry "DXVK_HUD" "$DXVK_HUD" "$STLGAMECFG"
		else
			writelog "INFO" "${FUNCNAME[0]} - Nothing selected"
			touch "$FUPDATE"
			DXVK_HUD="0"
			updateConfigEntry "DXVK_HUD" "0" "$STLGAMECFG"
		fi

		if [ -n "$2" ]; then
			"$2" "$AID" "${FUNCNAME[0]}"
		fi
	fi
}

function symlinkSteamUser {

	SteamUserDir="$GPFX/$DRCU/$STUS"

	if [ "$1" -eq 1 ]; then
		mkProjDir "$STLPROTSTUSDIR"

		if [ "$USEGLOBSUSYM" -eq 1 ]; then
			SUSYD="$STLPROTSTUSDIR/global"
		else
			SUSYD="$STLPROTSTUSDIR/$AID"
		fi

		writelog "INFO" "${FUNCNAME[0]} - Testing if creating a symlink '$SteamUserDir' pointing to '$SUSYD' is required"
		
		if [ ! -d "$SUSYD" ]; then
			writelog "INFO" "${FUNCNAME[0]} - '$SUSYD' does not yet exists"
			if [ -d "$SteamUserDir" ]; then
				mv "$SteamUserDir" "$SUSYD"
			else
				mkProjDir "$SUSYD"
			fi
		else
			writelog "INFO" "${FUNCNAME[0]} - '$SUSYD' does already exists"
		fi 

		if [ -L "$SteamUserDir" ]; then
			if [ "$(readlink "$SteamUserDir")" == "$SUSYD" ]; then
				writelog "INFO" "${FUNCNAME[0]} - '$SteamUserDir' is already a symlink pointing to '$SUSYD' - nothing to do"
			else
				writelog "INFO" "${FUNCNAME[0]} - '$SteamUserDir' is already a symlink pointing to the unexpected directory '$(readlink "$SteamUserDir")' instead of '$SUSYD' - nothing to do"
			fi
		else
			if [ -d "$SteamUserDir" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Syncing files from '$SteamUserDir' to '$SUSYD'"
				"$RSYNC" -amu "$SteamUserDir" "$SUSYD"
				BACKSUD="${SteamUserDir}_${PROGNAME,,}_$((900 + RANDOM % 100))"
				mv "$SteamUserDir" "$BACKSUD"
				writelog "INFO" "${FUNCNAME[0]} - Backing up '$SteamUserDir' to '$BACKSUD'"
			fi

			if [ ! -d "$SteamUserDir" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Creating '$SteamUserDir' symlink pointing to '$SUSYD' using command:"
				writelog "INFO" "${FUNCNAME[0]} - 'ln -s \"$SUSYD\" \"$SteamUserDir\"'"

				ln -s "$SUSYD" "$SteamUserDir"
			else
				writelog "SKIP" "${FUNCNAME[0]} - '$SteamUserDir' still exists - can't create a symlink pointing to '$SUSYD'"
			fi
		fi

		if [ "$(readlink "$SteamUserDir")" == "$SUSYD" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Pulling files from backup if existing and '$SteamUserDir' is empty and a symlink to '$SUSYD'"
			restoreSteamUser "restore-if-dst-is-empty"
		fi
	else
		writelog "SKIP" "${FUNCNAME[0]} - Symlinking $STUS is disabled - Checking if a symlink needs to be reverted"
		
		if [ -L "$SteamUserDir" ]; then
			SUSYD="$(readlink "$SteamUserDir")"
			writelog "INFO" "${FUNCNAME[0]} - '$SteamUserDir' points to '$SUSYD'"
			if [ -d "$SUSYD" ]; then
				rm "$SteamUserDir"
				mkProjDir "$SteamUserDir"
				if grep -q "$AID" <<< "$SUSYD"; then
					writelog "INFO" "${FUNCNAME[0]} - The directory '$SUSYD' where the symlink '$SteamUserDir' points to is game specific - "
					writelog "INFO" "${FUNCNAME[0]} - Migrating all files into the freshly created '$SteamUserDir' from it"
					"$RSYNC" -amu "$SUSYD" "$SteamUserDir"
				else
					writelog "INFO" "${FUNCNAME[0]} - The directory '$SUSYD' where the symlink '$SteamUserDir' points to is not game specific - "
					writelog "INFO" "${FUNCNAME[0]} - Not migrating any files into the freshly created '$SteamUserDir' from it - "
					writelog "INFO" "${FUNCNAME[0]} - Pulling files from backup if existing instead"
					restoreSteamUser "restore-if-dst-is-empty"	
				fi
			fi
		else
			writelog "SKIP" "${FUNCNAME[0]} - '$SteamUserDir' is no symlink - nothing to do"
		fi
	fi
}

function redirectSCDP {
	function checkCompatdataSteamUser {
		if [ "$REDIRSTEAMUSER" == "symlink" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Checking creation of a '$STUS' symlink, as REDIRSTEAMUSER is '$REDIRSTEAMUSER'"
			symlinkSteamUser 1
		elif [ "$REDIRSTEAMUSER" == "restore-backup" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Calling restoreSteamUser to migrate '$STUS', as REDIRSTEAMUSER is '$REDIRSTEAMUSER'"
			restoreSteamUser
		else
			writelog "INFO" "${FUNCNAME[0]} - Leaving '$STUS' directory untouched, as REDIRSTEAMUSER is '$REDIRSTEAMUSER'"
		fi
	}
	
	function SetCompatdataSymlink {
		DIR="$1"
		SYM="$2"
		writelog "INFO" "${FUNCNAME[0]} - Using '$DIR' as new $CODA dir and '$SYM' as symlink pointing to it"

		if [ ! -f "${DIR}/version" ]; then
			writelog "INFO" "${FUNCNAME[0]} - New $CODA '$DIR' does not exist yet"
			if [ -d "${STEAM_COMPAT_DATA_PATH}_SAC" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Moving found backed autocloud $CODA '${STEAM_COMPAT_DATA_PATH}_SAC' to '$DIR'"
				mkProjDir "${DIR%/*}"
				mv "${STEAM_COMPAT_DATA_PATH}_SAC" "$DIR"
			else
				writelog "INFO" "${FUNCNAME[0]} - Creating new $CODA dir '$DIR'"
				mkProjDir "$DIR"
			fi
		else
			writelog "INFO" "${FUNCNAME[0]} - Using existing $CODA '$DIR'"
			if [ -d "${STEAM_COMPAT_DATA_PATH}_SAC" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Found backed autocloud $CODA '${STEAM_COMPAT_DATA_PATH}_SAC'"
			fi
		fi
		
		if [ -L "$SYM" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Removing old symlink '$SYM'"
			rm "$SYM" 2>/dev/null #remove old symlink
		elif [ -d "$SYM" ]; then
			BACKSCDP="${SYM}-BAK$((100 + RANDOM % 100))"
			writelog "WARN" "${FUNCNAME[0]} - '$SYM' does still exist as directory - renaming to '$BACKSCDP'"
			mv "$SYM" "$BACKSCDP"		
		fi
		
		writelog "INFO" "${FUNCNAME[0]} - Creating symlink via 'ln -s \"$DIR\" \"$SYM\"'"
		ln -s "$DIR" "$SYM"
		notiShow "$(strFix "$NOTY_GLOBALTWEAK" "$DIR")"

		SPVF="$STEAM_COMPAT_DATA_PATH/${SHOSTL}-version"
		if [ ! -f "$SPVF" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Creating '$SPVF' with version '$DESTPROT'"
			echo "$DESTPROT" > "$SPVF"
		else
			SCDPSPV="$(cat "$SPVF")"
			if [ "$SCDPSPV" == "$DESTPROT" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Found '$SPVF' with version '$DESTPROT'"
			else
				writelog "INFO" "${FUNCNAME[0]} - Proton version '$SCDPSPV' in '$SPVF' doesn't match expected version '$DESTPROT' DEBUG"
			fi
		fi

		if [ "$REDIRCOMPDATA" == "global-proton" ]; then
			UBAID="${STEAM_COMPAT_DATA_PATH}/used_by-$AID"
			if [ ! -f "$UBAID" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Creating '$UBAID'" # and trying to trigger Steam First Time Setup"
				touch "$UBAID"
#				reCreateCompatdata "ccd" "$AID" - probably requires a rewrite if possible at all
			fi
		fi
		
		checkCompatdataSteamUser
	}
	
	function checkCompatdataSymlink {
		if [ -L "$STEAM_COMPAT_DATA_PATH" ] || [ -d "$STEAM_COMPAT_DATA_PATH" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Using $CODA '$REDIRCOMPDATA' mode"

			PVF="$STEAM_COMPAT_DATA_PATH/version"
			SCDPPV="$(cat "$PVF")"
			
			SPVF="$STEAM_COMPAT_DATA_PATH/${PROGNAME,,}-version"
			SCDPSPV="$(cat "$SPVF")"
			
			if [ -f "$SPVF" ]; then
				if [ "$SCDPSPV" == "$DESTPROT" ]; then
					writelog "INFO" "${FUNCNAME[0]} - Proton version '$SCDPSPV' in '$SPVF' matches expected version '$DESTPROT' (allowing minor version mismatch)"
					CDPVOK=1
				else
					writelog "INFO" "${FUNCNAME[0]} - Proton version '$SCDPSPV' in '$SPVF' is not the expected version '$DESTPROT'"
					CDPVOK=0
				fi
			else
				if [ ! -f "$PVF" ] && [ -d "$STEAM_COMPAT_DATA_PATH" ]; then
					writelog "INFO" "${FUNCNAME[0]} - STEAM_COMPAT_DATA_PATH doesn't have a proton version file '$PVF'"
					writelog "INFO" "${FUNCNAME[0]} - Steam probably just re-created the $CODA by creating the steam_autocloud.vdf"
					writelog "INFO" "${FUNCNAME[0]} - Moving the $CODA out of the way"
					mv "$STEAM_COMPAT_DATA_PATH" "${STEAM_COMPAT_DATA_PATH}_SAC"
					SCDPPV=0
				elif [ ! -f "$PVF" ] && [ -L "$STEAM_COMPAT_DATA_PATH" ]; then
					writelog "INFO" "${FUNCNAME[0]} - STEAM_COMPAT_DATA_PATH is a symlink - it should have a '$PVF' though - $(ls -la "$PVF") DEBUG"
					SCDPPV=0
				fi
				
				if [ "$SCDPPV" == "$DESTPROT" ] || [ "$SCDPPV" == "${ORGUSEPROTON//proton-}" ]; then
					writelog "INFO" "${FUNCNAME[0]} - Proton in $CODA '$STEAM_COMPAT_DATA_PATH' matches the expected version '$DESTPROT' (allowing minor version mismatch)"
					CDPVOK=1
				else
					writelog "INFO" "${FUNCNAME[0]} - Proton in $CODA '$STEAM_COMPAT_DATA_PATH' has not the expected version '$DESTPROT' but '$SCDPPV'"
					CDPVOK=0
				fi
			fi
		fi

		if [ -L "$STEAM_COMPAT_DATA_PATH" ]; then
			writelog "INFO" "${FUNCNAME[0]} - '$STEAM_COMPAT_DATA_PATH' is already a symbolic link - comparing versions"

			if [ "$(readlink "$STEAM_COMPAT_DATA_PATH")" == "$DESTCOMPDATA" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Symlink '$STEAM_COMPAT_DATA_PATH' points correctly to the expected directory '$DESTCOMPDATA'"
				CDSYMOK=1
			else
				writelog "WARN" "${FUNCNAME[0]} - Symlink '$STEAM_COMPAT_DATA_PATH' does not point correctly to the expected directory '$DESTCOMPDATA', but instead to '$(readlink "$STEAM_COMPAT_DATA_PATH")'"
				CDSYMOK=0
			fi

			if [ "$CDSYMOK" -eq 1 ] && [ "$CDPVOK" -eq 1 ]; then
				writelog "INFO" "${FUNCNAME[0]} - Both $CODA symlink '$STEAM_COMPAT_DATA_PATH' and Proton version are correct - nothing to do here"
			elif [ "$CDSYMOK" -eq 1 ] && [ "$CDPVOK" -eq 0 ]; then
				writelog "INFO" "${FUNCNAME[0]} - $CODA symlink '$STEAM_COMPAT_DATA_PATH' is correct, but Proton version is not - this is unusual but continuing anyway"
			elif [ "$CDSYMOK" -eq 0 ] && [ "$CDPVOK" -eq 1 ]; then
				writelog "INFO" "${FUNCNAME[0]} - $CODA symlink '$STEAM_COMPAT_DATA_PATH' is not the expected one, but Proton version matches - assuming manual configuration from the user and using it"
			elif [ "$CDSYMOK" -eq 0 ] && [ "$CDPVOK" -eq 0 ]; then
				writelog "INFO" "${FUNCNAME[0]} - $CODA symlink '$STEAM_COMPAT_DATA_PATH' is not the expected one and Proton version doesn't match as well, assuming the Proton version was changed - redirecting $CODA to '$DESTCOMPDATA'"
				SetCompatdataSymlink "$DESTCOMPDATA" "$STEAM_COMPAT_DATA_PATH"
			fi				
		elif [ -d "$STEAM_COMPAT_DATA_PATH" ]; then		
			writelog "INFO" "${FUNCNAME[0]} - '$STEAM_COMPAT_DATA_PATH' is the original directory"
			if [ -d "$DESTCOMPDATA" ]; then # probably not worth to check the proton version in $DESTCOMPDATA here as well(?)
				BACKSCDP="${STEAM_COMPAT_DATA_PATH}-BAK$((100 + RANDOM % 100))"
				writelog "INFO" "${FUNCNAME[0]} - '$DESTCOMPDATA' does already exist - moving '$STEAM_COMPAT_DATA_PATH' to '$BACKSCDP' and setting symlink"
				mv "$STEAM_COMPAT_DATA_PATH" "$BACKSCDP"
				SetCompatdataSymlink "$DESTCOMPDATA" "$STEAM_COMPAT_DATA_PATH"
			else
				if [ "$CDPVOK" -eq 1 ]; then
					writelog "INFO" "${FUNCNAME[0]} - '$DESTCOMPDATA' does not yet exist, moving '$STEAM_COMPAT_DATA_PATH' as the Proton version is correct and creating symlink"
					mv "$STEAM_COMPAT_DATA_PATH" "$DESTCOMPDATA"
					SetCompatdataSymlink "$DESTCOMPDATA" "$STEAM_COMPAT_DATA_PATH"
				else
					writelog "INFO" "${FUNCNAME[0]} - '$DESTCOMPDATA' does not yet exist, creating a new one, because '$STEAM_COMPAT_DATA_PATH' uses an incorrect Proton version"
					BACKSCDP="${STEAM_COMPAT_DATA_PATH}-BAK$((100 + RANDOM % 100))"
					writelog "INFO" "${FUNCNAME[0]} - Renaming '$STEAM_COMPAT_DATA_PATH' to '$BACKSCDP' and setting symlink"
					mv "$STEAM_COMPAT_DATA_PATH" "$BACKSCDP"
					SetCompatdataSymlink "$DESTCOMPDATA" "$STEAM_COMPAT_DATA_PATH"
				fi
			fi
		else
			writelog "INFO" "${FUNCNAME[0]} - '$STEAM_COMPAT_DATA_PATH' is neither a directory nor a symbolic link - creating it"
			SetCompatdataSymlink "$DESTCOMPDATA" "$STEAM_COMPAT_DATA_PATH"
		fi		
	}

	function fixDestCompat {
		DESTCOMPDATA2="${DESTCOMPDATA//--/-}"
		if [ -d "$DESTCOMPDATA" ] && [ ! -d "$DESTCOMPDATA2" ] && [ "$DESTCOMPDATA" != "$DESTCOMPDATA2" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Renaming old '${DESTCOMPDATA##*/}' to '${DESTCOMPDATA2##*/}'"
			mv "$DESTCOMPDATA" "$DESTCOMPDATA2"
			DESTCOMPDATA="$DESTCOMPDATA2"
		fi		
	}

	if [ -n "$STEAM_COMPAT_DATA_PATH" ]; then # should be enough
		VERSFIX="$(grep "${USEPROTON%-*}" "$PROTONCSV" | cut -d ';' -f1 | sort -nr | head -n1)"
		if [ -n "$VERSFIX" ]; then
			DESTPROT1="${VERSFIX//proton-}"
			writelog "INFO" "${FUNCNAME[0]} - Using Proton version with minor version fix '$DESTPROT1' for $CODA directory name"
		else
			DESTPROT1="${USEPROTON//proton-}"
			writelog "INFO" "${FUNCNAME[0]} - Using Proton version '$DESTPROT1' for '$CODA' directory name"
		fi

		DESTPROT="${DESTPROT1//Proton}"
		# above might have to be expanded later, depending on proton names
		
		if [ "$REDIRCOMPDATA" == "single-proton" ]; then
			DESTCOMPDATA="${STEAM_COMPAT_DATA_PATH//${STEAM_COMPAT_DATA_PATH##*/}/${PROGNAME,,}\/${STEAM_COMPAT_DATA_PATH##*/}-proton-${DESTPROT}}"
			fixDestCompat
			checkCompatdataSymlink
		elif [ "$REDIRCOMPDATA" == "global-proton" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Using global 'STEAM_COMPAT_DATA_PATH'"
			DESTCOMPDATA="$STLPROTCOMPDATDIR/${CODA}-proton-${DESTPROT}"
			fixDestCompat
			checkCompatdataSymlink
		else
			writelog "INFO" "${FUNCNAME[0]} - Using regular $CODA '$STEAM_COMPAT_DATA_PATH'"
			if [ -L "$STEAM_COMPAT_DATA_PATH" ]; then
				if [ -f "${STEAM_COMPAT_DATA_PATH}/used_by-$AID" ]; then
					rm "${STEAM_COMPAT_DATA_PATH}/used_by-$AID" 2>/dev/null
					writelog "INFO" "${FUNCNAME[0]} - '$STEAM_COMPAT_DATA_PATH' is a symlink. Removing it, as REDIRCOMPDATA is $REDIRCOMPDATA"
					rm "$STEAM_COMPAT_DATA_PATH"
					mkProjDir "$STEAM_COMPAT_DATA_PATH"
				else
					# See STL issue #692 for background on the above removing logic removing valid user prefixes
					writelog "INFO" "${FUNCNAME[0]} - '$STEAM_COMPAT_DATA_PATH' is a symlink, but we don't have a 'used_by-$AID' file in this game's prefix -- Assuming this is a user-created symlink and not removing"
					writelog "INFO" "${FUNCNAME[0]} - User-created symlinks are valid on Steam Deck to work around some Steam Client bugs"
				fi
			fi
		fi
	fi
}

function launchIGCS {
	IGCSPROCESS="$(grep "^Process=" "$IGCSINI" | cut -d '=' -f2)"
	writelog "INFO" "${FUNCNAME[0]} - Injecting '$IGCSDLL' into exe '${IGCSPROCESS%.*}' using '$IGCS'"
	writelog "INFO" "${FUNCNAME[0]} - IGCSDST '$IGCSDST'"
	rm "$IGCSINITLOCK" 2>/dev/null
	extProtonRun "R" "$IGCSDST"
}

function injectIGCS {
	writelog "INFO" "${FUNCNAME[0]} - Starting '$IGCS'"
	waitForGamePid
	writelog "INFO" "${FUNCNAME[0]} - Game is running, starting '$IGCS' in '$IGCSWAIT' seconds"
	touch "$IGCSINITLOCK"
	sleep "$IGCSWAIT"
	launchIGCS
}

function postIGCS {
	COUNTER=0

	while [ ! -f "$IGCSINITLOCK" ]; do
		writelog "INFO" "${FUNCNAME[0]} - Waiting for $IGCSINITLOCK to appear"
		if [ -f "$CLOSETMP" ] || [[ "$COUNTER" -ge "$IGCSWAIT" ]]; then
			break
		fi
		COUNTER=$((COUNTER+1))
		sleep 1
	done
	
	writelog "INFO" "${FUNCNAME[0]} - Waited '$COUNTER/$IGCSWAIT' seconds"

	IGCSWAITLEFT=$((IGCSWAIT - COUNTER + 2))
	writelog "INFO" "${FUNCNAME[0]} - Waiting (max $IGCSWAITLEFT more seconds) for $IGCS to initialize"
	COUNTER=0
	
	while [ -f "$IGCSINITLOCK" ]; do
		if [ -f "$CLOSETMP" ] || [[ "$COUNTER" -ge "$IGCSWAITLEFT" ]]; then
			break
		fi
		COUNTER=$((COUNTER+1))
		sleep 1
	done

	COUNTER=0
	if [ -f "$IGCSINITLOCK" ]; then
		writelog "SKIP" "${FUNCNAME[0]} - Lock file $IGCSINITLOCK still exists - giving up"
	else
		COUNTER=0
		WAITWIN=3
		writelog "INFO" "${FUNCNAME[0]} - $IGCS just started, now waiting a bit for its window"

		IGCSWIN="$("$XDO" search --name "$IGCS")"
		# use if $IGCS alone also matches games window:
		# IGCSWIN="$("$XDO" search --name "$SA.*.$IGCS")" # =+ steamapps
		while ! [ "$IGCSWIN" -eq "$IGCSWIN" ] 2>/dev/null; do
			if [[ "$COUNTER" -ge "$WAITWIN" ]]; then
				break
			fi
			COUNTER=$((COUNTER+1))
			sleep 1
		done

		writelog "INFO" "${FUNCNAME[0]} - Closing '$IGCS' window '$IGCSWIN'"
		"$XDO" windowactivate --sync "$IGCSWIN"	key "KP_Enter"

		writelog "INFO" "${FUNCNAME[0]} - And minimize false-positive UUU warn window"
		IGCSPROCESS="$(grep "^Process=" "$IGCSINI" | cut -d '=' -f2)"
		"$XDO" windowminimize "$("$XDO" search --name "${IGCSPROCESS%.*}")"

		if [ -f "$GWXTEMP" ]; then
			WIFO="$(cat "$GWXTEMP")"
			writelog "INFO" "${FUNCNAME[0]} - Setting focus on window '$WIFO'"
			"$XDO" windowactivate "$WIFO"
		else
			writelog "INFO" "${FUNCNAME[0]} - No '$GWXTEMP' found"
		fi
	fi
}
	
function selectIGCSdll {
	if [ -d "$EFD" ]; then
		fixShowGnAid
		export CURWIKI="$PPW/$IGCS"
		TITLE="${PROGNAME}-Select-IGCS-dll"
		pollWinRes "$TITLE"
		setShowPic
		
		PICKIGCSDLL="$("$YAD" --f1-action="$F1ACTION" --image "$SHOWPIC" --image-on-top --window-icon="$STLICON" --form --center --on-top "$WINDECO" \
		--separator="" --title="$TITLE" \
		--text="$(spanFont "$SGNAID - $GUI_SELECTIGCSDLL" "H")" \
		--field=" ":LBL " " \
		--field="$GUI_SELECTDLL":FL "${EFD}" --file-filter="$GUI_DLLFILES (*.dll)| *.dll" "$GEOM")"
		if [ -f "$PICKIGCSDLL" ]; then
			IGCSDLL="${PICKIGCSDLL##*/}"
			if [ ! -f "$EFD/$IGCSDLL" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Copying selected dll '$PICKIGCSDLL' to '$EFD'"
				cp "$PICKIGCSDLL" "$EFD"
			fi
			IGCSINI="$EFD/${IGCS}.ini"
			writelog "INFO" "${FUNCNAME[0]} - Inserting '$IGCSDLL' into '$IGCSINI'"
			sed "/^Dll=/d" -i "$IGCSINI"
			echo "Dll=$IGCSDLL" >> "$IGCSINI"
		else
			writelog "SKIP" "${FUNCNAME[0]} - No dll selected - skipping"
		fi
	fi
}

function createUUUPatchCommand {
	echo "$XDO windowactivate \"GAMEWINXID\" && sleep 1 && $XDO key \"grave\" && $XDO type \"exec $UUUPATCH\" && $XDO key \"KP_Enter\"" > "$UUUPATCHCOMMAND"
	chmod +x "$UUUPATCHCOMMAND"
}

function getGameWXID {
	if [ -n "$VRPGWINXIS" ]; then
		writelog "INFO" "${FUNCNAME[0]} - Using found variable VRPGWINXIS '$VRPGWINXIS' as GAMEWINXID"
		GAMEWINXID="$VRPGWINXIS"
	fi

	if [ -n "$GAMEWINXID" ]; then
		writelog "INFO" "${FUNCNAME[0]} - Already have the windowid '$GAMEWINXID'"
	else
		GAMEWINPID="$(getGameWindowPID)"
		writelog "INFO" "${FUNCNAME[0]} - Determining GAMEWINXID via GAMEWINPID '$GAMEWINPID'"
		GAMEWINXID="$(getGameWinXIDFromPid "$GAMEWINPID")"
 	fi

	if [ -n "$GAMEWINXID" ]; then
		export VRPGWINXIS="$GAMEWINXID"
	fi
}

function injectUUUPatch {
	if [ "$(find "$EFD" -name "$UUUPATCH" | wc -l)" -ge 1 ]; then
		writelog "INFO" "${FUNCNAME[0]} - starting UUU patch command auto executing '$UUUPATCH'"
		waitForGamePid
		getGameWXID

		if [ -n "$GAMEWINXID" ]; then
			echo "$GAMEWINXID" > "$GWXTEMP"
			
			sed "s:GAMEWINXID:$GAMEWINXID:g" -i "$UUUPATCHCOMMAND"
			writelog "INFO" "${FUNCNAME[0]} - starting patch command auto executing '$UUUPATCH'"
			
			if [ "$UUUPATCHWAIT" -ge 1 ]; then
				writelog "INFO" "${FUNCNAME[0]} - Game is running, starting UUU patch command '$UUUPATCHCOMMAND' in '$UUUPATCHWAIT' seconds"
				if [ ! -f "$TRAYCUSC" ] || grep -q "$UUUPATCH" "$TRAYCUSC"; then
					cp "$UUUPATCHCOMMAND" "$TRAYCUSC"
				fi
				sleep "$UUUPATCHWAIT"
				"$UUUPATCHCOMMAND"
			else
				writelog "INFO" "${FUNCNAME[0]} - UUUPATCHWAIT is '$UUUPATCHWAIT', so placing the UUU patch command behind the TrayIcon command '$TRAY_LCS' for manual execution"
				cp "$UUUPATCHCOMMAND" "$TRAYCUSC"
			fi
		else
			writelog "SKIP" "${FUNCNAME[0]} - game window id could not be found - can't start the UUU patch command"
		fi
	else
		writelog "SKIP" "${FUNCNAME[0]} - UE4 console script '$UUUPATCH' not found in game directory '$EFD'"
	fi
}

function checkUUUPatchLaunch {
	if [ "$UUUSEPATCH" -eq 1 ] || [ "$UUUSEVR" -eq 1 ]; then
		createUUUPatchCommand	
		injectUUUPatch &
	fi
}

function prepareUEVRpatch {
	if [ "$UUUSEVR" -eq 1 ]; then
		UUUPATCHFILE="$1"

		if [ ! -f "$UUUPATCHFILE" ]; then
			if [ -f "$GLOBALMISCDIR/${UUUPATCH}-${AID}" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Copying game specific '$GLOBALMISCDIR/${UUUPATCH}-${AID}' to '$UUUPATCHFILE'"
				cp "$GLOBALMISCDIR/$UUUPATCH-${AID}" "$UUUPATCHFILE"
			elif [ -f "$GLOBALMISCDIR/${UUUPATCH}" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Copying generic '$GLOBALMISCDIR/${UUUPATCH}' to '$UUUPATCHFILE'"
				cp "$GLOBALMISCDIR/$UUUPATCH" "$UUUPATCHFILE"
			else
				writelog "WARN" "${FUNCNAME[0]} - No source '$UUUPATCH' file found in '$GLOBALMISCDIR'"
			fi
		else
			writelog "INFO" "${FUNCNAME[0]} - '$UUUPATCHFILE' already available"
		fi
	fi	
}

function checkIGCSInjector {

	if [ "$UUUSEPATCH" -eq 1 ] || [ "$UUUSEVR" -eq 1 ]; then
		writelog "INFO" "${FUNCNAME[0]} - Enabling '$UUU' with '$IGCS' as UUU patch mode is enabled"
		UUUSEIGCS=1
	fi

	if [ "$UUUSEIGCS" -eq 1 ]; then
		writelog "INFO" "${FUNCNAME[0]} - Using '$UUU' with '$IGCS' is enabled"
		USEIGCS=1
	fi
	
	if [ "$USEIGCS" -eq 1 ]; then
		IGCSEXE="${IGCS}.exe"
		IGCSDST="$EFD/$IGCSEXE"
		if [ ! -f "$IGCSDST" ]; then
			writelog "INFO" "${FUNCNAME[0]} - '$IGCSDST' not found"
			IGCSDL="$STLDLDIR/igcs/"
			IGCSSRC="$IGCSDL/$IGCSEXE"
			mkProjDir "$IGCSDL"

			if [ ! -f "$IGCSSRC" ]; then
				IGCSDST="$IGCSDL/${IGCSZIP##*/}"
				if [ ! -f "$IGCSDST" ]; then
					 "$IGCSZIP" "$IGCSDST" "X" "'$IGCSDST' not found - downloading automatically from '$IGCSZIP'"
				fi
				"$UNZIP" "$IGCSDST" -d "$IGCSDL"
			fi
			
			if [ -f "$IGCSSRC" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Copying '$IGCSSRC' to '$IGCSDST'"
				cp "$IGCSSRC" "$IGCSDST"
			fi
		else
			writelog "INFO" "${FUNCNAME[0]} - '$IGCSDST' found"
		fi
		
		if [ -f "$IGCSDST" ]; then
			IGCSINI="$EFD/${IGCS}.ini"
			WSE="$(find "$EFD" -name "*-Win64-Shipping.exe" | head -n1)"

			if [ -n "$WSE" ]; then
				prepareUEVRpatch "${WSE%/*}/../$UUUPATCH"
			fi
			
			if [ ! -f "$IGCSINI" ]; then
				writelog "INFO" "${FUNCNAME[0]} - '$IGCSINI' not found - creating it"
				echo "[InjectionData]" > "$IGCSINI"
				echo "Process=$GAMEEXE" >> "$IGCSINI"
				if [ "$UUUSEIGCS" -eq 1 ]; then
					writelog "INFO" "${FUNCNAME[0]} - WSE is '$WSE'"
					
					if [ -n "$WSE" ]; then
						echo "Process=${WSE##*/}" >> "$IGCSINI"
					else
						echo "Process=$GAMEEXE" >> "$IGCSINI"
					fi
					writelog "INFO" "${FUNCNAME[0]} - Using '${UUU}.dll' as dll in '$IGCSINI'"
					echo "Dll=${UUU}.dll" >> "$IGCSINI"
				else
					echo "Process=$GAMEEXE" >> "$IGCSINI"
				fi
			fi
			
			IGCSDLL="$(grep "^Dll=" "$IGCSINI" | cut -d '=' -f2)"
			if [ "$UUUSEIGCS" -eq 1 ]; then
				if [ "$IGCSDLL" != "${UUU}.dll" ]; then
					writelog "INFO" "${FUNCNAME[0]} - Updating dll in '$IGCSINI' to '${UUU}.dll' because 'UUUSEIGCS' is enabled"
					sed "/^Dll=/d" -i "$IGCSINI"
					echo "Dll=${UUU}.dll" >> "$IGCSINI"
				fi
			fi

			IGCSDLL="$(grep "^Dll=" "$IGCSINI" | cut -d '=' -f2)"
			if [ ! -f "$EFD/$IGCSDLL" ]; then
				if [ "$UUUSEIGCS" -eq 1 ]; then
					UUUDL="$STLDLDIR/uuu"
					UUUSRC="$UUUDL/$IGCSDLL"
					mkProjDir "$UUUDL"	
					writelog "INFO" "${FUNCNAME[0]} - 'UUUSEIGCS' is enabled, but '$EFD/$IGCSDLL' is not available - checking if '$UUUSRC' is available"
					if [ ! -f "$UUUSRC" ]; then
						if [ -x "$(command -v "$XDGO" 2>/dev/null)" ]; then
							writelog "WARN" "${FUNCNAME[0]} - '$UUUSRC' was not found - opening Info requester, because it needs to be downloaded manually from '$UUUURL' and extracted to '$UUUDL'"
							export CURWIKI="$PPW/$UUU"
							TITLE="${PROGNAME}-$UUU-Info"
							pollWinRes "$TITLE"
							setShowPic

							"$YAD" --f1-action="$F1ACTION" --image "$SHOWPIC" --image-on-top --window-icon="$STLICON" --form --center --on-top "$WINDECO" \
							--title="$TITLE" --text="$(spanFont "$(strFix "$GUI_UUUINFO1" "$UUU")" "H")" \
							--field="Url: :RW" "$UUUURL" \
							--field="$GUI_UUUINFO2:LBL" " " \
							--field="$UUUDL":FBTN "$XDGO $UUUDL" "$GEOM"
						else
							writelog "SKIP" "${FUNCNAME[0]} - '$UUUSRC' was not found, but can't open the Info requester, because '$XDGO' was not found"
						fi
					fi
					
					if [ -f "$UUUSRC" ]; then
						writelog "INFO" "${FUNCNAME[0]} - Copying '$UUUSRC' to '$EFD'"
						cp "$UUUSRC" "$EFD"
					else
						writelog "SKIP" "${FUNCNAME[0]} -'$UUUSRC' could not be found - skipping"
					fi
				else
					writelog "INFO" "${FUNCNAME[0]} - No valid dll found in '$IGCSINI' - Choose one"
					selectIGCSdll
				fi
			fi

			IGCSDLL="$(grep "^Dll=" "$IGCSINI" | cut -d '=' -f2)"
			if [ -f "$EFD/$IGCSDLL" ]; then
				injectIGCS &
				postIGCS &
			else
				writelog "SKIP" "${FUNCNAME[0]} - Still no valid dll found in '$IGCSINI' - giving up"
			fi
		else
			writelog "SKIP" "${FUNCNAME[0]} - '$IGCSDST' not found and could not be created - skipping '$IGCS'"
		fi
	fi
}

function injectCustomProg {
	writelog "INFO" "${FUNCNAME[0]} - 'Injecting' custom command - i.e. starting delayed"
	waitForGamePid
	writelog "INFO" "${FUNCNAME[0]} - Game is running, starting custom command in '$INJECTWAIT' seconds"
	sleep "$INJECTWAIT"
	launchCustomProg
}

function delayGameForCustomLaunch {
	if [ "$USECUSTOMCMD" -eq 1 ] && [ "$FORK_CUSTOMCMD" -eq 1 ] && [ "$ONLY_CUSTOMCMD" -eq 0 ] && [ "$WAITFORCUSTOMCMD" -ge 1 ]; then
		COUNTER=0
		MAXTRY="$WAITFORCUSTOMCMD"

		function CUCOPID {
			"$PGREP" -a "" | grep "${CUSTOMCMD##*/}" | grep "Z:" | grep "\.exe" | grep -v "CrashHandler" | cut -d ' ' -f1 | tail -n1
		}

		function waitforCustomPid {
				while [ -z "$(CUCOPID)" ]; do 
					if [[ "$COUNTER" -ge "$MAXTRY" ]]; then
						writelog "SKIP" "${FUNCNAME[0]} - Giving up waiting for custom program pid"
						break
					else
						writelog "WAIT" "${FUNCNAME[0]} - Waiting for custom program process $(CUCOPID)"
						COUNTER=$((COUNTER+1))
						sleep 1
					fi
				done
				
				if [ -n "$(CUCOPID)" ]; then
					writelog "INFO" "${FUNCNAME[0]} - Custom program process found at $(CUCOPID) after $COUNTER seconds"
				fi
		}

		waitforCustomPid

		if [ "$WAITFORCUSTOMCMD" -gt 1 ]; then
			RESTWAIT=$((WAITFORCUSTOMCMD - COUNTER))
			if [ "$RESTWAIT" -gt 0 ]; then
				writelog "INFO" "${FUNCNAME[0]} - Waiting $RESTWAIT more seconds before proceeding with loading the game"
				sleep "$RESTWAIT"
			fi
		fi
	else
		writelog "SKIP" "${FUNCNAME[0]} - Nothing to do"
	fi
}

function checkCustomLaunch {
	if [ "$ONLYWICO" -eq 1 ]; then
		# only start $WICO 
		writelog "INFO" "${FUNCNAME[0]} - 'ONLYWICO' is enabled - starting only $WICO"
		launchCustomProg "ONLYWICO"
	else
		# start a custom program:
		if [ -n "$USECUSTOMCMD" ] ; then
			if [ "$USECUSTOMCMD" -eq 1 ] ; then
				writelog "INFO" "${FUNCNAME[0]} - USECUSTOMCMD is set to '$USECUSTOMCMD' - trying to start custom program '$CUSTOMCMD'"
			
				if [ "$INJECT_CUSTOMCMD" -eq 1 ]; then
					injectCustomProg &
				else
					# fork in background and continue
					if [ "$ONLY_CUSTOMCMD" -eq 1 ]; then
						SECONDS=0
					fi

					if [ "$FORK_CUSTOMCMD" -eq 1 ]; then
						writelog "INFO" "${FUNCNAME[0]} - FORK_CUSTOMCMD is set to 1 - forking the custom program in background and continue"
						launchCustomProg
					# or wait
					else
						writelog "INFO" "${FUNCNAME[0]} - FORK_CUSTOMCMD is set to 0 - starting the custom program regularly"
						launchCustomProg
					fi

					if [ "$ONLY_CUSTOMCMD" -eq 1 ]; then
						writelog "INFO" "${FUNCNAME[0]} - ONLY_CUSTOMCMD is set to 1 means only custom program '$CUSTOMCMD' is supposed to start - exiting here"
						duration=$SECONDS
						logPlayTime "$duration"
						writelog "INFO" "${FUNCNAME[0]} - ## CUSTOMCMD STOPPED after '$duration' seconds playtime"
						closeSTL " ######### STOP EARLY $PROGNAME $PROGVERS #########"
						exit
					fi
				fi
			else
				if [ -n "$CUSTOMCMD" ] && [[ ! "$CUSTOMCMD" =~ ${DUMMYBIN}$ ]]; then
					writelog "SKIP" "${FUNCNAME[0]} - USECUSTOMCMD is '$USECUSTOMCMD' therefore skipping the custom program '$CUSTOMCMD'"
				fi
			fi
		fi
	fi
}

function setFWSArch {
	if [ -z "$FWSARCH" ]; then
		FWSARCH="64"
		if [ -n "$GP" ] && [ -f "$GP" ]; then
			if [ "$(getArch "$GP")" == "32" ]; then
				FWSARCH="32"
			fi
		fi
	fi
}

function dlFWS {
	setFWSArch
	mkProjDir "$FWSDLDIR/$FWSARCH"
	DSTFILE="${FWS,,}_x64.zip"

	if [ "$FWSARCH" == "32" ]; then
		DSTFILE="${DSTFILE//_x64}"
		SPAT="86"
	else
		SPAT="64"
	fi
	DLCHK="md5sum"

	INCHK="$("$WGET" -q "${FWSURL%%/fws*}" -O - 2> >(grep -v "SSL_INIT") | grep -A1 "x${SPAT} ZIP Package" | grep MD5 | grep -oP '> \K[^<]+')"
	DLDST="$FWSDLDIR/$FWSARCH/$DSTFILE"
	
	if [ ! -f "$DLDST" ]; then
		notiShow "$(strFix "$NOTY_DLCUSTOMPROTON" "$DSTFILE")"
		dlCheck "$FWSURL/$DSTFILE" "$DLDST" "$DLCHK" "Downloading '$DSTFILE'" "$INCHK"
	fi

	FWSEXE="$FWSDLDIR/$FWSARCH/${FWS}.exe"
	if [ ! -f "$FWSEXE" ]; then
		if [ -f "$DLDST" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Extracting $DSTFILE in '$FWSDLDIR/$FWSARCH'"
			"$UNZIP" -q "$DLDST" -d "$FWSDLDIR/$FWSARCH"
		else
			writelog "SKIP" "${FUNCNAME[0]} - Downloading '$FWS' failed! Disabling '$FWS'"
			USEFWS=0
		fi
	fi

	if [ ! -f "$FWSEXE" ]; then
		writelog "SKIP" "${FUNCNAME[0]} - Extracting '$FWS' failed! Disabling '$FWS'"
		USEFWS=0
	fi
}

function checkFWS {
	if [ "$USEFWS" -eq 1 ]; then
		dlFWS
		if [ "$USEFWS" -eq 1 ]; then
			writelog "INFO" "${FUNCNAME[0]} - 'USEFWS' is enabled - starting '$FWS' exe '$FWSEXE'"
			setFWSArch
			IPAK="vcrun2010-x64"
			if [ "$FWSARCH" == "32" ]; then
				IPAK="${IPAK//x64/x86}"
			fi
			writelog "INFO" "${FUNCNAME[0]} - Installing '$IPAK' into '$GPFX' using '$RUNWINE'"
			installSteWoShPak "$IPAK" "$GPFX" "$RUNWINE"
			writelog "INFO" "${FUNCNAME[0]} - Starting '$FWSEXE' forked into the background"
			restoreOrgVars
			(sleep 2; "$RUNPROTON" run "$FWSEXE") &
			emptyVars "O" "X"
		fi
	fi
}

function togWindows {
	function windowminimize {
		rm "$STLMINWIN" 2>/dev/null
		while read -r WN; do
			WINNAME="${WN##*[[:blank:]]}"
			if "$XPROP" -id "$WINNAME" | grep "_NET_WM_ACTION_MINIMIZE" -q ; then
				if "$XPROP" -id "$WINNAME" | grep "_NET_WM_STATE_HIDDEN" -q ; then
					writelog "SKIP" "${FUNCNAME[1]} ${FUNCNAME[0]} - Skipping minimized '$WINNAME'"
				else
					writelog "INFO" "${FUNCNAME[1]} ${FUNCNAME[0]} - Minimizing '$WINNAME'"
					echo "$WINNAME" >> "$STLMINWIN"
					"$XDO" "${FUNCNAME[0]}" "$WINNAME"
				fi
			fi
		done <<< "$("$XPROP" -root | grep "_NET_CLIENT_LIST(WINDOW)" | cut -d '#' -f2 | tr ',' '\n')"
	}

	function windowraise {
		if [ ! -f "$STLMINWIN" ]; then
			writelog "SKIP" "${FUNCNAME[0]} - Skipping, because no minimized window file STLMINWIN found"
		else
			while read -r WN; do
				WINNAME="${WN##*[[:blank:]]}"
				writelog "INFO" "${FUNCNAME[0]} - Raising '$WINNAME'"
				"$XDO" "${FUNCNAME[0]}" "$WINNAME"
				COUNTER=0
				MAXTRY=3
				while grep -q "_NET_WM_STATE_HIDDEN" -q <<< "$("$XPROP" -id "$WINNAME")"; do
					if [[ "$COUNTER" -ge "$MAXTRY" ]]; then
						echo "$WINNAME" >> "${STLMINWIN}_lazy"
						break
					else
						writelog "INFO" "${FUNCNAME[0]} - '$WINNAME' minimized after $COUNTER tries - raising again"
						"$XDO" "${FUNCNAME[0]}" "$WINNAME"
						COUNTER=$((COUNTER+1))
					fi
				done

			done < "$STLMINWIN"

			if [ -f "${STLMINWIN}_lazy" ]; then
				while read -r WN; do
					WINNAME="${WN##*[[:blank:]]}"
					writelog "INFO" "${FUNCNAME[0]} - Raising lazy '$WINNAME'"
					"$XDO" "${FUNCNAME[0]}" "$WINNAME"
				done < "${STLMINWIN}_lazy"
			fi

			rm "$STLMINWIN" "${STLMINWIN}_lazy" 2>/dev/null
		fi
	}

	if [ "$TOGGLEWINDOWS" -eq 1 ]; then
		writelog "INFO" "${FUNCNAME[0]} - Setting windows to $1"
		"$1"
	fi
}

function installWinetricksPaks {
	WTPAKS="$1"
	WTWINE="$2"
	WTRUN="$3"

	WTSHMLOG="$STLSHM/WINETRICKS.log"
	
	if [ "$WTRUN" == "wineVortexRun" ]; then
		WTPFX="$VORTEXPFX"
	else
		WTPFX="$GPFX"
	fi

	if [ "$USEWINE" -eq 1 ]; then
		 WTPFX="$GWFX"
	fi

	if [ -n "$WTPAKS" ] && [ "$WTPAKS" != "$NON" ] && [ "$WTPAKS" != "0" ]; then
		chooseWinetricks
		mapfile -d " " -t -O "${#INSTPAKS[@]}" INSTPAKS < <(printf '%s' "$WTPAKS")

		WTLOG="$WTPFX/winetricks.log"

		if [ ! -f "$WTLOG" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Installing '$WTPAKS' silently with $WINETRICKS"
			notiShow "$(strFix "$NOTY_WTINST" "$WTPAKS" "$("$WINETRICKS" -V | cut -d ' ' -f1)" "$("$WTWINE" --version)")"
			restoreOrgVars
			if [ -n "$4" ] && [ "$4" == "F" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Using 'force' mode as argument '$4' was given"
				"$WTRUN" "$WINETRICKS" --force --unattended "${INSTPAKS[@]}" >> "$WTSHMLOG" 2>/dev/null
			else
				"$WTRUN" "$WINETRICKS" --unattended "${INSTPAKS[@]}" >> "$WTSHMLOG" 2>/dev/null
			fi
			notiShow "$NOTY_WTFIN"
			emptyVars "O" "X"
			writelog "INFO" "${FUNCNAME[0]} - '$WINETRICKS' Installation of '$WTPAKS' exited"
		fi

		if [ -f "$WTLOG" ]; then
			rmDupLines "$WTLOG"
			if [ ! -f "${WTLOG//.log/.checked}" ]; then
				mapfile -t -O "${#NOTINSTALLED[@]}" NOTINSTALLED <<< "$(comm -23 <(echo "${INSTPAKS[*]}" | tr ' ' '\n' | sort) <(sort < "$WTLOG"))"
				if [ -n "${NOTINSTALLED[0]}" ]; then
					writelog "INFO" "${FUNCNAME[0]} - Trying to installing following new or previously missed packages now: '${NOTINSTALLED[*]}'"
					notiShow "$(strFix "$NOTY_WTINST" "${NOTINSTALLED[*]}" "$("$WINETRICKS" -V | cut -d ' ' -f1)" "$("$WTWINE" --version)")"
					"$WTRUN" "$WINETRICKS" --force --unattended "${NOTINSTALLED[@]}" >> "$WTSHMLOG" 2>/dev/null
					notiShow "$NOTY_WTFIN"
				else
					writelog "INFO" "${FUNCNAME[0]} - All packages of '$WTPAKS' are already installed - nothing to do"
					touch "${WTLOG//.log/.checked}"
				fi
				unset NOTINSTALLED
			else
				writelog "INFO" "${FUNCNAME[0]} - Found ${WTLOG//.log/.checked} - Nothing to do"
			fi
		fi
		unset INSTPAKS
	fi
}

# start winetricks before game launch:
function checkWinetricksLaunch {
	# gui:
	if [ -n "$RUN_WINETRICKS" ]; then
		if [ "$RUN_WINETRICKS" -eq 1 ]; then
			writelog "INFO" "${FUNCNAME[0]} - Launching '$WINETRICKS' before game start"
			extWine64Run "$WINETRICKS" --gui  >> "$STLSHM/WINETRICKS_GUI.log" 2>/dev/null
		fi
	fi
	# silent:
	installWinetricksPaks "$WINETRICKSPAKS" "$RUNWINE" "extWine64Run"
}

function chooseWinetricks {
	if [ -n "$WINETRICKS" ]; then
		writelog "SKIP" "${FUNCNAME[0]} - 'WINETRICKS variable' already exists and points to '$WINETRICKS'"
	else
		if [ "$DLWINETRICKS" -eq 1 ] || [ "$ONSTEAMDECK" -eq 1 ] || [ "$INFLATPAK" -eq 1 ] ; then
			WTDLLAST="${WTDLDIR}.txt"
			MAXAGE=1440

			if [ ! -f "$DLWT" ] || [ ! -f "$WTDLLAST" ] || test "$(find "$WTDLLAST" -mmin +"$MAXAGE")"; then
				gitUpdate "$WTDLDIR" "$WINETRICKSURL"
				echo "$(date) - ${FUNCNAME[0]}" > "$WTDLLAST"
			fi

			if [ -f "$DLWT" ]; then
				WINETRICKS="$DLWT"
				writelog "INFO" "${FUNCNAME[0]} - Using '$DLWT' with version '$($DLWT -V | cut -d ' ' -f1)'"
			else
				writelog "SKIP" "${FUNCNAME[0]} - DLWINETRICKS is set to '$DLWINETRICKS', but '$DLWT' was not found!"
			fi
		else
			if [ -x "$(command -v "$SYSWINETRICKS")" ]; then
				WINETRICKS="$SYSWINETRICKS"
				writelog "INFO" "${FUNCNAME[0]} - Using systemwide winetricks with version '$($SYSWINETRICKS -V | cut -d ' ' -f1)'"
			fi	
		fi
	fi
}

function SetWineDebugChannels {
	if [ -n "$1" ]; then
		AID="$1"
		setAIDCfgs
	fi
	loadCfg "$STLGAMECFG"
	fixShowGnAid
	export CURWIKI="$PPW/Wine-Debug"
	TITLE="${PROGNAME}-${FUNCNAME[0]}"
	pollWinRes "$TITLE"
	setShowPic	

	WDCTXT="winedebugchannels.txt"
	WDC="$GLOBALMISCDIR/$WDCTXT"

	WDCSEL="$(
	while read -r wtch; do
		if grep -q "\-${wtch}" <<< "$STLWINEDEBUG"; then
			echo TRUE
		else
			echo FALSE
		fi
		if grep -q "+${wtch}" <<< "$STLWINEDEBUG"; then
			echo TRUE
		else
			echo FALSE
		fi
		echo "$wtch"
	done < "$WDC" | \
	"$YAD" --f1-action="$F1ACTION" --image "$SHOWPIC" --image-on-top --window-icon="$STLICON" --center "$WINDECO" --list --checklist --column="$GUI_MINUS":CHK --column="$GUI_PLUS":CHK --column="$GUI_WDCH" --separator=";" --print-all \
	--text="$(spanFont "$(strFix "$GUI_WDCDIALOG" "$SGNAID")" "H")" --title="$TITLE" --button="$BUT_CAN:0" --button="$BUT_SELECT:2" "$GEOM")"
	case $? in
		0)	{
				writelog "INFO" "${FUNCNAME[0]} - Selected '$BUT_CAN' - Cancelling selection"
			}
		;;
		2)	{
				writelog "INFO" "${FUNCNAME[0]} - Selected '$BUT_SELECT' - Saving Debug Options"

				if [ -z "$WDCSEL" ]; then
					writelog "INFO" "${FUNCNAME[0]} - Nothing selected"
				else
					unset STLWINEDEBUG
					while read -r chanline;do
						chan="$(cut -d ';' -f3 <<< "$chanline")"
						if grep -q "TRUE;FALSE" <<< "$chanline"; then
							STLWINEDEBUG="${STLWINEDEBUG},-${chan}"
						elif grep -q "FALSE;TRUE" <<< "$chanline"; then
							STLWINEDEBUG="${STLWINEDEBUG},+${chan}"
						elif grep -q "TRUE;TRUE" <<< "$chanline"; then
							STLWINEDEBUG="${STLWINEDEBUG},-${chan}"
						fi
					done <<< "$WDCSEL"
					touch "$FUPDATE"
					writelog "INFO" "${FUNCNAME[0]} - Saving following Wine Debug options: '$STLWINEDEBUG'"
					updateConfigEntry "STLWINEDEBUG" "${STLWINEDEBUG#,*}" "$STLGAMECFG"
				fi
			}
		;;
	esac
}

function WinetricksPick {
	WTPREF="$1"

	unset CURWTPAKS OTHERPAKS PAKSEL

	if [ "$WINETRICKSPAKS" == "$NON" ]; then
		declare -a CURWTPAKS
	else
		mapfile -d " " -t -O "${#CURWTPAKS[@]}" CURWTPAKS <<< "$(printf '%s\n' "$WINETRICKSPAKS" | sed '/^[[:space:]]*$/d')"
	fi

	while read -r line; do
		mapfile -d " " -t -O "${#PAKSEL[@]}" PAKSEL <<< "${line%% *}"
	done <<< "$(winetricks "$WTPREF" list)"

	while read -r curpak; do
	if [[ ! "${PAKSEL[*]}" =~ $curpak ]]; then
		mapfile -d " " -t -O "${#OTHERPAKS[@]}" OTHERPAKS <<< "${curpak%% *}"
	fi
	done <<< "$(printf "%s\n" "${CURWTPAKS[@]}")"

	fixShowGnAid
	export CURWIKI="$PPW/Winetricks"
	TITLE="${PROGNAME}-WinetricksPackageSelection-$WTPREF"
	pollWinRes "$TITLE"

	setShowPic
	# TODO? some yad/gtk warnings in WTPREF=apps DESCR:
	WTPICKS="$(
	while read -r packline; do
		PACKNAME="${packline%% *}"

		if [[ "${CURWTPAKS[*]}" =~ $PACKNAME ]]; then
			echo TRUE
		else
			echo FALSE
		fi

		echo "$PACKNAME"

		DESCRRAW="${packline#* }"
		DESCR1="${DESCRRAW//$(grep -oP '\(\K[^\)]+' <<< "$DESCRRAW")}";
		DESCR2="${DESCR1//\!}"
		DESCR="${DESCR2//&/&amp}"
		echo "${DESCR#"${DESCR%%[![:space:]]*}"}"
	done <<< "$("$WINETRICKS" "$WTPREF" list)"	 | \
	"$YAD" --f1-action="$F1ACTION" --image "$SHOWPIC" --image-on-top --window-icon="$STLICON" --center "$WINDECO" --list --checklist --column="$GUI_ADD" --column="$GUI_WTPACK" --column="$GUI_WTDESC" --separator="" --print-column="2" \
	--text="$(spanFont "$(strFix "$GUI_WTPACKDIALOG" "$SGNAID")" "H")" --title="$TITLE" --button="$BUT_CAN:0" --button="$BUT_SELECT:2" "$GEOM")"
	case $? in
		0)	{
				writelog "INFO" "${FUNCNAME[0]} - Selected '$BUT_CAN' - Cancelling selection"
			}
		;;
		2)	{
				writelog "INFO" "${FUNCNAME[0]} - Selected '$BUT_SELECT' - Saving Selection"

				if [ -z "$WTPICKS" ]; then
					writelog "INFO" "${FUNCNAME[0]} - Nothing selected"
					WTPICKS=""
				fi
				
				unset WINETRICKSPAKS
				while read -r line; do
					WINETRICKSPAKS="$WINETRICKSPAKS $line"
				done <<< "$WTPICKS"

				while read -r line; do
					WINETRICKSPAKS="$WINETRICKSPAKS $line"
				done <<< "${OTHERPAKS[*]}"

				if [ -z "$WINETRICKSPAKS" ] || [ "$WINETRICKSPAKS" == "  " ]; then
					WINETRICKSPAKS="$NON"
				fi

				WINETRICKSPAKS="${WINETRICKSPAKS#*[[:blank:]]}"
				WINETRICKSPAKS="${WINETRICKSPAKS%*[[:blank:]]}"

				declare -A WTNODUPPAKS
				for i in $WINETRICKSPAKS; do
					WTNODUPPAKS[$i]=1
				done

				WINETRICKSPAKS="${!WTNODUPPAKS[*]}"

				touch "$FUPDATE"
				updateConfigEntry "WINETRICKSPAKS" "$WINETRICKSPAKS" "$STLGAMECFG"
			}
		;;
	esac					
	if [ -n "$2" ]; then
		"$2" "$AID" "${FUNCNAME[0]}"
	fi
}

function cleanDropDown {
	CURSEL="$1"
	OPTIONS="$2"
	
	FILTOPTS="${OPTIONS//\!$CURSEL\!/\!}"
	FILTOPTS="!${FILTOPTS//$CURSEL\!/\!}"
	FILTOPTS="${FILTOPTS//\!\!/\!}"
	echo "$CURSEL$FILTOPTS"
}

function chooseWinetricksPrefix {
	if [ -n "$1" ]; then
		AID="$1"
		setAIDCfgs
	fi

	if [ ! -f "$STLGAMECFG" ]; then
		writelog "ERROR" "${FUNCNAME[0]} - Game config '$STLGAMECFG' not found - exiting"
	else
		chooseWinetricks
		loadCfg "$STLGAMECFG"
		ORGWINETRICKSPAKS="$WINETRICKSPAKS"
		
		writelog "INFO" "${FUNCNAME[0]} - Opening dialog to choose a winetricks prefix"
		export CURWIKI="$PPW/Winetricks"
		TITLE="${PROGNAME}-${FUNCNAME[0]}"
		pollWinRes "$TITLE"
		setShowPic

		WTLOG="$GPFX/winetricks.log"

		function WTPAKINSTLIST {
			unset WTLIST

			if [ -f "$WTLOG" ]; then
				rmDupLines "$WTLOG"
			fi

			while read -r line; do
				if [ -f "$WTLOG" ] && grep -q "^$line$" "$WTLOG"; then
#					echo "$line $GUI_WTAI"
					WTLIST="$WTLIST $line $GUI_WTAI,"
				else
#					echo "$line"
					WTLIST="$WTLIST $line,"
				fi
			done <<< "$(tr ' ' '\n' <<< "$WINETRICKSPAKS")"
			WTLIST="${WTLIST/ /}"
			WTLIST="${WTLIST%,*}"
			echo "$WTLIST"
		}

		createProtonList X
		if [ -z "$WTPROTON" ]; then
			WTPROTON="$USEPROTON"
		fi

		WTCATPFX="$("$YAD" --f1-action="$F1ACTION" --image "$SHOWPIC" --image-on-top --window-icon="$STLICON" --form --center --on-top $WINDECO \
		--title="$TITLE" --separator=";" \
		--text="$(spanFont "$GUI_CHOOSEWTCATPFX" "H")" \
		--field=" ":LBL " " \
		--field="$GUI_WTCATPFX!$GUI_CHOOSEWTCATPFX":CB "dlls!apps!dlls!fonts" \
		--field="$GUI_WTPROTON!$(strFix "$DESC_WTPROTON" "$BUT_INSTALL")":CB "$(cleanDropDown "${WTPROTON//\"}" "$PROTYADLIST")" \
		--field="$GUI_WTPROTONSAVE!$(strFix "$DESC_WTPROTONSAVE" "$BUT_INSTALL")":CHK "FALSE" \
		--field=" ":LBL " " \
		--field="$(spanFont "$GUI_CURSELWTPACKS" "H")":LBL " " \
		--field="$(WTPAKINSTLIST)":LBL " " \
		--button="$BUT_SELECT:2" --button="$BUT_DONE:4" --button="$BUT_INSTALL:6" "$GEOM"
		)"
		case $? in
			2)	{
					WTPREF="$(cut -d ';' -f2 <<< "$WTCATPFX")" # WEAK - will be broken when adding fields
					writelog "INFO" "${FUNCNAME[0]} - Selected '$BUT_SELECT' - Opening '$WTPREF' list"
					WinetricksPick "$WTPREF" "${FUNCNAME[0]}"
				}
			;;
			4)	{
					writelog "INFO" "${FUNCNAME[0]} - Selected '$BUT_DONE'"
					if [ "$ORGWINETRICKSPAKS" != "$WINETRICKSPAKS" ]; then
						rm "${WTLOG//.log/.checked}" 2>/dev/null
						writelog "INFO" "${FUNCNAME[0]} - Changed will be installed before next game start"
					else
						writelog "INFO" "${FUNCNAME[0]} - Package list hasn't changed"
					fi
				}
			;;
			6)	{
					WTPROTON="$(cut -d ';' -f3 <<< "$WTCATPFX")"
					writelog "INFO" "${FUNCNAME[0]} - Selected '$BUT_INSTALL' - Installing '$WINETRICKSPAKS' using '$WTPROTON'"
					RUNWTPROTON="$(getProtPathFromCSV "$WTPROTON")"

					if [ ! -f "$RUNWTPROTON" ]; then
						RUNWTPROTON="$(fixProtonVersionMismatch "WTPROTON" "$STLGAMECFG" X)"
					fi

					writelog "INFO" "${FUNCNAME[0]} - using proton binary '$RUNWTPROTON' for '$WTPROTON'"

					if [ -f "$(dirname "$RUNWTPROTON")/$DBW" ]; then
						RUNWTWINE="$(dirname "$RUNWTPROTON")/$DBW"
					elif [ -f "$(dirname "$RUNWTPROTON")/$FBW" ]; then
						RUNWTWINE="$(dirname "$RUNWTPROTON")/$FBW"
					fi
					
					writelog "INFO" "${FUNCNAME[0]} - Using wine '$RUNWTWINE' for winetricks"

					WTPROTONSAVE="$(cut -d ';' -f4 <<< "$WTCATPFX")"
					if [ "$WTPROTONSAVE" == "TRUE" ];then
						writelog "INFO" "${FUNCNAME[0]} - Saving Winetricks Proton WTPROTON '$WTPROTON' into '$STLGAMECFG'"
						touch "$FUPDATE"
						updateConfigEntry "WTPROTON" "$WTPROTON" "$STLGAMECFG"
					fi

					if [ -f "$RUNWTWINE" ]; then
						rm "${WTLOG//.log/.checked}" 2>/dev/null
						installWinetricksPaks "$WINETRICKSPAKS" "$RUNWTWINE" "extWine64Run"
					else
						writelog "ERROR" "${FUNCNAME[0]} - Could not find wine binary for current proton '$WTPROTON'"
					fi
				}
			;;
		esac
	fi
}

# start $WINECFG before game launch:
function checkWineCfgLaunch {
	if [ -n "$RUN_WINECFG" ]; then
		if [ "$RUN_WINECFG" -eq 1 ]; then
			writelog "INFO" "${FUNCNAME[0]} - Starting '$WINECFG' at prefix '$GPFX' with Wine '$RUNWINE':"
			if [ "$USEWINE" -eq 0 ]; then
				#513
				WINE="$RUNWINE" WINEARCH=win64 WINEDEBUG="$STLWINEDEBUG" WINEPREFIX="$GPFX" "$RUNWINE" "${WINECFG}.exe" 2>&1 | tee "$STLSHM/${FUNCNAME[0]}.log"
			else
				extWine64Run "$RUNWINECFG"
			fi
		else
			writelog "WARN" "${FUNCNAME[0]} - Function was called but RUN_WINECFG ('$RUN_WINECFG') was not enabled - skipping"
		fi
	else
		writelog "WARN" "${FUNCNAME[0]} - Function was called but RUN_WINECFG ('$RUN_WINECFG') was not defined - skipping"
	fi
}

function regEdit {
	REGEDIT="regedit"
	if [ -z "$1" ]; then
		writelog "INFO" "${FUNCNAME[0]} - Starting $REGEDIT without arguments"
		extWine64Run "$RUNWINE" "$REGEDIT"
	else
		writelog "INFO" "${FUNCNAME[0]} - Starting $REGEDIT with argument $1"
		if [ "$USEWINE" -eq 0 ]; then
			extWine64Run "$RUNWINE" "$REGEDIT" "$1"
		else
			extWine64Run "$RUNWINE" "$RUNREGEDIT" "$1"
		fi
		writelog "INFO" "${FUNCNAME[0]} - Applied '$1' using '$REGEDIT' - Setting REGEDIT to 0 now in '$STLGAMECFG'"
		updateConfigEntry "REGEDIT" "0" "$STLGAMECFG"
	fi
}

function customRegs {
	TEMPREG="$GPFX/VirtualDesktop.reg"

	if [ "$VIRTUALDESKTOP" -eq 1 ]; then
		SETVD=1
		if [ -z "$VDRES" ] || [ "$VDRES" == "$NON" ]; then
			VDRES="$(getScreenRes r)"
		fi
				
		if [ -f "$TEMPREG" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Looks like virtual desktop was already applied before"
			if grep -q "$VDRES" "$TEMPREG"; then
				writelog "SKIP" "${FUNCNAME[0]} - The configured resolution in '$TEMPREG' did not change - nothing to do"
				SETVD=0
			else
				writelog "INFO" "${FUNCNAME[0]} - The configured resolution in '$TEMPREG' changed - updating to '$VDRES'"
			fi
		fi

		if [ "$SETVD" -eq 1 ]; then
			if touch "$TEMPREG"; then
				writelog "INFO" "${FUNCNAME[0]} - VIRTUALDESKTOP is set to 1 - enabling virtual desktop"
				{
				echo "Windows Registry Editor Version 5.00"
				echo "[HKEY_CURRENT_USER\Software\Wine\Explorer]"
				echo "\"Desktop\"=\"Default\""
				echo "[HKEY_CURRENT_USER\Software\Wine\Explorer\Desktops]"
				echo "\"Default\"=\"$VDRES\""
				} >> "$TEMPREG"
				if [ -f "$TEMPREG" ]; then
					regEdit "$TEMPREG"
				else
					writelog "SKIP" "${FUNCNAME[0]} - '$TEMPREG' should be here, but it isn't!"
				fi
			else
				writelog "SKIP" "${FUNCNAME[0]} - Could not create '$TEMPREG' - skipping!"
			fi
		fi
	elif [ "$VIRTUALDESKTOP" -eq 0 ]; then
		if [ -f "$TEMPREG" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Virtual desktop is disabled, but was enabled before - removing the registry value"
			sed "s:\[:\[-:g" -i "$TEMPREG"
			regEdit "$TEMPREG"
			rm "$TEMPREG"
		fi		
	fi

	if [ "$REGEDIT" -eq 1 ]; then
		mkProjDir "$STLREGDIR"
		if [ -f "$STLREGDIR/$AID.reg" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Applying registry file '$STLREGDIR/$AID.reg'"
			regEdit "$STLREGDIR/$AID.reg"
		else
			writelog "INFO" "${FUNCNAME[0]} - No game specific regfile found. Opening the regedit editor"
			regEdit
		fi
	fi
}

function useNyrna {
	if [ -n "$RUN_NYRNA" ]; then
		if [ "$RUN_NYRNA" -eq 1 ]; then
			if "$PGREP" -f "$NYRNA" >/dev/null; then
				writelog "SKIP" "${FUNCNAME[0]} - '$NYRNA' already running - skipping"
				RUN_NYRNA=0
			else
			writelog "INFO" "${FUNCNAME[0]} - Starting '$NYRNA'"
			"$NYRNA" &
			fi
		fi
	fi
}

function useReplay {
	if [ -n "$RUN_REPLAY" ]; then
		if [ "$RUN_REPLAY" -eq 1 ]; then
			if "$PGREP" -fx "$(command -v "$REPLAY")" >/dev/null; then
				writelog "SKIP" "${FUNCNAME[0]} - '$REPLAY' already running - skipping"
				RUN_REPLAY=0
			else
			writelog "INFO" "${FUNCNAME[0]} - Starting '$REPLAY'"
			"$REPLAY" &
			fi
		fi
	fi
}

function killPrefixOnGameExit {
	waitForGamePid
	GPID="$(GAMEPID)"
	if [ -n "$GPID" ]; then
		writelog "INFO" "${FUNCNAME[0]} - Game pid '$GPID' found"
	fi
	writelog "INFO" "${FUNCNAME[0]} - Waiting for '$GPID' closing to kill Proton"
		
	tail --pid="$GPID" -f /dev/null
	writelog "INFO" "${FUNCNAME[0]} - Game process '$GPID' finished - Force closing Proton"
	if [ "$USEWINE" -eq 0 ]; then
		WINEPREFIX="$GPFX" "$RUNWINESERVER" -k
	else
		WINEPREFIX="$GWFX" "$RUNWINESERVER" -k
	fi

	touch "$CLOSETMP"
}

function StateSteamWebHelper {
	if [ "$TOGSTEAMWEBHELPER" -eq 1 ]; then
		SWH="steamwebhelper"

		if [ "$1" == "pause" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Stopping all '$SWH' processes"
			SIGVAL="-SIGSTOP"
		elif [ "$1" == "cont" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Continuing all '$SWH' processes"
			SIGVAL="-SIGCONT"
		else
			writelog "INFO" "${FUNCNAME[0]} - No argument - Toggling '$SWH' processes"
			TESTPID="$("$PGREP" "$SWH" | grep -v "$("$PGREP" "${SWH}\.")" | head -n1)"
			SWHSTATE="$(ps -q "$TESTPID" -o state --no-headers)"
			SIGVAL="-SIGSTOP"
			if [ "$SWHSTATE" = "T" ] ; then
				SIGVAL="-SIGCONT"
			fi
		fi

		while read -r swhpid; do
			if [ -n "$swhpid" ] && [ "$swhpid" -eq "$swhpid" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Executing 'kill \"$SIGVAL\" \"$swhpid\"' to '$1' the $SWH"
				kill "$SIGVAL" "$swhpid"
			fi
		done <<< "$("$PGREP" "$SWH")"
	fi
}

function dlWDIB {
	mkProjDir "$WDIBDLDIR"
	WDIBDSRC="$GHURL/$("$WGET" -q "$WDIBURL" -O - | grep -m1 -E 'releases.*download.*exe*' | cut -d '"' -f2 | head -n1)"

	if [ ! -f "$RUNWDIB" ]; then
		writelog "INFO" "${FUNCNAME[0]} - Downloading '$WDIB' to '$WDIBDLDIR'"
		dlCheck "$WDIBDSRC" "$RUNWDIB" "X" "Downloading '$WDIB' to '$WDIBDLDIR'"
	fi

	if [ -f "$RUNWDIB" ]; then
		writelog "SKIP" "${FUNCNAME[0]} - Found $RUNWDIB - skipping download"
	fi
}

# start wine-discord-ipc-bridge
function checkWDIB {
	if [ "$ISGAME" -eq 2 ] && [ "$USE_WDIB" -eq 1 ] && [ "$ISGAME" -eq 2 ] && [ "$USEWINE" -eq 0 ]; then
		dlWDIB

		if [ ! -f "$RUNWDIB" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Download failed - can't start '$WDIB' - skipping"
			USE_WDIB=0
		else
			writelog "INFO" "${FUNCNAME[0]} - Starting '$RUNWDIB' in the backgound for '$AID'"
			extProtonRun "F" "$RUNWDIB"
			killPrefixOnGameExit &
		fi
	fi
}

function checkSteamAppIDFile {
	if [ -d "$EFD" ] && [ "$STLPLAY" -eq 0 ]; then
		GSAIT="$EFD/$SAIT"
		CSAIT="$EFD/check-$SAIT"

		if [ ! -f "$CSAIT" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Creating new control file '$CSAIT'"
			if [ ! -f "$GSAIT" ]; then
				echo "OWNSAIT=\"0\"" > "$CSAIT"
			else
				echo "OWNSAIT=\"1\"" > "$CSAIT"
			fi
		fi

		if [ "$STEAMAPPIDFILE" -eq 1 ]; then	
			if [ ! -f "$GSAIT" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Creating '$GSAIT' because STEAMAPPIDFILE is enabled"
				echo "$AID" > "$GSAIT"
			else
				writelog "INFO" "${FUNCNAME[0]} - STEAMAPPIDFILE is enabled and '$GSAIT' already exists - nothing to do"
			fi
		else
			if [ ! -f "$GSAIT" ]; then
				writelog "INFO" "${FUNCNAME[0]} - STEAMAPPIDFILE is disabled and there's no '$GSAIT' - nothing to do"
			else
				if [ ! -f "$CSAIT" ]; then
					writelog "INFO" "${FUNCNAME[0]} - Removing '$GSAIT' because STEAMAPPIDFILE is disabled"
					rm "$GSAIT" 2>/dev/null	
				else
					loadCfg "$CSAIT" X
					if [ "$OWNSAIT" -eq 1 ]; then
						writelog "INFO" "${FUNCNAME[0]} - OWNSAIT is '$OWNSAIT', means the game ships an own '$SAIT'. Leaving untouched and enabling STEAMAPPIDFILE"
						updateConfigEntry "STEAMAPPIDFILE" "1" "$STLGAMECFG"
						STEAMAPPIDFILE=1				
					else
						writelog "INFO" "${FUNCNAME[0]} - Removing '$GSAIT' because the game doesn't own it and STEAMAPPIDFILE is disabled"
						rm "$GSAIT" 2>/dev/null	
					fi
				fi
			fi
		fi
	fi
}

function checkPulse {
	if [ "$CHANGE_PULSE_LATENCY" -eq 1 ]; then
		writelog "INFO" "${FUNCNAME[0]} - Setting PULSE_LATENCY_MSEC to '$STL_PULSE_LATENCY_MSEC'"
		export PULSE_LATENCY_MSEC="$STL_PULSE_LATENCY_MSEC"
	fi
}

function getProtWinePath {
	CHECKWINED="${1%/*}/$DBW"
	CHECKWINEF="${1%/*}/$FBW"
	if [ -f "$CHECKWINED" ]; then
		echo "$CHECKWINED"
	elif [ -f "$CHECKWINEF" ]; then
		echo "$CHECKWINEF"
	fi
}

function listSteWoShPaks {
	STSHT1="${STEWOS,,}"
	STSHTXT="${STSHT1//\ /-}.txt"
	STESHALIST="$GLOBALMISCDIR/$STSHTXT"
	cut -d ';' -f1 "$STESHALIST"
}

function getGameDirFromAM {
	APPMAFE="$1"
	GIRAW="$(grep "\"installdir\"" "$APPMAFE" | awk -F '"installdir"' '{print $NF}')"
	GINS="$(awk '{$1=$1};1' <<< "${GIRAW//\"/}")"
	OUTGD="${APPMAFE%/*}/common/$GINS"
	if [ -d "$OUTGD" ]; then
		echo "$OUTGD"
	fi
}

function getGameDirFromAID {
	APPMAFE="$(listAppManifests | grep -m1 "appmanifest_${1}.acf")"
	getGameDirFromAM "$APPMAFE"
}

function runExe {
	IFILE="$1"
	AIDORPFX="$2"
	INSTWINE="$3"
	INSTARGS="$4"
	
	mapfile -d " " -t -O "${#INSTARGSARR[@]}" INSTARGSARR < <(printf '%s' "${INSTARGS//\"}")

	if [ "$AIDORPFX" -eq "$AIDORPFX" ] 2>/dev/null; then
		writelog "INFO" "${FUNCNAME[0]} - '$AIDORPFX' seems to be a SteamAppId - determining its pfx" E
		setGPfxFromAppMa "$AIDORPFX"
		if [ -n "$GPFX" ]; then
			IPFX="$GPFX"
			IAID="$AIDORPFX"
		fi
	else
		IPFX="$AIDORPFX"
		IAID="$(grep -oP "$CODA/\K[^/pfx]+" <<< "$IPFX")"
	fi
	
	if [ "$INSTWINE" != "$NON" ]; then
		IWINE="$INSTWINE"
	else
		if [ "$IAID" -eq "$IAID" ] 2>/dev/null; then
			IAIDCFG="$STLGAMEDIRID/$IAID.conf"
			if [ -f "$IAIDCFG" ]; then
				IUSEPROT="$(grep "^USEPROTON=" "$IAIDCFG" | cut -d '=' -f2)"
				writelog "INFO" "${FUNCNAME[0]} - Searching for wine for '$IUSEPROT' defined in $IAIDCFG"
				IRUNPROT="$(getProtPathFromCSV "${IUSEPROT//\"}")"
				if [ -f "$IRUNPROT" ]; then
					IWINE="$(getProtWinePath "$IRUNPROT")"
					writelog "INFO" "${FUNCNAME[0]} - Using '$IWINE' for installing '$1'"
				else
					writelog "SKIP" "${FUNCNAME[0]} - Could not find path for proton '${IUSEPROT//\"}' in '$IAIDCFG'"
				fi
			fi
		fi
		
		if [ ! -f "$IAIDCFG" ] || [ ! -f "$IWINE" ]; then
			writelog "INFO" "${FUNCNAME[0]} - No wine binary found - falling back to wine from FIRSTUSEPROTON '$FIRSTUSEPROTON'"
			IRUNPROT="$(getProtPathFromCSV "$FIRSTUSEPROTON")"
			if [ -f "$IRUNPROT" ]; then
				IWINE="$(getProtWinePath "$IRUNPROT")"
				writelog "INFO" "${FUNCNAME[0]} - Using '$IWINE' for installing '$IFILE'"
			else
				writelog "SKIP" "${FUNCNAME[0]} - Could not find path for proton '$FIRSTUSEPROTON' in '$IAIDCFG'"
			fi
		fi
	fi
	
	if [ -n "$IPFX" ] && [ -f "$IWINE" ] && [ -f "$IFILE" ]; then
		cd "${IFILE%/*}" >/dev/null || return
		if [ -n "$USEMSI" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Installing package via command 'WINEPREFIX=$IPFX $IWINE msiexec /i $IFILE ${INSTARGS//\"/}'"
			WINEDEBUG="-all" WINEPREFIX="$IPFX" "$IWINE" msiexec /i "$IFILE" "${INSTARGSARR[@]}" >"$STLSHM/${FUNCNAME[0]}_${IFILE##*/}.log" 2>"$STLSHM/${FUNCNAME[0]}_${IFILE##*/}.log"
		else
			if [[ "$1" =~ "dotnet" ]]; then
				MOGUID="$(WINEPREFIX="$IPFX" "$IWINE" uninstaller --list | grep "Wine Mono Windows Support" | cut -d '|' -f1)"
				if [ -n "$MOGUID" ]; then
					writelog "INFO" "${FUNCNAME[0]} - Uninstalling Mono before installing '${IFILE##*/}'"
					WINEPREFIX="$IPFX" "$IWINE" uninstaller --remove "$MOGUID" >"$STLSHM/${FUNCNAME[0]}_mono-uninst.log" 2>"$STLSHM/${FUNCNAME[0]}_mono-uninst.log"
				fi
			fi
			WINEDEBUG="-all" WINEPREFIX="$IPFX" "$IWINE" "$IFILE" "${INSTARGSARR[@]}" >"$STLSHM/${FUNCNAME[0]}_${IFILE##*/}.log" 2>"$STLSHM/${FUNCNAME[0]}_${IFILE##*/}.log"
		fi
		cd - >/dev/null || return
	else
		writelog "SKIP" "${FUNCNAME[0]} - At least one component of the package installation is missing, check above logs"
	fi
}

function installSteWoShPak {
	AIDORPFX="$2"
	if [ -n "$3" ]; then
		INSTWINE="$3"
	else
		INSTWINE="$NON"
	fi

	STSHT1="${STEWOS,,}"
	STSHTXT="${STSHT1//\ /-}.txt"
	STESHALIST="$GLOBALMISCDIR/$STSHTXT"

	CORED="$STEAM_COMPAT_CLIENT_INSTALL_PATH/$SAC/$STEWOS/_CommonRedist/"

	if grep -q "^\"$1\";" "$STESHALIST"; then
		RELPATH="$(grep "^\"$1\";" "$STESHALIST" | cut -d ';' -f2)"
		INSTARGS="$(grep "^\"$1\";" "$STESHALIST" | cut -d ';' -f3)"
		USEMSI="$(grep "^\"$1\";" "$STESHALIST" | cut -d ';' -f4)"
		IFILE="$CORED/${RELPATH//\"/}"
		notiShow "$(strFix "$NOTY_INSTSTART" "$1")"
		writelog "INFO" "${FUNCNAME[0]} - 'runExe \"$IFILE\" \"$AIDORPFX\" \"$INSTWINE\" \"$INSTARGS\"'"
		runExe "$IFILE" "$AIDORPFX" "$INSTWINE" "$INSTARGS"
		notiShow "$(strFix "$NOTY_INSTSTOP" "$1")"
	else
		writelog "SKIP" "${FUNCNAME[0]} - Could not find '$1' in '$STESHALIST' - doesn't seem to be a valid '$STEWOS' name"
	fi
}

# generic Mod functions (Vortex + MO2):

function prepModGameSym {
	DSTL="$1"
	gdir="$2"
	if [ -n "$2" ]; then
		if [ ! -L "$DSTL" ] || [ "$(readlink "$DSTL")" != "$gdir" ]; then
			if [ -L "$DSTL" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Removing symlink '$DSTL' pointing to '$(readlink "$DSTL")'"
				rm "$DSTL" 2>/dev/null
			fi
			if [ -d "$DSTL" ]; then
				writelog "SKIP" "${FUNCNAME[0]} - Not creating symlink from '$gdir' to '$DSTL', because '$DSTL' is a real directory"
			else
				writelog "INFO" "${FUNCNAME[0]} - Creating symlink from '$gdir' to '$DSTL'"
				ln -s "$gdir" "$DSTL"
			fi
		fi
	fi
}

function setModGameReg {
	DSTPFX="$1" 
	MODWINE="$2"
	if [ -f "$MODGREG" ]; then
		WINEPREFIX="$DSTPFX" "$MODWINE" regedit "$MODGREG" 2>/dev/null
		WINEPREFIX="$DSTPFX" "${MODWINE}64" regedit "$MODGREG" 2>/dev/null
		rm "$MODGREG" 2>/dev/null
	fi	
}

function setModGameSyms {
	SYMODE="$1" # MODE - either 'li' or 'set'
	SRCPFX="$2" # Game prefix
	MODGNA="$3" # Game name
	MODGID="$4" # Game Steam ID
	DSTPFX="$5" # Mod manager prefix
	CHKAPMA="$6" # Game app-manifest (.acf)

	if [ -f "$MO2INSTFAIL" ]; then
		writelog "SKIP" "${FUNCNAME[0]} - '$MO2INSTFAIL' found - seems like installation failed previously - skipping ${FUNCNAME[0]}"
	elif [ ! -d "$SRCPFX" ]; then
		writelog "SKIP" "${FUNCNAME[0]} - '$SRCPFX' missing - looks like the game was removed or never started yet"
	else
		if [ "$SYMODE" == "li" ]; then
			echo "$MODGID;$MODGNA;$SRCPFX;"
		else
			mkProjDir "$DSTPFX/$DRCU/$STUS/$DOCS/$MYGAMES"
			mkProjDir "$DSTPFX/$DRCU/$STUS/$ADLO/cache"
			
			MODLOOT="$DSTPFX/$DRCU/$STUS/$ADLO/LOOT"
			if [ -L "$MODLOOT" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Removing symlink '$MODLOOT' for creating a real directory instead - is it worth/useful to migrate the content to '$MODLOOT'?"
			fi
			mkProjDir "$MODLOOT"

			writelog "INFO" "${FUNCNAME[0]} - Found game '$MODGNA ($MODGID)' with pfx '$SRCPFX'"
			# maybe merge redundant code later:
			
			if [ -d "$SRCPFX/$DRCU/$STUS/$DOCS/$MYGAMES" ]; then
				while read -r gdir; do
					DSTL="$DSTPFX/$DRCU/$STUS/$DOCS/$MYGAMES/${gdir##*/}"
					prepModGameSym "$DSTL" "$gdir"
				done <<< "$(find -L "$SRCPFX/$DRCU/$STUS/$DOCS/$MYGAMES" -mindepth 1 -maxdepth 1 '(' -type d -o -type l -xtype d ')')"
			fi

			if [ -d "$SRCPFX/$DRCU/$STUS/$DOCS" ]; then
				while read -r gdir; do
					if [ "${gdir##*/}" == "$MYGAMES" ]; then
						while read -r gsdir; do
							DSTL="$DSTPFX/$DRCU/$STUS/$DOCS/$MYGAMES/${gsdir##*/}"
							prepModGameSym "$DSTL" "$gsdir"
						done <<< "$(find -L "$SRCPFX/$DRCU/$STUS/$DOCS/$MYGAMES" -mindepth 1 -maxdepth 1 '(' -type d -o -type l -xtype d ')')"
					elif [ "${gdir##*/}" == "$EAGA" ]; then
						mkProjDir "$DSTPFX/$DRCU/$STUS/$DOCS/$EAGA"
						while read -r geadir; do
							DSTL="$DSTPFX/$DRCU/$STUS/$DOCS/$EAGA/${geadir##*/}"
							prepModGameSym "$DSTL" "$geadir"
						done <<< "$(find -L "$SRCPFX/$DRCU/$STUS/$DOCS/$EAGA" -mindepth 1 -maxdepth 1 '(' -type d -o -type l -xtype d ')')"
					elif [ "${gdir##*/}" == "$LAGA" ]; then
						mkProjDir "$DSTPFX/$DRCU/$STUS/$DOCS/$LAGA"
						while read -r gladir; do
							DSTL="$DSTPFX/$DRCU/$STUS/$DOCS/$LAGA/${gladir##*/}"
							prepModGameSym "$DSTL" "$gladir"
						done <<< "$(find -L "$SRCPFX/$DRCU/$STUS/$DOCS/$LAGA" -mindepth 1 -maxdepth 1 '(' -type d -o -type l -xtype d ')')"
					elif [ "${gdir##*/}" == "$BIOW" ]; then
						mkProjDir "$DSTPFX/$DRCU/$STUS/$DOCS/$BIOW"
						while read -r gbiodir; do
							DSTL="$DSTPFX/$DRCU/$STUS/$DOCS/$BIOW/${gbiodir##*/}"
							prepModGameSym "$DSTL" "$gbiodir"
						done <<< "$(find -L "$SRCPFX/$DRCU/$STUS/$DOCS/$BIOW" -mindepth 1 -maxdepth 1 '(' -type d -o -type l -xtype d ')')"
					else
						DSTL="$DSTPFX/$DRCU/$STUS/$DOCS/${gdir##*/}"
						prepModGameSym "$DSTL" "$gdir"
					fi
				done <<< "$(find -L "$SRCPFX/$DRCU/$STUS/$DOCS" -mindepth 1 -maxdepth 1 -not -empty '(' -type d -o -type l -xtype d ')')"
			fi

			if [ -d "$SRCPFX/$DRCU/$STUS/$MYDOCS" ] && [ ! -L "$SRCPFX/$DRCU/$STUS/$MYDOCS" ]; then
				while read -r gdir; do
					if [ "${gdir##*/}" == "$MYGAMES" ]; then
						while read -r gsdir; do
							DSTL="$DSTPFX/$DRCU/$STUS/$DOCS/$MYGAMES/${gsdir##*/}"
							prepModGameSym "$DSTL" "$gsdir"
						done <<< "$(find -L "$SRCPFX/$DRCU/$STUS/$MYDOCS/$MYGAMES" -mindepth 1 -maxdepth 1 '(' -type d -o -type l -xtype d ')')"
					elif [ "${gdir##*/}" == "$EAGA" ]; then
						mkProjDir "$DSTPFX/$DRCU/$STUS/$DOCS/$EAGA"
						while read -r geadir; do
							DSTL="$DSTPFX/$DRCU/$STUS/$DOCS/$EAGA/${geadir##*/}"
							prepModGameSym "$DSTL" "$geadir"
						done <<< "$(find -L "$SRCPFX/$DRCU/$STUS/$MYDOCS/$EAGA" -mindepth 1 -maxdepth 1 '(' -type d -o -type l -xtype d ')')"
					elif [ "${gdir##*/}" == "$LAGA" ]; then
						mkProjDir "$DSTPFX/$DRCU/$STUS/$DOCS/$LAGA"
						while read -r gladir; do
							DSTL="$DSTPFX/$DRCU/$STUS/$DOCS/$LAGA/${gladir##*/}"
							prepModGameSym "$DSTL" "$gladir"
						done <<< "$(find -L "$SRCPFX/$DRCU/$STUS/$MYDOCS/$LAGA" -mindepth 1 -maxdepth 1 '(' -type d -o -type l -xtype d ')')"
					elif [ "${gdir##*/}" == "$BIOW" ]; then
						mkProjDir "$DSTPFX/$DRCU/$STUS/$DOCS/$BIOW"
						while read -r gbiodir; do
							DSTL="$DSTPFX/$DRCU/$STUS/$DOCS/$BIOW/${gbiodir##*/}"
							prepModGameSym "$DSTL" "$gbiodir"
						done <<< "$(find -L "$SRCPFX/$DRCU/$STUS/$DOCS/$BIOW" -mindepth 1 -maxdepth 1 '(' -type d -o -type l -xtype d ')')"
					else
						DSTL="$DSTPFX/$DRCU/$STUS/$DOCS/${gdir##*/}"
						prepModGameSym "$DSTL" "$gdir"
					fi
				done <<< "$(find -L "$SRCPFX/$DRCU/$STUS/$MYDOCS" -mindepth 1 -maxdepth 1 -not -empty '(' -type d -o -type l -xtype d ')')"
			fi

			if [ -d "$SRCPFX/$DRCU/$STUS/$APDA" ]; then
				while read -r gdir; do
					if [ "${gdir##*/}" != "Microsoft" ] ; then
						DSTL="$DSTPFX/$DRCU/$STUS/$ADRO/${gdir##*/}"
						prepModGameSym "$DSTL" "$gdir"
					fi
				done <<< "$(find -L "$SRCPFX/$DRCU/$STUS/$APDA" -mindepth 1 -maxdepth 1 -not -empty '(' -type d -o -type l -xtype d ')')"
			fi

			if [ -d "$SRCPFX/$DRCU/$STUS/$ADLO" ]; then
				while read -r gdir; do
					if [ "${gdir##*/}" != "openvr" ] && [ "${gdir##*/}" != "Microsoft" ] && [ "${gdir##*/}" != "cache" ] ; then
						if [ "${gdir##*/}" == "$MO" ] && [ ! -L "$gdir" ]; then
							writelog "WARN" "${FUNCNAME[0]} - Renaming old real directory '$gdir' to '${gdir}_OLD', to make place for a symlink into '$DSTPFX'"
							mv "$gdir" "${gdir}_OLD"
						else
							DSTL="$DSTPFX/$DRCU/$STUS/$ADLO/${gdir##*/}"
							prepModGameSym "$DSTL" "$gdir"
						fi
					fi
				done <<< "$(find -L "$SRCPFX/$DRCU/$STUS/$ADLO" -mindepth 1 -maxdepth 1 -not -empty '(' -type d -o -type l -xtype d ')')"
			fi

			if [ -d "$SRCPFX/$DRCU/$STUS/$ADLOLO" ]; then
				while read -r gdir; do
					if [ "${gdir##*/}" != "openvr" ] && [ "${gdir##*/}" != "Microsoft" ] ; then
						if [ "${gdir##*/}" == "$MO" ] && [ ! -L "$gdir" ]; then
							writelog "WARN" "${FUNCNAME[0]} - Renaming old real directory '$gdir' to '${gdir}_OLD', to make place for a symlink into '$DSTPFX'"
							mv "$gdir" "${gdir}_OLD"
						else
							DSTL="$DSTPFX/$DRCU/$STUS/$ADLOLO/${gdir##*/}"
							prepModGameSym "$DSTL" "$gdir"
						fi
					fi
				done <<< "$(find -L "$SRCPFX/$DRCU/$STUS/$ADLOLO" -mindepth 1 -maxdepth 1 -not -empty '(' -type d -o -type l -xtype d ')')"
			fi
						
			if [ -d "$SRCPFX/$DRCU/$STUS/$ADLO/LOOT" ]; then
				while read -r gdir; do
					DSTL="$MODLOOT/${gdir##*/}"
					prepModGameSym "$DSTL" "$gdir"
				done <<< "$(find -L "$SRCPFX/$DRCU/$STUS/$ADLO/LOOT" -mindepth 1 -maxdepth 1 -not -empty '(' -type d -o -type l -xtype d ')')"
			fi
			
			if [ -d "$SRCPFX/$DRCU/$STUS/$LSAD" ]; then
				while read -r gdir; do
					if [ "${gdir##*/}" != "openvr" ] && [ "${gdir##*/}" != "Microsoft" ] ; then
						DSTL="$DSTPFX/$DRCU/$STUS/$ADLO/${gdir##*/}"
						prepModGameSym "$DSTL" "$gdir"
					fi
				done <<< "$(find -L "$SRCPFX/$DRCU/$STUS/$LSAD" -mindepth 1 -maxdepth 1 -not -empty '(' -type d -o -type l -xtype d ')')"
			fi

			if [ -d "$SRCPFX/$DRCU/$STUS/$SAGE/$CDPR" ]; then
				mkProjDir "$DSTPFX/$DRCU/$STUS/$SAGE/$CDPR"
				while read -r gdir; do
						DSTL="$DSTPFX/$DRCU/$STUS/$SAGE/$CDPR/${gdir##*/}"
						prepModGameSym "$DSTL" "$gdir"
				done <<< "$(find -L "$SRCPFX/$DRCU/$STUS/$SAGE/$CDPR" -mindepth 1 -maxdepth 1 -not -empty '(' -type d -o -type l -xtype d ')')"
			fi

			MSREG="$SRCPFX/$SREG"
			if [ -f "$MSREG" ]; then
				if grep -qi "^\"installed path\"=" "$MSREG"; then
					MODGREG="$STLSHM/modgames.reg"
					if [ ! -f "$MODGREG" ]; then
						echo "Windows Registry Editor Version 5.00" > "$MODGREG"
					fi
					MEFD="$(getGameDirFromAM "$CHKAPMA")"
					if [ -d "$MEFD" ]; then
						writelog "INFO" "${FUNCNAME[0]} - Game Dir is '$MEFD' - adding the windows variant into the registry, because it is required for this game"
						grep -i -B2 "^\"installed path\"=" "$MSREG" | grep -v "^#\|LastKey\|CurrentVersion\|^--" | head -n1 | sed "s:^\[Software:\[HKEY_LOCAL_MACHINE\\\Software:" | sed "s:\\\\Wow6432Node::" >> "$MODGREG"
						# the path could be grepped as well, but at least two games had the Steamworks Shared path in the reg value instead here
						echo "\"installed path\"=\"Z:${MEFD//\//\\\\}\\\\\"" >> "$MODGREG"
					else
						writelog "SKIP" "${FUNCNAME[0]} - Game Dir '$MEFD' not found"
					fi
				fi
			else
				writelog "SKIP" "${FUNCNAME[0]} - '$MSREG' not found"
			fi
		fi
	fi
}

function listWinSteamLibraries {
	COUNTER=1
	SL1="${SROOT%*/}"
	echo "\"$COUNTER\" \"Z:${SL1//\//\\\\}\""

	listSteamLibraries
	
	unset SLARR
	mapfile -t -O "${#SLARR[@]}" SLARR <<< "$SL1"

	while read -r line; do
		COUNTER=$((COUNTER+1))
		W1="${line//\"}"
		W1="${line//\/steamapps/}"
		mapfile -t -O "${#SLARR[@]}" SLARR <<< "$W1"
		W2="${W1//\//\\\\}"
		echo "\"$COUNTER\" \"Z:$W2\""
	done < "$STELILIST"
}

function installDotNet {
	INSTPFX="$1"
	INSTWINE="$2"
	if [ -n "$3" ]; then
		DNVER="$3"
	else
		DNVER="48"
	fi
	LOGSUFFIX=" ${4}"
	DNFORCE="$5"
	chooseWinetricks
	ILOG="$STLSHM/installDotNet.log"
	DNLOGPRETTYNAME="${ILOG}${LOGSUFFIX}"  # Mainly used for HMM game install logs
	rm "${ILOG}${LOGNAME}" 2>/dev/null

	# Experiment -- Add option to 'force' dotnet install (idea here is to fix dotnet48 failing)
	# Adding --force will force it to always be installed for a given prefix, even if it is already installed  -- May not even fix issues, but could
	writelog "INFO" "${FUNCNAME[0]} - Starting $DOTN$DNVER install - check ${DNLOGPRETTYNAME}"
	if [ -z "$DNFORCE" ]; then
		writelog "INFO" "${FUNCNAME[0]} - WINEDEBUG=\"-all\" WINEPREFIX=\"$INSTPFX\" WINE=\"$INSTWINE\" \"$WINETRICKS\" --unattended \"$DOTN$DNVER\""
		
		WINEDEBUG="-all" WINEPREFIX="$INSTPFX" WINE="$INSTWINE" "$WINETRICKS" --unattended "$DOTN$DNVER" >> "${DNLOGPRETTYNAME}"
	else
		writelog "INFO" "${FUNCNAME[0]} - WINEDEBUG=\"-all\" WINEPREFIX=\"$INSTPFX\" WINE=\"$INSTWINE\" \"$WINETRICKS\" --force --unattended \"$DOTN$DNVER\""
		
		WINEDEBUG="-all" WINEPREFIX="$INSTPFX" WINE="$INSTWINE" "$WINETRICKS" --force --unattended "$DOTN$DNVER" >> "${DNLOGPRETTYNAME}"
	fi

	# WINEDEBUG="-all" WINEPREFIX="$INSTPFX" WINE="$INSTWINE" "$WINETRICKS" --unattended "$DOTN$DNVER" >> "${ILOG}${LOGSUFFIX}"
	writelog "INFO" "${FUNCNAME[0]} - Stopped $DOTN$DNVER install - check ${DNLOGPRETTYNAME}"
}

function updateWineRegistryKey {
	REGOP="$1"  # i.e. "add", "delete"
	REGPATH="$2"
	REGVAL="$3"
	WINEPFX="$4"
	WINERUNCMD="$5"

	writelog "INFO" "${FUNCNAME[0]} - Removing key '$REGVAL' from '$REGPATH' using '$WINERUNCMD'"
	WINEPREFIX="$WINEPFX" "$WINERUNCMD" reg "${REGOP}" "${REGPATH}" "/v" "${REGVAL}" "/f"
}

### HEDGEMODMANAGER (HMM) BEGIN

# NOTE: This was written with HMM in mind, but it may work generally too
# Returns the download URL to the latest GitHub actions build of a repository and the commit SHA it was built from separated by a comma
#
# EX: DefinitelyNotValve/HalfLife2EpisodeThree/suites/12345678/artifacts/87654321;0df23c5 
function fetchLatestGitHubActionsBuild {
    PROJAPIURL="$1"
    ARTIFACTNUM=$2

    # /actions/runs
    ARTIFACTRUNSRESP="$( curl -s "${PROJAPIURL}/actions/runs" | "$JQ" '.workflow_runs[0]' )"
    ARTIFACTRUNSUITEID="$( echo "$ARTIFACTRUNSRESP" | "$JQ" '.check_suite_id' )"
    LATESTARTIFACTURL="$( echo "$ARTIFACTRUNSRESP" | "$JQ" '.artifacts_url' | cut -d '"' -f 2 )"

    # /actions/runs/<artifact_id>/artifacts
    LATESTARTIFACTRESP="$( curl -s "${LATESTARTIFACTURL}" | "$JQ" ".artifacts[${ARTIFACTNUM}]" )"
    LATESTARTIFACTID="$( echo "$LATESTARTIFACTRESP" | "$JQ" ".id" )"
    LATESTARTIFACTSHA="$( echo "$LATESTARTIFACTRESP" | "$JQ" ".workflow_run.head_sha" | cut -d '"' -f 2 )"
    
    ARTIFACTDLURL="suites/${ARTIFACTRUNSUITEID}/artifacts/${LATESTARTIFACTID}"
    echo "${ARTIFACTDLURL};${LATESTARTIFACTSHA::7}"
}

# HMM doesn't really have a "setup" exe, but MO2 and Vortex use this naming convention so... keeping it :-)
function getLatestHMMVer {
	HMMSET="HedgeModManager"
	
	writelog "INFO" "${FUNCNAME[0]} - Searching for latest '$HMMSET' Release under '$HMMPROJURL'"
	HMMSETUP="$( getLatestGitHubExeVer "HedgeModManager" "https://github.com/thesupersonic16/HedgeModManager" )"
	if [ -n "$HMMSETUP" ]; then
		writelog "INFO" "${FUNCNAME[0]} - Found '$HMMSETUP'"
	else
		writelog "ERROR" "${FUNCNAME[0]} - Could not find any '$HMMSET' Release"
	fi
}

function checkLatestHMM {
	AVAILABLEHMMVER="$1"
	HMMSPATH="$2"

	HMMUPDATEAVAILABLE=0

	# Auto-update executable - May not be needed if HMM auto updater works
	if [ -f "$HMMVERFILE" ]; then
		CURRHMMVER="$( head -n 1 "$HMMVERFILE" )"
		if [[ "$CURRHMMVER" = "$AVAILABLEHMMVER" ]]; then
			writelog "INFO" "${FUNCNAME[0]} - Latest HedgeModManager already downloaded - Nothing to do"  # Probably have to do a version check here later
			echo "Latest HedgeModManager is already downloaded or was downloaded previously"
		else
			writelog "INFO" "${FUNCNAME[0]} - HedgeModManager update is available ($CURRHMMVER -> $AVAILABLEHMMVER) - Updating"
			echo "HedgeModManager update is available ($CURRHMMVER -> $AVAILABLEHMMVER) - Updating"
			if [ -f "$HMMSPATH" ]; then
				rm "$HMMSPATH"
			else
				writelog "INFO" "${FUNCNAME[0]} - HedgeModManager executable doesn't exist - nothing to remove before updating"  # Could happen if EXE is removed but version tracking file is not
				echo "No existing HedgeModManager executable"
			fi
			HMMUPDATEAVAILABLE=1
		fi
	else
		writelog "INFO" "${FUNCNAME[0]} - No HedgeModManager version file found at '$HMMVERFILE' - Nothing to check, assuming we need to update"
		echo "Could not get existing HedgeModManager version - Downloading latest '$AVAILABLEHMMVER'"
		HMMUPDATEAVAILABLE=1
	fi
}

function dlLatestHMM {

	function dlLatestHMMDev {
		HMMARCHIVENAME="${HMM}-Release.zip"
		HMMARCHIVEPATH="$HMMDLDIR/${HMMARCHIVENAME}"

		HMMSETUP="${HMM}.exe"
		HMMSETUPBASE="$( basename "${HMMSETUP}" )"  # Doing this in case "HMMSETUP" ever changes
		HMMSPATH="$HMMDLDIR/$HMMSETUP"

		HMMUPDATEAVAILABLE=0

		HMMAPIURLPATH="${HMMPROJURL//$GHURL}"
		HMMLATESTDEV="${HMMPROJURL}/$( fetchLatestGitHubActionsBuild "${AGHURL}/repos${HMMAPIURLPATH}" 1 )"  # Used to get the latest dev version SHA
		HMMLATESTDEVURL="https://nightly.link${HMMAPIURLPATH}/workflows/build/rewrite/${HMMARCHIVENAME}"  # Use nightly.link to get latest artifact download link for HMM
		HMMVER="$( echo "$HMMLATESTDEV" | cut -d ";" -f 2 )"

		writelog "INFO" "${FUNCNAME[0]} - HedgeModManager artifact URL: '$HMMLATESTDEVURL' ($HMMVER)"

		checkLatestHMM "$HMMVER" "$HMMSPATH"

		mkProjDir "$HMMDLDIR"
		if [ ! -f "$HMMSPATH" ] || [ "$HMMUPDATEAVAILABLE" -eq 1 ]; then
			# No exe OR we need to update, check if we have the archive to extract it from
			writelog "INFO" "${FUNCNAME[0]} - Either no HedgeModManager executable downloaded and extracted, or there is an update available - HMMUPDATEAVAILABLE is '${HMMUPDATEAVAILABLE}'"
			if [ ! -f "$HMMARCHIVEPATH" ] || [ "$HMMUPDATEAVAILABLE" -eq 1 ]; then
				# (No archive and no exe) or update available, download from GitHub
				writelog "INFO" "${FUNCNAME[0]} - Either no HedgeModManager artifact present, or an update is available - HMMUPDATEAVAILABLE is '${HMMUPDATEAVAILABLE}'"
				
				# Download
				writelog "INFO" "${FUNCNAME[0]} - Downloading latest HedgeModManager Development Artifact from URL '$HMMLATESTDEVURL'"
				echo "Downloading latest HedgeModManager Development Artifact"
				notiShow "$(strFix "$NOTY_HMMDL" "$HMMDLVER")" "X"
				dlCheck "$HMMLATESTDEVURL" "$HMMARCHIVEPATH" "X" "Downloading latest HedgeModManager Development '$HMMVER'" &>/dev/null
			else
				# We have existing archive but no executable 
				writelog "INFO" "${FUNCNAME[0]} - Found existing and up-to-date HedgeModManager archive at '$HMMSPATH' - Extracting"
				echo "Found up-to-date HedgeModManager Development release archive - Extracting "
			fi

			# Extract
			# Check if download success
			if [ -f "$HMMARCHIVEPATH" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Downloaded latest HedgeModManager Artifact - Extracting archive at '$HMMARCHIVEPATH'"
				echo "Extracting latest HedgeModManager Development Artifact"
				"$UNZIP" -qo "$HMMARCHIVEPATH" -d "$HMMDLDIR"  # Extract quiet and overwrite existing file if present without confirmation
				
				# If download sucess, try to extract
				if [ -f "$HMMSPATH" ]; then
					writelog "INFO" "${FUNCNAME[0]} - Successfully extracted HedgeModManager archive at '$HMMSPATH'"
					echo "Successfully extracted HedgeModManager archive"
					writelog "Info" "${FUNCNAME[0]} - Removing archive '$HMMARCHIVENAME' after successful extraction"
					rm "$HMMARCHIVEPATH"
					echo "$HMMVER" > "$HMMVERFILE"  # Update version on successfull download and extract
				else
					# Download failed
					writelog "WARN" "${FUNCNAME[0]} - Failed to extract HedgeModManager archive at '$HMMSPATH'" 
					echo "Failed to extract HedgeModManager archive"
				fi
			else
				# Download failed
				writelog "WARN" "${FUNCNAME[0]} - Failed to download latest HedgeModManager Development archive ('$HMMVER') to '$( basename "$HMMSETUP" )'"
				echo "Failed to download latest HedgeModManager development release archive"
			fi			
		else
			# We have executable - Nothing to do
			writelog "INFO" "${FUNCNAME[0]} - Found existing and up-to-date HedgeModManager executable at '$HMMSPATH'"
			echo "Found up-to-date HedgeModManager executable - Nothing to download"
		fi
	}

	# Download latest HedgeModManager stable release 
	function dlLatestHMMStable {
		getLatestHMMVer

		# These values return the version URL from GitHub, so when we called "basename" we're getting the URL basename
		# The format that comes back is something like /releases/7.8-2/HedgeModManager.exe
		if [ -n "$HMMSETUP" ]; then
			mkProjDir "$HMMDLDIR"
			HMMSETUPBASE="$( basename "$HMMSETUP" )"
			HMMVER="$( dirname "$HMMSETUP" )"
			HMMVER="${HMMVER##*/}"
			HMMSPATH="$HMMDLDIR/$HMMSETUPBASE"

			echo "Latest available version is '$HMMVER' - Checking to see if we are up-to-date"
			checkLatestHMM "$HMMVER" "$HMMSPATH"

			if [ ! -f "$HMMSPATH" ] || [ "$HMMUPDATEAVAILABLE" -eq 1 ]; then
				DLURL="${HMMPROJURL//"HedgeModManager"}$HMMSETUP"
				writelog "INFO" "${FUNCNAME[0]} - Downloading '$HMMSETUPBASE' to '$( basename "$HMMDLDIR" )' from '$DLURL'"
				echo "Downloading HedgeModManager ${HMMVER}"
				notiShow "$(strFix "$NOTY_HMMDL" "$HMMVER")" "X"
				dlCheck "$DLURL" "$HMMSPATH" "X" "Downloading HedgeModManager $HMMSETUP $HMMVER" &>/dev/null
				if [ -f "$HMMSPATH" ]; then
					writelog "INFO" "${FUNCNAME[0]} - Successfully downloaded HedgeModManager $HMMVER - continuing installation"
					echo "Successfully downloaded HedgeModManager $HMMVER to '$( basename "$HMMSETUP" )'"
					echo "$HMMVER" > "$HMMVERFILE"
				else
					writelog "ERROR" "${FUNCNAME[0]} - Failed to download HedgeModManager from '$DLURL'"
					echo "Failed to download HedgeModManager"
				fi
			else
				writelog "INFO" "${FUNCNAME[0]} - HedgeModManager executable already downloaded - Nothing to do"
				echo "HedgeModManager is up-to-date"
			fi
		else
			writelog "SKIP" "${FUNCNAME[0]} - No HMMSETUP defined - nothing to download - skipping"
			echo "Could not find HedgeModManager release"
		fi
	}

	# Internet connection check
	if ! ping -q -c1 github.com &>/dev/null; then
		writelog "WARN" "${FUNCNAME[0]} - Looks like we're offline or GitHub is down, not attempting to download HedgeModManager when offline - May cause issues if no HMM exe is downloaded!"
		writelog "WARN" "${FUNCNAME[0]} - Will still attempt to install Winetricks as they may be cached"
		echo "WARNING: Can't reach GitHub - Not attempting to download HedgeModManager"

		# Set HMMVER offline if we have it in the HMMVERFILE + some warning logging if there is no version file
		if [ -f "$HMMVERFILE" ]; then
			HMMVER="$( head -n 1 "$HMMVERFILE" )"
			if [ -z "$HMMVER" ]; then
				writelog "WARN" "${FUNCNAME[0]} - HedgeModManager version stored in HMMVERFILE at '$HMMVERFILE' appears to be empty, installation may have failed last time!"
			else
				writelog "INFO" "${FUNCNAME[0]} - HedgeModManager version stored in HMMVERFILE is '$HMMVER' - It seems like HedgeModManager successfully installed before, so running offline should work fine"
			fi

			if [ -f "$HMMDLDIR/${HMM}.exe" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Offline HedgeModManager executable found in '$HMMDLDIR/${HMM}.exe' - Assuming that this is a valid, pre-downloaded HMM executable that the user placed for offline use"
				HMMSPATH="$HMMDLDIR/$HMMSETUP"
			else
				writelog "WARN" "${FUNCNAME[0]} - No Offline HedgeModManager executable found in '$HMMDLDIR' with name '${HMM}.exe' - Installation will probably not work when we get to 'installHMM' stage!"
			fi
		else
			writelog "WARN" "${FUNCNAME[0]} - No HMMVERFILE found at '$HMMVERFILE' - HedgeModManager may not have been installed and so may fail to start offline!"
		fi
	fi

	DLVER="$1"
	if [ -z "$DLVER" ]; then
		writelog "INFO" "${FUNCNAME[0]} - No value passed for whether user wants stable or development HedgeModManager - Assuming they want stable!"
	fi
	writelog "INFO" "${FUNCNAME[0]} - User wants HedgeModManager '${DLVER:-stable}'"

	# This will come from desktop file usually
	if [[ "$DLVER" = "$HMMAUTO" ]]; then
		DLVER="$HMMDLVER"
	fi

	if [[ "$DLVER" = "$HMMDEV" ]]; then
		# Get latest GitHub artifacts ver
		writelog "INFO" "${FUNCNAME[0]} - Checking latest available HedgeModManager Development version"
		echo "Checking latest available HedgeModManager Development version"

		dlLatestHMMDev
	else
		# If we don't pass dev, assume we want stable
		writelog "INFO" "${FUNCNAME[0]} - Checking latest available HedgeModManager Release/Stable version"
		echo "Checking latest available HedgeModManager Release version"
		
		dlLatestHMMStable
	fi
}

# NOTE: Winetricks *needs* GE-Proton to install dotnet48 correctly!
function setHMMVars {
	HMMPFX="${HMMCOMPDATA}/pfx"
	if [ -z "$HMMEXE" ]; then
		HMMEXE="$HMMDLDIR/${HMM}.exe"
		writelog "INFO" "${FUNCNAME[0]} - HMM EXE was not set - It is now '$HMMEXE'"
	fi
	HMMGAMES="$GLOBALMISCDIR/hmmgames.txt"
	if [ -z "$HMMWINE" ] || [ ! -f "$HMMWINE" ]; then
		if [ "$USEHMMPROTON" == "$NON" ]; then
			if [ ! -f "$PROTONCSV" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Looking for available Proton versions"
				getAvailableProtonVersions "up" X
			fi

			if ! grep -q "^GE" "$PROTONCSV"; then
				writelog "INFO" "${FUNCNAME[0]} - calling autoBumpGE"
				autoBumpGE "X"
			else
				writelog "INFO" "${FUNCNAME[0]} - Seems like we have a GE-Proton version available already"
			fi

			SETHMMPROT="$(grep "^GE" "$PROTONCSV" | sort -V | tail -n1)"
			
			SETHMMPROT="${SETHMMPROT%%;*}"
			
			USEHMMPROTON="$SETHMMPROT"

			touch "$FUPDATE"
			updateConfigEntry "USEHMMPROTON" "$USEHMMPROTON" "$STLDEFGLOBALCFG"
			writelog "INFO" "${FUNCNAME[0]} - USEHMMPROT is '$NON', so using latest GE-Proton"
		else
			writelog "INFO" "${FUNCNAME[0]} - USEHMMPROTON was set -- it is '$USEHMMPROTON'"
			SETHMMPROT="$USEHMMPROTON"
		fi

		# Sometimes ProtonCSV can have a version of GE-Proton that doesn't actually exist (or that used to exist, but doesn't anymore)
		#
		# This check forces it to look in the file in a different order (reverse version sort order `sort -Vr`) which should get it to find GE-Proton
		# and updates the relevant HMM Proton/Wine variables + writes out to config file 
		#
		# The real fix here is to correctly re-populate the Proton versions in ProtonCSV.txt so that STL never tries to use an invalid Proton version to begin with! 
		#
		# This check could be much cleaner, but the check is here outside of the above check to force the Proton value to get updated for any existing users
		if [ ! -f "$( getProtPathFromCSV "$SETHMMPROT" )" ]; then
			writelog "WARN" "${FUNCNAME[0]} - SETHMMPROT was not a directory -- Attempting to find it again"
			SETHMMPROT="$(grep "^GE" "$PROTONCSV" | sort -Vr | tail -n1)"
			SETHMMPROT="${SETHMMPROT%%;*}"

			if [ ! -f "$( getProtPathFromCSV "$SETHMMPROT" )" ]; then
				writelog "ERROR" "${FUNCNAME[0]} - Still could not find GE-Proton in PROTONCSV - This should be reported!"
			else
				writelog "INFO" "${FUNCNAME[0]} - SETHMMPROT was updated to value '$SETHMMPROT'"
				USEHMMPROTON="$SETHMMPROT"

				touch "$FUPDATE"
				updateConfigEntry "USEHMMPROTON" "$USEHMMPROTON" "$STLDEFGLOBALCFG"
			fi
		fi

		setModWine "SETHMMPROT" "HMMRUNPROT" "HMMWINE"
	fi
}

# Doesn't really "install" HMM, just creates the prefix for it if it doesn't already exist
# HMM's UI needs `dotnet48` to run and `d3dx9 vcrun2019 d3dcompiler_47` to render - we don't want to install this for every game, give HMM its own prefix to run in
# We can remove these if HMM ever works with Wine out of the box
function installHMM {
	if [ -f "$HMMSPATH" ]; then
		setHMMVars
		chooseWinetricks  # Force install of Winetricks earlier to prevent potential missing Winetricks var 
		if [ -f "$HMMEXE" ]; then
			writelog "INFO" "${FUNCNAME[0]} - HedgeModManager executable found at '$HMMEXE' - Checking if we need to set up its Wine prefix"
			if [ ! -d "$HMMCOMPDATA" ]; then
				writelog "INFO" "${FUNCNAME[0]} - No existing HedgeModManager prefix found - Creating one"
				echo "Installing HedgeModManager $HMMVER"
				notiShow "$( strFix "$NOTY_HMMINST" "$HMMVER" )" "X"
				mkProjDir "$HMMCOMPDATA/pfx"

				# Install dotnet48
				writelog "INFO" "${FUNCNAME[0]} - Installing dotnet48 for $HMM"
				installDotNet "$HMMPFX" "$HMMWINE" "48" "HMMPREFIX" "X"  # 'X' here is to enable the experimental '--force' parameter
				writelog "INFO" "${FUNCNAME[0]} - Done"

				# Setup prefix with Proton
				touch "${HMMCOMPDATA}/tracked_files"
				STEAM_COMPAT_CLIENT_INSTALL_PATH="$SROOT" STEAM_COMPAT_DATA_PATH="$HMMCOMPDATA" "$HMMRUNPROT" "run" 2> "$STLSHM/${FUNCNAME[0]}_protonrun.log"
				
				# Install other needed Winetricks 
				writelog "INFO" "${FUNCNAME[0]} - Installing 'd3dx9' 'vcrun2019' 'd3dcompiler_47' with '$HMMWINE' - These extra Winetricks are needed for HedgeModManager to run as well"
				OGGPFX="$GPFX"
				GPFX="$HMMPFX"
				RUNWINE="$HMMWINE"
				installWinetricksPaks "d3dx9 vcrun2019 d3dcompiler_47" "$HMMWINE" "extWine64Run"

				writelog "INFO" "${FUNCNAME[0]} - Installing extra 7zip dependency -- Experimental, may not work"
				installWinetricksPaks "7zip" "$HMMWINE" "extWine64Run"

				GPFX="$OGGPFX"
				writelog "INFO" "${FUNCNAME[0]} - Finished installing extra HedgeModManager winetricks"

				configureHMMPfxReg &>/dev/null

				writelog "INFO" "${FUNCNAME[0]} - Finished setting up HedgeModManager prefix"
				echo "Successfully installed HedgeModManager $HMMVER"
				notiShow "$NOTY_HMMINSTFIN" "X"
			else
				writelog "SKIP" "${FUNCNAME[0]} - HedgeModManager prefix already exists - Not recreating - Skipping installation"
				
				configureHMMPfxReg &>/dev/null  # The registry configuration needed may change overtime and may not have been fully configured at installation
			
				echo "Finished installing HedgeModManager"
			fi
		else
			writelog "ERROR" "${FUNCNAME[0]} - HedgeModManager '$HMMEXE' went missing - Maybe user is connected to the Internet"
			echo "HedgeModManager executable '$HMMEXE' went missing or was never downloaded to begin with - Are you connected to the Internet?"
		fi
	else
		writelog "SKIP" "${FUNCNAME[0]} - '$HMMSPATH' not found - Nothing to install - skipping"
	fi

	# Create .desktop file for 1-click install support and adding HMM to application menu
	writelog "INFO" "${FUNCNAME[0]} - Adding HedgeModManager to application menu and setting up link handlers"
	echo "Adding HedgeModManager to application menu and setting up link handlers"
	createHMMDesktopFile
}

# Remove Steam reg keys - needed to get HMM to find games with our prefix
function configureHMMPfxReg {
	writelog "INFO" "${FUNCNAME[0]} - Removing extra Steam registry keys from HedgeModManager prefix '$HMMPFX'"

	# Reg paths
	HKLMSTEAM="HKEY_LOCAL_MACHINE\\Software\\Wow6432Node\\Valve\\Steam"
	HKCUSTEAM="HKEY_CURRENT_USER\\Software\\Valve\\Steam"
	KHCUSTEAMACTPRO="${HKCUSTEAM}\\ActiveProcess"

	# Reg values
	STEXE="SteamExe"
	STPA="SteamPath"
	INSTPA="InstallPath"
	STCLIDLL="SteamClientDll"
	STCLIDLL64="SteamClientDll64"

	# HKEY_LOCAL_MACHINE
	updateWineRegistryKey "delete" "$HKLMSTEAM" "$INSTPA" "$HMMPFX" "$HMMWINE"

	# KEY_CURRENT_USER
	updateWineRegistryKey "delete" "$HKCUSTEAM" "$STEXE" "$HMMPFX" "$HMMWINE"
	updateWineRegistryKey "delete" "$HKCUSTEAM" "$STPA" "$HMMPFX" "$HMMWINE"

	# ActiveProcess
	updateWineRegistryKey "delete" "$KHCUSTEAMACTPRO" "$STPA" "$HMMPFX" "$HMMWINE"
	updateWineRegistryKey "delete" "$KHCUSTEAMACTPRO" "$STCLIDLL" "$HMMPFX" "$HMMWINE"
	updateWineRegistryKey "delete" "$KHCUSTEAMACTPRO" "$STCLIDLL64" "$HMMPFX" "$HMMWINE"

	writelog "INFO" "${FUNCNAME[0]} - Finished removing registry keys from HedgeModManager prefix"
}

# Game-specific Winetricks
function prepareHMMGameWinetricks {
	# HMMGTWEAKAID="$1"  # Game AppID
	HMMGINSTPFX="$2"  # Prefix to install winetricks to (i.e. game prefix) 

	# Set GPFX to game's prefix - Can't guarantee current GPFX will be the game's prefix so force it to ensure winetrick(s) are installed to the game's prefix and not HMM's prefix
	OGGPFX="$GPFX"
	GPFX="$HMMGINSTPFX"
	writelog "SKIP" "${FUNCNAME[0]} - No known tweaks needed for HMM mods currently - skipping"
	# case $HMMGTWEAKAID in
	# "71340")
	# 	writelog "INFO" "${FUNCNAME[0]} - AppID '$HMMGTWEAKAID' determined to be Sonic Generations"
	# 	GPFXSTUS="$HMMGPFX/$DRCU/$STUS"
	# 	if [ -d "$GPFXSTUS" ]; then
	# 		# Install d3d to Sonic Generations' prefix
	# 		writelog "INFO" "${FUNCNAME[0]} - Applying 'd3dcompiler_47' winetrick for Direct3D 11 mod support"
	# 		echo "Sonic Generations: Installing 'd3dcompiler_47' for Direct3D 11 mod support"
		
	# 		RUNWINE="$HMMWINE"
	# 		installWinetricksPaks "d3dcompiler_47" "$HMMWINE" "extWine64Run" &>/dev/null
	# 		writelog "INFO" "${FUNCNAME[0]} - Finished installing 'd3dcompiler47' for Sonic Generations"
	# 	else
	# 		writelog "INFO" "${FUNCNAME[0]} - Seems like Sonic Generations is not installed - skipping"
	# 	fi
	# 	;;
	# esac
	GPFX="$OGGPFX"
}

# Install dotnet48 for every 64bit game
function prepareHMMGames {
	setHMMVars
	
	# Get all hardcoded HMM supported games
	writelog "INFO" "${FUNCNAME[0]} - Reading all hardcoded HedgeModManager supported games from '$HMMGAMES'"
	echo "Setting up installed HedgeModManager compatible games"
	notiShow "$NOTY_HMMCONFIG" "X"
	while read -r HMMG; do
		# Get HMM game information from hmmgames.txt lines - games are stored as: "game name";appid;"architecture"
		HMMGN="$( echo "$HMMG" | cut -d ";" -f 1 | cut -d '"' -f2 )"
		HMMGAID="$( echo "$HMMG" | cut -d ";" -f 2 | cut -d '"' -f2 )"
		HMMGARCH="$( echo "$HMMG" | cut -d ";" -f 3 | cut -d '"' -f2 )"

		# Sometimes on Steam Deck it seems like the Wineprefix is created in a different library folder than the one the game is installed in
		# Might be a Steam Client bug, but if it persists / if this is the new behaviour, this check may need updated!
		HMMGAPPMA="$( listAppManifests | grep -m1 "${HMMGAID}.acf" )"
		HMMGPFX="$( setGPfxFromAppMa "$HMMGAID" "$HMMGAPPMA" )"
		if [ ! -d "$HMMGPFX" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Wineprefix for game '$HMMGN ($HMMGAID)' did not already exist at '$HMMGPFX' - The game may not have been started before!"
		fi

		# If HMM game is 64bit, installed and has a compatdata dir, install dotnet48 for that game
		if [[ "$HMMGARCH" = "64" ]]; then
			GPFX="$HMMPFX"

			# Check if we have a valid compatdata for a game (pfx/drive_c/users/steamuser)
			GPFXSTUS="$HMMGPFX/$DRCU/$STUS"
			if [ -d "$GPFXSTUS" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Found compatdata dir for '$HMMGN' at '$GPFXSTUS' - Assuming it is installed"

				writelog "INFO" "${FUNCNAME[0]} - Install dotnet48 for install 64bit HedgeModManager game '$HMMGN'"
				notiShow "$( strFix "$NOTY_HMMGAMCONFIG" "$HMMGN" )" "X"
				if [ -z "$1" ]; then
					echo "Running configuration for '$HMMGN'"
					installDotNet "$HMMGPFX" "$HMMWINE" "48" "$HMMGN" &>/dev/null
					writelog "INFO" "${FUNCNAME[0]} - Finished installing dotnet48 for '$HMMGN'"
				else
					echo "Running configuration for '$HMMGN' using --force"
					installDotNet "$HMMGPFX" "$HMMWINE" "48" "$HMMGN" "X" &>/dev/null
					writelog "INFO" "${FUNCNAME[0]} - Finished installing dotnet48 for '$HMMGN' using --force"
				fi
			else
				writelog "SKIP" "${FUNCNAME[0]} - Could not find compatdata dir for '$HMMGN' - Assuming that it is not installed"
			fi
		else
			writelog "SKIP" "${FUNCNAME[0]} - '$HMMGN' is 32bit, skipping"
		fi

		writelog "INFO" "${FUNCNAME[0]} - Checking if we need to apply any game-specific tweaks to improve mod compatibility"
		prepareHMMGameWinetricks "$HMMGAID" "$HMMGPFX"
	done <$HMMGAMES
	echo "Finished configuring installed HedgeModManager games" 
}

function startHMM {
	# TODO HMM button on UI somewhere in future? Not sure
	HMMDLVERARG="$1"
	HMMDOTNETFORCE="$2"

	dlLatestHMM "$HMMDLVERARG"
	installHMM

	# If this variable has *any* value, `--force` will be added to the installDotNet for each HMM game - This essentially forces a reinstall of dotnet for each game on each HMM bootup
	prepareHMMGames "$HMMDOTNETFORCE" 
	
	writelog "INFO" "${FUNCNAME[0]} - Starting HedgeModManager in prefix '$HMMPFX' with Wine '$HMMWINE' and using executable at '$HMMEXE'"
	echo "Starting HedgeModManager"
	notiShow "$( strFix "$NOTY_HMMSTART" "$HMMVER" )" "X"

	WINEDEBUG="-all" WINEPREFIX="$HMMPFX" "$HMMWINE" "$HMMEXE" "$HMMARGS" 2>&1 | tee "$STLSHM/${FUNCNAME[0]}.log"
}

# This will only remove the HMM Wineprefix and download executable files
# It will not remove any installed Winetricks or mods 
function uninstallHMM {
	writelog "INFO" "${FUNCNAME[0]} - Preparing to uninstall HedgeModManager"
	echo "Preparing to uninstall HedgeModManager"

	# Compatdata aka "Install" directory
	# This may not be the same one in the cfg folder if the user moved it
	if [ -d "$HMMCOMPDATA" ]; then
		writelog "INFO" "${FUNCNAME[0]} - Removing HedgeModManager compatdata folder"
		echo "Removing HedgeModManager compatdata"
		rm -rf "$HMMCOMPDATA"
	fi
	# Downloads dir - Should always be in STL cfg dir
	if [ -d "$HMMDLDIR" ]; then
		writelog "INFO" "${FUNCNAME[0]} - Removing HedgeModManager downloads directory"
		echo "Removing HedgeModManager SteamTinkerLaunch directory"
		rm -rf "$HMMDLDIR"
	fi
	# Remove desktop files
	if [ -d "$HMMDFPA" ]; then
		echo "Removing HedgeModManager Desktop file at '$HMMDFPA'" 
		rm "$HMMDFPA"
	fi
	if [ -d "$HMMDFDLPA" ]; then
		echo "Removing HedgeModManager Desktop file at '$HMMDFDLPA'"
		rm "$HMMDFPA"
	fi
	
	writelog "INFO" "${FUNCNAME[0]} - Successfully uninstalled HedgeModManager"
	echo "Uninstalled HedgeModManager"
}

function listSupportedHMMGames {
	# List HMM compatible games (taken from misc/hmmgames.txt), like:
	# Game Name (appid) (architecture)
	while read -r HMMGAME; do 
		HMMGAMENAME="$( echo "$HMMGAME" | cut -d ";" -f 1 | cut -d '"' -f2 )"
		HMMGAMEAID="$( echo "$HMMGAME" | cut -d ";" -f 2 | cut -d '"' -f2 )"
		HMMGAMEARCH="$( echo "$HMMGAME" | cut -d ";" -f 3 | cut -d '"' -f2 )"

		echo "$HMMGAMENAME ($HMMGAMEAID) ($HMMGAMEARCH-bit)"
	done < "$GLOBALMISCDIR/hmmgames.txt"
}

# Output installed HMM supported games in the format "Game (AppID) -> /path/to/prefix" 
function listInstalledHMMGames {
	writelog "INFO" "${FUNCNAME[0]} - Looking for installed HedgeModManager games"
	OGGPFX="$GPFX"
	while read -r HMMGAME; do
		HMMGN="$( echo "$HMMGAME" | cut -d ";" -f 1 | cut -d '"' -f2 )"
		HMMGAID="$( echo "$HMMGAME" | cut -d ";" -f 2 | cut -d '"' -f2 )"

		# Check if game has compatdata dir, if it does then assume it is installed
		# also attempt to preserve existing GPFX, though this will probably only be called from the command line 
		HMMGAPPMA="$( listAppManifests | grep -m1 "${HMMGAID}.acf" )"
		HMMGPFX="$( setGPfxFromAppMa "$HMMGAID" "$HMMGAPPMA" )"
		
		# Check if it has a "proper" directory structure and is not just a blank compatdata
		if [ -d "$HMMGPFX/$DRCU/$STUS" ]; then
			printf "%s (%s) -> %s\n" "$HMMGN" "$HMMGAID" "$HMMGPFX"
		fi
	done < "$GLOBALMISCDIR/hmmgames.txt"
	GPFX="$OGGPFX"
}

function listOwnedHMMGames {
	writelog "INFO" "${FUNCNAME[0]} - Looking for owned HedgeModManager games"

	HMMGAMES="$GLOBALMISCDIR/hmmgames.txt"
	while read -r line; do
		OWNEDHMMGAMELINE="$( grep "\"$line\"" "$HMMGAMES" )"
		OWNEDHMMGAMENAME="$( echo "$OWNEDHMMGAMELINE" | cut -d ";" -f 1 | cut -d '"' -f 2 )"
		OWNEDHMMGAMEAID="$( echo "$OWNEDHMMGAMELINE" | cut -d ";" -f 2 | cut -d '"' -f 2 )"
		OWNEDHMMGAMEARCH="$( echo "$OWNEDHMMGAMELINE" | cut -d ";" -f 3 | cut -d '"' -f 2 )"

		# If we have all of these, we can safely assume the game is installed -- Virtually identical logic to Vortex's list-owned
		if [ -n "$OWNEDHMMGAMENAME" ] && [ -n "$OWNEDHMMGAMEAID" ] && [ -n "$OWNEDHMMGAMEARCH" ]; then
			printf "%s (%s) (%s-bit)\n" "$OWNEDHMMGAMENAME" "$OWNEDHMMGAMEAID" "$OWNEDHMMGAMEARCH"
		fi
	done <<< "$(getOwnedAids)"
}

# Handle incoming mod download requests for HMM via "gamebananaidentifier:modurl" (ex: hedgemmgens:https://gamebanana.com/mmdl/455806,Mod,50766)
# HMM starts as a separate process for this, so it's fine to just call the exe (+selected proton +correct prefix) with the `-gb` parameter
# WILL NOT WORK WITH GAMEBANANA BROWSER URLs!!!
function dlHedgeMod {
	setHMMVars

	if [ ! -d "$HMMPFX" ]; then
		writelog "INFO" "${FUNCNAME[0]} - HedgeModManager is not installed!"
		echo "It looks like HedgeModManager is not installed. Can't download URL, please try again!"
		notiShow "$NOTY_HMMDLMODFAIL" "X"  # Temp, use strings and better message later
	else
		writelog "INFO" "${FUNCNAME[0]} - Downloading HedgeModManager mod '$1' using '$HMMEXE' in prefix '$HMMPFX' with Wine '$HMMWINE'"

		# GameBanana Mime handler and Mod ID
		BANANAHANDLER="$( echo "$1" | cut -d ":" -f 1 )"

		MODGAMENAME="$( grep "$BANANAHANDLER" "$HMMGAMES" | cut -d ";" -f 1 | cut -d '"' -f 2 )"
		MODID="$( basename "$( echo "$1" | cut -d ":" -f 3 )" | cut -d "," -f 3 )"
		
		echo "Downloading HedgeModManager $MODGAMENAME mod '$1'..."
		notiShow "$( strFix "$NOTY_HMMDLMOD" "$MODGAMENAME" "$MODID" )" "X"

		WINEDEBUG="-all" WINEPREFIX="$HMMPFX" "${HMMWINE}" "${HMMEXE}" -gb "$1" &>/dev/null
	fi
}

# Create a .desktop file entry/entries for HedgeModManager
#
# This seems to not work on Steam Deck - Maybe the .desktop file should just called xdg-open?
# Though the issue seemed more to be that HMM's desktop file wasn't being called at all from Firefox... 
function createHMMDesktopFile {
	HMMICONNM="icon256.png"
	HMMICOPATH="$HMMDLDIR/$HMMICONNM"
	HMMICOURL="${HMMPROJURL}/raw/rewrite/HedgeModManager/Resources/Graphics/${HMMICONNM}"
	
	# Download HMM icon file from HMM repo to the HMM DL folder if it wasn't already downloaded 
	if [ ! -f "$HMMICOPATH" ]; then 
		"$WGET" "$HMMICOURL" -O "$HMMICOPATH"
	fi

	# Generate application launch .desktop file - Re-create each time to set correct path
	if [ -f "$HMMDFPA" ]; then
		rm "$HMMDFPA"
	fi
	writelog "INFO" "${FUNCNAME[0]} - Creating new HedgeModManager desktop file at '$HMMDFPA'"
	{
		echo "[Desktop Entry]"
		echo "Type=Application"
		echo "Categories=Game;"
		echo "Name=${HMMNICE}"
		echo "Comment=A mod manager for Hedgehog Engine games on PC (Installed by SteamTinkerLaunch)"
		echo "MimeType=x-scheme-handler/hedgemm"
		echo "Exec=$(realpath "$0") ${HMM,,} start ${HMMAUTO} \"%u\""  # "hmm start" takes dl channel as argument, next arg is the URL
		echo "Icon=${HMMICOPATH}"
		echo "Terminal=false"
		echo "X-KeepTerminal=false"
	} > "$HMMDFPA"

	# Get all HMM mime handlers in use on GameBanana from hardcoded list in hmmgames.txt
	HMMGAMEMIMES="x-scheme-handler/hedgemm"
	while read -r HMMGAME; do
		# 4th col in hmmgames.txt is the MimeType name
		HMMGAMEMIMES+=";x-scheme-handler/$( echo "$HMMGAME" | cut -d ";" -f 4 | cut -d '"' -f2 )"
	done < "$GLOBALMISCDIR/hmmgames.txt"

	if [ ! -f "$HMMDFDLPA" ]; then
		writelog "INFO" "${FUNCNAME[0]} - Creating HedgeModManager Desktop file for handing supported game MimeTypes"
	else
		writelog "INFO" "${FUNCNAME[0]} - Updating HedgeModManager Desktop file for handing supported game MimeTypes"
		rm "$HMMDFDLPA"
	fi

	# Create Desktop file for handling mod dowwnloads using HMM handlers
	{
		echo "[Desktop Entry]"
		echo "Type=Application"
		echo "Categories=Utilities;"
		echo "Name=${HMM} ($PROGNAME) - GameBanana Handler"
		echo "Comment=Link Handler - For internal use only"
		echo "Icon=$STLICON"
		echo "MimeType=$HMMGAMEMIMES"
		echo "Terminal=false"
		echo "X-KeepTerminal=false"
		echo "Path=$HMMDLDIR"
		echo "Exec=$(realpath "$0") ${HMM,,} u %u"  # "hmm start" takes dl channel as argument, next arg is the URL
		echo "NoDisplay=false"
		echo "Hidden=false"
	} >> "$HMMDFDLPA"

	# Associate GameBanana Mimes with DL desktop file
	if [ -x "$(command -v "$XDGMIME" 2>/dev/null)" ]; then
		writelog "INFO" "${FUNCNAME[0]} - Setting download defaults for HedgeModManager GameBanana protocols via '$XDGMIME' pointing at '$HMMDFDLPA'"
		for HMMMIME in ${HMMGAMEMIMES//;/ }; do
			"$XDGMIME" default "$HMMDFDL" "$HMMMIME"
		done
	else
		writelog "SKIP" "${FUNCNAME[0]} - Required Mime handler '$XDGMIME' not found - couldn't set download defaults for HedgeModManager GameBanana protocols - skipping"
	fi
}

### HEDGEMODMANAGER (HMM) END

#### MO2 + Vortex ####
# NOTE: This was written with MO2 and Vortex in mind (seems to also currently work for HMM)
# It relies on projects having proper releases and tagging
# It may need tweaking if this is used for other projects in future or might require an entirely new function
function getLatestGitHubExeVer {
    SETUPNAME="$1"
    PROJURL="$2"

    RELEASESURL="${PROJURL}/releases"
    EXPANDEDASSETSURL="${RELEASESURL}/expanded_assets"
    TAGSURL="${PROJURL}/tags"

    TAGSGREP="${RELEASESURL#"$GHURL"}/tag"

    LATESTTAG="$("$WGET" -q "${TAGSURL}" -O - 2> >(grep -v "SSL_INIT") | grep -m1 "$TAGSGREP" | grep -oE "${TAGSGREP}[^\"]+")"
    LATESTVER="${LATESTTAG##*/}"

    LATESTRELEASEURL="${EXPANDEDASSETSURL}/${LATESTVER}"

    SETUPFILE="$("$WGET" -q "${LATESTRELEASEURL}" -O - 2> >(grep -v "SSL_INIT") | grep "exe" | grep -m1 "$SETUPNAME" | grep -oE "${SETUPNAME}[^\"]+")"
    echo "${SETUPFILE}"
}

#### VORTEX START: ####

function addVortexStage {
	if [ ! -f "$VORTEXSTAGELIST" ]; then 
		{
		echo "# List of directories, which ${VTX^} uses as 'Stage directories'"
		echo "# (see Wiki for a comprehensive description)"
		} > "$VORTEXSTAGELIST"
	fi

	if [ -z "$1" ]; then
		export CURWIKI="$PPW/${VTX^}"
		TITLE="${PROGNAME}-AddVortexStage"
		pollWinRes "$TITLE"

		NEWVS="$("$YAD" --f1-action="$F1ACTION" --window-icon="$STLICON" --form --center --on-top "$WINDECO" \
		--file --directory \
		--title="$TITLE" \
		--text="$(spanFont "$GUI_SELECTVORTEXDIR" "H")" "$GEOM")"
	else
		if [ -d "$1" ]; then
			NEWVS="$1"
		elif [ -d "$(dirname "$1")" ]; then
			if mkProjDir "$1"; then
				NEWVS="$1"
			else
				writelog "SKIP" "${FUNCNAME[0]} - Skipping invalid argument '$1'"
			fi
		fi
	fi
	
	if [ -n "$NEWVS" ]; then
		echo "$NEWVS" >> "$VORTEXSTAGELIST"
		rmDupLines "$VORTEXSTAGELIST"
	fi
}

function wineVortexRun {
	sleep 1 # required!
	LC_ALL="C" PATH="$STLPATH" LD_LIBRARY_PATH="" LD_PRELOAD="" WINE="$VORTEXWINE" WINEARCH="win64" WINEDEBUG="-all" WINEPREFIX="$VORTEXPFX" "$@" > "$VWRUN" 2>/dev/null
}

function cleanVortex {
	MSCOR="mscorsvw.exe"
	if "$PGREP" "$MSCOR" >/dev/null; then
		writelog "INFO" "${FUNCNAME[0]} - Killing leftovers of $MSCOR"
		"$PKILL" -9 "$MSCOR"
	fi
}

function setVortexDLMime {
	writelog "INFO" "${FUNCNAME[0]} - INFO: Linking Nexus Mods downloads to ${VTX^}"

	VD="$VTX-${PROGNAME,,}-dl.desktop"
	FVD="$HOME/.local/share/applications/$VD"

	if [ ! -f "$FVD" ]; then
		writelog "INFO" "${FUNCNAME[0]} - Creating new desktop file $FVD"
		{
		echo "[Desktop Entry]"
		echo "Type=Application"
		echo "Categories=Utilities;"
		echo "Name=${VTX^} ($PROGNAME - ${PROGNAME,,})"
		echo "Comment=Link Handler - For internal use only"
		echo "Icon=$STLICON"
		echo "MimeType=x-scheme-handler/nxm;x-scheme-handler/nxm-protocol"
		echo "Terminal=false"
		echo "X-KeepTerminal=false"
		echo "Path=$(dirname "$VORTEXEXE")"
		echo "Exec=$(realpath "$0") $VTX u %u"
		echo "NoDisplay=false"
		echo "Hidden=false"
		} >> "$FVD"
		
		MO2D="$MO-${PROGNAME,,}-dl.desktop"
		FMO2D="$HOME/.local/share/applications/$MO2D"
		if [ -f "$FMO2D" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Renaming desktopfile ${FMO2D} to ${FMO2D}-off, because '$VD' was created"
			mv "$FMO2D" "${FMO2D}-off"
		fi
	else
		if grep -q "$VORTEXPFX" "$FVD"; then
			writelog "INFO" "${FUNCNAME[0]} - Desktopfile $FVD seems to be up2date"
			return
		else
			writelog "INFO" "${FUNCNAME[0]} - Renaming desktopfile $FVD and creating a new one for ${PROGNAME,,}"
			mv "$FVD" "$FVD-old"
			setVortexDLMime
		fi	
	fi

	# setting mime types for nxm
	if [ -x "$(command -v "$XDGMIME" 2>/dev/null)" ]; then
		writelog "INFO" "${FUNCNAME[0]} - Setting download defaults for nexusmod protocol via $XDGMIME pointing at $VD"
		"$XDGMIME" default "$VD" x-scheme-handler/nxm
		"$XDGMIME" default "$VD" x-scheme-handler/nxm-protocol
	else
		writelog "SKIP" "${FUNCNAME[0]} - $XDGMIME not found - couldn't set download defaults for nexusmod protocol - skipping"
	fi
}

function getLatestVortVer {
	VSET="$VTX-setup"
	writelog "INFO" "${FUNCNAME[0]} - Search for latest ${VTX^} stable Release"
	VORTEXSETUP="$(getLatestGitHubExeVer "$VSET" "$VORTEXPROJURL")"
	writelog "INFO" "${FUNCNAME[0]} - Found '$VORTEXSETUP'"
	echo "VORTEXSETUP=$VORTEXSETUP" > "$VTST"
}

function dlLatestVortex {
	getLatestVortVer

	if [ -n "$VORTEXSETUP" ]; then
		export VSPATH="$VORTEXDLDIR/$VORTEXSETUP"

		# download:
		if [ ! -d "$VORTEXDLDIR" ]; then
			mkProjDir "$VORTEXDLDIR"
		fi

		if [ ! -f "$VSPATH" ]; then
			VVRAW="$(grep -oP "${VSET}-\K[^X]+" <<< "$VORTEXSETUP")"
			VORTEXVERSION="${VVRAW%.exe}"
			
			DLURL="$VORTEXPROJURL/releases/download/v$VORTEXVERSION/$VORTEXSETUP"
			# no idea how the sha512 is formatted in the yaml, so simply checking the size
			DLCHK="stat"
			INCHK="$("$WGET" -q "${DLURL//$VORTEXSETUP/latest.yml}" -O - 2> >(grep -v "SSL_INIT") | grep "size:" | gawk -F': ' '{print $2}')"

			writelog "INFO" "${FUNCNAME[0]} - Downloading $VORTEXSETUP to $VORTEXDLDIR from '$DLURL'"
			if [ -n "$1" ]; then
				notiShow "$(strFix "$NOTY_DLCUSTOMPROTON" "$VORTEXSETUP")" "S"
				dlCheck "$DLURL" "$VSPATH" "$DLCHK" "Downloading '$VORTEXSETUP'" "$INCHK"
				notiShow "$(strFix "$NOTY_DLCUSTOMPROTON2" "$VORTEXSETUP")" "S"
			else
				notiShow "$(strFix "$NOTY_DLCUSTOMPROTON" "$VORTEXSETUP")"
				dlCheck "$DLURL" "$VSPATH" "$DLCHK" "Downloading '$VORTEXSETUP'" "$INCHK"
				notiShow "$(strFix "$NOTY_DLCUSTOMPROTON2" "$VORTEXSETUP")"
			fi
		fi	
	else
		writelog "SKIP" "${FUNCNAME[0]} - No VORTEXSETUP defined - nothing to download - skipping"
	fi
}

function getVortexStage {
	if [ -z "$VORTEXSTAGING" ]; then
		WANTSTAGE="$1"
		mkProjDir "$WANTSTAGE"
		if [ -d "$WANTSTAGE" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Created dir '$WANTSTAGE' $PARTLOG"
			VORTEXSTAGING="$WANTSTAGE"
		fi
	fi 	
}

function getInstalledGamesWithVortexSupport {
	getVortexSupported
	if [ "$(listInstalledGameIDs | wc -l)" -eq 0 ]; then
		writelog "SKIP" "${FUNCNAME[0]} - No installed games found!"
	else
		mapfile -t -O "${#INSTGAMES[@]}" INSTGAMES <<< "$(listInstalledGameIDs)"
		mapfile -t -O "${#INSTVGAMES[@]}" INSTVGAMES <<< "$(comm -12 <(printf "%s\n" "${VOSTIDS[@]}" | sort -u) <(printf "%s\n" "${INSTGAMES[@]}" | sort -u))"
		if [ -n "$1" ]; then
			printf "%s\n" "${INSTVGAMES[@]}"
		fi
	fi
}

function dlVortexSupportedList {
	VORTEXGAMES="$GLOBALMISCDIR/$VOGAT"
	VORTSUPURL="https://www.nexusmods.com/about/vortex/"
	VORTHTMLLIST="$STLSHM/${VOGAT//txt/html}"
	VORTTMPLIST="$STLSHM/${VOGAT//.txt/-temp.txt}"

	if [ ! -f "$VORTHTMLLIST" ]; then
		dlCheck "$VORTSUPURL" "$VORTHTMLLIST" "X" "Downloading list of ${VTX^} supported games"
	fi

	awk '/supported-games/,/Vortex FAQ/' "$VORTHTMLLIST" | grep -oP "(?<=<li><a href=).*" | grep -v "Nexus Mods" | sed "s:^\"/:\":; s:\">:\";\":; s:</a></li>:\":" | sort -o "$VORTTMPLIST"
	readarray -t VTXOLGAMES <<<"$( grep -wF -f "$VORTTMPLIST" "$VORTEXGAMES" > "${VORTTMPLIST//-temp/-temp2}"
	{
		cat "${VORTTMPLIST//-temp/-temp2}"
		comm -23 "$VORTEXGAMES" "${VORTTMPLIST//-temp/-temp2}"
	} | sort -u )"

	for VTXOLG in "${VTXOLGAMES[@]}"; do
		VTXGN="$( echo "$VTXOLG" | cut -d ";" -f 2 | cut -d '"' -f 2 )"
		VTXGAID="$( echo "$VTXOLG" | cut -d ";" -f 3 | cut -d '"' -f 2 )"
		printf "%s (%s)\n" "$VTXGN" "$VTXGAID"
	done

	rm "${VORTTMPLIST//-temp/-temp2}" "$VORTTMPLIST" 2>/dev/null
}

function getGameSteamCollections {
	SCGAME="$1"

	if [ -z "$SUSDA" ] || [ -z "$STUIDPATH" ]; then
		setSteamPaths
	fi
	if [ -d "$SUSDA" ]; then
		SC="$STUIDPATH/$SRSCV"

		if [ ! -f "$SC" ]; then
			writelog "SKIP" "${FUNCNAME[0]} - File '${SC##*/}' not found in steam userid dir - skipping"
		else
			writelog "INFO" "${FUNCNAME[0]} - File '${SC##*/}' found in steam userid dir - searching collections for game '$SCGAME'"

			while read -r SCAT; do
				mapfile -t -O "${#GSCATS[@]}" GSCATS <<< "$SCAT"
			done <<< "$(sed -n "/\"$SCGAME\"/,/}/p;" "$SC" | sed -n "/\"tags\"/,/}/p" | sed -n "/{/,/}/p" | grep -v '{\|}' | awk '{print $2}' | sed "s:\"::g")"
			if [ -n "$2" ]; then
				OUT1="$(printf "%s," "${GSCATS[@]}")"
				printf "%s\n" "${OUT1%*,}"
			fi
		fi
	else
		writelog "SKIP" "${FUNCNAME[0]} - '$SUSDA' not found - this should not happen! - skipping"
	fi
}

function VortexGamesDialog {
	writelog "INFO" "${FUNCNAME[0]} - Opening ${VTX^} Dialog for en/disabling ${VTX^} for installed games"
	setVortexVars
	getInstalledGamesWithVortexSupport
	export CURWIKI="$PPW/${VTX^}"
	TITLE="${PROGNAME}-${VTX^} Toggle"
	pollWinRes "$TITLE"

	setShowPic
	VGNLIST="$STLSHM/VGNLIST.txt"
	VGNSCLIST="$STLSHM/VGNSCLIST.txt"

	VINGAMES="$(while read -r f; do
		loadCfg "$GEMETA/$f.conf" X
		VTXGAMFILENAME="$( grep "$f" "$VORTEXGAMES" | cut -d ";" -f 2 | cut -d '"' -f 2 )"
		if [ -n "$VTXGAMFILENAME" ]; then
			GNAM="$VTXGAMFILENAME"
			GNAM="$( echo "${VTXGAMFILENAME//$'\n'/;}" | cut -d ";" -f 2 )"
		fi
		writelog "INFO" "${FUNCNAME[0]} - Game is '$VTXGAMFILENAME'"

		if [ ! -f "$STLGAMEDIRID/${f}.conf" ]; then
			writelog "SKIP" "${FUNCNAME[0]} - Game config '$STLGAMEDIRID/${f}.conf' not found, so creating a minimal one from '$STLDEFGAMECFG'"
			grep -v "config Version" "$STLDEFGAMECFG" >> "$STLGAMEDIRID/${f}.conf"
		fi

		if grep -q "Vortex" <<< "$(getGameSteamCollections "$f" "X")"; then
			echo TRUE
			echo "$f"
			echo "$GNAM"
			echo "$GUI_Y"
			echo "$f" >> "$VGNSCLIST"
		else
			if grep -q "^USEVORTEX=\"0\"" "$STLGAMEDIRID/${f}.conf" || ! grep -q "^USEVORTEX=" "$STLGAMEDIRID/${f}.conf"; then
				echo FALSE
				echo "$f"
				echo "$GNAM"
				echo "$GUI_N"
			else
				echo TRUE
				echo "$f"
				echo "$GNAM"
				echo "$GUI_N"
			fi
		fi
	done <<< "$(printf "%s\n" "${INSTVGAMES[@]}")" | \
	"$YAD" --f1-action="$F1ACTION" --image "$SHOWPIC" --image-on-top --window-icon="$STLICON" --center "$WINDECO" --list --checklist --column="Use Vortex" --column="Game ID" --column="Game Title" --column "Vortex Steam Collection" --separator=";" --print-column="2" \
	--text="$(spanFont "$GUI_VINFO" "H")\n<span font=\"italic\">($GUI_VINFO1)</span>" --title="$TITLE" "$GEOM")"
	case $? in
		0)
			while read -r checkvgame; do
				VGNAM="$(grep "^$checkvgame" "$VGNLIST" | awk -F ';' '{print $2}')"
				GVCFG="$STLGAMEDIRID/${checkvgame}.conf"

				if ! grep -q "$checkvgame" <<< "${VINGAMES[@]}"; then
					writelog "INFO" "${FUNCNAME[0]} - Disabling ${VTX^} for '$VGNAM' in '$GVCFG', if not already disabled"
					touch "$FUPDATE"
					updateConfigEntry "USEVORTEX" "0" "$GVCFG"
					if grep -q "$checkvgame" "$VGNSCLIST" 2>/dev/null; then
						writelog "WARN" "${FUNCNAME[0]} - To really disable ${VTX^} for '$VGNAM', the game needs to be removed from the ${VTX^} Steam Collection manually"
					fi
				else
					writelog "INFO" "${FUNCNAME[0]} - Enabling ${VTX^} for '$VGNAM' if not already enabled"
					touch "$FUPDATE"
					updateConfigEntry "USEVORTEX" "1" "$GVCFG"
				fi
			
			done <<< "$(printf "%s\n" "${INSTVGAMES[@]//\"/}")"			
			
		;;
		1) writelog "INFO" "${FUNCNAME[0]} - Selected CANCEL"
		;;
	esac

	rm "$VGNLIST" "$VGNSCLIST" 2>/dev/null
}

function VortexSymDialog {
	setVortexVars
	VPDRC="$VORTEXPFX/$DRC"
	if [ -d "$VPDRC" ]; then
		export CURWIKI="$PPW/${VTX^}"	
		TITLE="${PROGNAME}-${VTX^} Symlinks"
		pollWinRes "$TITLE"

		setShowPic

		cd "$VPDRC" >/dev/null || return
		find . -type l -printf '%p\n%l\n' | "$YAD" --f1-action="$F1ACTION" --image "$SHOWPIC" --image-on-top --window-icon="$STLICON" --center "$WINDECO" --list --column="Symlink in '${VPDRC}/'" --column="Points to Game WinePrefix" --print-column="3" \
		--text="$(spanFont "$GUI_VOSY" "H")\n" --title="$TITLE" "$GEOM"
		cd - >/dev/null || return
	else
		writelog "SKIP" "${FUNCNAME[0]} - Directory '$VPDRC' not found "
	fi
}

function getVortexSupported {
	function gVSIDs {
		SDIR="$1"
		if [ -d "$SDIR" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Searching for SteamIDs in '$SDIR'"
			mapfile -t -O "${#VOSTIDS[@]}" VOSTIDS <<< "$(grep -iR "STEAMAPP_ID =\|STEAM_ID =\|steamAppId:" "$SDIR" | grep -v "module.exports" | grep -oP "'\K[^']+" | grep "[0-9]" | sort -u)"
		fi
	}

	setVortexVars
	VGPDIR="$VORTEXINSTDIR/$RABP"
	VUPDIR="$VORTEXPFX/$DRCU/$STUS/$APDA/Vortex/plugins"

	gVSIDs "$VGPDIR"
	gVSIDs "$VUPDIR"
}

# If extra formatting is added this file may need updated 
function getVortexSupportedNames {
	VOSTINDEXJS="index.js"
	VOSTINFOJSON="info.json"

	VORTEXPFX="${VORTEXCOMPDATA//\"/}/pfx"
	VORTEXINSTDIR="$VORTEXPFX/$BTVP"
	VORTEXEXE="$VORTEXINSTDIR/${VTX^}.exe"

	if [ ! -f "$VORTEXEXE" ]; then
		writelog "ERROR" "${FUNCNAME[0]} - Cannot get Vortex game list - No Vortex executable at '$VORTEXEXE' - Vortex may not be installed"
		echo "Cannot get Vortex game list - Are you sure Vortex is installed?"
		return
	fi

	VGPDIR="$VORTEXINSTDIR/$RABP"
	for VOSTGAMDIR in "$VGPDIR/game-"*/; do
		if [ -f "$VOSTGAMDIR/$VOSTINDEXJS" ] && [ -f "$VOSTGAMDIR/$VOSTINFOJSON" ]; then
			# Get Vortex game name from the Vortex supported gamedir's `info.json` file  
			VOSTGAMDIRNAM="$( "$JQ" '.name' "$VOSTGAMDIR/$VOSTINFOJSON" | sed 's-^"--g;s-^Game:--g;s-"$--g;s-^Stub:--g;s-^Game--g;s-^\ --g' )"

			# Match Steam AppIDs from `index.js` file - grep order is order if preference to search on 
			VOSTGAMDIRAID="$( sed "s-'--g;s-\"--g" "$VOSTGAMDIR/$VOSTINDEXJS" | grep -ioE "steamAppId: [0-9]+|STEAMAPP_ID = [0-9]+|STEAM_ID = [0-9]+|APPID = [0-9]+|steamId: [0-9]+" | grep -oE "[0-9]+" | head -n1 )"

			# If we still can't find it, try to find it based on the domain name (*usually* but not always, this is directory name without game- pfx)
			# from the Vortex games list (this list may be incomplete, so we don't search on it by default)
			if [ -z "$VOSTGAMDIRAID" ]; then
				VORTEXGAMES="$GLOBALMISCDIR/$VOGAT"
				VSGDN="$( basename "$VOSTGAMDIR" | sed 's:game-::g' )"
				VOSTGAMDIRAID="$( grep -im1 "$VSGDN" "$VORTEXGAMES" | cut -d ";" -f 3 | cut -d '"' -f 2 )"
				# If we *STILL* can't find it, search Vortex games list based on the game's "full" name in `info.json`
				if [ -z "$VOSTGAMDIRAID" ]; then
					VOSTGAMDIRAID="$( grep -im1 "$VOSTGAMDIRNAM" "$VORTEXGAMES" | cut -d ";" -f 3 | cut -d '"' -f 2 )"
					# Special hack for kotor as Vortex groups these two games together annoyingly and doesn't list them separately - an improved way to handle this would be welcome
					if [[ $VOSTGAMDIRNAM = *"Knights of the Old Republic"* ]]; then 
						printf "Star Wars: Knights of the Old Republic (32370)\nStar Wars: Knights of the Old Republic II (208580)\n"
						continue 
					fi
				fi 
			fi
			
			printf '%s (%s)\n' "$VOSTGAMDIRNAM" "$VOSTGAMDIRAID"
		else
			writelog "SKIP" "${FUNCNAME[0]} - Could not find '$VOSTINDEXJS' or '$VOSTINFOJSON' for Vortex game in '$VOSTGAMDIR' - Skipping"
		fi
	done
}

function checkVortexRegs {
	function addReg {
		MODGREG="$STLSHM/modgames.reg"
		if [ ! -f "$MODGREG" ]; then
			echo "Windows Registry Editor Version 5.00" > "$MODGREG"
		fi
		{
			echo "[$1]"
			echo "\"$2\"=\"$3\""
		} >> "${MODGREG}"
	}

	if grep -q "Wow6432Node" <<< "$1"; then
		REGKEY="$1"
		REG32KEY="${REGKEY//\\Wow6432Node\\/}"
	elif grep -q "WOW6432Node" <<< "$1"; then
		REGKEY="${1//WOW6432Node/Wow6432Node}"
		REG32KEY="${REGKEY//\\Wow6432Node\\/}"
	else
		REG32KEY="$1"
		REGKEY="${REG32KEY//Software\\\\/Software\\\\Wow6432Node\\\\}"
	fi
	PATHKEY="$2"
	INSTP="$3"

	writelog "INFO" "${FUNCNAME[0]} - Checking RegKey '$REGKEY' and updating RegKey '$REG32KEY' in registry for game '$NEXUSGAMEID' now"

	# check if registry path exists:
	if wineVortexRun "$VORTEXWINE" reg QUERY "$REGKEY" >/dev/null ; then
		writelog "INFO" "${FUNCNAME[0]} - Registry path $REGKEY already set"
		# value of the currently set registry path:
		REGPATH="$(wineVortexRun "$VORTEXWINE" reg QUERY "$REGKEY" | grep -i "$PATHKEY" | awk -F 'REG_SZ' '{print $NF}' | awk '{$1=$1};1' | tr -d "\n\r")"
		if [ "$REGPATH" == "${INSTP//\\\\/\\}" ]; then
			writelog "INFO" "${FUNCNAME[0]} - The registry entry '$REGPATH' for '$PATHKEY' is identical to the gamepath '${INSTP//\\\\/\\}'"
		else
			if [ -n "$REGPATH" ]; then
				writelog "WARN" "${FUNCNAME[0]} - The registry entry '$REGPATH' for '$PATHKEY' is not equal to gamepath '${INSTP//\\\\/\\}' - resetting registry to '${INSTP//\\\\/\\}'"
			else
				writelog "WARN" "${FUNCNAME[0]} - The registry entry for '$PATHKEY' is empty - resetting registry to '${INSTP//\\\\/\\}'"
			fi
			wineVortexRun "$VORTEXWINE" reg DELETE "$REGKEY" /f >/dev/null
		fi						
	else
		writelog "NEW" "${FUNCNAME[0]} - Registry path '$REGKEY' does not exist - creating '$PATHKEY' entry for '$INSTP'"
	fi
	if [ -n "$INSTP" ]; then
		addReg "$REG32KEY" "$PATHKEY" "$INSTP"
	else
		writelog "SKIP" "${FUNCNAME[0]} - INSTP is empty - REG32KEY is '$REG32KEY' and PATHKEY is '$PATHKEY'"
	fi
}

function setVortSet {
	echo "${VTX^}.exe --set $1" >> "$VORTSETCMD"
}

function runVortex {
	cd "$VORTEXINSTDIR" >/dev/null || return
	wineVortexRun "$VORTEXWINE" "${VTX^}.exe" "$@"
	cd - >/dev/null || return
}

function runVortSetCmd {
	if [ -f "$VORTSETCMD" ]; then
		rmDupLines "$VORTSETCMD"
		cd "$VORTEXINSTDIR" >/dev/null || return
		wineVortexRun "$VORTEXWINE" "$VORTSETCMD"
		cd - >/dev/null || return
	fi
}

function setVortexDLPath {
	# configure Vortex Download Dir:
	if [ ! -d "$VORTEXDOWNLOADPATH" ]; then
		writelog "INFO" "${FUNCNAME[0]} - Creating ${VTX^} Download Dir '$VORTEXDOWNLOADPATH'"
		mkProjDir "$VORTEXDOWNLOADPATH"
	fi

	VDPF="$VORTEXDOWNLOADPATH/__vortex_downloads_folder"
	if [ ! -f "$VDPF" ]; then
		echo "{\"instance\":\"empty\"}" > "$VDPF"
	fi

	VORTEXDOWNLOADWINPATH="Z:${VORTEXDOWNLOADPATH//\//\\\\}"
	writelog "INFO" "${FUNCNAME[0]} - Setting ${VTX^} Download WinDir '$VORTEXDOWNLOADWINPATH' in ${VTX^}"
	echo "@echo off" > "$VORTSETCMD"
	setVortSet "settings.downloads.path=true"
	setVortSet "settings.downloads.path=\\\"$VORTEXDOWNLOADWINPATH\\\""
}

function setGameVortexStaging {
	VGAMEDIR="$1"

	if [ ! -d  "$VGAMEDIR" ]; then
		writelog "ERROR" "${FUNCNAME[0]} - argument 1 '$1' is no valid directory - can't continue"
	else
		writelog "INFO" "${FUNCNAME[0]} - Looking for the mount point of the partition where the game dir '$VGAMEDIR' is"
		# find matching Staging Directory:
		GAMEMP="$(df -P "$VGAMEDIR" | awk 'END{print $NF}')"
		writelog "INFO" "${FUNCNAME[0]} - Mount point of partition where the game is installed: '$GAMEMP'"
		unset CONFSTAGE VORTEXSTAGING

		if [ -f "$VORTEXSTAGELIST" ]; then
			CONFSTAGE="$(grep "${GAMEMP}/" "$VORTEXSTAGELIST")"
		fi

		if [ -n "$CONFSTAGE" ]; then
			if [ -d "$CONFSTAGE" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Configured VORTEXSTAGING dir found: '$CONFSTAGE'"
				VORTEXSTAGING="$CONFSTAGE"
			else
				writelog "ERROR" "${FUNCNAME[0]} - Configured entry '$CONFSTAGE' found in '$VORTEXSTAGELIST', but this isn't a useable directory"
			fi
		fi

		if [ -z "$VORTEXSTAGING" ]; then
			if [ "$DISABLE_AUTOSTAGES" -eq 1 ]; then
				writelog "SKIP" "${FUNCNAME[0]} - VORTEXSTAGING is empty and autostages was disabled by the user - skipping vortex"
				USEVORTEX="0"
			else
				PARTLOG=" - using that as VORTEXSTAGING dir for all games on partition' $GAMEMP'"
				HOMEMP="$(df -P "${STLVORTEXDIR%/*}" | awk 'END{print $NF}')"
				writelog "INFO" "${FUNCNAME[0]} - HOMEMP is $HOMEMP and GAMEMP is $GAMEMP"

				# don't pollute base steam installation with a ~/.steam/steam/Vortex dir, so default to $STLVORTEXDIR/stageing
				if [ "$GAMEMP" == "$HOMEMP" ]; then	
					getVortexStage "$STLVORTEXDIR/staging"
				fi

				# try in base directory of the partition:
				getVortexStage "$GAMEMP/${VTX^}"

				# then try in the current SteamLibrary dir besides steamapps, as it should be writeable by the user and is unused from steam(?):
				getVortexStage "$(awk -F 'steamapps' '{print $1}' <<< "$VGAMEDIR")${VTX^}"

				# updating Vortex config with the new found VORTEXSTAGING dir:
				touch "$VORTEXSTAGELIST"
				if [ -n "$VORTEXSTAGING" ]; then
					if ! grep -q "$VORTEXSTAGING" < "$VORTEXSTAGELIST"; then
						writelog "INFO" "${FUNCNAME[0]} - Adding '$VORTEXSTAGING' to the ${VTX^} Stage List '$VORTEXSTAGELIST'"
						addVortexStage "$VORTEXSTAGING"
					fi
				fi
			fi
		fi

		if [ -z "$VORTEXSTAGING" ]; then
			writelog "SKIP" "${FUNCNAME[0]} - No useable staging directory autodetected - giving up"
			USEVORTEX="0"
		fi

		if [ -n "$VORTEXSTAGING" ]; then
			writelog "INFO" "${FUNCNAME[0]} - VORTEXSTAGING set to '$VORTEXSTAGING' - configuring '$NEXUSGAMEID' Staging folder installPath"
			VGSGM="$VORTEXSTAGING/$NEXUSGAMEID/mods"

			writelog "INFO" "${FUNCNAME[0]} - Creating ${VTX^} Staging folder '$VGSGM'"
			mkProjDir "$VGSGM"

			VGSGMSF="$VGSGM/__vortex_staging_folder"
			if [ ! -f "$VGSGMSF" ]; then
				echo "{\"instance\":\"empty\",\"game\":\"NEXUSGAMEID\"}" > "$VGSGMSF"
			fi

			GAMESTAGINGWINFOLDER="Z:${VGSGM//\//\\\\}"
			GAMESTAGINGWINFOLDER="${GAMESTAGINGWINFOLDER//$NEXUSGAMEID/\{GAME\}}"
			writelog "INFO" "${FUNCNAME[0]} - Setting Staging folder '$GAMESTAGINGWINFOLDER' in Vortex"

			setVortSet "settings.mods.installPath.$NEXUSGAMEID=true"
			setVortSet "settings.mods.installPath.$NEXUSGAMEID=\"\\\"$GAMESTAGINGWINFOLDER\\\"\""
			setVortSet "settings.mods.activator.$NEXUSGAMEID=\"\\\"hardlink_activator\\\"\""
		fi
	fi
}

function activateVortexGame {
	NEXUSGAMEID="$(grep "\"$1\"" "$VORTEXGAMES" | cut -d ';' -f1)"
	NEXUSGAMEID="${NEXUSGAMEID//\"}"
	if [ -n "$NEXUSGAMEID" ]; then
 # TODO check if the game is already activated
#		if ! grep -q "lastActiveProfile.$NEXUSGAMEID" "$VWRUN"; then
			NEXRAND="$(tr -dc 'a-zA-Z0-9' < /dev/urandom | fold -w 9 | head -n1)" # valid?
			writelog "INFO" "${FUNCNAME[0]} - Activating game '$NEXUSGAMEID' ($1) in ${VTX^}" "E"
			setVortSet "settings.mods.activator.$NEXUSGAMEID=\"\\\"hardlink_activator\\\"\""
			setVortSet "settings.profiles.activeProfileId=\"\\\"$NEXRAND\\\"\""
			setVortSet "settings.profiles.lastActiveProfile.$NEXUSGAMEID=\"\\\"$NEXRAND\\\"\""
			setVortSet "settings.profiles.nextProfileId=\"\\\"$NEXRAND\\\"\""
			runVortSetCmd
#		else
#			writelog "SKIP" "${FUNCNAME[0]} - Seems like '$NEXUSGAMEID' ($1) is already activated in ${VTX^}" "E"
#		fi
	else
		writelog "ERROR" "${FUNCNAME[0]} - No valid  NEXUSGAMEID found for '$1'" "E"
	fi
}

function setupGameVortex {
	VZGAMEDIR="Z:${1//\//\\\\}"
	VORTGETSET="$STLSHM/vortgetset.txt"

	if [ ! -f "$VORTGETSET" ]; then 
		WINEDEBUG="-all" WINEPREFIX="$VORTEXPFX" "$VORTEXWINE" "$VORTEXEXE" "--get" "settings" > "$VORTGETSET" 2>/dev/null
	fi

	if [ -f "$VORTGETSET" ] && grep -q "$NEXUSGAMEID=\"hardlink_activator\"" "$VORTGETSET"; then
		writelog "SKIP" "${FUNCNAME[0]} - '$NEXUSGAMEID' is already added to Vortex"
	else
		writelog "INFO" "${FUNCNAME[0]} - Activating game dir '$VZGAMEDIR' for '$NEXUSGAMEID ($VAID)' in Vortex"
		setVortSet "settings.gameMode.discovered.$NEXUSGAMEID.environment.SteamAPPId=\"\\\"$VAID\\\"\""
		setVortSet "settings.gameMode.discovered.$NEXUSGAMEID.hidden=false"
		setVortSet "settings.gameMode.discovered.$NEXUSGAMEID.path=true"
		setVortSet "settings.gameMode.discovered.$NEXUSGAMEID.path=\"\\\"$VZGAMEDIR\\\"\""
		setVortSet "settings.gameMode.discovered.$NEXUSGAMEID.pathSetManually=true"
	fi
}

function setInstPathReg {
	NEXUSGAMEFILE="$VORTEXINSTDIR/$RABP/game-$NEXUSGAMEID/index.js"

	if [ ! -f "$NEXUSGAMEFILE" ]; then
		writelog "WARN" "${FUNCNAME[0]} - Could not find '$NEXUSGAMEFILE' - maybe ${VTX} uses a different name for the game than '$NEXUSGAMEID'?"
	else
		writelog "INFO" "${FUNCNAME[0]} - Found '$NEXUSGAMEFILE' - looking for usable data"

		# search registry install path in NEXUSGAMEFILE
		if grep -E 'instPath.*winapi.RegGetValue' "$NEXUSGAMEFILE" -A1 | grep "HKEY_LOCAL_MACHINE" -q ; then
			writelog "INFO" "${FUNCNAME[0]} - Found some instPath registry value in '$NEXUSGAMEFILE' - trying to extract it"
			REGKEY=""
			PATHKEY=""
			RAWREG="$(grep -E 'instPath.*winapi.RegGetValue' "$NEXUSGAMEFILE" -A3 | tr -d "\n\r" | awk -F 'RegGetValue' '{print $2}' | cut -d';' -f1 | tr -s " " | sed "s:^(::g" | sed "s:)$::g" | sed 's/, /,/g' | awk '{$1=$1;print}')"

			if [ -n "$RAWREG" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Analyzing found registry snippet $RAWREG"

				if grep -q "HKEY" <<< "$RAWREG"; then
					writelog "INFO" "${FUNCNAME[0]} - Found a HKEY entry: $RAWREG - working on it"
					SNIP="','S" # :)
					REGWIP1="${RAWREG//HINE$SNIP/HINE\\S}"
					REGWIP="${REGWIP1//T_USER','S/T_USER\\\\S}"
					
					writelog "INFO" "${FUNCNAME[0]} - REGWIP is $REGWIP"

					REGWIPKEY="$(awk -F ',' '{print $1}' <<< "$REGWIP" | sed "s:'::g")"
					PATHKEY="$(awk -F ',' '{print $2}' <<< "$REGWIP" | sed "s:'::g")"

					if grep -q -i "WOW6432Node" <<< "$REGWIPKEY"; then
						writelog "INFO" "${FUNCNAME[0]} - Squeezing in a 'WOW6432Node' into the '$REGWIPKEY' string"
						REGKEY="${REGWIPKEY/[Ss][Oo][Ff][Tt][Ww][Aa][Rr][Ee]/Software\\\\\\WOW6432Node}"
					else
						REGKEY="$REGWIPKEY"
					fi

					writelog "INFO" "${FUNCNAME[0]} - Final REGKEY is '$REGKEY'"
				else
					if grep -q "hive" <<< "$RAWREG"; then
						writelog "INFO" "${FUNCNAME[0]} - Found a hive, key, name placeholder - required?"
					else
						writelog "SKIP" "${FUNCNAME[0]} - No valid registry found in cut entry '$RAWREG' - skipping"
					fi
				fi
			else
				writelog "SKIP" "${FUNCNAME[0]} - Haven't found any useable registry entries in '$NEXUSGAMEFILE' - skipping registry insert"
			fi

			# insert registry key when found:
			if [ -n "$REGKEY" ] && [ -n "$PATHKEY" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Inserting registry key '$REGKEY' '$PATHKEY' 'Z:${VGAMEDIR//\//\\\\}'"
				checkVortexRegs "$REGKEY" "$PATHKEY" "Z:${VGAMEDIR//\//\\\\}"
			else
				writelog "SKIP" "${FUNCNAME[0]} - REGKEY '$REGKEY' or PATHKEY '$PATHKEY' is empty - skipping registry insert"
			fi
		fi
	fi
}

function prepareVortexGame {
	VAID="$1"
	if grep -q "\"$VAID\"" "$SEENVORTEXGAMES" 2>/dev/null; then
		NEXUSGAMEID="$(grep "\"$VAID\"" "$VORTEXGAMES" | cut -d ';' -f1)"
		writelog "INFO" "${FUNCNAME[0]} - '$NEXUSGAMEID ($VAID)' is already setup for '${VTX^}' - remove from '$SEENVORTEXGAMES' for retry"
	else
		if grep -q "\"$VAID\"" "$VORTEXGAMES"; then
			if [ -z "$NEXUSGAMEID" ]; then
				NEXUSGAMEID="$(grep "\"$VAID\"" "$VORTEXGAMES" | cut -d ';' -f1)"
				NEXUSGAMEID="${NEXUSGAMEID//\"}"
				updateConfigEntry "NEXUSGAMEID" "$NEXUSGAMEID" "$STLGAMECFG"
				updateConfigEntry "NEXUSGAMEID" "$NEXUSGAMEID" "$GEMETA/$AID.conf"
			fi

			VGNAME="$(grep "\"$VAID\"" "$VORTEXGAMES" | cut -d ';' -f2)"
			VGNAME="${VGNAME//\"}"
			writelog "INFO" "${FUNCNAME[0]} - $(strFix "$NOTY_PREPVTX" "$VGNAME" "$VAID" "$NEXUSGAMEID")"
			notiShow "$(strFix "$NOTY_PREPVTX" "$VGNAME" "$VAID" "$NEXUSGAMEID")" "S" 
			# prepare symlinks in VORTEXPFX
			VAPPMAFE="$(listAppManifests | grep -m1 "${VAID}.acf")"
			VGPFX="$(setGPfxFromAppMa "$VAID" "$VAPPMAFE")"

			GPFXSTUS="$VGPFX/$DRCU/$STUS"
			if [ -d "$GPFXSTUS" ]; then
				setModGameSyms "set" "$VGPFX" "$VGNAME" "$VAID" "$VORTEXPFX" "$VAPPMAFE"
				VGAMEDIR="$(getGameDirFromAID "$VAID")"
				writelog "INFO" "${FUNCNAME[0]} - Game dir for '$VAID' found is: '$VGAMEDIR')"
				setInstPathReg
				checkVortexRegs "HKEY_LOCAL_MACHINE\\Software\\\Wow6432Node\\\Valve\\\Steam\\\Apps\\$VAID" "Installed Path" "Z:${VGAMEDIR//\//\\\\}"
				setModGameReg "$VORTEXPFX" "$VORTEXWINE"
			fi

			grep "\"$VAID\"" "$VORTEXGAMES" >> "$SEENVORTEXGAMES"
			rmDupLines "$SEENVORTEXGAMES"
			if [ ! -d  "$VGAMEDIR" ]; then
				writelog "ERROR" "${FUNCNAME[0]} - variable VGAMEDIR '$VGAMEDIR' is no valid directory - can't continue"
			elif [ -z  "$VGAMEDIR" ]; then
				writelog "ERROR" "${FUNCNAME[0]} - variable VGAMEDIR does not exist - can't continue"
			else
				setupGameVortex "$VGAMEDIR"
				setGameVortexStaging "$VGAMEDIR"
			fi

			if [ -z "$2" ]; then
				writelog "INFO" "${FUNCNAME[0]} - $(strFix "$NOTY_APPLVTX" "$NEXUSGAMEID" "$VORTSETCMD")"
				notiShow "$(strFix "$NOTY_APPLVTX" "$NEXUSGAMEID" "$VORTSETCMD")" "S" 
				runVortSetCmd
				writelog "INFO" "${FUNCNAME[0]} - Symlinks, registry entries and $VTX settings for '$NEXUSGAMEID' should be ready at this point for ${VTX^}"
			fi
		else
			writelog "SKIP" "${FUNCNAME[0]} - Skip game '$VAID' is not supported by ${VTX^} or the ID is not listed in '$VORTEXGAMES'" "E"
		fi
	fi
}

function prepareAllInstalledVortexGames {
	writelog "INFO" "${FUNCNAME[0]} - Preparing all installed games supported by ${VTX^}" "E"
	setVortexVars
	while read -r line ;do
		unset NEXUSGAMEID
		prepareVortexGame "$line" "X"
	done <<< "$(getInstalledGamesWithVortexSupport X)"
	writelog "INFO" "${FUNCNAME[0]} - Applying ${VTX^} settings for all games via autogenerated cmd '$VORTSETCMD'" "E"
	runVortSetCmd
	writelog "INFO" "${FUNCNAME[0]} - Symlinks, registry entries and $VTX settings for all found supported games should be ready at this point for ${VTX^}" "E"
}

function setVortexConfigVdf {
	mkdir -p "$VORTEXPFX/$DRC/$PFX86S/config"
	mkdir -p "$VORTEXPFX/$DRC/$PFX86S/$SAC"
	VTXSTCFG="$VORTEXPFX/$DRC/$PFX86S/$COCOV"
	writelog "INFO" "${FUNCNAME[0]} - Updating '$COCOV' in the ${VTX^} pfx, to make newly games available when auto-detectable"
	cp "$CFGVDF" "$VTXSTCFG"
	while read -r line; do
		BIF="$(awk '{print $2}' <<< "$line")"
		BIF="${BIF//\"}"
		sed "s:$BIF:Z\:$BIF:" -i "$VTXSTCFG"
	done <<< "$(grep "BaseInstallFolder" "$VTXSTCFG")"
}

function resetVortexSettings {
	setVortexVars
	runVortex "--get" "settings"
	grep -v "^info\: Epic" "$VWRUN" > "$STLSHM/vortsetbefore.txt"
	rm "$VWRUN" 2>/dev/null
	setVortexDLPath
	setVortexConfigVdf
	rm "$SEENVORTEXGAMES" 2>/dev/null
	prepareAllInstalledVortexGames
	runVortex "--get" "settings"
	grep -v "^info\: Epic" "$VWRUN" > "$STLSHM/vortsetafter.txt"
	
	writelog "INFO" "${FUNCNAME[0]} - Diff between ${VTX^} settings before and after reset:" "E"
	diff -u "$STLSHM/vortsetbefore.txt" "$STLSHM/vortsetafter.txt"
}

function startVortex {
	setVortexVars
	askVortex "$1"
	if [ "$USEVORTEX" -eq 1 ]; then
		if [ ! -f "$VORTEXEXE" ]; then
			writelog "WARN" "${FUNCNAME[0]} - VORTEXEXE '$VORTEXEXE' does not exist - installing now"
			StatusWindow "$(strFix "$NOTY_DLCUSTOMPROTON" "${VTX^}")" "dlLatestVortex S" "DownloadVortexStatus"
			StatusWindow "$(strFix "$NOTY_INSTSTART" "${VTX^}")" "installVortex" "InstallVortexStatus"
		fi

		if [ "$RUN_VORTEX_WINETRICKS" -eq 1 ]; then
			writelog "INFO" "${FUNCNAME[0]} - Starting $WINETRICKS before Vortex"
			chooseWinetricks
			WINE="$VORTEXWINE" WINEDEBUG="-all" WINEPREFIX="$VORTEXPFX" "$WINETRICKS"
		fi

		if [ "$RUN_VORTEX_WINECFG" -eq 1 ]; then
			writelog "INFO" "${FUNCNAME[0]} - Starting $WINECFG before Vortex"
			WINE="$VORTEXWINE" WINEDEBUG="-all" WINEPREFIX="$VORTEXPFX" "$WINECFG"
		fi

		if [ ! -d "$VORTEXDOTNETDIR" ] || [ ! -f "$VORTEXDOTNETDIR/dotnet.exe" ]; then
			writelog "INFO" "${FUNCNAME[0]} - DotNet6 is not installed yet"
			DNSRC="windowsdesktop-runtime-6.0.6-win-x64.exe"
			DLSITE="${VORTEXDOWNLOADPATH}/site"
			if [ ! -f "$DLSITE/$DNSRC" ]; then
				if [ -f "${VORTEXINSTDIR}/${VTXRAA}" ]; then
					RAWDNDL="$(grep -am1 "$DNSRC" "${VORTEXINSTDIR}/${VTXRAA}" | grep -oP '="\K[^"},]+')"
					echo "RAWDNDL '$RAWDNDL'"
					if grep -q "^https" <<< "$RAWDNDL"	&& grep -q "exe$" <<< "$RAWDNDL"; then
						writelog "INFO" "${FUNCNAME[0]} - Using download URL found in $VTX '${VTXRAA}'"
						DNDL="$RAWDNDL"
						dlCheck "$DNDL" "$DLSITE/$DNSRC" "X" " Downloading installer '$DNSRC' for DotNet6"
					fi		
				fi
				
				if [ ! -f "$DLSITE/$DNSRC" ]; then
					writelog "INFO" "${FUNCNAME[0]} - Using hardcoded download URL for DotNet6"
					DNDL="https://download.visualstudio.microsoft.com/download/pr/9d6b6b34-44b5-4cf4-b924-79a00deb9795/2f17c30bdf42b6a8950a8552438cf8c1/$DNSRC"
				fi
				mkdir -p "$DLSITE"
				dlCheck "$DNDL" "$DLSITE/$DNSRC" "X" " Downloading installer '$DNSRC' for DotNet6"
			fi
			if [ -f "$DLSITE/$DNSRC" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Starting installation of DotNet6 using '$DLSITE/$DNSRC'"
				cd "$DLSITE" >/dev/null || return
				wineVortexRun "$VORTEXWINE" "$DNSRC" "/quiet"
				cd - >/dev/null || return
			fi			
		fi

		if [ -f "$VORTEXEXE" ]; then
			setVortexDLMime
			setVortexDLPath
			setVortexConfigVdf

			if [ -n "$2" ] && [ "$2" -eq "$2" ] 2>/dev/null; then
				StatusWindow "${VTX^}" "prepareVortexGame $2" "PrepareVortexGameStatus"
			elif [ -n "$AID" ] && [ "$AID" != "$PLACEHOLDERAID" ]; then
				StatusWindow "${VTX^}" "prepareVortexGame $AID" "PrepareVortexGameStatus"
			fi

			if [ -n "$NEXUSGAMEID" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Starting ${VTX^} now with command 'runVortex \"--game\" \"$NEXUSGAMEID\"' in WINEPREFIX '$VORTEXPFX'"
				runVortex "--game" "$NEXUSGAMEID"
			else
				if [ "$2" == "url" ]; then
					if [ -z "$3" ]; then
						writelog "INFO" "${FUNCNAME[0]} - need arg3"
						howto
					else
						writelog "INFO" "${FUNCNAME[0]} - Starting ${VTX^} now with command 'runVortex \"-d\" \"$3\""
						runVortex "-d" "$3"
					fi
				elif [ "$2" == "getset" ]; then
					writelog "INFO" "${FUNCNAME[0]} - Showing ${VTX^} settings as requested"
					runVortex "--get" "settings"
					grep -v "^info: Epic" "$VWRUN"
					rm "$VWRUN" 2>/dev/null
				elif [ "$1" == "activate" ]; then
					writelog "INFO" "${FUNCNAME[0]} - Activating game '$2'"
					activateVortexGame "$2"
				else
					StatusWindow "${VTX^}" "prepareAllInstalledVortexGames" "PrepareVortexGameStatus"
					writelog "INFO" "${FUNCNAME[0]} - Starting ${VTX^} without options" "E"
					runVortex
				fi
			fi

			cleanVortex
			writelog "INFO" "${FUNCNAME[0]} - ${VTX^} exited - starting game now"
		else
			writelog "ERROR" "${FUNCNAME[0]} - VORTEXEXE '$VORTEXEXE' not found! - exit"
			exit
		fi
	fi
}

function setVortexSELaunch {
	if [ "$1" == "$AID" ] && [ -d "$EFD" ]; then
		SEEXE="$EFD/$2"
		if [ ! -f "$SEEXE" ]; then
			writelog "SKIP" "${FUNCNAME[0]} - Special exe '$2' for '$SGNAID' not found in gamedir '$EFD' - starting normal exe"
		else
			writelog "INFO" "${FUNCNAME[0]} - Found special exe '$2' for '$SGNAID' in gamedir '$EFD'"
			export CURWIKI="$PPW/Vortex"
			TITLE="ScriptExtenderRequester"
			pollWinRes "$TITLE"

			"$YAD" --f1-action="$F1ACTION" --window-icon="$STLICON" --center "$WINDECO" \
			--title="$TITLE" \
			--text="$GUI_SEBINFOUND '$EFD/$2'" \
			--button="${GE^^}":0 \
			--button="$BUT_SAVERUN ${GE^^}":1 \
			--button="$BUT_SAVERUN ${2^^}":2 \
			"$GEOM"
			
			case $? in
				0)  {
					writelog "INFO" "${FUNCNAME[0]} - Starting with the regular Game Exe '$GE'"
					USECUSTOMCMD="0"
					}
				;;
				1) 	{
					writelog "INFO" "${FUNCNAME[0]} - Starting with the regular Game Exe '$GE' and don't ask again"
					USECUSTOMCMD="0"
					updateConfigEntry "SELAUNCH" "0" "$STLGAMECFG"
					}
				;;
				2)  {
					writelog "INFO" "${FUNCNAME[0]} - Starting with the Script Extender Exe '$2' and saving as default"
					writelog "INFO" "${FUNCNAME[0]} - Configuring default start of special exe '$2' by enabling SELAUNCH in '$STLGAMECFG'"
					updateConfigEntry "CUSTOMCMD" "$SEEXE" "$STLGAMECFG"
					updateConfigEntry "USECUSTOMCMD" "1" "$STLGAMECFG"
					updateConfigEntry "ONLY_CUSTOMCMD" "1" "$STLGAMECFG"
					updateConfigEntry "SELAUNCH" "0" "$STLGAMECFG"
					CUSTOMCMD="$SEEXE"
					USECUSTOMCMD="1"
					ONLY_CUSTOMCMD=1
					writelog "INFO" "${FUNCNAME[0]} - Starting $SEEXE instead of the game exe directly after this ${VTX^} instance"
					}
				;;
			esac
		fi
	fi
}

function checkVortexSELaunch {
	# (mostly for Vortex)
	# if $1 is 1 check if a preconfigured exe instead of the game is defined/found - f.e. script extender for skyrim, fallout etc
	# if $1 is 2 it is assumed the check already happended before'

	if [ -z "$1" ]; then
		writelog "INFO" "${FUNCNAME[0]} - using fix '2' as SECHECK"
		SECHECK="2"
	else
		writelog "INFO" "${FUNCNAME[0]} - using argument 1 '$1' as SECHECK"
		SECHECK="$1"
	fi

	if [ "$SECHECK" -eq 0 ]; then
		writelog "INFO" "${FUNCNAME[0]} - SELAUNCH set to '$SECHECK' - skipping any SE checks and directly starting what is configured in '$STLGAMECFG'"
	else	
		if [ "$SECHECK" -eq 2 ] && [ -n "$SELAUNCH" ] && [ "$SELAUNCH" -eq 1 ]; then
			writelog "SKIP" "${FUNCNAME[0]} - Skipping option $SECHECK because SELAUNCH is already enabled"
		else
			setVortexSELaunch "377160" "f4se_loader.exe" "$SECHECK" # Fallout4
			setVortexSELaunch "611660" "f4sevr_loader.exe" "$SECHECK"	# Fallout4 VR
			setVortexSELaunch "611670" "sksevr_loader.exe" "$SECHECK" # Skyrim VR
			setVortexSELaunch "489830" "skse64_loader.exe" "$SECHECK" # Skyrim Special Edition
			setVortexSELaunch "72850" "skse_loader.exe" "$SECHECK"	# Skyrim
			setVortexSELaunch "933480" "skse_loader.exe" "$SECHECK"	# Enderal
			setVortexSELaunch "22300" "fose_loader.exe" "$SECHECK"	# Fallout 3
			setVortexSELaunch "22370" "fose_loader.exe" "$SECHECK"	# Fallout 3 GOTY
			setVortexSELaunch "22380" "nvse_loader.exe" "$SECHECK"	# Fallout New Vegas 
			setVortexSELaunch "22330" "obse_loader.exe" "$SECHECK"	# Oblivion
		fi
	fi
}

function getInstVtxVers {
	grep -ahm1 "\"version\": " "${VORTEXINSTDIR}/${VTXRAA}" | cut -d ':' -f2 | cut -d '"' -f2 # fragile
}

function VortexOptions {
	export CURWIKI="$PPW/Vortex"
	TITLE="${PROGNAME}-${FUNCNAME[0]}"

	if [ "$ONSTEAMDECK" -eq 1 ]; then
		pollWinRes "$TITLE" 1
	else
		pollWinRes "$TITLE" 4
	fi

	setShowPic

	VTXHEAD="${VTX^} Options"

	if [ -n "${VORTEXCOMPDATA}" ]; then
		TT_CODA="${VTX^} $CODA: $VORTEXCOMPDATA"
	fi

	if [ -f "${VORTEXSTAGELIST}" ]; then
		TT_STAGES="$(cat "${VORTEXSTAGELIST}")"
	fi

	if [ -f "${VORTEXINSTDIR}/${VTXRAA}" ]; then
		TT_CODA="$(printf '%s\n%s\n' "${TT_CODA}" "Version installed: $(getInstVtxVers)")"
	fi
	mkProjDir "$VORTEXDLDIR"
	VTXDLV="$(find "${VORTEXDLDIR}" -name "${VTX}-setup*" | sort -V | tail -n1 | awk -F'${VTX}-setup' '{print $NF}')"
	if [ -n "$VTXDLV" ]; then
		VSD1="${VTXDLV//${VORTEXDLDIR}\/${VTX}-setup-}"
		VSD="${VSD1//.exe}"
		TT_DL="Newest setup downloaded: ${VSD}"
	fi

	getLatestVortVer
	if [ -n "$VORTEXSETUP" ]; then
		VSO1="${VORTEXSETUP//${VTX}-setup-}"
		VSO="${VSO1//.exe}"
		TT_DL="$(printf '%s\n%s\n' "$TT_DL" "Newest setup online: ${VSO}")"
	fi
	
	if [ "$ONSTEAMDECK" -eq 1 ]; then
		INVTX="$(realpath "$0") $VTX install"
	else
		INVTX="$(realpath "$0") $VTX install gui"
	fi
	
	"$YAD" --f1-action="$F1ACTION" --image "$SHOWPIC" --image-on-top --center --window-icon="$STLICON" --form --center "$WINDECO" --title="$TITLE" \
	--text="$VTXHEAD" --columns="$COLCOUNT" --f1-action="$F1ACTIONCG" --separator="" \
	--field="$FBUT_GUISET_VTXINST!$TT_CODA":FBTN "$INVTX" \
	--field="$FBUT_GUISET_VTXSTART":FBTN "$(realpath "$0") $VTX start" \
	--field="$FBUT_GUISET_VTXSTAGE!$TT_STAGES":FBTN "$(realpath "$0") $VTX stage" \
	--field="$FBUT_GUISET_VTXGAMES":FBTN "$(realpath "$0") $VTX games" \
	--field="$FBUT_GUISET_VTXSYMS":FBTN "$(realpath "$0") $VTX symlinks" \
	--field="$FBUT_GUISET_VTXDL!$TT_DL":FBTN "$(realpath "$0") $VTX download" \
	--button="$BUT_DONE:0" "$GEOM"

	writelog "INFO" "${FUNCNAME[0]} - Selected '$BUT_DONE' - Closing Menu"
}

function setModWine {
	USEDNPROTONVAR="$1"
	USEDNPROTON="${!1}"
	DNPROTON="${!2}"
	DNWINEVAR="$3"
	INUVP="$USEDNPROTON"

	if [ -z "$DNPROTON" ] || [ ! -f "$DNPROTON" ]; then
		if [ -z "${ProtonCSV[0]}" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Getting avaialble Proton versions"
			getAvailableProtonVersions "up" X
		fi
		DNPROTON="$(getProtPathFromCSV "$USEDNPROTON")"
		if [ ! -f "$DNPROTON" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Proton version mismatch"
			DNPROTON="$(fixProtonVersionMismatch "$USEDNPROTONVAR" "$STLDEFGLOBALCFG" X)"
			writelog "INFO" "${FUNCNAME[0]} - Resolve, USEDNPROTONVAR is now '$USEDNPROTONVAR'"
		fi
		writelog "INFO" "${FUNCNAME[0]} - DNPROTON is '${DNPROTON}'"

		if [ ! -f "$DNPROTON" ]; then
			createDLProtList
			DLURL="$(printf "%s\n" "${ProtonDLList[@]}" | grep -m1 "$USEDNPROTON")"
			if [ -n "$DLURL" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Downloading: '$DLURL'" "E"
				StatusWindow "$GUI_DLCUSTPROT" "dlCustomProton ${DLURL//|/\"}" "DownloadCustomProtonStatus"
				DNPROTON="$(getProtPathFromCSV "$USEDNPROTON")"
			else
				writelog "SKIP" "${FUNCNAME[0]} - No download URL found for requested '$USEDNPROTON' - skipping" "E"
			fi
		else
			writelog "INFO" "${FUNCNAME[0]} - DNPROTON is a file -- it is '$DNPROTON'"
		fi
	fi

	if [ -n "$DNPROTON" ] && [ -f "$DNPROTON" ]; then
		export "$2"="$DNPROTON"
		CHECKDNWINED="$(dirname "$DNPROTON")/$DBW"
		CHECKDNWINEF="$(dirname "$DNPROTON")/$FBW"

		if [ -f "$CHECKDNWINED" ]; then
			FWINEVAR="$CHECKDNWINED"
		elif [ -f "$CHECKDNWINEF" ]; then
			FWINEVAR="$CHECKDNWINEF"
		else
			writelog "ERROR" "${FUNCNAME[0]} - $DNWINEVAR was not found - can't continue"
		fi
		
		if [ -f "$FWINEVAR" ]; then
			export "$DNWINEVAR"="$FWINEVAR"
		fi
		
		if [ "$INUVP" != "$USEDNPROTON" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Updating 'USEDNPROTON' in '${STLDEFGLOBALCFG##*/}' to '$USEDNPROTON'" "E"
			touch "$FUPDATE"
			updateConfigEntry "$USEDNPROTONVAR" "$USEDNPROTON" "$STLDEFGLOBALCFG"
		fi
	else
		writelog "ERROR" "${FUNCNAME[0]} - DNPROTON was not found - can't continue" "E"
	fi
}

function setVortexVars {
	VORTEXPFX="${VORTEXCOMPDATA//\"/}/pfx"
	if [ -z "$VORTEXEXE" ]; then
		VORTEXINSTDIR="$VORTEXPFX/$BTVP"
		VORTEXEXE="$VORTEXINSTDIR/${VTX^}.exe"
	fi

	if [ "$USEVORTEXPROTON" == "$NON" ]; then
		if [ ! -f "$PROTONCSV" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Looking for available Proton versions"
			getAvailableProtonVersions "up" X
		fi

		if ! grep -q "^GE" "$PROTONCSV"; then
			writelog "INFO" "${FUNCNAME[0]} - Seems like there is no GE Proton available - getting one:"
			autoBumpGE "X"
		fi

		delEmptyFile "$PROTONCSV"

		if [ ! -f "$PROTONCSV" ]; then
			writelog "ERROR" "${FUNCNAME[0]} - Could find '$PROTONCSV'"
		else
			SETVTXPROT="$(grep "^GE" "$PROTONCSV" | sort -V | tail -n1)"
			SETVTXPROT="${SETVTXPROT%%;*}"
			USEVORTEXPROTON="$SETVTXPROT"
			touch "$FUPDATE"
			updateConfigEntry "USEVORTEXPROTON" "$USEVORTEXPROTON" "$STLDEFGLOBALCFG"
			writelog "INFO" "${FUNCNAME[0]} - USEVORTEXPROTON is '$NON', so using latest Proton-GE '$SETVTXPROT' automatically" "E"
		fi
	else
		SETVTXPROT="$USEVORTEXPROTON"
	fi
	VORTEXDOTNETDIR="$VORTEXPFX/$DRC/Program Files/dotnet"

	export DOTNET_ROOT="$VTX_DOTNET_ROOT"
	
	writelog "INFO" "${FUNCNAME[0]} - Using $USEVORTEXPROTON for $VTX"

	VORTEXGAMES="$GLOBALMISCDIR/$VOGAT"
	if [ -z "$VORTEXWINE" ] || [ ! -f "$VORTEXWINE" ]; then
		setModWine "SETVTXPROT" "VORTEXPROTON" "VORTEXWINE"
	fi
}

function installVortex {
	if [ -z "$VORTEXSETUP" ]; then
		if [ -f "$VTST" ]; then 
			source "$VTST"
		fi
	fi

	if [ -z "$VSPATH" ]; then
		VSPATH="$VORTEXDLDIR/$VORTEXSETUP"
	fi

	if [ -f "$VSPATH" ]; then
		setVortexVars
		if [ -f "$VORTEXEXE" ]; then
			writelog "SKIP" "${FUNCNAME[0]} - '$VORTEXEXE' does already exists - nothing to install - skipping" "E"
		else
			if [ ! -f "$VORTEXPROTON" ]; then
				writelog "SKIP" "${FUNCNAME[0]} - VORTEXPROTON '$VORTEXPROTON' not found - can't continue" "E"
			else
				writelog "INFO" "${FUNCNAME[0]} - Using '$VORTEXPROTON' for installation" "E"
				mkProjDir "$VORTEXCOMPDATA"
				notiShow "$(strFix "$NOTY_INSTSTART" "${DOTN^}")" "S"
				installDotNet "$VORTEXPFX" "$VORTEXWINE" "48"
				touch "${VORTEXCOMPDATA}/tracked_files"
				STEAM_COMPAT_CLIENT_INSTALL_PATH="$SROOT" STEAM_COMPAT_DATA_PATH="$VORTEXCOMPDATA" "$VORTEXPROTON" "run" 2> "$STLSHM/${FUNCNAME[0]}_protonrun.log"
				notiShow "$GUI_DONE" "S"
				sleep 3
				writelog "INFO" "${FUNCNAME[0]} - Installing '$VSPATH' into '$VORTEXPFX'" E
				notiShow "$(strFix "$NOTY_INSTSTART" "${VSPATH##*/}")" "S"
				writelog "INFO" "${FUNCNAME[0]} - 'WINEDEBUG=\"-all\" WINEPREFIX=\"$VORTEXPFX\" \"$VORTEXWINE\" \"$VSPATH\" \"/S\"'" E
				WINEDEBUG="-all" WINEPREFIX="$VORTEXPFX" "$VORTEXWINE" "$VSPATH" "/S"
				notiShow "$(strFix "$NOTY_INSTSTOP" "${VSPATH##*/}")" "S"
				writelog "INFO" "${FUNCNAME[0]} - Base ${VTX^} installation finished" E
				setVortexDLMime
				notiShow "$GUI_DONE" "S"
			fi
		fi
	else
		writelog "SKIP" "${FUNCNAME[0]} - '$VSPATH' not found - nothing to install - skipping"
	fi
}

function installVortexGui {
	export CURWIKI="$PPW/Vortex"
	TITLE="${PROGNAME}-${FUNCNAME[0]}"
	pollWinRes "$TITLE"
	setShowPic

	createProtonList X

	if [ -f "${VORTEXINSTDIR}/${VTXRAA}" ]; then
		GUI_VTXINST="$(printf '%s\n%s\n' "${GUI_VTXINST}" "Version installed: $(getInstVtxVers)")"
	fi
	mkProjDir "$VORTEXDLDIR"
	VTXDLV="$(find "${VORTEXDLDIR}" -name "${VTX}-setup*" | sort -V | tail -n1 | awk -F'${VTX}-setup' '{print $NF}')"
	if [ -n "$VTXDLV" ]; then
		VSD1="${VTXDLV//${VORTEXDLDIR}\/${VTX}-setup-}"
		VSD="${VSD1//.exe}"
		GUI_VTXINST="$(printf '%s\n%s\n' "${GUI_VTXINST}" "Newest setup downloaded: ${VSD}")"
	fi

	getLatestVortVer
	if [ -n "$VORTEXSETUP" ]; then
		VSO1="${VORTEXSETUP//${VTX}-setup-}"
		VSO="${VSO1//.exe}"
		GUI_VTXINST="$(printf '%s\n%s\n' "${GUI_VTXINST}" "Newest setup online: ${VSO}")"
	fi
	
	VTXINSTARGS="$("$YAD" --f1-action="$F1ACTION" --image "$SHOWPIC" --image-on-top --window-icon="$STLICON" --form --center --on-top $WINDECO \
		--title="$TITLE" --separator="|" \
		--text="$(spanFont "$GUI_VTXINST" "H")" \
		--field="$GUI_USEVORTEXPROTON!$DESC_USEVORTEXPROTON ('USEVORTEXPROTON')":CB "$(cleanDropDown "$USEVORTEXPROTON" "$PROTYADLIST")" \
		--button="$BUT_CAN:0" --button="$BUT_INSTALL:2" "$GEOM"
		)"
		case $? in
			0)	{
					writelog "INFO" "${FUNCNAME[0]} - Selected '$BUT_CAN' - Exiting"
				}
			;;
			2)	{
					mapfile -d "|" -t -O "${#VTARR[@]}" VTARR < <(printf '%s' "$VTXINSTARGS")
					USEVORTEXPROTON="${VTARR[0]}"
					StatusWindow "$(strFix "$NOTY_DLCUSTOMPROTON" "${VTX^}")" "dlLatestVortex S" "DownloadVortexStatus"
					StatusWindow "$(strFix "$NOTY_INSTSTART" "${VTX^}")" "installVortex" "InstallVortexStatus"
				}
			;;	
		esac
}

function askVortex {
	if [ "$USEVORTEX" -eq "1" ] && [ "$1" == "ask" ]; then
		if [ "$WAITVORTEX" -gt 0 ]; then
			writelog "INFO" "${FUNCNAME[0]} - Opening ${VTX^} Requester with timeout '$WAITVORTEX'"
			fixShowGnAid
			export CURWIKI="$PPW/Vortex"
			TITLE="${PROGNAME}-OpenVortex"
			pollWinRes "$TITLE"

			setShowPic

			"$YAD" --f1-action="$F1ACTION" --image "$SHOWPIC" --image-on-top --window-icon="$STLICON" --form --center --on-top "$WINDECO" \
			--title="$TITLE" \
			--text="$(spanFont "$SGNAID - $GUI_ASKVORTEX" "H")" \
			--button="$BUT_VORTEX":0 \
			--button="$BUT_CAN":4 \
			--timeout="$WAITVORTEX" \
			--timeout-indicator=top \
			"$GEOM"

			case $? in
				0)  {
						writelog "INFO" "${FUNCNAME[0]} - Selected to Start ${VTX^}, so not disabling it"
					}
				;;
				4)  {
						writelog "INFO" "${FUNCNAME[0]} - Selected CANCEL - Not starting ${VTX^}"
						USEVORTEX="0"
					}
				;;
				70) {
						writelog "INFO" "${FUNCNAME[0]} - TIMEOUT - Not starting ${VTX^}"
						USEVORTEX="0"
					}
				;;
			esac
		else
			writelog "INFO" "${FUNCNAME[0]} - ${VTX^} Requester was skipped because WAITVORTEX is '$WAITVORTEX'"
		fi
	fi
}

# vtxWinecfg and mo2Winecfg are separate functions and separate from oneTimeWinetricks in case they may need some custom logics
function vtxWinecfg {
	setVortexVars
	getWinecfgExecutable

	if [ -d "$VORTEXPFX" ]; then
		writelog "INFO" "${FUNCNAME[0]} - Running Winecfg for Vortex"
		writelog "INFO" "${FUNCNAME[0]} - WINEDEBUG=\"-all\" WINEPREFIX=\"$VORTEXPFX\" \"$VORTEXWINE\" \"$OTWINECFGEXE\""
		WINEDEBUG="-all" WINEPREFIX="$VORTEXPFX" "$VORTEXWINE" "$OTWINECFGEXE"
	else
		writelog "ERROR" "${FUNCNAME[0]} - Vortex is not installed, cannot run Winecfg for Vortex"
		echo "Vortex is not installed, cannot run Winecfg for Vortex"
	fi
}

#### VORTEX STOP ####

function warnInvalidModToolLaunch {
	MODTOOLNAME="$1"
	"$YAD" --title="SteamTinkerLaunch - $MODTOOLNAME Invalid Usage" --text="$( strFix "$GUI_MODTOOLINVALIDUSAGE" "$MODTOOLNAME")" --button="OK"
}

#### MO2 MOD ORGANIZER START: ####

function getLatestMO2Ver {
	MO2SET="Mod.Organizer"

	writelog "INFO" "${FUNCNAME[0]} - Search for latest '$MO2SET' Release under '$MO2PROJURL'"
	MO2SETUP="$(getLatestGitHubExeVer "$MO2SET" "$MO2PROJURL")"
	if [ -n "$MO2SETUP" ]; then
		writelog "INFO" "${FUNCNAME[0]} - Found '$MO2SETUP'"
	else
		writelog "ERROR" "${FUNCNAME[0]} - Could not find any '$MO2SET' Release"
	fi
}

function dlLatestMO2 {
	getLatestMO2Ver

	if [ -n "$MO2SETUP" ]; then
		mkProjDir "$MO2DLDIR"
		MO2SPATH="$MO2DLDIR/$MO2SETUP"
		if [ ! -f "$MO2SPATH" ]; then
			MO2VRAW="$(grep -oP "${MO2SET}-\K[^X]+" <<< "$MO2SETUP")"
			MO2VERSION="${MO2VRAW%.exe}"
			DLURL="$MO2PROJURL/releases/download/v$MO2VERSION/$MO2SETUP"
			writelog "INFO" "${FUNCNAME[0]} - Downloading $MO2SETUP to $MO2DLDIR from '$DLURL'"
			
			if [ -n "$1" ]; then
				notiShow "$(strFix "$NOTY_DLCUSTOMPROTON" "$MO2SETUP")" "S"
				dlCheck "$DLURL" "$MO2SPATH" "X" "Downloading '$MO2SETUP'"
				notiShow "$(strFix "$NOTY_DLCUSTOMPROTON2" "$MO2SETUP")" "S"
			else
				notiShow "$(strFix "$NOTY_DLCUSTOMPROTON" "$MO2SETUP")"
				dlCheck "$DLURL" "$MO2SPATH" "X" "Downloading '$MO2SETUP'"
				notiShow "$(strFix "$NOTY_DLCUSTOMPROTON2" "$MO2SETUP")"	
			fi
			if [ -f "$MO2SPATH" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Download succeeded - continuing installation"
			else
				writelog "ERROR" "${FUNCNAME[0]} - Download failed!"
			fi
		fi	
	else
		writelog "SKIP" "${FUNCNAME[0]} - No MO2SETUP defined - nothing to download - skipping"
	fi
}

function setMO2Vars {
	if [ -z "$MOINST" ]; then
		MOINST="$NON"
	fi

	if [ "$MOINST" == "$NON" ]; then
		if [ -n "$GPFX" ]; then
			MOINST="portable"
			writelog "INFO" "${FUNCNAME[0]} - Found the variable for the game wineprefix '$GPFX', so using a $MOINST instance of '$MO2'"
			MO2PFX="$GPFX"
			MO2CODA="${GPFX//\/pfx}"
		else
			MOINST="global"
			writelog "INFO" "${FUNCNAME[0]} - No game wineprefix found in env, so using a $MOINST instance of '$MO2'"
			MO2CODA="$MO2COMPDATA"
			MO2PFX="${MO2COMPDATA//\"/}/pfx"
		fi
	else
		writelog "INFO" "${FUNCNAME[0]} - The '$MO2' instance was already set to '$MOINST' during this run"
	fi
	
	if [ -z "$MO2EXE" ]; then
		MO2EXE="$MO2PFX/$MOERPATH"
		NXMG="nxmhandler"
		NMXHLOG="$MO2PFX/$DRCU/$STUS/$ADLO/$MO/${NXMG}.log"
	fi
	MO2GAMES="$GLOBALMISCDIR/mo2games.txt"
	writelog "INFO" "${FUNCNAME[0]} - The $MO2 helper-file is set to '$MO2GAMES'"

	if [ -z "$MO2WINE" ] || [ ! -f "$MO2WINE" ]; then
		writelog "INFO" "${FUNCNAME[0]} - Preparing Proton variables for a $MOINST $MO2 instance"

		if [ "$MOINST" == "portable" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Using proton version '$USEPROTON', which is currently configured for the game $GAMENAME"
			SETMO2PROT="$USEPROTON"	
		else
			if [ "$USEMO2PROTON" == "$NON" ]; then
				if [ ! -f "$PROTONCSV" ]; then
					writelog "INFO" "${FUNCNAME[0]} - Looking for available Proton versions"
					getAvailableProtonVersions "up" X
				fi

				if ! grep -q "^GE" "$PROTONCSV"; then
					autoBumpGE "X"
				fi
			
				SETMO2PROT="$(grep "^GE" "$PROTONCSV" | sort -V | tail -n1)"
				SETMO2PROT="${SETMO2PROT%%;*}"
				USEMO2PROTON="$SETMO2PROT"
				touch "$FUPDATE"
				updateConfigEntry "USEMO2PROTON" "$USEMO2PROTON" "$STLDEFGLOBALCFG"
				writelog "INFO" "${FUNCNAME[0]} - USEMO2PROTON is '$NON', so using latest Proton-GE '$SETMO2PROT' automatically" "E"
			else
				SETMO2PROT="$USEMO2PROTON"
			fi
		fi
		
		writelog "INFO" "${FUNCNAME[0]} - Using $SETMO2PROT for $MO"
		setModWine "SETMO2PROT" "MO2RUNPROT" "MO2WINE"
	fi
}

function installMO2 {
	dlLatestMO2 "S"

	if [ -f "$MO2SPATH" ]; then
		setMO2Vars
		if [ -f "$MO2EXE" ]; then
			writelog "SKIP" "${FUNCNAME[0]} - '$MO2EXE' does already exists - nothing to install - skipping"
		elif [ -f "$MO2INSTFAIL" ]; then
			writelog "SKIP" "${FUNCNAME[0]} - '$MO2INSTFAIL' found - seems like installation failed previously - skipping further attempts to avoid loops"
		else
			if [ -f "$MO2RUNPROT" ]; then 
				writelog "INFO" "${FUNCNAME[0]} - Using '$MO2RUNPROT' for installation" "E"
				mkProjDir "$MO2CODA"
				touch "${MO2COMPDATA}/tracked_files"
				STEAM_COMPAT_CLIENT_INSTALL_PATH="$SROOT" STEAM_COMPAT_DATA_PATH="$MO2CODA" "$MO2RUNPROT" "run" 2> "$STLSHM/${FUNCNAME[0]}_protonrun.log"
				writelog "INFO" "${FUNCNAME[0]} - Installing '$MO2SPATH' into '$MO2PFX'"
				notiShow "$(strFix "$NOTY_INSTSTART" "${MO2SPATH##*/}")"
				# the '$MO2SPATH' installer at least fails on the Steam Deck, so using $INNOEXTRACT for the installation if available
				MININNO=1.9
				WIMOINST=1

				if [ -f "$(command -v "$INNOEXTRACT")" ]; then
					INNOVER="$("$INNOEXTRACT" --version | head -n1 | cut -d ' ' -f2)"
					if [ "$(printf '%s\n' "$MININNO" "$INNOVER" | sort -V | head -n1)" != "$MININNO" ] || grep -qi "[A-Z]" <<< "$INNOVER" ; then
						writelog "ERROR" "${FUNCNAME[0]} - Version for '$INNOEXTRACT' is invalid. You need to at least version '$MININNO'"
						writelog "ERROR" "${FUNCNAME[0]} - Starting $MO2EXE using wine/proton instead"
						WIMOINST=1
					else
						WIMOINST=0
					fi

					if [ "$WIMOINST" -eq 0 ]; then
						writelog "INFO" "${FUNCNAME[0]} - Using $INNOEXTRACT binary found in path: '$(command -v "$INNOEXTRACT")'"
						MO2DST="$MO2PFX/$MORDIR"
						mkProjDir "$MO2DST"
						"$INNOEXTRACT" -m -s -d "$MO2DST" "$MO2SPATH"
						if [ -d "$MO2DST/app" ]; then
							mv "$MO2DST/app" "$MO2DST/${MO2^^}"
							writelog "INFO" "${FUNCNAME[0]} - Installed '$MO' into '$MO2DST/${MO2^^}' using '$INNOEXTRACT'"
						else
							writelog "WARN" "${FUNCNAME[0]} - Extraction of '$MO' into '$MO2DST/${MO2^^}' using $INNOEXTRACT failed or the output directory is called differently"
						fi
					fi
				fi

				if [ "$WIMOINST" -eq 1 ]; then
					if [ "$ONSTEAMDECK" -eq 1 ]; then
						writelog "WARN" "${FUNCNAME[0]} - Unfortunately '$INNOEXTRACT' is required to install $MO on the Steam Deck, but it wasn't found"
					else
						writelog "INFO" "${FUNCNAME[0]} - '$INNOEXTRACT' not found, trying to use the installer '$MO2SPATH' regularly"
						sleep 3
						WINEDEBUG="-all" WINEPREFIX="$MO2PFX" "$MO2WINE" "$MO2SPATH" "/VERYSILENT"
					fi
				fi

				if [ ! -f "$MO2EXE" ]; then
					writelog "WARN" "${FUNCNAME[0]} - '$MO2EXE' not found after installation, creating '$MO2INSTFAIL' to avoid further attempts"
					date > "$MO2INSTFAIL"
				fi
				notiShow "$(strFix "$NOTY_INSTSTOP" "${MO2SPATH##*/}")" "S"
				writelog "INFO" "${FUNCNAME[0]} - Base ${MO} installation finished"
				notiShow "$GUI_DONE" "S"
			else
				writelog "SKIP" "${FUNCNAME[0]} - MO2RUNPROT '$MO2RUNPROT' not found, can't continue with $MO installion"
			fi
		fi
	else
		writelog "SKIP" "${FUNCNAME[0]} - '$MO2SETUP' not found - nothing to install - skipping"
	fi
}

function checkInstalledMO2Games {
	if [ -f "$MO2INSTFAIL" ]; then
		writelog "SKIP" "${FUNCNAME[0]} - '$MO2INSTFAIL' found - seems like installation failed previously - skipping ${FUNCNAME[0]}"
	elif [ ! -d "$SRCPFX" ]; then
		if [ -n "$1" ]; then
			SYMODE="$1"
		else
			SYMODE="set"
		fi

		while read -r line; do
			MGID="$(cut -d ';' -f2 <<< "$line")"
			MGID="${MGID//\"}"

			while read -r sl; do
				CHKAPMA="$sl/$SA/appmanifest_${MGID}.acf"
				if [ -f "$CHKAPMA" ]; then
					MGNA1="$(cut -d ';' -f1 <<< "$line")"
					MGNA="${MGNA1//\"}"
					MGPFX="$(dirname "$CHKAPMA")/$CODA/${MGID}/pfx"
					setModGameSyms "$SYMODE" "$MGPFX" "$MGNA" "$MGID" "$MO2PFX" "$CHKAPMA"
				fi
			done <<< "$(printf "%s\n" "${SLARR[@]}")"
		done < "$MO2GAMES"
		setModGameReg "$MO2PFX" "$MO2WINE"
	fi
}

function prepAllMO2Games {
	MO2STDIR="$MO2PFX/$DRC/$PFX86S"
	MO2SADIR="$MO2STDIR/$SA"
	mkProjDir "$MO2SADIR"
	
	rm "$MO2SADIR/$LIFOVDF" 2>/dev/null
	{
		echo "\"LibraryFolders\""
		echo "{"
		listWinSteamLibraries
		echo "}"
	} >> "$MO2SADIR/$LIFOVDF"

	checkInstalledMO2Games "$1"
}

# Output supported MO2 games in format "Name (AppID)"
function listMO2Games {
	MO2GAMES="$GLOBALMISCDIR/mo2games.txt"
	while read -r MO2GAM; do
		MO2GAMNAM="$( echo "$MO2GAM" | cut -d ";" -f 1 | cut -d '"' -f 2 )"
		MO2GAMAID="$( echo "$MO2GAM" | cut -d ";" -f 2 | cut -d '"' -f 2 )"

		printf "%s (%s)\n" "$MO2GAMNAM" "$MO2GAMAID"
	done <$MO2GAMES
}

function manageMO2GInstance {
	setMO2Vars
	if [ ! -f "$MO2EXE" ]; then
		StatusWindow "$(strFix "$NOTY_INSTSTART" "$MO")" "installMO2" "InstallMO2Status"
	fi

	echo "$MOINST" > "$LAMOINST"

	if [ -f "$MO2INSTFAIL" ]; then
		writelog "SKIP" "${FUNCNAME[0]} - '$MO2INSTFAIL' found - seems like installation failed previously - skipping ${FUNCNAME[0]}"
	else
		if [ -z "$1" ]; then
			writelog "SKIP" "${FUNCNAME[0]} - argument 1 '$1' is invalid"
		else
			writelog "INFO" "${FUNCNAME[0]} - Looking for '$1' in '$MO2GAMES'"
			if grep -q "$1" "$MO2GAMES"; then
				MO2AID="$1"
				MO2GA1="$(grep -m1 "\"$MO2AID\"" "$MO2GAMES" | cut -d ';' -f1)"
				MO2GAM="${MO2GA1//\"}"

				MO2GAMIN1="$(grep -m1 "\"$MO2AID\"" "$MO2GAMES" | cut -d ';' -f3)"
				MO2GAMINI="${MO2GAMIN1//\"}"
	
				if [ -n "$MO2GAM" ]; then
					if [ -n "$2" ] && [ "$2" == "portable" ]; then
						MOIN="$MO2PFX/$MOERDIR"
						writelog "INFO" "${FUNCNAME[0]} - preparing '$2' instance in '$MOIN' for '$1'"
						GLOBMOIN="${MO2COMPDATA//\"/}/pfx/$DRCU/$STUS/$ADLO/$MO/$MO2GAM"
					else
						MOIN="$MO2PFX/$DRCU/$STUS/$ADLO/$MO/$MO2GAM"
						GLOBMOIN="$MOIN"
					fi

					MODPRDE="$MOIN/profiles/Default"
					MODLIST="$MODPRDE/modlist.txt"
					MOININI="$MOIN/${MO}.ini"
					MOINEW=0

					GLOBZMOIN="Z:${GLOBMOIN//\//\\\\}"

					if [ ! -f "$MOININI" ]; then
						MO2GADI="$(getGameDirFromAID "$MO2AID")"

						writelog "INFO" "${FUNCNAME[0]} - Creating an initial '$MOININI'"

						if [ -d "$MO2GADI" ]; then
							MO2GAZDI="Z:${MO2GADI//\//\\\\}"
							mkProjDir "$MOIN"
							touch "$MOININI"
							{
							echo "[General]"
							echo "gameName=$MO2GAMINI"
							echo "selected_profile=@ByteArray(Default)"
							echo "gamePath=@ByteArray($MO2GAZDI)"	
							echo "[Settings]"
							echo "download_directory=${GLOBZMOIN}\\\\downloads"
							echo "cache_directory=${GLOBZMOIN}\\\\webcache"
							echo "mod_directory=${GLOBZMOIN}\\\mods"
							echo "overwrite_directory=${GLOBZMOIN}\\\\overwrite"
							echo "profiles_directory=${GLOBZMOIN}\\\\profiles"
							} >> "$MOININI"
							MOINEW=1
						else
							writelog "SKIP" "${FUNCNAME[0]} - '$MO2AID' is a supported Id, but the game installation could not be found"
						fi
					else
						writelog "INFO" "${FUNCNAME[0]} - '$MOININI' does already exist"
						if grep -q "${GLOBZMOIN}" "$MOININI"; then
							writelog "INFO" "${FUNCNAME[0]} - and it uses $PROGNAME paths"
						else
							# XXXXXXXXXXXX maybe TODO optionally add above paths if missing
							writelog "INFO" "${FUNCNAME[0]} - the file was created by the user, leaving it unmodified"
						fi
					fi
					if [ -d "$MOIN" ]; then
						if [ -n "$2" ]; then
							if [ "$2" == "portable" ]; then
								writelog "INFO" "${FUNCNAME[0]} - Using $2 instance"
								MO2INST="$2"	
							else
								writelog "INFO" "${FUNCNAME[0]} - Using $MO instance '$MO2GAM'"
								MO2INST="$MO2GAM"
							fi
						else
							if [ "$MOINEW" -eq 1 ]; then
								writelog "INFO" "${FUNCNAME[0]} - Created initial $MO instance '$MO2GAM'"
							else
								writelog "SKIP" "${FUNCNAME[0]} - $MO instance '$MO2GAM' already exists"
							fi
						fi
					fi
				else
					writelog "INFO" "${FUNCNAME[0]} - Could not find game name for '$MO2AID' - starting regularly with default instance"
				fi
			else
				STAMO2=0
				writelog "SKIP" "${FUNCNAME[0]} - '$1' is no supported $MO game"
				listMO2Games
			fi
		fi
	fi
}

function createAllMO2Instances {
	setMO2Vars
	while read -r line; do
		manageMO2GInstance "$line"
	done <<< "$(prepAllMO2Games "li" | cut -d ';' -f1)"
}

function prepareMO2 {
	setMO2Vars
	STAMO2=1
	if [ -n "$1" ] && [ "$1" != "$NON" ]; then
		if [ "$1" -eq "$1" ] 2>/dev/null; then
			if [ -n "$MOINST" ] && [ "$MOINST" == "portable" ]; then
				manageMO2GInstance "$1" "$MOINST"
			else
				manageMO2GInstance "$1"
			fi

			if [ "$2" == "disabled" ]; then
				STAMO2=0
			fi
		else
			if grep -q "^\"$1\"" "$MO2GAMES"; then
				writelog "INFO" "${FUNCNAME[0]} - Using $MO instance '$1'"
				MO2INST="$1"
			fi
		fi
	else
		if [ ! -f "$MO2EXE" ]; then
			StatusWindow "$(strFix "$NOTY_INSTSTART" "$MO")" "installMO2" "InstallMO2Status"
		fi

		if [ -f "$MO2INSTFAIL" ]; then
			writelog "SKIP" "${FUNCNAME[0]} - '$MO2INSTFAIL' found - seems like installation failed previously - skipping ${FUNCNAME[0]}"
		else
			if [ "$MOINST" == "global" ]; then
				updateMO2GlobConf
				writelog "INFO" "${FUNCNAME[0]} - Updating/creating $MO instances for $MOINST instance"
				createAllMO2Instances
				STAMO2=1
			else
				writelog "SKIP" "${FUNCNAME[0]} - $MOINST instance running - nothing to prepare"
			fi
		fi
	fi

	if [ "$STAMO2" -eq 1 ] && [ "$2" != "disabled" ]; then
		if [ ! -f "$MO2EXE" ]; then
			StatusWindow "$(strFix "$NOTY_INSTSTART" "$MO")" "installMO2" "InstallMO2Status"
		fi

		if [ "$MOINST" == "global" ]; then
			writelog "INFO" "${FUNCNAME[0]} - preparing all games for $MOINST instance"
			prepAllMO2Games "set"
		fi

		if [ -f "$MO2EXE" ]; then
			if [ "$MOINST" == "global" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Checking for instance to be launched as $MOINST instance"
				if [ -z "$MO2INST" ]; then
					if [ -f "$NMXHLOG" ]; then
						writelog "INFO" "${FUNCNAME[0]} - No $MO instance provided - searching last one found in '$NMXHLOG'"
						RINST1="$(tac "$NMXHLOG" | grep -m1 \"reg\")"
						RINST2="${RINST1##*\"reg\" }"
						RINST="$(cut -d '"' -f2 <<< "$RINST2")"
						if [ -n "$RINST" ]; then
							MO2INST1="$(grep -m1 "\"$RINST\"" "$MO2GAMES" | cut -d ';' -f1)"
							MO2INST="${MO2INST1//\"}"
							writelog "INFO" "${FUNCNAME[0]} - Found '$RINST' as last used game in '$NMXHLOG', so using instance '$MO2INST'"
							MO2AID="$(grep -m1 "\"$RINST\"" "$MO2GAMES" | cut -d ';' -f2)"
							manageMO2GInstance "${MO2AID//\"}" "X"
							if [ -z "$EFD" ]; then
								if [ -z "$APPMAFE" ]; then
									APPMAFE="$(listAppManifests | grep -m1 "${MO2AID//\"}.acf")"
								fi
								EFD="$(getGameDirFromAM "$APPMAFE")"
							fi
						fi
					else
						writelog "INFO" "${FUNCNAME[0]} - No log '$NMXHLOG' found, so the last used instance can't be determined - using last supported instance installed instead"
						LAINST="$(checkInstalledMO2Games "li" | tail -n1)"
						MO2INST="$(cut -d ';' -f2 <<< "$LAINST")"
						MO2AID="$(cut -d ';' -f1 <<< "$LAINST")"
					fi
				fi
			fi

			if [ -n "$MO2INST" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Using $MO instance '$MO2INST'"
			else
				writelog "INFO" "${FUNCNAME[0]} - No $MO instance provided"
			fi

			setMO2DLMime
		else
			writelog "ERROR" "${FUNCNAME[0]} - No '$MO2EXE' found - can't continue"
		fi
	fi
}

function startMO2 {
	prepareMO2 "$NON" "gui"
	if [ -d "${MO2EXE%/*}" ] ; then
		writelog "INFO" "${FUNCNAME[0]} - Starting '$MO2EXE'" E
		PFXSUTEMP="$GPFX/$DRCU/$STUS/Temp"
		mkProjDir "$PFXSUTEMP"
		cd "${MO2EXE%/*}" >/dev/null || return

		if [ -n "$MO2INST" ]; then
			writelog "INFO" "${FUNCNAME[0]} - WINEDEBUG=\"-all\" WINEPREFIX=\"$MO2PFX\" \"$MO2WINE\" \"$MO2EXE\" -i \"$MO2INST\"" E
			WINEDEBUG="-all" WINEPREFIX="$MO2PFX" "$MO2WINE" "$MO2EXE" -i "$MO2INST" 2>&1 | tee "$STLSHM/${FUNCNAME[0]}_${IFILE##*/}.log"
		else
			writelog "INFO" "${FUNCNAME[0]} - WINEDEBUG=\"-all\" WINEPREFIX=\"$MO2PFX\" \"$MO2WINE\" \"$MO2EXE\"" E
			WINEDEBUG="-all" WINEPREFIX="$MO2PFX" "$MO2WINE" "$MO2EXE" 2>&1 | tee "$STLSHM/${FUNCNAME[0]}_${IFILE##*/}.log"
		fi
		cd - >/dev/null || return
		mkProjDir "$PFXSUTEMP"
	elif [ -f "$MO2INSTFAIL" ]; then
		writelog "ERROR" "${FUNCNAME[0]} - '$MO2INSTFAIL' found - seems like installation failed previously - can't start '$MO'"
	else
		writelog "SKIP" "${FUNCNAME[0]} - Could not find '$MO2EXE' - can't start $MO - this should not happen" E
	fi
}

function dlMod2nexurl {
	setMO2Vars

	MONGUR1="${1//nxm:\/\/}"
	MONGURL="${MONGUR1%%/*}"
	MYPORTDLDAT="${STLMO2DLDATDIR}/${MONGURL}.conf"

	function dlMod2globnexurl {
		MYGLOBDLDAT="${STLMO2DLDATDIR}/global.conf"

		if [ -f "$MYGLOBDLDAT" ]; then
			source "$MYGLOBDLDAT"
			if [ -d "${GMO2EXE%/*}" ] && [ -f "$RUNPROTON" ] && [ -n "$STEAM_COMPAT_CLIENT_INSTALL_PATH" ] && [ -n "$STEAM_COMPAT_DATA_PATH" ]; then
				MYINST="$(grep -m1 "\"${MONGURL}\"" "$MO2GAMES" | cut -d ';' -f1)"
				MYINST="${MYINST//\"/}"
				if [ -n "$MYINST" ]; then
					writelog "INFO" "${FUNCNAME[0]} - Starting global '$RUNPROTON run ${MO}.exe -i $MYINST $1'"
					STEAM_COMPAT_CLIENT_INSTALL_PATH="$STEAM_COMPAT_CLIENT_INSTALL_PATH" STEAM_COMPAT_DATA_PATH="$STEAM_COMPAT_DATA_PATH" "$RUNPROTON" "run" "${MO}.exe" -i "$MYINST" "$1" 2>&1 | tee /tmp/RUNMO2DL.log
				else
					writelog "ERROR" "${FUNCNAME[0]} - Could not find a valid $MO instance for '${MONGURL}' - giving up"
				fi
			else
				writelog "ERROR" "${FUNCNAME[0]} - Attempted to download Url '$1' for game '$MONGURL', but seems like global '$MYGLOBDLDAT' has incomplete data - giving up" "E"
			fi
		else
			writelog "ERROR" "${FUNCNAME[0]} - Attempted to download Url '$1' for game '$MONGURL', but the source script '$MYGLOBDLDAT' for global $MO is missing - giving up" "E"
		fi
	}

	if [ -f "$LAMOINST" ] && grep -q "global" "$LAMOINST"; then
		writelog "INFO" "${FUNCNAME[0]} - The last used $MO2 instance was global', so using the global $MO installation for the download" "E"
		dlMod2globnexurl "$1"
	elif [ -f "$MYPORTDLDAT" ]; then
		source "$MYPORTDLDAT"
		if [ -d "${GMO2EXE%/*}" ] && [ -f "$RUNPROTON" ] && [ -n "$STEAM_COMPAT_CLIENT_INSTALL_PATH" ] && [ -n "$STEAM_COMPAT_DATA_PATH" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Download Url '$1' for game '$MONGURL' using data from portable '$MYPORTDLDAT'"
			cd "${GMO2EXE%/*}" >/dev/null || return
			writelog "INFO" "${FUNCNAME[0]} - Starting portable '$RUNPROTON run ${MO}.exe $1'"
			STEAM_COMPAT_CLIENT_INSTALL_PATH="$STEAM_COMPAT_CLIENT_INSTALL_PATH" STEAM_COMPAT_DATA_PATH="$STEAM_COMPAT_DATA_PATH" "$RUNPROTON" run "${MO}.exe" "$1" 2>&1 | tee /tmp/RUNMO2DL.log
			cd - >/dev/null || return
		else
			writelog "ERROR" "${FUNCNAME[0]} - Attempted to download Url '$1' for game '$MONGURL', but seems like portable '$MYPORTDLDAT' has incomplete data - trying global $MO" "E"
			dlMod2globnexurl "$1"
		fi
	else
		writelog "INFO" "${FUNCNAME[0]} - Attempted to download Url '$1' for game '$MONGURL', but the source script '$MYPORTDLDAT' for portable $MO2 is missing - trying to start a global $MO" "E"
		dlMod2globnexurl "$1"
	fi
}

function setMO2DLMime {
	setMO2Vars

	MO2D="$MO-${PROGNAME,,}-dl.desktop"
	FMO2D="$HOME/.local/share/applications/$MO2D"
	
	if [ ! -f "$FMO2D" ]; then
		writelog "INFO" "${FUNCNAME[0]} - Creating new desktop file $MO2D"
		{
		echo "[Desktop Entry]"
		echo "Type=Application"
		echo "Categories=Utilities;"
		echo "Name=$MO ($PROGNAME - ${PROGNAME,,})"
		echo "Comment=Link Handler - For internal use only"
		echo "Icon=$STLICON"
		echo "MimeType=x-scheme-handler/nxm;x-scheme-handler/nxm-protocol"
		echo "Terminal=false"
		echo "X-KeepTerminal=false"
		echo "Path=$(dirname "$MO2EXE")"
		echo "Exec=$(realpath "$0") mo2 u %u"
		echo "NoDisplay=false"
		echo "Hidden=false"
		} >> "$FMO2D"
		
		VD="$VTX-${PROGNAME,,}-dl.desktop"
		FVD="$HOME/.local/share/applications/$VD"
		if [ -f "$FVD" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Renaming desktopfile ${FVD} to ${FVD}-off, because '$MO2D' was created"
			mv "$FVD" "$FVD-off"
		fi
	else
		if grep -q "$MO2PFX" "$FMO2D"; then
			writelog "INFO" "${FUNCNAME[0]} - Desktopfile '$FMO2D' looks to be up2date"
			return
		else
			writelog "INFO" "${FUNCNAME[0]} - Renaming desktopfile '$FMO2D' and creating a new one for ${PROGNAME,,}"
			mv "$FMO2D" "$FMO2D-old"
			setMO2DLMime
		fi	
	fi

	# setting mime types for nxm

	if [ -x "$(command -v "$XDGMIME" 2>/dev/null)" ]; then
		writelog "INFO" "${FUNCNAME[0]} - Setting download defaults for nexusmod protocol via $XDGMIME pointing at $MO2D"
		"$XDGMIME" default "$MO2D" x-scheme-handler/nxm
		"$XDGMIME" default "$MO2D" x-scheme-handler/nxm-protocol
	else
		writelog "SKIP" "${FUNCNAME[0]} - $XDGMIME not found - couldn't set download defaults for nexusmod protocol - skipping"
	fi
}

function checkMO2 {
	if [ "$MO2MODE" != "disabled" ]; then
		writelog "INFO" "${FUNCNAME[0]} - MO2MODE is '$MO2MODE' - starting MO2"

		if [ "$WAITMO2" -gt 0 ]; then
			writelog "INFO" "${FUNCNAME[0]} - Opening $MO Requester with timeout '$WAITMO2'"
			fixShowGnAid
			export CURWIKI="$PPW/Mod-Organizer-2"
			TITLE="${PROGNAME}-Open-Mod-Organizer2"
			pollWinRes "$TITLE"

			setShowPic
#			--button="$BUT_MO2_SIL":4 
			"$YAD" --f1-action="$F1ACTION" --image "$SHOWPIC" --image-on-top --window-icon="$STLICON" --form --center --on-top "$WINDECO" \
			--title="$TITLE" \
			--text="$(spanFont "$SGNAID - $GUI_ASKMO2" "H")" \
			--button="$BUT_MO2_GUI":0 \
			--button="$BUT_MO2_SKIP":6 \
			--timeout="$WAITMO2" \
			--timeout-indicator=top \
			"$GEOM"

			case $? in
				0)  {
						writelog "INFO" "${FUNCNAME[0]} - Selected to start $MO with gui"
						MO2MODE="gui"
					}
				;;
				4)  {
						writelog "INFO" "${FUNCNAME[0]} - Selected to start $MO with mods silently"
						MO2MODE="silent"
					}
				;;
				6)  {
						writelog "INFO" "${FUNCNAME[0]} - Selected CANCEL - Not starting $MO at all"
						MO2MODE="disabled"
					}
				;;
				70) {
						writelog "INFO" "${FUNCNAME[0]} - TIMEOUT - Starting $MO2 gui" # with mods silently"
						MO2MODE="gui"
					}
				;;
			esac
		else
			writelog "INFO" "${FUNCNAME[0]} - $MO Requester was skipped because WAITMO2 is '$WAITMO2' - not changing MO2MODE '$MO2MODE'"
		fi
		prepareMO2 "$AID" "$MO2MODE"
		if [ "$MO2MODE" != "disabled" ] && [ "$USECUSTOMCMD" -eq 1 ]; then
			writelog "INFO" "${FUNCNAME[0]} - Disabling custom command, because $MO2 is enabled"
			USECUSTOMCMD=0
		fi
	fi
}

function mo2Winecfg {
	setMO2Vars
	getWinecfgExecutable

	if [ -d "$MO2PFX" ]; then
		writelog "INFO" "${FUNCNAME[0]} - Running Winecfg for MO2"
		writelog "INFO" "${FUNCNAME[0]} - WINEDEBUG=\"-all\" WINEPREFIX=\"$VORTEXPFX\" \"$MO2WINE\" \"$OTWINECFGEXE\""
		WINEDEBUG="-all" WINEPREFIX="$MO2PFX" "$MO2WINE" "$OTWINECFGEXE"
	else
		writelog "ERROR" "${FUNCNAME[0]} - ModOrganizer 2 is not installed, cannot run Winecfg for MO2"
		echo "ModOrganizer 2 is not installed, cannot run Winecfg for ModOrganizer 2"
	fi
}

#### MO2 MOD ORGANIZER STOP ####

# dprs:
function dlLatestDprs {
	writelog "INFO" "${FUNCNAME[0]} - Search for latest $DPRS version online"
	LATDPRS="$("$WGET" -q "${DPRSRELURL}/latest" -O - 2> >(grep -v "SSL_INIT") | grep -m1 "${DPRS}-v*.*.exe" | grep -oE "${DPRS}-v[^\"]+")"

	if [ -n "$LATDPRS" ]; then
		DSPATH="$DPRSDLDIR/$LATDPRS"

		if [ ! -f "$DSPATH" ]; then
			DPRSVR1="${LATDPRS//$DPRS-}"
			DPRSVRS="${DPRSVR1//.exe}"
		
			DLURL="$DPRSRELURL/download/$DPRSVRS/$LATDPRS"
			writelog "INFO" "${FUNCNAME[0]} - Downloading $LATDPRS to $VORTEXDLDIR from '$DLURL'"
			notiShow "$(strFix "$NOTY_DLCUSTOMPROTON" "$LATDPRS")"
			dlCheck "$DLURL" "$DSPATH" "X" "Downloading '$LATDPRS'"
			notiShow "$(strFix "$NOTY_DLCUSTOMPROTON2" "$LATDPRS")"
		else
			writelog "SKIP" "${FUNCNAME[0]} - Already have the latest version in '$DSPATH'"
		fi	
	else
		writelog "SKIP" "${FUNCNAME[0]} - No valid '$DPRS' version found ('$LATDPRS') - nothing to download - skipping"
	fi
}

function dlLatestDepsProg {
	writelog "INFO" "${FUNCNAME[0]} - Search for latest $DEPS version online"
	DEPS64ZIP="${DEPS}_x64_Release.zip"
	DEPS32ZIP="${DEPS64ZIP//64/86}"

	LATDEPSR1="$("$WGET" -q "${DEPURL}/latest" -O - 2> >(grep -v "SSL_INIT") | grep -m1 "$DEPS64ZIP")"
	LATDEPSR2="${LATDEPSR1%/*}"
	LATDEPSV="${LATDEPSR2##*/}"

	if [ -n "$LATDEPSV" ]; then
		DLDIR="$DEPSDLDIR/$LATDEPSV"

		if [ -s "$DEPSLATDIR" ] && [ "$(readlink -f "$DEPSLATDIR")" == "$(readlink -f "$DLDIR")" ]; then
			writelog "SKIP" "${FUNCNAME[0]} - Symlink '$DEPSLATDIR' already points to latest version '$DLDIR'" E
		else
			mkProjDir "$DLDIR/64"
			mkProjDir "$DLDIR/32"
			DEPS64ZPATH="$DLDIR/$DEPS64ZIP"
			DEPS32ZPATH="$DLDIR/$DEPS32ZIP"

			if [ ! -f "$DEPS64ZPATH" ]; then	
				DLURL="$DEPURL/download/$LATDEPSV/$DEPS64ZIP"
				writelog "INFO" "${FUNCNAME[0]} - Downloading $DEPS64ZIP to '$DLDIR' from '$DLURL'"
				notiShow "$(strFix "$NOTY_DLCUSTOMPROTON" "$DEPS64ZIP")" "S"
				dlCheck "$DLURL" "$DEPS64ZPATH" "X" "Downloading '$DEPS64ZIP'"
				notiShow "$(strFix "$NOTY_DLCUSTOMPROTON2" "$DEPS64ZIP")" "S"
			else
				writelog "SKIP" "${FUNCNAME[0]} - Already have '$DEPS64ZIP' in '$DLDIR'"
			fi
			
			if [ ! -f "$DEPS32ZPATH" ]; then	
				DLURL="$DEPURL/download/$LATDEPSV/$DEPS32ZIP"
				writelog "INFO" "${FUNCNAME[0]} - Downloading $DEPS32ZIP to '$DLDIR' from '$DLURL'"
				notiShow "$(strFix "$NOTY_DLCUSTOMPROTON" "$DEPS64ZIP")" "S"
				dlCheck "$DLURL" "$DEPS32ZPATH" "X" "Downloading '$DEPS32ZIP'"
				notiShow "$(strFix "$NOTY_DLCUSTOMPROTON2" "$DEPS64ZIP")" "S"
			else
				writelog "SKIP" "${FUNCNAME[0]} - Already have '$DEPS32ZIP' in '$DLDIR'"
			fi

			rm "$DEPSLATDIR" 2>/dev/null
			writelog "INFO" "${FUNCNAME[0]} - 'ln -s \"$DLDIR\" \"$DEPSLATDIR\"'" E
			ln -s "$DLDIR" "$DEPSLATDIR"
			
			if [ ! -f "$DEPSL64" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Extracting $DEPS64ZIP to '$DLDIR/64'"
				"$UNZIP" -q "$DEPS64ZPATH" -d "$DLDIR/64"
				notiShow "$GUI_DONE" "S"
			fi

			if [ ! -f "$DEPSL32" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Extracting $DEPS32ZIP to '$DLDIR/32'"
				"$UNZIP" -q "$DEPS32ZPATH" -d "$DLDIR/32"
				notiShow "$GUI_DONE" "S"
			fi 		
		fi
	else
		writelog "SKIP" "${FUNCNAME[0]} - No valid '$DEPS' version found ('$LATDPRS') - nothing to download - skipping"
	fi
}

function checkDepsLaunch {
	if [ "$RUN_DEPS" -eq 1 ] && [ "$ISGAME" -eq 2 ] && [ "$USEWINE" -eq 0 ]; then

		if [ "$DEPSAUTOUP" -eq 1 ] || [ ! -f "$DEPSL64" ]; then
			StatusWindow "$(strFix "$NOTY_DLCUSTOMPROTON" "$DEPS")" "dlLatestDepsProg" "DownloadDepsStatus"
		fi

		writelog "INFO" "${FUNCNAME[0]} - Starting '$DEPS' for '$GE ($AID)'"

		if [ "$(getArch "$GP")" == "32" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Using '$DEPSL32' as '$GE' is 32bit" 
			DEPSEXE="$DEPSL32"
		elif [ "$(getArch "$GP")" == "64" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Using '$DEPSL64' as '$GE' is 64bit" 
			DEPSEXE="$DEPSL64"
		else
			writelog "INFO" "${FUNCNAME[0]} - Could not get architecture of '$GP' - using '$DEPSL64'" 
			DEPSEXE="$DEPSL64"	
		fi
		
		if [ ! -f "$DEPSEXE" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Installing failed - can't start '$DEPSEXE' - skipping"
			RUN_DEPS=0
		else
#			installWinetricksPaks "vcrun2019" "$RUNWINE" "extWine64Run" # looks like this is not needed - can't see any difference
			WGP="$(extWine64Run "$RUNWINE" winepath -w "$GP")"
			writelog "INFO" "${FUNCNAME[0]} - Starting '$DEPSEXE' using extWine64Run for the game '$WGP'"
			extWine64Run "$RUNWINE" "$DEPSEXE" "$WGP"
		fi
	fi
}

function startDepressurizer {
	if [ ! -d "$DPRSCOMPDATA" ]; then
		writelog "INFO" "${FUNCNAME[0]} - Creating '$DPRS' $CODA and installing deps"
		mkProjDir "$DPRSCOMPDATA"
		reCreateCompatdata "ccd" "$DPRS" "s"
	fi

	mkProjDir "$DPRSDLDIR"
	if [ "$DPRSPAUTOUP" -eq 1 ]; then
		dlLatestDprs
	fi
	
	DPRSEXE="$(find "${DPRSDLDIR}" -name "${DPRS}-v*.exe" | sort -V | tail -n1)"
	
	if [ ! -f "$DPRSEXE" ] || { [ "$(getArch "$DPRSEXE")" -ne "32" ] && [ "$(getArch "$DPRSEXE")" -ne "64" ];}; then
		dlLatestDprs
		DPRSEXE="$(find "${DPRSDLDIR}" -name "${DPRS}-v*.exe" | sort -V | tail -n1)"
	fi

	if [ ! -f "$DPRSEXE" ]; then
		writelog "ERROR" "${FUNCNAME[0]} - Could not find or download a '$DPRS' exe"
	else

	# copy or symlink required vdf files from steam to the DPRSCOMPDATA

	DPRSPFX="${DPRSCOMPDATA//\"/}/pfx"
	VDFDSTDIR="$DPRSPFX/$DRC/$PFX86S"

	if [ -z "$SUSDA" ] || [ -z "$STUIDPATH" ]; then
		setSteamPaths
	fi
	SC="$STUIDPATH/$SRSCV"
	FSCV="$STUIDPATH/config/$SCVDF"

	AIDST="$VDFDSTDIR/$AAVDF"
	PIDST="$VDFDSTDIR/$APVDF"
	SRSDST="$VDFDSTDIR/$USDA/$STEAMUSERID/$SRSCV"
	SRLDST="$VDFDSTDIR/$USDA/${FLCV//$SUSDA\/}"
	SCDST="$VDFDSTDIR/$USDA/${FLCV//$SUSDA\/}"
	SCSHDST="$VDFDSTDIR/$USDA/$STEAMUSERID/$SCRSH"
	
	AISRC="$FAIVDF"
	PISRC="$PIVDF"
	SRSSRC="$STUIDPATH/$SRSCV"
	SRLSRC="$FLCV"
	SCSRC="$STUIDPATH/config/$SCVDF"
	SCSHSRC="$STUIDPATH/$SCRSH"

	{
		echo "SC $SC"
		echo "FLCV $FLCV"
		echo "FSCV $FSCV"
		echo "AIDST $AIDST"
		echo "PIDST $PIDST"
		echo "SRSDST $SRSDST"
		echo "SRLDST $SRLDST"
		echo "SCDST $SCDST"
		echo "SCSHDST $SCSHDST"
		echo "AISRC $AISRC"
		echo "PISRC $PISRC"
		echo "SRSSRC $SRSSRC"
		echo "SRLSRC $SRLSRC"
		echo "SCSRC $SCSRC"
		echo "SCSHSRC $SCSHSRC"
	} > "$STLSHM/${DPRS}-paths.txt"

	function cleanCpSrcTo {
		if [ -f "$1" ]; then
			mkProjDir "${2%/*}"
			if ! cmp -s "$1" "$2" || [ -L "$2" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Copying '$1' to '$2'"
				rm "$2" 2>/dev/null
				cp "$1" "$2"
			else
				writelog "SKIP" "${FUNCNAME[0]} - '$2' is identical to '$1'"
			fi
		else
			writelog "SKIP" "${FUNCNAME[0]} - Source file '$1' not found"
		fi
	}

	function cleanLnSrcTo {
		if [ -f "$1" ]; then
			mkProjDir "${2%/*}"
			if [ "$(readlink -f "$2")" == "$(readlink -f "$1")" ]; then
				writelog "SKIP" "${FUNCNAME[0]} - '$2' is already pointing to '$1'"
			else
				writelog "INFO" "${FUNCNAME[0]} - Symlinking '$1' to '$2'"
				rm "$2" 2>/dev/null
				ln -s "$1" "$2"
			fi
		else
			writelog "SKIP" "${FUNCNAME[0]} - Source file '$1' not found"
		fi	
	}
	
	if [ "$DPRSUSEVDFSYMLINKS" -eq 1 ]; then
		writelog "INFO" "${FUNCNAME[0]} - Symlinking required vdf files from the linux steam install into '$DPRSCOMPDATA'"
		cleanLnSrcTo "$AISRC" "$AIDST"
		cleanLnSrcTo "$PISRC" "$PIDST"
		cleanLnSrcTo "$SRSSRC" "$SRSDST"
		cleanLnSrcTo "$SRLSRC" "$SRLDST"
		cleanLnSrcTo "$SCSRC" "$SCDST"
		cleanLnSrcTo "$SCSHSRC" "$SCSHDST"
	elif [ "$DPRSUSEVDFSYMLINKS" -eq 0 ]; then
		writelog "INFO" "${FUNCNAME[0]} - Copying required vdf files from the linux steam install to '$DPRSCOMPDATA'"
		cleanCpSrcTo "$AISRC" "$AIDST"
		cleanCpSrcTo "$PISRC" "$PIDST"
		cleanCpSrcTo "$SRSSRC" "$SRSDST"
		cleanCpSrcTo "$SRLSRC" "$SRLDST"
		cleanCpSrcTo "$SCSRC" "$SCDST"
		cleanCpSrcTo "$SCSHSRC" "$SCSHDST"
	else
		writelog "WARN" "${FUNCNAME[0]} - DPRSUSEVDFSYMLINKS is neither '1' nor '0' - this shouldn't happen!"
	fi

	# start $DPRS via proton starting here

		writelog "INFO" "${FUNCNAME[0]} - Using Proton Version '$USEDPRSPROTON'"
			
		if test -z "$DPRSPROTON" || [ ! -f "$DPRSPROTON" ]; then
			if [ -z "${ProtonCSV[0]}" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Don't have the Array of available Proton versions yet - creating"
				getAvailableProtonVersions "up" X
			fi
			DPRSPROTON="$(getProtPathFromCSV "$USEDPRSPROTON")"
		fi

		if [ ! -f "$DPRSPROTON" ]; then
			DPRSPROTON="$(fixProtonVersionMismatch "USEDPRSPROTON" "$STLGAMECFG" X)"
		fi

		if [ ! -f "$DPRSPROTON" ]; then
			writelog "WARN" "${FUNCNAME[0]} - proton file '$DPRSPROTON' for proton version '$USEDPRSPROTON' not found - trying 'USEPROTON' instead"
			DPRSPROTON="$(getProtPathFromCSV "$USEPROTON")"
		fi

		CHECKWINED="$(dirname "$DPRSPROTON")/$DBW"
		CHECKWINEF="$(dirname "$DPRSPROTON")/$FBW"
		if [ -f "$CHECKWINED" ]; then
			DPRSWINE="$CHECKWINED"
		elif [ -f "$CHECKWINEF" ]; then
			DPRSWINE="$CHECKWINEF"
		fi

		if [ -f "$DPRSWINE" ];then
			writelog "INFO" "${FUNCNAME[0]} - Starting '$DPRSEXE' using '$DPRSWINE'"
			DPRSWINEDEBUG="-all"
			DPRSSUDIR="$DPRSPFX/$DRCU/$STUS/$APDA/$DPRS"
			mkProjDir "$DPRSSUDIR"
			cd "$DPRSSUDIR" >/dev/null || return
			sleep 1
			LC_ALL="C" PATH="$STLPATH" LD_LIBRARY_PATH="" LD_PRELOAD="" WINE="$DPRSWINE" WINEARCH="win64" WINEDEBUG="$DPRSWINEDEBUG" WINEPREFIX="$DPRSPFX" "$DPRSWINE" "$DPRSEXE" >/dev/null 2>/dev/null
			cd - >/dev/null || return
		else
			writelog "ERROR" "${FUNCNAME[0]} - Proton Wine for not found - can't start '$DPRSEXE'"
		fi
	fi
}

function checkDep {
	CATNAM="$1"
	CHECKPROG="$2"

	if [ -n "${!CATNAM##*[!0-9]*}" ]; then
		if [ "${!CATNAM}" -eq 1 ]; then
			if [ ! -x "$(command -v "$CHECKPROG")" ]; then
				writelog "WARN" "${FUNCNAME[0]} - Disabling '$CATNAM' because '$CHECKPROG' is missing"
				notiShow "$(strFix "$NOTY_PROGRAMMISSING" "$CATNAM" "$CHECKPROG")"
				unset "$CATNAM"
			fi
		fi
	fi
}

function checkExtDeps {
	if [ -z "$NOTY" ]; then
		NOTY="notify-send"
	fi

	checkDep "USEGAMEMODERUN" "$GAMEMODERUN"
	checkDep "USEGAMESCOPE" "$GAMESCOPE"
	checkDep "RUN_NYRNA" "$NYRNA"
	checkDep "STRACERUN" "$STRACE"
	checkDep "RUN_WINETRICKS" "$WINETRICKS"
	checkDep "WINETRICKSPAKS" "$WINETRICKS"
	checkDep "RUN_REPLAY" "$REPLAY"
	checkDep "USELUXTORPEDA" "$LUXTORPEDACMD"
	checkDep "USEROBERTA" "$ROBERTACMD"
	checkDep "USEBOXTRON" "$BOXTRONCMD"
	checkDep "RUNSBSVR" "$VRVIDEOPLAYER"
	checkDep "USENETMON" "$NETMON"
	checkDep "USENOTIFIER" "$NOTY"
	checkDep "CHECKHMD" "$LSUSB"
	checkDep "BACKUPSTEAMUSER" "$RSYNC"
	checkDep "USESPECIALK" "$SEVZA"
	checkDep "USEMANGOAPP" "$MANGOAPP"
	checkDep "USEOBSCAP" "$OBSCAP"
}

function setYadBin {
	local YADINSTLDLDIR
	local YADINSTLDEPS

	function findYad {
		SEARCHDIR="$1"

		for f in "$SEARCHDIR"/*
		do
			MATCHFILE="$( basename "$f" | grep -ioE "(.*yad).*\.appimage$" )"
			if [ -f "$SEARCHDIR/$MATCHFILE" ]; then
				echo "$MATCHFILE"
				return
			fi
		done
	}

	if [ -f "$1" ]; then
		YADFILE="$1"
	elif [ "$1" == "conty" ]; then
		writelog "INFO" "${FUNCNAME[0]} - Using conty as yad binary"
		if [ ! -f "$CONTYDLDIR/$CONTY" ]; then
			StatusWindow "$(strFix "$NOTY_DLCUSTOMPROTON" "${CONTY%%.*}")" "dlConty" "DownloadContyStatus"
		else
			writelog "INFO" "${FUNCNAME[0]} - Found Conty binary in '$CONTYDLDIR/$CONTY'"
		fi

		if [ -f "$CONTYDLDIR/$CONTY" ]; then
			if [ "$(readlink "$CONTYDLDIR/$YAD")" == "$CONTYDLDIR/$CONTY" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Symlink '$CONTYDLDIR/$YAD' already points to '$CONTYDLDIR/$CONTY'"
			else
				writelog "INFO" "${FUNCNAME[0]} - Creating symlink '$CONTYDLDIR/${YAD##*/}' pointing to '$CONTYDLDIR/$CONTY'"
				ln -s "$CONTYDLDIR/$CONTY" "$CONTYDLDIR/${YAD##*/}"
			fi

			if [ "$(readlink "$CONTYDLDIR/${YAD##*/}")" == "$CONTYDLDIR/$CONTY" ]; then
				YADFILE="$CONTYDLDIR//${YAD##*/}"
			fi
		fi

	elif [ "$1" == "ai" ] || [ "$1" == "appimage" ]; then
		YADSTLIMAGE="Yad-8418e37-x86_64.AppImage"
		YAIDL="$YAIURL/$YADSTLIMAGE/$YADSTLIMAGE"
		YADAPPIMAGE="$YADSTLIMAGE"
		DLCHK="sha512sum"
		mkProjDir "$YADAIDLDIR"

		if [ -n "$2" ] && grep -q "^http" <<< "$2"; then
			YAIDL="$2"
			DLCHK="X"
			if grep -q "AppImage$" <<< "$YAIDL"; then
				YADAPPIMAGE="${YAIDL##*/}"
			else
				YADAPPIMAGE="Yad-$(date +%Y%m%d)-x86_64.AppImage"
			fi

			writelog "INFO" "${FUNCNAME[0]} - Trying to download $YAD from provided url '$YAIDL'"
		elif [ -n "$2" ] && [ -f "$2" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Trying to use provided file '$2' for yad"
			YAIDST="$2"
			DLCHK="X"
		elif [ -n "$2" ] && [ ! -f "$2" ]; then
			if [ "$2" == "sd" ]; then
				export ONSTEAMDECK=1
				YADAIDLDIR="$STLSDPATH"
				YAIDST="$YADAIDLDIR/$YADAPPIMAGE"
				YAIURL="$GHURL/frostworx/steamtinkerlaunch-tweaks/releases/download"
				YAIDL="$YAIURL/$YADSTLIMAGE/$YADSTLIMAGE"
				YADAPPIMAGE="$YADSTLIMAGE"

				# If offline and Yad isn't installed, try to find Yad somewhere sensible
				if [ "$INTERNETCONNECTION" -eq 0 ] && ! [ -f "$YAIDST" ]; then
					writelog "WARN" "${FUNCNAME[0]} - No internet connection, searching for locally saved Yad AppImage"
					echo "No internet connection, searching for locally saved Yad AppImage..."
					YADINSTLDLDIR="$( findYad "$STLDLDIR/yadappimage" )"
					YADINSTLDEPS="$( findYad "$STLDEPS" )"

					if [ -f "$STLDLDIR/yadappimage/$YADAPPIMAGE" ]; then
						# Yad in $HOME/.config/steamtinkerlaunch/downloads with full matching name
						writelog "INFO" "${FUNCNAME[0]} - Found local Yad AppImage in '$STLDLDIR/yadappimage/$YADAPPIMAGE'"
						echo "Found local Yad AppImage in '$STLDLDIR/yadappimage/$YADAPPIMAGE'!"
						mv "$STLDLDIR/yadappimage/$YADAPPIMAGE" "$YAIDST" || steamDeckInstallFail
					elif [ -f "$STLDEPS/$YADAPPIMAGE" ]; then
						# Yad in $HOME/stl/deps with full matching name
						writelog "INFO" "${FUNCNAME[0]} - Found local Yad AppImage in '$STLDEPS/$YADAPPIMAGE'"
						echo "Found local Yad AppImage in '$STLDEPS/$YADAPPIMAGE'!"
						mv "$STLDEPS/$YADAPPIMAGE" "$YAIDST" || steamDeckInstallFail
					elif [ -n "$YADINSTLDLDIR" ]; then
						# Partial match for Yad in STLDLDIR but only with filename starting with `yad` and ending with `.appimage` (case insensitive)
						writelog "INFO" "${FUNCNAME[0]} - Found local Yad AppImage in '$STLDLDIR/yadappimage/$YADINSTLDLDIR'"
						echo "Found local Yad AppImage in '$STLDLDIR/yadappimage/$YADINSTLDLDIR'!"
						mv "$STLDLDIR/yadappimage/$YADINSTLDLDIR" "$YAIDST" || steamDeckInstallFail
					elif [ -n "$YADINSTLDEPS" ]; then
						# Partial match for Yad in STLDEPS but only with filename starting with `yad` and ending with `.appimage` (case insensitive)
						writelog "INFO" "${FUNCNAME[0]} - Found local Yad AppImage in '$STLDEPS/$YADINSTLDEPS'"
						echo "Found local Yad AppImage in '$STLDEPS/$YADINSTLDEPS'!"
						mv "$STLDEPS/$YADINSTLDEPS" "$YAIDST" || steamDeckInstallFail
					else
						# No match for Yad anywhere, offline installation will most likely fail
						# Some ISPs will fail the offline check even if a user is online, so we will attempt to download Yad anyway if we can't find it - This may be problematic though!
						# Here be dragons!
						writelog "ERROR" "${FUNCNAME[0]} - Cannot find locally saved Yad AppImage, will attempt to download from GitHub anyway - See #704"
						echo "Cannot find locally saved Yad AppImage, will attempt to download from GitHub anyway - See #704"
						# return 1;
					fi
				else
					writelog "INFO" "${FUNCNAME[0]} - Downloading default AppImage for SteamDeck to '$YADAIDLDIR'"
				fi
			else
				writelog "WARN" "${FUNCNAME[0]} - Provided string '$2' is neither a http download url nor a valid absolute path to a file - downloading and using the default instead"
			fi
		fi

		if [ -f "$YAIDST" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Using Yad AppImage under '$YAIDST'"
		else
			YAIDST="$YADAIDLDIR/$YADAPPIMAGE"
			if [ "$DLCHK" == "sha512sum" ]; then
				INCHK="$("$WGET" -q "${YAIDL}.${DLCHK}" -O - 2> >(grep -v "SSL_INIT") | cut -d ' ' -f1)"
			else
				INCHK="$NON"
			fi	

			# Only show download notification if we didn't find local AppImage on Steam Deck
			if [ "$ONSTEAMDECK" -eq 1 ]; then
				notiShow "$( strFix "$NOTY_STEAMDECK_DEPSDOWNLOAD" "Yad" )" "X"
				strFix "$NOTY_STEAMDECK_DEPSDOWNLOAD" "Yad"
			fi
			
			# Yad Download
			dlCheck "$YAIDL" "$YAIDST" "$DLCHK" "Downloading '$YAIDL' to '$YAIDST'" "$INCHK"
		fi
		if [ -f "$YAIDST" ]; then
			YADFILE="$YAIDST"
		fi
	else
		writelog "ERROR" "${FUNCNAME[0]} - '$1' is no valid option"
	fi
	
	if [ -n "$YADFILE" ]; then
		MINYAD="7.2"
		chmod +x "$YADFILE" 2>/dev/null
		if [ "$ONSTEAMDECK" -eq 1 ]; then
			# skipping version check on SteamDeck, because the program might have been started via ssh, and yad requires a display
			writelog "INFO" "${FUNCNAME[0]} - Using '$YADFILE' on SteamDeck"
			if [ ! -f "$YADAIDLDIR/yad" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Creating symlink from '$YADFILE' to '$YADAIDLDIR/$YAD'"
				ln -s "$YADFILE" "$YADAIDLDIR/yad"
			fi
			touch "$FUPDATE"
			updateConfigEntry "YAD" "$YADAIDLDIR/yad" "$STLDEFGLOBALCFG"  # Update Yad entry on config file on Steam Deck to point to symlink in deps dir
		else
			YADVER="$("$YADFILE" --version | tail -n1 | cut -d ' ' -f1)"
			if [ "$(printf '%s\n' "$MINYAD" "$YADVER" | sort -V | head -n1)" != "$MINYAD" ] || grep -qi "[A-Z]" <<< "$YADVER" ; then
				writelog "ERROR" "${FUNCNAME[0]} - Version for '$YADFILE' is invalid. You need to at least version '$MINYAD'"
			else
				writelog "INFO" "${FUNCNAME[0]} - configuring yad binary to '$YADFILE'"
				touch "$FUPDATE"
				updateConfigEntry "YAD" "$YADFILE" "$STLDEFGLOBALCFG"
			fi
		fi
	fi
}

function checkIntDeps {

	if [ "$SKIPINTDEPCHECK" -eq 1 ] || [ "$1" == "yad" ]; then
		writelog "INFO" "${FUNCNAME[0]} - Skipping dependency check for internally used programs"
	else
		DEPSMISSING=0

		while read -r INTDEP; do
			if [ ! -x "$(command -v "${!INTDEP}")" ]; then
				writelog "ERROR" "${FUNCNAME[0]} - ${!INTDEP} not found!" "E"
				notiShow "$(strFix "$NOTY_NOTFOUND" "${!INTDEP}")"
				DEPSMISSING=1
			fi
		done <<< "$(sed -n "/^#STARTINTDEPS/,/^#ENDINTDEPS/p;/^#ENDINTDEPS/q" "$0" | grep -v "^#" | cut -d '=' -f1)"

		if [ -z "$YAD" ]; then
			YAD="$(command -v "yad")"
		fi

		if [ -n "$YAD" ] && [ ! -f "$YAD" ]; then
			OYAD="$YAD"
			writelog "WARN" "${FUNCNAME[0]} - Configured YAD '$YAD' was not found!  Trying to find in in a new location" "E"
			NYAD="$(command -v "yad")"
			if [ -n "$NYAD" ] && [ "$NYAD" != "$OYAD" ];then
				writelog "INFO" "${FUNCNAME[0]} - Updating YAD from '$OYAD' to '$NYAD'" "E"
				YAD="$NYAD"
				touch "$FUPDATE"
				updateConfigEntry "YAD" "$NYAD" "$STLDEFGLOBALCFG"
			else
				writelog "WARN" "${FUNCNAME[0]} - Could not find a new $YAD version" "E"
			fi
		fi

		if [ ! -x "$(command -v "$YAD")" ]; then
			DEPSMISSING=1
			writelog "ERROR" "${FUNCNAME[0]} - '$YAD' was not found! Check '${PROGCMD} --help' for alternatives and/or read '$PROJECTPAGE/wiki/Yad'" "E"
			notiShow "$(strFix "$NOTY_NOTFOUND" "$YAD")"
		fi

		setAwkBin
		
		if [ "$ONSTEAMDECK" -eq 1 ]; then
			writelog "INFO" "${FUNCNAME[0]} - Skipping yad version check on SteamDeck"
		else
			MINYAD="7.2"
			YADVER="0"

			if [ -f "$YAD" ]; then
				YADVER="$("$YAD" --version | tail -n1 | cut -d ' ' -f1)"
				writelog "INFO" "${FUNCNAME[0]} - Result of version check for yad binary '$YAD' is '$YADVER'"
			fi

			if [ "$(printf '%s\n' "$MINYAD" "$YADVER" | sort -V | head -n1)" != "$MINYAD" ]; then 
				writelog "ERROR" "${FUNCNAME[0]} - Yad version '$YADVER' is too old. You need to update to at least '$MINYAD'" "E"
				notiShow "$(strFix "$NOTY_NOTFOUND2" "$YADVER" "$MINYAD")"
				if [ "$1" != "--help" ] && [ "$1" != "-h" ]; then
					exit
				fi
			fi
		fi

		if [ "$DEPSMISSING" -eq 1 ]; then
			writelog "ERROR" "${FUNCNAME[0]} - Above programs need to be installed to use '${PROGNAME,,}'" "E"
			writelog "ERROR" "${FUNCNAME[0]} The dependency check can be disabled by enabling 'SKIPINTDEPCHECK' - exiting now" "E"
			if [ "$1" != "--help" ] && [ "$1" != "-h" ]; then
				exit
			fi
		fi
	fi
}

#####################################################
### CORE LAUNCH START ###

function setLinGameVals {
	if [ "$ISGAME" -eq 3 ]; then
		writelog "INFO" "${FUNCNAME[0]} - Looks like this is a native linux game - disabling some values which are only useful for win games"
		USEVORTEX="0"
		WINETRICKSPAKS="$NON"
		RUN_WINETRICKS="0"
		RUN_WINECFG="0"
		REGEDIT="0"
		VIRTUALDESKTOP="0"
		USERESHADE="0"
		INSTALL_RESHADE="0"
		UUUSEIGCS="0"
		IGCSDST="0"
		USESPECIALK="0"
		USEFWS="0"
		USEGEOELF="0"
	fi
}

function prepareProton {
	if [ "$ISGAME" -eq 2 ]; then
		if [ "$USEWINE" -eq 0 ]; then
			if [ "$EARLYUSEWINE" -eq 1 ]; then
				writelog "INFO" "${FUNCNAME[0]} - Wine has just been disabled, so preparing Proton now"
				getAvailableProtonVersions "up"
				checkStartMode
			fi

			if [ "$HAVEINPROTON" -eq 0 ]; then
				if [ -n "$USEPROTON" ] && [ ! -f "$(getProtPathFromCSV "$USEPROTON")" ]; then
					fixProtonVersionMismatch "USEPROTON" "$STLGAMECFG"
				fi
			
				# (re)initialize Proton dependant variables, when USEPROTON changed in a menu above
				if [ -n "$USEPROTON" ] && [ "$USEPROTON" != "$FIRSTGAMEUSEPROTON" ] && [ "$ISGAME" -eq 2 ]; then
					writelog "INFO" "${FUNCNAME[0]} - setNewProtVars, because '$USEPROTON' != '$FIRSTGAMEUSEPROTON'"
					setNewProtVars "$(getProtPathFromCSV "$USEPROTON")"
				fi
			else
				USEPROTON="$INPROTV"
				setNewProtVars "$(getProtPathFromCSV "$USEPROTON")"
				writelog "INFO" "${FUNCNAME[0]} - Checking the Proton version is not required, because $SLO is used. Proton version set in Steam is '$USEPROTON'"
			fi
			
			if [ "$USEWINEDEBUGPROTON" -eq 1 ]; then
				writelog "INFO" "${FUNCNAME[0]} - Using '$STLWINEDEBUG' as Proton 'WINEDEBUG' parameters, because 'USEWINEDEBUGPROTON' is enabled"
				export WINEDEBUG="$STLWINEDEBUG"
			fi

			if [ -n "$STLWINEDLLOVERRIDES" ] && [ "$STLWINEDLLOVERRIDES" != "$NON" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Using '$STLWINEDLLOVERRIDES' as 'WINEDLLOVERRIDES' parameter"
				export WINEDLLOVERRIDES="$WINEDLLOVERRIDES;$STLWINEDLLOVERRIDES"
			fi
		fi
		
		# export DXVK_CONFIG_FILE if STLDXVKCFG was found or if USEDLSS is enabled:
		DXDLSSCFG="$GLOBALMISCDIR/dxvk-no-nvapiHack.conf"

		if [ "$USE_STLDXVKCFG" -eq 1 ]; then
			if [ ! -f "$STLDXVKCFG" ]; then
				writelog "INFO" "${FUNCNAME[0]} - USE_STLDXVKCFG is enabled, but the config '$STLDXVKCFG' does not exist yet - creating a blank one"
				echo "## $(strFix "$STLDXVKCFG_WARNING" "$DXVKURL")" > "$STLDXVKCFG"
			fi
			export DXVK_CONFIG_FILE="$STLDXVKCFG"
			if [ -n "$DXVK_HUD" ] && [ "$DXVK_HUD" -eq 0 ]; then
				writelog "INFO" "${FUNCNAME[0]} - disabling variable DXVK_HUD which is set to 0 to make the variable DXVK_CONFIG_FILE functional"
				unset DXVK_HUD
			fi
			writelog "INFO" "${FUNCNAME[0]} - exporting variable 'DXVK_CONFIG_FILE' pointing to '$DXVK_CONFIG_FILE'"
		elif [ "$USEDLSS" -eq 1 ] && [ -f "$DXDLSSCFG" ]; then
			writelog "INFO" "${FUNCNAME[0]} - DLSS is enabled and '$DXDLSSCFG' was found - enabling all options required for DLSS"
			export DXVK_CONFIG_FILE="$DXDLSSCFG"
			if [ -n "$DXVK_HUD" ] && [ "$DXVK_HUD" -eq 0 ]; then
				writelog "INFO" "${FUNCNAME[0]} - disabling variable DXVK_HUD which is set to 0 to make the variable DXVK_CONFIG_FILE functional"
				unset DXVK_HUD
			fi
			export PROTON_ENABLE_NVAPI=1
			export PROTON_HIDE_NVIDIA_GPU=0
		fi

		# set VKD3D variables, if it's STL_ variant is != "$NON"

		if [ "$STL_VKD3D_CONFIG" != "$NON" ]; then
			export VKD3D_CONFIG="$STL_VKD3D_CONFIG"
		fi

		if [ "$STL_VKD3D_DEBUG" != "$NON" ]; then
			export VKD3D_DEBUG="$STL_VKD3D_DEBUG"
		fi

		if [ "$STL_VKD3D_SHADER_DEBUG" != "$NON" ]; then
			export VKD3D_SHADER_DEBUG="$STL_VKD3D_SHADER_DEBUG"	
		fi

		if [ "$STL_VKD3D_LOG_FILE" != "$NON" ]; then
			export VKD3D_LOG_FILE="$STL_VKD3D_LOG_FILE"
		fi

		if [ "$STL_VKD3D_VULKAN_DEVICE" != "$NON" ]; then
			export VKD3D_VULKAN_DEVICE="$STL_VKD3D_VULKAN_DEVICE"
		fi

		if [ "$STL_VKD3D_FILTER_DEVICE_NAME" != "$NON" ]; then
			export VKD3D_FILTER_DEVICE_NAME="$STL_VKD3D_FILTER_DEVICE_NAME"
		fi

		if [ "$STL_VKD3D_DISABLE_EXTENSIONS" != "$NON" ]; then
			export VKD3D_DISABLE_EXTENSIONS="$STL_VKD3D_DISABLE_EXTENSIONS"
		fi

		if [ "$STL_VKD3D_TEST_DEBUG" != "$NON" ]; then
			export VKD3D_TEST_DEBUG="$STL_VKD3D_TEST_DEBUG"
		fi

		if [ "$STL_VKD3D_TEST_FILTER" != "$NON" ]; then
			export VKD3D_TEST_FILTER="$STL_VKD3D_TEST_FILTER"
		fi

		if [ "$STL_VKD3D_TEST_EXCLUDE" != "$NON" ]; then
			export VKD3D_TEST_EXCLUDE="$STL_VKD3D_TEST_EXCLUDE"
		fi

		if [ "$STL_VKD3D_TEST_PLATFORM" != "$NON" ]; then
			export VKD3D_TEST_PLATFORM="$STL_VKD3D_TEST_PLATFORM"
		fi

		if [ "$STL_VKD3D_TEST_BUG" != "$NON" ]; then
			export VKD3D_TEST_BUG="$STL_VKD3D_TEST_BUG"
		fi

		if [ "$STL_VKD3D_PROFILE_PATH" != "$NON" ]; then
			export VKD3D_PROFILE_PATH="$STL_VKD3D_PROFILE_PATH"
		fi	

		# shortcut to enable all required flags for SBSVR with $GEOELF
		if [ "$SBSVRGEOELF" -eq 1 ]; then
			writelog "INFO" "${FUNCNAME[0]} - $PROGNAME - $SBSVRGEOELF enabled - starting game in SBS-VR using $GEOELF"
			export RUNSBSVR=1
			export USEGEOELF=1
		# shortcut to enable all required flags for SBSVR with ${RESH}
		elif [ "$SBSVRRS" -eq 1 ]; then
			writelog "INFO" "${FUNCNAME[0]} - $PROGNAME - SBSVRRS enabled - starting game in SBS-VR using ${RESH}"
			export RUNSBSVR=1
			export INSTALL_RESHADE=1
			export RESHADE_DEPTH3D=1
			export USERESHADE=1
			export ENABLE_VKBASALT=0
		fi

		if [ "$SBSRS" -eq 1 ]; then
			writelog "INFO" "${FUNCNAME[0]} - $PROGNAME - SBSRS enabled - starting game in SBS using ${RESH}"
			export INSTALL_RESHADE=1
			export RESHADE_DEPTH3D=1
			export USERESHADE=1
			export ENABLE_VKBASALT=0
		fi
	else
		writelog "SKIP" "${FUNCNAME[0]} - No Proton game"
	fi	
}

function sortGameArgs {
	if [ -z "$SLOARGS" ] || [ "$SLOARGS" == "$NON" ]; then
		SLOARGS="$NON"

		if [ "$SORTGARGS" -eq 1 ]; then
			if [ "${#ORGCMDARGS[@]}" -ge 1 ]; then
				CFSTG="coming from Steam/the game"
				if [ -n "$ARGUMENTS" ]; then
					writelog "INFO" "${FUNCNAME[0]} - Game arguments '$ARGUMENTS' $CFSTG directly"
					writelog "INFO" "${FUNCNAME[0]} - Separating them from the found arguments '${ORGCMDARGS[*]}'"
					
					while read -r arg; do
						if [ -n "$arg" ] && [ "$arg" != "" ] && grep -q -- "$arg" <<< "$ARGUMENTS" ; then
							writelog "INFO" "${FUNCNAME[0]} - '$arg' is an argument $CFSTG, because it is within ARGUMENTS: '$ARGUMENTS'"
							mapfile -d " " -t -O "${#HARGSARR[@]}" HARGSARR <<< "$arg"
						elif [[ ! "${HARGSARR[*]}" =~ $arg ]] && [ -n "$arg" ] && [ "$arg" != "" ]; then
							writelog "INFO" "${FUNCNAME[0]} - '$arg' is probably an argument coming from $SLO"
							mapfile -d " " -t -O "${#SLOARRGS[@]}" SLOARRGS <<< "$arg"
						else
							writelog "SKIP" "${FUNCNAME[0]} - skipping '$arg'"
						fi
					done <<< "$(printf "%s\n" "${ORGCMDARGS[@]}")"

					if [ "${#HARGSARR[@]}" -ge 1 ] && [ "$HARDARGS" == "$NOPE" ]; then
						writelog "INFO" "${FUNCNAME[0]} - Filling empty game config variable 'HARDARGS' with arguments $CFSTG"
						HARDARGSR="$(printf "%s" "${HARGSARR[@]}" | tr '\n' ' ')"
						HARDARGS="${HARDARGSR%*[[:blank:]]}"
						touch "$FUPDATE"
						updateConfigEntry "HARDARGS" "$HARDARGS" "$STLGAMECFG"
					fi

				else
					writelog "INFO" "${FUNCNAME[0]} - No game arguments $CFSTG found"
					writelog "INFO" "${FUNCNAME[0]} - So assuming '${ORGCMDARGS[*]}' comes completely from $SLO."
					while read -r arg; do
						mapfile -d " " -t -O "${#SLOARRGS[@]}" SLOARRGS <<< "$arg"
					done <<< "$(printf "%s\n" "${ORGCMDARGS[@]}")"
				fi

				if [ "${#SLOARRGS[@]}" -ge 1 ]; then
					SLOARGSR="$(printf "%s" "${SLOARRGS[@]}" | tr '\n' ' ')"
					SLOARGS="${SLOARGSR%*[[:blank:]]}"
					writelog "INFO" "${FUNCNAME[0]} - Set SLOARGS to '$SLOARGS'"
				fi
			else
				writelog "SKIP" "${FUNCNAME[0]} - No game arguments $CFSTG or via $SLO"
			fi
		else
			writelog "SKIP" "${FUNCNAME[0]} - Sorting the game arguments is disabled"
		fi
	else
		writelog "SKIP" "${FUNCNAME[0]} - Nothing to do on the 2nd run"
	fi
}

function initOldProtonArr {
	delEmptyFile "$PROTONCSV"
	if [ -f "$PROTONCSV" ]; then
		unset ProtonCSV
		writelog "INFO" "${FUNCNAME[0]} - Creating an initial array with available Proton versions using the file '$PROTONCSV' which was created during a previous run"
		mapfile -t -O "${#ProtonCSV[@]}" ProtonCSV < "$PROTONCSV"
	fi
}

function initFirstProton {
	initOldProtonArr
	if [ "$HAVEINPROTON" -eq 1 ]; then
		writelog "INFO" "${FUNCNAME[0]} - skipping function, because Proton version is provided by commandline ($PROGCMD used via '$SLO')"
	else
		writelog "INFO" "${FUNCNAME[0]} - Initializing Proton"

		FUP1="$(grep "^USEPROTON=" "$STLDEFGAMECFG" | cut -d '=' -f2)"
		FIRSTUSEPROTON="${FUP1//\"}"

		if [ -z "$FIRSTUSEPROTON" ]; then
			writelog "INFO" "${FUNCNAME[0]} - No Proton version available in template yet - searching for one"
			FIRSTUSEPROTON="$(getDefaultProton)"
			touch "$FUPDATE"
			updateConfigEntry "USEPROTON" "$USEPROTON" "$STLDEFGAMECFG"
			writelog "INFO" "${FUNCNAME[0]} - Updated 'USEPROTON' in '$STLDEFGAMECFG' to '$USEPROTON'"
		fi
		if [ ! -f "$(getProtPathFromCSV "$FIRSTUSEPROTON")" ]; then
			USEPROTON="$FIRSTUSEPROTON"
			fixProtonVersionMismatch "USEPROTON" "$STLDEFGAMECFG"
			FUP1="$(grep "^USEPROTON=" "$STLDEFGAMECFG" | cut -d '=' -f2)"
			FIRSTUSEPROTON="${FUP1//\"}"
		fi

		writelog "INFO" "${FUNCNAME[0]} - Initial Proton version 'FIRSTUSEPROTON' from '$STLDEFGAMECFG' is '$FIRSTUSEPROTON'"
	fi
}

function setMangoHudCfg {
	if [ "$USEMANGOHUDSTLCFG" -eq 1 ]; then
		mkProjDir "$MAHUCID"
		mkProjDir "$MAHUCTI"
		MHIC="$MAHUCID/${AID}.conf"
		writelog "INFO" "${FUNCNAME[0]} - Using internal $MAHU config '$MHIC' as requested"
		getGameName "$AID"
		MHTC="$MAHUCTI/${GAMENAME}.conf"
		
		if [ ! -f "$MHIC" ]; then
			writelog "WARN" "${FUNCNAME[0]} - '$MHIC' does not exist (yet) - trying to create it from the template '$MAHUTMPL'"
			if [ ! -f "$MAHUTMPL" ]; then
				writelog "WARN" "${FUNCNAME[0]} - The template '$MAHUTMPL' does not exist (yet) - trying to get the upstream example config"
				MAHUEX="/usr/share/doc/mangohud/MangoHud.conf.example"
				if [ -f "$MAHUEX" ]; then
					writelog "INFO" "${FUNCNAME[0]} - Copying '$MAHUEX' to '$MAHUTMPL'"
					cp "$MAHUEX" "$MAHUTMPL"
				else
					writelog "SKIP" "${FUNCNAME[0]} - Could not find '$MAHUEX'"
				fi
			fi
			
			if ! grep -q "$MAHULID/XXX" "$MAHUTMPL" && ! grep -q "^output_folder" "$MAHUTMPL" ; then
				writelog "INFO" "${FUNCNAME[0]} - Appending default $MAHU output_folder to '$MAHUTMPL', because none is configured"
				echo "output_folder = $MAHULID/XXX" >> "$MAHUTMPL"
			fi
			
			if [ -f "$MAHUTMPL" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Copying '$MAHUTMPL' to '$MHIC'"
				cp "$MAHUTMPL" "$MHIC"
				if grep -q "$MAHULID/XXX" "$MHIC"; then
					writelog "INFO" "${FUNCNAME[0]} - Setting $MAHU output_folder to '$MAHULID/$AID' in $MHIC"
					sed "s:$MAHULID/XXX:$MAHULID/$AID:" -i "$MHIC"
				fi
			else
				writelog "SKIP" "${FUNCNAME[0]} - Could not find or create '$MAHUTMPL'"
			fi
		fi
		if [ -f "$MHIC" ]; then
			if grep -q "$MAHULID/$AID" "$MHIC"; then
				mkProjDir "$MAHULID/$AID"
				mkProjDir "$MAHULTI"
				createSymLink "${FUNCNAME[0]}" "$MAHULID/$AID" "$MAHULTI/${GAMENAME}"
			fi

			writelog "INFO" "${FUNCNAME[0]} - Pointing variable MANGOHUD_CONFIGFILE to '$MHIC'"
			export MANGOHUD_CONFIGFILE="$MHIC"
			createSymLink "${FUNCNAME[0]}" "$MHIC" "$MHTC"
		else
			writelog "SKIP" "${FUNCNAME[0]} - Could not find or create '$MHIC'"
		fi
	fi
}

function autoBumpGE {
	if { [ "$AUTOBUMPGE" -eq 1 ] && grep -q "^GE" <<< "$USEPROTON" && [ "$ISGAME" -eq 2 ];} || [ -n "$1" ]; then
		writelog "INFO" "${FUNCNAME[0]} - Current Proton version is $USEPROTON"
		dlLatestGE "lge" "X"
		getAvailableProtonVersions "up" X

		if [ ! -f "$PROTONCSV" ]; then
			writelog "ERROR" "${FUNCNAME[0]} - Could not find '$PROTONCSV'"
		else	
			NEWESTGE="$(grep "^GE" "$PROTONCSV" | sort -V | tail -n1)"
			NEWESTGE="${NEWESTGE%%;*}"
			if [ "$NEWESTGE" == "$USEPROTON" ]; then
				writelog "SKIP" "${FUNCNAME[0]} - $USEPROTON is already the newest GE Proton version"
			else
				writelog "INFO" "${FUNCNAME[0]} - $(strFix "$NOTY_BUMP" "$USEPROTON" "$USEPROTON" "$NEWESTGE")"
				notiShow "$(strFix "$NOTY_BUMP" "$USEPROTON" "$USEPROTON" "$NEWESTGE")"
				USEPROTON="$NEWESTGE"
				touch "$FUPDATE"
				updateConfigEntry "USEPROTON" "$USEPROTON" "$STLGAMECFG"
			fi
		fi
	fi
}

function autoBumpProton {
	if [ "$AUTOBUMPPROTON" -eq 1 ] && grep -v -q "^GE" <<< "$USEPROTON" && [ "$ISGAME" -eq 2 ]; then
		writelog "INFO" "${FUNCNAME[0]} - Current Proton version is $USEPROTON"
		NEWESTPROTON="$(grep -v "^GE" "$PROTONCSV" | sort -V | tail -n1)"
		NEWESTPROTON="${NEWESTPROTON%%;*}"
		if [ "$NEWESTPROTON" == "$USEPROTON" ]; then
			writelog "SKIP" "${FUNCNAME[0]} - $USEPROTON is already the newest official Proton version"
		else
			writelog "INFO" "${FUNCNAME[0]} - $(strFix "$NOTY_BUMP" "$USEPROTON" "$USEPROTON" "$NEWESTPROTON")"
			notiShow "$(strFix "$NOTY_BUMP" "$USEPROTON" "$USEPROTON" "$NEWESTPROTON")"
			USEPROTON="$NEWESTPROTON"
			touch "$FUPDATE"
			updateConfigEntry "USEPROTON" "$USEPROTON" "$STLGAMECFG"
		fi
	fi
}

function checkPev {
	if [ "$ISGAME" -eq 2 ] && [ -f "$GP" ]; then
		unset USEPEVA
		mapfile -d " " -t -O "${#USEPEVA[@]}" USEPEVA < <(printf '%s' "USEPEV_PELDD USEPEV_PEPACK USEPEV_PERES USEPEV_PESCAN USEPEV_PESEC USEPEV_PESTR USEPEV_READPE")

		if [ -n "$USEALLPEV" ] && [ "$USEALLPEV" -eq 1 ]; then
			while read -r SUSEPEV; do
				if [ -n "$SUSEPEV" ]; then
					export "$SUSEPEV=1"
				fi
			done <<< "$(printf "%s\n" "${USEPEVA[@]}")"
		fi

		while read -r USEPEV; do
			if [ "${!USEPEV}" -eq 1 ]; then
				PEVCMD="${USEPEV##*_}"
				PEVCMD="${PEVCMD,,}"
				if [ -x "$(command -v "$PEVCMD")" ]; then
					PEVDSTI="$STLGPEVKD/$PEVCMD/id/$AID"
					PEVDSTT="$STLGPEVKD/$PEVCMD/title/$GN"
					
					if [ "$PEVCMD" == "$PERES" ]; then
						if [ ! -d "$PEVDSTI" ] || [ "$(find "$PEVDSTI" -type f | wc -l)" -eq 0 ]; then
							mkProjDir "$PEVDSTI"
							writelog "INFO" "${FUNCNAME[0]} - $USEPEV is enabled, extracting data from '$GP' using '$PEVCMD' to '$PEVDSTI'"
							cd "$PEVDSTI" >/dev/null || return
							notiShow "$(strFix "$NOTY_ANALYZE" "$GE" "$PEVCMD")"
							"$PEVCMD" -x "$GP" &
							cd - >/dev/null || return
						else
							writelog "SKIP" "${FUNCNAME[0]} - $USEPEV is enabled, but already have files in '$PEVDSTI'"
						fi
					else
						PEVDSTF="$PEVDSTI/$PEVCMD-$AID.txt"
						if [ ! -f "$PEVDSTF" ]; then
							mkProjDir "$PEVDSTI"
							writelog "INFO" "${FUNCNAME[0]} - $USEPEV is enabled, using command '$PEVCMD' to write data from '$GP' into '$PEVDSTF'"
							notiShow "$(strFix "$NOTY_ANALYZE" "$GE" "$PEVCMD")"
							"$PEVCMD" "$GP" > "$PEVDSTF" &
						else
							writelog "SKIP" "${FUNCNAME[0]} - $USEPEV is enabled, but already have the datafile '$PEVDSTF'"
						fi
					fi
					mkProjDir "${PEVDSTT%/*}"
					if [ ! -L "$PEVDSTT" ]; then
						ln -rs "$PEVDSTI" "$PEVDSTT"	
					fi
				else
					writelog "SKIP" "${FUNCNAME[0]} - $USEPEV is enabled, but command '$PEVCMD' could not be found"
				fi
			fi
		done <<< "$(printf "%s\n" "${USEPEVA[@]}")"
	fi
}

function checkAllPev {
	if  [ -n "$USEALLPEV" ] && [ "$USEALLPEV" -eq 1 ]; then
		writelog "INFO" "${FUNCNAME[0]} - 'USEALLPEV' is enabled, extracting data from '$GP' with all supported pev tools"
		checkPev
	fi
}

function setDxvkVars {	
	if [ "$PROTON_USE_WINED3D" -eq 0 ]; then
		writelog "INFO" "${FUNCNAME[0]} - Exporting variable 'DXVK_FRAME_RATE=$DXVK_FPSLIMIT' to limit game framerate"
		export DXVK_FRAME_RATE=$DXVK_FPSLIMIT
	fi
}

function prepareLaunch {
	rm "$CLOSETMP" 2>/dev/null
	rm "$KILLSWITCH" 2>/dev/null

	linkLog

	createProjectDirs
	fixShowGnAid
	saveCfg "$STLDEFGLOBALCFG" X
	loadCfg "$STLDEFGLOBALCFG" X
	writelog "START" "######### Game Launch: $SGNAID #########"

	getGameData "$AID"

	writelog "INFO" "${FUNCNAME[0]} - Game launch args '${ORGGCMD[*]}'"
	writelog "INFO" "${FUNCNAME[0]} - Gamedir '$GFD'"
	if [ -n "$GPFX" ]; then
		writelog "INFO" "${FUNCNAME[0]} - Proton wineprefix '$GPFX'"
	fi

	if [ -z "${INGCMD[*]}" ] && [ -n "${ORGGCMD[*]}" ]; then
		writelog "INFO" "${FUNCNAME[0]} - No INGCMD but valid ORGGCMD - May be Non-Steam game"
	fi
	writelog "INFO" "${FUNCNAME[0]} -------------------"
	writelog "INFO" "${FUNCNAME[0]} - CreateGameCfg:"
	createGameCfg

	writelog "INFO" "${FUNCNAME[0]} - First LoadCfg: $STLGAMECFG"
	loadCfg "$STLGAMECFG"

	checkPev

	autoBumpGE
	autoBumpProton
	autoBumpReShade

	if [ "$ISGAME" -eq 2 ] && [ "$HAVEINPROTON" -eq 0 ]; then
		FIRSTGAMEUSEPROTON="$USEPROTON"
		writelog "INFO" "${FUNCNAME[0]} - Initial Proton version from the game config: '$FIRSTGAMEUSEPROTON'"
		if [ -n "$USEPROTON" ] && [ ! -f "$(getProtPathFromCSV "$USEPROTON")" ]; then
			fixProtonVersionMismatch "USEPROTON" "$STLGAMECFG"
		fi

		writelog "INFO" "${FUNCNAME[0]} - Initializing internal Proton Vars for '$FIRSTGAMEUSEPROTON' using setNewProtVars"
		setNewProtVars "$(getProtPathFromCSV "$USEPROTON")"
	fi
	
	writelog "INFO" "${FUNCNAME[0]} - OpenTrayIcon:"
	openTrayIcon X

	fixCustomMeta "$CUMETA/$AID.conf" # will be removed again later
	loadCfg "$CUMETA/$AID.conf" X
	loadCfg "$GEMETA/$AID.conf" X
	
	writelog "INFO" "${FUNCNAME[0]} - sortGameArgs:"
	sortGameArgs

	if [ "$ONSTEAMDECK" -eq 1 ]; then
		writelog "INFO" "${FUNCNAME[0]} - steamdeckControl:"
		steamdeckControl
	fi

	checkWaitRequester

	if [ -z "$1" ]; then
		writelog "INFO" "${FUNCNAME[0]} - AskSettings:"
		askSettings
	else
		MainMenu "$AID"
	fi

	writelog "INFO" "${FUNCNAME[0]} - Second LoadCfg after menus: $STLGAMECFG"
	loadCfg "$STLGAMECFG"

	# Setup DXVK
	if [ -n "$DXVK_SCALE" ] && [ "$DXVK_HUD" != "0" ]; then
		writelog "INFO" "${FUNCNAME[0]} - appending 'scale=$DXVK_SCALE' to the DXVK_HUD variable '$DXVK_HUD'"
		DXVK_HUD="${DXVK_HUD},scale=$DXVK_SCALE"
	fi
	setDxvkVars

	# in case a path changed in between, call createProjectDirs again:
	createProjectDirs

	

	# autoapply configuration settings based on the steam collections the game is in:
	autoCollectionSettings

	checkAllPev

	writelog "INFO" "${FUNCNAME[0]} - sortGameArgs again, in case something changed above:"
	sortGameArgs

	if [ "$ISGAME" -eq 2 ]; then
		writelog "INFO" "${FUNCNAME[0]} - symlinkSteamUser:"
		symlinkSteamUser "$USESUSYM"

		writelog "INFO" "${FUNCNAME[0]} - restoreSteamUser:"
		restoreSteamUser

		writelog "INFO" "${FUNCNAME[0]} - prepareProton:"
		prepareProton
	fi
####

	writelog "INFO" "${FUNCNAME[0]} - setLinGameVals :"
	setLinGameVals

#################

	# override tweak settings
	writelog "INFO" "${FUNCNAME[0]} - CheckTweakLaunch:"
	checkTweakLaunch

	if [ "$ISGAME" -eq 2 ]; then
		writelog "INFO" "${FUNCNAME[0]} - checkXliveless:"
		checkXliveless

		# choose either system winetricks or downloaded one
		writelog "INFO" "${FUNCNAME[0]} - chooseWinetricks:"
		chooseWinetricks
	fi

	# check dependencies - disable functions if dependency programs are missing and/or warn
	writelog "INFO" "${FUNCNAME[0]} - checkExtDeps:"
	checkExtDeps
	writelog "INFO" "${FUNCNAME[0]} - checkExtDeps done"

	if [ "$ISGAME" -eq 2 ]; then
		writelog "INFO" "${FUNCNAME[0]} - setWineVars:"
		setWineVars

		# start winetricks gui if RUN_WINETRICKS is 1 or silently if WINETRICKSPAKS is not empty
		writelog "INFO" "${FUNCNAME[0]} - CheckWinetricksLaunch:"
		checkWinetricksLaunch

		# start $WINECFG if RUN_WINECFG is 1
		writelog "INFO" "${FUNCNAME[0]} - CheckWineCfgLaunch:"
		checkWineCfgLaunch

		# apply some regs if requested
		writelog "INFO" "${FUNCNAME[0]} - CustomRegs:"
		customRegs
	fi

	# minimize all open windows if TOGGLEWINDOWS is 1
	writelog "INFO" "${FUNCNAME[0]} - TogWindows:"
	togWindows windowminimize

	# Pause steamwebhelper if requested
	writelog "INFO" "${FUNCNAME[0]} - StateSteamWebHelper:"
	StateSteamWebHelper pause

	if [ "$ISGAME" -eq 2 ]; then
		# install ${RESH} if INSTALL_RESHADE is 1
		writelog "INFO" "${FUNCNAME[0]} - InstallReshade:"
		installReshade

		# install Depth3D Shader if RESHADE_DEPTH3D is 1
		writelog "INFO" "${FUNCNAME[0]} - installDepth3DReshade:"
		installDepth3DReshade

		# start game with ${RESH} if USERESHADE is 1
		writelog "INFO" "${FUNCNAME[0]} - checkReshade:"
		checkReshade

		# start game with ${RESH} if USERESHADE is 1
		writelog "INFO" "${FUNCNAME[0]} - useSpecialK:"
		useSpecialK

		# start game with $GEOELF if USEGEOELF is 1
		writelog "INFO" "${FUNCNAME[0]} - configureGeoElf:"
		configureGeoElf
		
		# open Shader Menu if CHOOSESHADERS is 1
		writelog "INFO" "${FUNCNAME[0]} - ChooseShaders:"
		chooseShaders
	fi

	# configure $MAHU
	if [ "$USEMANGOHUD" -eq 1 ]; then
		if [ -f "$MAHUBIN" ] || [ "$MAHUVAR" -eq 1 ]; then
			writelog "INFO" "${FUNCNAME[0]} - setMangoHudCfg:"
			setMangoHudCfg
		else
			writelog "SKIP" "${FUNCNAME[0]} - USEMANGOHUD is enabled, but $MAHU binary '$MAHUBIN' not found - disabling USEMANGOHUD"
			USEMANGOHUD=0
		fi
	fi

	# start $NYRNA if RUN_NYRNA is 1
	writelog "INFO" "${FUNCNAME[0]} - UseNyrnaz:"
	useNyrna

	# start $REPLAY if RUN_REPLAY is 1
	writelog "INFO" "${FUNCNAME[0]} - UseReplay:"
	useReplay

	# start game with side-by-side VR if RUNSBSVR is not 0 
	writelog "INFO" "${FUNCNAME[0]} - CheckSBSVRLaunch:"
	checkSBSVRLaunch "$NON"

	if [ "$RUNSBS" -eq 1 ]; then
		writelog "INFO" "${FUNCNAME[0]} - CheckSBSLaunch:"
		checkSBSLaunch
	fi

	# start Vortex if USEVORTEX is 1
	if [ "$USEVORTEX" -eq 1 ]; then
		writelog "INFO" "${FUNCNAME[0]} - ${VTX^} is enabled - startVortex:"
		startVortex "ask" "$AID"
		# (for Vortex) if SELAUNCH is 0 start a preconfigured exe directly
		writelog "INFO" "${FUNCNAME[0]} - CheckVortexSELaunch with argument '$SELAUNCH':"
		checkVortexSELaunch "$SELAUNCH"
	fi

	writelog "INFO" "${FUNCNAME[0]} - checkMO2:"
	checkMO2
	
	# set other screen resolution
	writelog "INFO" "${FUNCNAME[0]} - setNewRes:"
	setNewRes
	
	# start custom user script
	writelog "INFO" "${FUNCNAME[0]} - customUserScriptStart:"
	customUserScriptStart
	
	# redirect STEAM_COMPAT_DATA_PATH on request
	writelog "INFO" "${FUNCNAME[0]} - redirectSCDP:"
	redirectSCDP

	if [ "$ISGAME" -eq 2 ]; then
		# start igcsinjector if USEIGCS is enabled
		writelog "INFO" "${FUNCNAME[0]} - checkIGCSInjector:"
		checkIGCSInjector

		# check if openvr-fsr is enabled
		writelog "INFO" "${FUNCNAME[0]} - checkOpenVRFSR:"
		checkOpenVRFSR
	fi

	# start '$FWS' if USEFWS is enabled
	writelog "INFO" "${FUNCNAME[0]} - CheckFWS:"
	checkFWS

	# load custom variables if available
	loadCustomVars

	# start a custom program if USECUSTOMCMD is enabled
	writelog "INFO" "${FUNCNAME[0]} - CheckCustomLaunch:"
	checkCustomLaunch

	if [ "$ISGAME" -eq 2 ]; then
		# start a custom program if UUUSEPATCH or UUUSEVR is enabled
		writelog "INFO" "${FUNCNAME[0]} - checkUUUPatchLaunch:"
		checkUUUPatchLaunch
	fi

	# start strace process in the background if STRACERUN is 1
	writelog "INFO" "${FUNCNAME[0]} - CheckStraceLaunch:"
	checkStraceLaunch

	# start network monitor process in the background if USENETMON is enabled and NETMON found
	writelog "INFO" "${FUNCNAME[0]} - CheckNetMonLaunch:"
	checkNetMonLaunch

	# start wine-discord-ipc-bridge when game starts if USE_WDIB is -eq 1
	writelog "INFO" "${FUNCNAME[0]} - checkWDIB:"
	checkWDIB

	# set pulse latency if CHANGE_PULSE_LATENCY is 1
	writelog "INFO" "${FUNCNAME[0]} - checkPulse:"
	checkPulse

	# create/remove steam_appid.txt
	writelog "INFO" "${FUNCNAME[0]} - checkSteamAppIDFile:"
	checkSteamAppIDFile

	# Automatic Grid Update Check before_game
	if [ "$SGDBAUTODL" == "before_game" ] && [ "$STLPLAY" -eq 0 ]; then
		writelog "INFO" "${FUNCNAME[0]} - Automatic Grid Update Check '$SGDBAUTODL'"
		getGrids "$AID" &
	fi

	if [ "$ISGAME" -eq 2 ]; then
		# Create GameTitle Symlink in STLCOMPDAT if enabled
		writelog "INFO" "${FUNCNAME[0]} - setCompatDataTitle:"
		setCompatDataTitle
	fi

	# delay game launch if requested via WAITFORCUSTOMCOMMAND
	delayGameForCustomLaunch
	
	# GAME START
	writelog "INFO" "${FUNCNAME[0]} - launchSteamGame:"
	launchSteamGame

	if [ "$KEEPSTLOPEN" -eq 1 ]; then
		writelog "INFO" "${FUNCNAME[0]} - KEEPSTLOPEN is enabled - re-opening the $PROGNAME menu"
		prepareLaunch X
	else
		# GAME ENDED - Closing:
		writelog "STOP" "######### CLEANUP #########"
		closeSTL "######### DONE - $PROGNAME $PROGVERS #########"
	fi
}

function switchProton {
	writelog "INFO" "${FUNCNAME[0]} - Switching used Proton and its Variables to version '$1'"

	if [ ! -f "$(getProtPathFromCSV "$1")" ]; then
		writelog "INFO" "${FUNCNAME[0]} - Tried to switch to Proton '$1', but it is not available"
		if [ "$AUTOPULLPROTON" -eq 1 ]; then
			writelog "INFO" "${FUNCNAME[0]} - AUTOPULLPROTON is enabled, so trying to download and enable '$1'"
			createDLProtList
			DLURL="$(printf "%s\n" "${ProtonDLList[@]}" | grep -m1 "$1")"
			if [ -n "$DLURL" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Download for requested '$1' found: '$DLURL'"
				StatusWindow "$GUI_DLCUSTPROT" "dlCustomProton ${DLURL//|/\"}" "DownloadCustomProtonStatus"
			else
				writelog "SKIP" "${FUNCNAME[0]} - No download URL found for requested '$1' - skipping"
			fi
		else
			writelog "SKIP" "${FUNCNAME[0]} - AUTOPULLPROTON is disabled, so giving up switching to proton version '$1'"
		fi
	else
		writelog "INFO" "${FUNCNAME[0]} - Requested Proton version '$1' found under '$(getProtPathFromCSV "$1")'"
	fi

	if [ -f "$(getProtPathFromCSV "$1")" ]; then
		USEPROTON="$1"
		setNewProtVars "$(getProtPathFromCSV "$USEPROTON")"
	fi
}

function prepareProtonDBRating {
	if [ "$USEPDBRATING" ] && [ "$STLPLAY" -eq 0 ]; then
		PDBRAINFO="$STLSHM/PTB-${AID}.txt"
		PDBRASINF="${PDBRAINFO//-/short-}"

		if [ ! -f "$PDBRAINFO" ];then
			mapfile -d ";" -t -O "${#PDBARR[@]}" PDBARR <<< "$(getProtonDBRating "$AID")"
			PDBCONFI="${PDBARR[0]}"
			PDBSCORE="${PDBARR[1]}"
			PDBTOTAL="${PDBARR[2]}"
			PDBTREND="${PDBARR[3]}"
			PDBBESTT="${PDBARR[4]}"
			printf '<b>ProtonDB Rating Trend:</b> %s' "${PDBTREND^}" > "$PDBRASINF"
			printf '<u>%s</u>\n<b>Confidence:</b> %s\n<b>Score:</b> %s\n<b>Total Votes:</b> %s\n<b>Rating Trend:</b> %s\n<b>Best Rating:</b> %s\n' "$GUI_USEPDBRATING" "${PDBCONFI}" "${PDBSCORE}" "${PDBTOTAL}" "${PDBTREND}" "${PDBBESTT}" > "$PDBRAINFO"
		fi
	fi
}

function getProtonDBRating {
	if [ -n "$1" ]; then
		AID="$1"
	fi

	PDBAPI="https://www.protondb.com/api/v1/reports/summaries/XXX.json"

	if [ ! -x "$(command -v "$JQ")" ]; then
		writelog "WARN" "${FUNCNAME[0]} - Can't get data from '${PDBAPI//XXX/$AID}' because '$JQ' is not installed"
	else
		DMIN=1440

		if [ -n "$PDBRATINGCACHE" ] && [ "$PDBRATINGCACHE" -ge 1 ]; then
			PDBDLDIR="$STLDLDIR/proton/rating"
			mkProjDir "$PDBDLDIR"
			PDBAJ="$PDBDLDIR/${AID}.json"
			if [ ! -f "$PDBAJ" ] || test "$(find "$PDBAJ" -mmin +"$(( DMIN * PDBRATINGCACHE ))")"; then
				rm "$PDBAJ" 2>/dev/null
				dlCheck "${PDBAPI//XXX/$AID}" "$PDBAJ" "X" "$NON"
			fi

			if [ -f "$PDBAJ" ]; then
				"$JQ" -r '. | "\(.confidence);\(.score);\(.total);\(.trendingTier);\(.bestReportedTier)"' "$PDBAJ"
			fi
		else
			"$WGET" -q "${PDBAPI//XXX/$AID}" -O - 2> >(grep -v "SSL_INIT") | "$JQ" -r '. | "\(.confidence);\(.score);\(.total);\(.trendingTier);\(.bestReportedTier)"'
		fi
	fi
}

function fixProtonVersionMismatch {
	if [ "$ISGAME" -eq 2 ]; then
		ORGPROTCAT="$1"
		MIMAPROT="${!1}"

		if [[ "$MIMAPROT" =~ "experimental" ]]; then
			# Look for replacement Proton Experimental - There should only ever be one Proton Experimental version installed at a time
			writelog "INFO" "${FUNCNAME[0]} - Mismatch for 'experimental' Proton version - Looking for updated Proton Experimental"

			# Even though there should only be one Experimental version, only take the first one just in case (should not cause issues, hopefully)
			REPLACEMENTEXPERIMENTAL="$( grep 'experimental' "$PROTONCSV" | head -1 | cut -d ';' -f1 )" 
			if [ -n "$REPLACEMENTEXPERIMENTAL" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Found potential replacement for Proton Experimental with '$REPLACEMENTEXPERIMENTAL'"
				switchProton "$REPLACEMENTEXPERIMENTAL"
			else
				# If no Proton replacement, fall back to first Proton version in ProtonCSV
				# Not ideal but a user might've uninstalled Proton Experimental, and we can't assume what versions of Proton they will have except that they'll have *some* version
				FALLBACKPROTON="$( head -1 "$PROTONCSV" )"
				writelog "INFO" "${FUNCNAME[0]} - No potential replacement for Proton Experimental found, falling back to first Proton version in ProtonCSV ('$FALLBACKPROTON')"
				switchProton "$FALLBACKPROTON"
			fi

			touch "$FUPDATE"
			updateConfigEntry "USEPROTON" "$USEPROTON" "$2"
		elif [[ "$MIMAPROT" =~ "proton-unknown" ]]; then
			# Should we fall back to first item in ProtonCSV here?
			writelog "INFO" "${FUNCNAME[0]} - Skipping function for 'proton-unknown' Proton version"
		else
			writelog "INFO" "${FUNCNAME[0]} - Incoming category is '$ORGPROTCAT' with value '$MIMAPROT'"
			writelog "INFO" "${FUNCNAME[0]} - Looking for an alternative similar version for '$MIMAPROT'"

			notiShow "$(strFix "$NOTY_WANTPROTON3" "$MIMAPROT")"

			if [ ! -f "$PROTONCSV" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Looking for available Proton versions"
				getAvailableProtonVersions "up"
			fi

			MIMAPROTSHORT="^${MIMAPROT%-*}"
			NEWMINORPROT="$(grep "$MIMAPROTSHORT" "$PROTONCSV" | cut -d ';' -f1 | sort -nr | head -n1)"

			if [ -f "$(getProtPathFromCSV "${NEWMINORPROT//\"/}")" ] && [ -n "${NEWMINORPROT//\"/}" ]; then
				NEWMINORRUN="$(getProtPathFromCSV "${NEWMINORPROT//\"/}")"
				writelog "INFO" "${FUNCNAME[0]} - Found Proton '$NEWMINORPROT' in path '$NEWMINORRUN' as an alternative for the requested '$MIMAPROT'"
			elif grep -q "GE" <<< "$MIMAPROT"; then
				writelog "INFO" "${FUNCNAME[0]} - No alternative for '$MIMAPROT' found directly"
				NEWMINORPROT="$(grep "GE" "$PROTONCSV" | cut -d ';' -f1 | sort -nr | head -n1)"
				if [ -f "$(getProtPathFromCSV "${NEWMINORPROT//\"/}")" ]; then
					NEWMINORRUN="$(getProtPathFromCSV "${NEWMINORPROT//\"/}")"
					writelog "INFO" "${FUNCNAME[0]} - Using found '$NEWMINORPROT' instead, as it is at least also a GE Proton like the requested '$MIMAPROT'"
				fi
			fi

			if [ -n "$3" ]; then
				if [ -f "$NEWMINORRUN" ]; then
					writelog "INFO" "${FUNCNAME[0]} - found '$NEWMINORRUN'"
					echo "$NEWMINORRUN"
				fi
			else
				if [ -f "$NEWMINORRUN" ]; then
					switchProton "$NEWMINORPROT"
					notiShow "$(strFix "$NOTY_WANTPROTON2" "$NEWMINORPROT" "$MIMAPROT")"
				elif [ "$AUTOLASTPROTON" -eq 1 ]; then
					writelog "INFO" "${FUNCNAME[0]} - Automatically selecting newest official one"
					setNOP
				else
					writelog "INFO" "${FUNCNAME[0]} - Asking for one"
					needNewProton
				fi
			fi

			if [ ! -f "$(getProtPathFromCSV "$MIMAPROT")" ] && [ "$ORGPROTCAT" == "USEPROTON" ] && [ "$MIMAPROT" != "$NEWMINORPROT" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Automatically updating USEPROTON to '$USEPROTON' in '$2'"
				touch "$FUPDATE"
				updateConfigEntry "USEPROTON" "$USEPROTON" "$2"
				setInternalProtonVars
			fi
		fi
	fi
}

function dlConty {
	function upChkConty {
		DLCHK="sha256sum"

		notiShow "$(strFix "$NOTY_DLCONTY" "$CONTYRELURL/$CONTYDLVERS")" "S"
		dlCheck "$CONTYRELURL/$CONTYDLVERS" "$CONTYDLDIR/$CONTY" "$DLCHK" "Downloading '$CONTYRELURL/$CONTYDLVERS' to '$CONTYDLDIR'" "$INCHK"
		notiShow "$GUI_DONE" "S"		
	}

	mkProjDir "$CONTYDLDIR"
	CONTYDLVERS="$("$WGET" -q "$CONTYRELURL" -O - 2> >(grep -v "SSL_INIT") | grep -m1 "download.*.$CONTY" | grep -oP 'releases\K[^"]+')"
	CONTYVERS="${CONTYDLVERS%/*}"
	CONTYVERS="${CONTYVERS##*/}"
	
	INCHK="$("$WGET" -q "${CONTYRELURL}/tag/${CONTYVERS}" -O - 2> >(grep -v "SSL_INIT")| grep "SHA256" -A10 | grep -m1 "${CONTY}" | cut -d ' ' -f1)"
		
	if [ -f "$CONTYDLDIR/$CONTY" ]; then
		if [ "$UPDATECONTY" -eq 1 ]; then
			if [ -f "$CONTYDLDIR/version.txt" ]; then
				DLVERS="$(cat "$CONTYDLDIR/version.txt")"
			else
				DLVERS="0.0"
			fi

			if [ "$DLVERS" == "$CONTYVERS" ]; then
				writelog "SKIP" "${FUNCNAME[0]} - Skipping downloading Conty - existing version is identical to the latest upstream version '$CONTYVERS'"
			else
				writelog "INFO" "${FUNCNAME[0]} - Updating the available Conty version '$DLVERS' with the newer version '$CONTYVERS'"
				upChkConty
			fi
		else
			writelog "SKIP" "${FUNCNAME[0]} - Skipping downloading Conty - already have one, and update is disabled"
		fi
	else
		upChkConty
	fi

	if [ -f "$CONTYDLDIR/$CONTY" ]; then
		DLSHA="$(sha256sum "$CONTYDLDIR/$CONTY" | cut -d ' ' -f1)"
		writelog "INFO" "${FUNCNAME[0]} - : Downloaded $CONTY has sha256sum '$DLSHA' and should have '$INCHK'"

		if [ "$INCHK" == "$DLSHA" ]; then
			writelog "INFO" "${FUNCNAME[0]} - : $(strFix "$NOTY_CHECKSUM_OK" "$DLSHA")"
			notiShow "$(strFix "$NOTY_CHECKSUM_OK" "$DLSHA")" "S"
			chmod +x "$CONTYDLDIR/$CONTY"
			export RUNCONTY="$CONTYDLDIR/$CONTY"
			if grep -q "[0-9]" <<< "$CONTYVERS"; then
				writelog "INFO" "${FUNCNAME[0]} - Updating Conty version to '$CONTYVERS' in '$CONTYDLDIR/version.txt'"
				echo "$CONTYVERS" > "$CONTYDLDIR/version.txt"
			else
				writelog "SKIP" "${FUNCNAME[0]} - No version found in Url - not writing '$CONTYDLDIR/version.txt'"
			fi
		else
			writelog "ERROR" "${FUNCNAME[0]} - $(strFix "$NOTY_CHECKSUM_NOK" "$DLSHA") - removing the download"
			notiShow "$(strFix "$NOTY_CHECKSUM_NOK" "$DLSHA")" "S"
			rm "$CONTYDLDIR/$CONTY"
		fi
	fi
}

function updateConty {
	if [ "$UPDATECONTY" -eq 1 ]; then
		if [ ! -f "$CONTYDLDIR/version.txt" ]; then
			writelog "INFO" "${FUNCNAME[0]} - No Conty version file found in - so simply downloading latest release"
			StatusWindow "$(strFix "$NOTY_DLCUSTOMPROTON" "${CONTY%%.*}")" "dlConty" "DownloadContyStatus"
		else
			CONTYDLVERS="$("$WGET" -q "$CONTYRELURL" -O - 2> >(grep -v "SSL_INIT") | grep -m1 "download.*.$CONTY" | grep -oP 'releases\K[^"]+')"
			CONTYVERS="${CONTYDLVERS%/*}"
			CONTYVERS="${CONTYVERS##*/}"
			if [ -f "$CONTYDLDIR/version.txt" ]; then
				DLVERS="$(cat "$CONTYDLDIR/version.txt")"
			else
				DLVERS="0.0"
			fi
			writelog "INFO" "${FUNCNAME[0]} - $(strFix "$NOTY_UPDATECONTY" "$CONTYVERS" "$DLVERS")"
			notiShow "$(strFix "$NOTY_UPDATECONTY" "$CONTYVERS" "$DLVERS")"
			StatusWindow "$(strFix "$NOTY_DLCUSTOMPROTON" "${CONTY%%.*}")" "dlConty" "DownloadContyStatus"
		fi
	fi
}

function askConty {
		writelog "INFO" "${FUNCNAME[0]} - Opening Ask Conty Requester"
		fixShowGnAid
		export CURWIKI="$PPW/Conty"
		TITLE="${PROGNAME}-SelectConty"
		pollWinRes "$TITLE"

		setShowPic

		"$YAD" --f1-action="$F1ACTION" --image "$SHOWPIC" --image-on-top --window-icon="$STLICON" --form --center --on-top "$WINDECO" \
		--title="$TITLE" \
		--text="$(spanFont "$SGNAID - $GUI_ASKCONTY" "H")" \
		--button="$BUT_DLCONTY":0 \
		--button="$BUT_SELCONTY":2 \
		--button="$SKIPCONTY":4 \
		"$GEOM"

		case $? in
			0)  {
					writelog "INFO" "${FUNCNAME[0]} - Selected to download Conty"
					StatusWindow "$(strFix "$NOTY_DLCUSTOMPROTON" "${CONTY%%.*}")" "dlConty" "DownloadContyStatus"
				}
			;;
			2)  {
					writelog "INFO" "${FUNCNAME[0]} - Selected to pick local Conty executable"
					PICKCONT="$("$YAD" --file)"

					if [ -f "$PICKCONT" ]; then
						writelog "INFO" "${FUNCNAME[0]} - Picked '$PICKCONT' as Conty executable"
						export RUNCONTY="$PICKCONT"
						touch "$FUPDATE"
						updateConfigEntry "CUSTCONTY" "$PICKCONT" "$STLDEFGLOBALCFG"
						CUSTCONTY="$PICKCONT"
					else
						writelog "SKIP" "${FUNCNAME[0]} - No Conty executable selected - skipping"
						export RUNCONTY="$NON"
					fi
				}
			;;
			4)  {
					writelog "SKIP" "${FUNCNAME[0]} - Selected CANCEL - Not using Conty"
					export RUNCONTY="$NON"
				}
			;;
		esac
}

function findConty {
	if [ -n "$CUSTCONTY" ] && [ "$CUSTCONTY" != "$NON" ] && [ -x "$CUSTCONTY" ]; then
		writelog "INFO" "${FUNCNAME[0]} - Using custom Conty '$CUSTCONTY'"
		export RUNCONTY="$CUSTCONTY"
	elif [ -x "$CONTYDLDIR/$CONTY" ]; then
		writelog "INFO" "${FUNCNAME[0]} - Using downloaded Conty '$CONTYDLDIR/$CONTY'"
		updateConty
		export RUNCONTY="$CONTYDLDIR/$CONTY"
	elif [ -x "$(command -v "$CONTY")" ]; then
		writelog "INFO" "${FUNCNAME[0]} - Using Conty in 'PATH' '$("$WHICH" "$CONTY")'"
		RUNCONTY="$(command -v "$CONTY")"
		export RUNCONTY
	else
		writelog "INFO" "${FUNCNAME[0]} - No Conty found - Opening requester"
		askConty
		if [ "$RUNCONTY" != "$NON" ]; then
			"${FUNCNAME[0]}"
		fi
	fi
}

function checkConty {
	if [ "$AUTOCONTY" -eq 1 ]; then
		if [ "$(getArch "$GP")" == "32" ]; then
			CONTYMODE=1
		else
			CONTYMODE=0
		fi
	elif [ "$USECONTY" -eq 1 ]; then
		CONTYMODE=2
	else
		CONTYMODE=0
	fi
	
	if [ "$CONTYMODE" -ge 1 ]; then
		findConty
			
		if [ -x "$RUNCONTY" ] && [ "$RUNCONTY" != "$NON" ]; then
			if [ "$CONTYMODE" -eq 1 ]; then
				writelog "INFO" "${FUNCNAME[0]} - '$GP' is 32bit - Starting it using Conty executable '$RUNCONTY'"
			else
				writelog "INFO" "${FUNCNAME[0]} - Starting '$GP' using Conty executable '$RUNCONTY', because 'USECONTY' is enabled"
			fi
		else
			writelog "SKIP" "${FUNCNAME[0]} - No Conty executable found 'RUNCONTY' is '$RUNCONTY' - continuing regularly"
			CONTYMODE=0
		fi
	fi
}

function logPlayTime {
	# Takes seconds and converts it into HH:MM:SS
	function getLengthPlayed {
		((h=${1}/3600))
		((m=(${1}%3600)/60))
		((s=${1}%60))

		if [ $h -gt 0 ]; then
			printf "%02d hrs, %02d mins, %02d secs" $h $m $s
		elif [ $m -gt 0 ]; then
			printf "%02d mins, %02d secs" $m $s
		else
			printf "%02d secs" $s
		fi
	}

	if [ "$LOGPLAYTIME" -eq 1 ] && [ -n "$GN" ] ; then
		mkProjDir "$PLAYTIMELOGDIR"
		TIMEPLAYEDSTR="$(date +%d.%m.%Y) for $(getLengthPlayed "$1")" # different date formats?
		echo "$TIMEPLAYEDSTR" >> "$PLAYTIMELOGDIR/${GN}.log"
	fi
}

function setHuyList {
	HUTXT="helpurls.txt"

	HELPURLLIST="$GLOBALMISCDIR/$HUTXT"
	
	if [ -f "$STLCFGDIR/$HUTXT" ]; then
		HELPURLLIST="$STLCFGDIR/$HUTXT"
	fi

	DHU="defhelpurl"
	
	if [ -z "$HELPURL" ] || [ "$HELPURL" == "$NON" ]; then 
		HELPURL="$(grep "$DHU" "$HELPURLLIST" | cut -d ';' -f2)"
	fi
	HUYLIST="$(while read -r line; do cut -d ';' -f1 <<<"$line"; done <<< "$(grep -v "$DHU" "$HELPURLLIST")" | tr '\n' '!')"
	
	loadCfg "$GEMETA/$AID.conf" X
	 
	if [ -n "$METACRITIC_FULLURL" ]; then
		HUYLIST="${HUYLIST}metacritic!"
	fi 

	if [ -n "$GAMEMANUALURL" ]; then
		HUYLIST="${HUYLIST}gamemanual!"
	fi 
	
	export HUYLIST
}

function checkHelpUrl {
	WANTHELPURL="$1"
	if [ -n "$WANTHELPURL" ] && [ "$WANTHELPURL" != "$NON" ] && [ ! -f "$STLSHM/KillBrowser-$AID.txt" ]; then

		if [ "$WANTHELPURL" == "metacritic" ]; then
			HELPURL="$METACRITIC_FULLURL"
		elif [ "$WANTHELPURL" == "gamemanual" ]; then
			HELPURL="$GAMEMANUALURL"
		else
			HELPURL="$(grep "$WANTHELPURL" "$HELPURLLIST" | grep -v "$DHU" | cut -d ';' -f2)"
			writelog "INFO" "${FUNCNAME[0]} - Searching Help Url for '$WANTHELPURL' with command: 'grep \"$WANTHELPURL\" \"$HELPURLLIST\" | grep -v \"$DHU\" | cut -d ';' -f2'"
		fi

		if [ -n "$HELPURL" ]; then
			HELPURLNQ="${HELPURL//\"}"

			if [ -z "$BROWSER" ] || [ "$BROWSER" -eq "$NON" ]; then
				writelog "INFO" "${FUNCNAME[0]} - No web browser selected falling back to '$XDGO'"
				writelog "WARN" "${FUNCNAME[0]} - If issues occur opening web pages try setting a browser manually"
				BROWSER="$XDGO"
			fi

			writelog "INFO" "${FUNCNAME[0]} - Selected to open '${HELPURLNQ//AID/$AID}' with '$BROWSER'"
			# If $BROWSER is $XDGO we don't want to kill it as it will likely kill something like Steam instead
			if [ "$BROWSER" != "$XDGO" ]; then
				if ! "$PGREP" -f "$BROWSER" >/dev/null; then
					touch "$STLSHM/KillBrowser-$AID.txt"
				fi
			fi
		
			"$BROWSER" "${HELPURLNQ//AID/$AID}" 2>/dev/null & 
		fi
	fi
}

function HelpUrlMenu {
	if [ -n "$1" ]; then
		AID="$1"
		setAIDCfgs
	fi
	fixShowGnAid
	export CURWIKI="$PPW/Help-Url"
	TITLE="${PROGNAME}-${FUNCNAME[0]}"
	pollWinRes "$TITLE"
	setShowPic
	setHuyList

	WANTHELPURL="$("$YAD" --f1-action="$F1ACTION" --image "$SHOWPIC" --image-on-top --window-icon="$STLICON" --form --center --on-top "$WINDECO" \
	--title="$TITLE" --separator="\n" \
	--text="$(spanFont "$SGNAID $(strFix "$GUI_ASKOPURL" "$1")" "H")" \
	--field="$GUI_HELPURL!$DESC_HELPURL ":CB "$(cleanDropDown "${HELPURL}" "${HUYLIST}${NON}")" \
	--button="$BUT_CAN":0 \
	--button="$BUT_OPURL":2 \
	"$GEOM"	)"

	case $? in
		0)  {
				checkHelpUrl "$WANTHELPURL"
				writelog "INFO" "${FUNCNAME[0]} - Selected '$BUT_CAN' - Leaving"
			}
		;;
		2)  {
				writelog "INFO" "${FUNCNAME[0]} - Selected '$BUT_OPURL' - Opening '$WANTHELPURL' in browser"
				checkHelpUrl "$WANTHELPURL"
			}
		;;
	esac
}

function checkPlayTime {
	WASSTESTA="$STLSHM/SteamStart_${AID}.txt"
	if [ ! -f "$WASSTESTA" ]; then
		writelog "INFO" "${FUNCNAME[0]} - The game was not started via '$PROGCMD' but directly from Steam - skipping Crash Requester"
	elif [ -z "$1" ]; then
		writelog "INFO" "${FUNCNAME[0]} - The game was not even started"
	else
		if [  -n "$CRASHGUESS" ] && [ "$1" -le "$CRASHGUESS" ]; then
			writelog "INFO" "${FUNCNAME[0]} - The game stopped after '$1' seconds - opening CrashGuess Requester"
			steamdeckControl
			fixShowGnAid
			export CURWIKI="$PPW/Crash-Guess"
			TITLE="${PROGNAME}-CrashGuess"
			pollWinRes "$TITLE"

			setShowPic

			setHuyList

			WANTHELPURL="$("$YAD" --f1-action="$F1ACTION" --image "$SHOWPIC" --image-on-top --window-icon="$STLICON" --form --center --on-top "$WINDECO" \
			--title="$TITLE" --separator="\n" \
			--text="$(spanFont "$SGNAID $(strFix "$GUI_ASKCRASHGUESS" "$1")" "H")" \
			--field="$GUI_HELPURL!$DESC_HELPURL ":CB "$(cleanDropDown "${HELPURL}" "${HUYLIST}${NON}")" \
			--button="$BUT_RETRYCG":0 \
			--button="$BUT_SKIPCG":2 \
			--button="$BUT_NO":4 \
			"$GEOM"	)"

			case $? in
				0)  {
						checkHelpUrl "$WANTHELPURL"
						writelog "INFO" "${FUNCNAME[0]} - Selected '$BUT_RETRYCG' so opening settings"
						duration=0
						SECONDS=0
						prepareLaunch X
					}
				;;
				2)  {
						writelog "INFO" "${FUNCNAME[0]} - Selected '$BUT_SKIPCG' - Setting CRASHGUESS to 0 for $SGNAID"
						updateConfigEntry "CRASHGUESS" "0" "$STLGAMECFG"
					}
				;;
				4)  {
						writelog "SKIP" "${FUNCNAME[0]} - Selected '$BUT_NO' - Exiting regularly"
					}
				;;
			esac
		else
			writelog "INFO" "${FUNCNAME[0]} - Playtime '$1' was longer than CRASHGUESS '$CRASHGUESS', not opening the requester"
		fi
	fi
	rm "$WASSTESTA" 2>/dev/null
}

function fixSymlinks {
	if [ "$FIXSYMLINKS" -eq 1 ]; then
		if [ ! -f "$RUNPROTON" ]; then
			writelog "SKIP" "${FUNCNAME[0]} - Fixing Symlinks is enabled, but RUNPROTON '$RUNPROTON' does not exist"
		else
			LRUNPROTDIR="${RUNPROTON%/*}"
			ORUNPROTDIR="$(readlink -f "$LRUNPROTDIR")"
			writelog "INFO" "${FUNCNAME[0]} - Starting Symlink Fix as requested"

			# the loop needs >1 second even without updating any symlinks and might need much longer with many syminks to be recreated
			# maybe worth to create a parsable checkfile to skip it on the next run?
			while read -r fixme; do
				SYML="$(awk -F ';' '{print $1}' <<< "$fixme")"
				OFIL="$(awk -F ';' '{print $2}' <<< "$fixme")"

				# make sure the found result is correct
				if [ "$(readlink -f "${SYML//\"}")" == "$(readlink -f "${OFIL//\"}")" ]; then
					OFIA="${OFIL//\"}"
					OFIB="${OFIA##*/files/}"
					OFIC="${OFIB//\/x86_64-windows}"
					OFID="${OFIC//\/i386-windows}"
					OOUT="${OFID##*/dist/}"
					
					if [ -n "$OOUT" ] && [ "$OOUT" != "" ]; then
						if [ -d "$LRUNPROTDIR/files" ]; then
							NFIL="$LRUNPROTDIR/files/$OOUT"
						elif [ -d "$LRUNPROTDIR/dist" ]; then
							NFIL="$LRUNPROTDIR/dist/$OOUT"
						else
							writelog "SKIP" "${FUNCNAME[0]} - No 'files' or 'dist' dir found in '$LRUNPROTDIR'"
						fi

						unset NEWFILE
						if [ -f "$NFIL" ]; then
							NEWFILE="$NFIL"
						elif [ -f "${NFIL//lib64\/wine/lib64\/wine\/x86_64-windows}" ]; then
							NEWFILE="${NFIL//lib64\/wine/lib64\/wine\/x86_64-windows}"
						elif [ -f "${NFIL//lib\/wine/lib\/wine\/i386-windows}" ]; then
							NEWFILE="${NFIL//lib\/wine/lib\/wine\/i386-windows}"
						else
							writelog "SKIP" "${FUNCNAME[0]} - No equivalent file found for '$OOUT' in '$LRUNPROTDIR'" # collect in generic nofile/${PROTONVERSION}.txt file to skip early?
						fi

						if [ -f "$NEWFILE" ]; then
							writelog "INFO" "${FUNCNAME[0]} - Symlink '${SYML//\"}' points to '${OFIL//\"}', but '$NEWFILE' would be correct - fixing:"
							rm "${SYML//\"}"
							writelog "INFO" "${FUNCNAME[0]} - 'ln -s \"$NEWFILE\" \"${SYML//\"}\"'"
							ln -s "$NEWFILE" "${SYML//\"}"
						fi
					fi
				else
					writelog "SKIP" "${FUNCNAME[0]} - '${SYML//\"}' does not point to '${OFIL//\"}' but to '$(readlink -f "${SYML//\"}")' - Skipping"
				fi
			done <<< "$(find "${GPFX}/${DRC}" -type l -exec echo \"{}\" \; -exec readlink -v {} \; | grep -v "$LRUNPROTDIR\|$ORUNPROTDIR\|$STUS" | grep -iB1 "Proton" | grep -v "^\-\-" | sed 'N;s/\n/;\"/' | sed 's/$/\"/')"
			writelog "INFO" "${FUNCNAME[0]} - Stop Symlink Fix"
		fi
	else
		writelog "SKIP" "${FUNCNAME[0]} - Fixing Symlinks is not enabled"
	fi
}

function unSymlink {
	if [ "$UNSYMLINK" -eq 1 ]; then
			LRUNPROTDIR="${RUNPROTON%/*}"
			ORUNPROTDIR="$(readlink -f "$LRUNPROTDIR")"
			writelog "INFO" "${FUNCNAME[0]} - Starting unsymlinking as requested - might needs some time, depending on the symlink count"

			while read -r unsym; do
				SYML="$(awk -F ';' '{print $1}' <<< "$unsym")"
				OFIL="$(awk -F ';' '{print $2}' <<< "$unsym")"
				mv "${SYML//\"}" "${SYML//\"}_OLD"
				cp "${OFIL//\"}" "${SYML//\"}"
				if [ -f "${SYML//\"}" ]; then
					rm "${SYML//\"}_OLD"
				else
					writelog "SKIP" "${FUNCNAME[0]} - Copying to '${SYML//\"}' failed - reverting symlink"
					mv "${SYML//\"}_OLD" "${SYML//\"}"
				fi
			done <<< "$(find "${GPFX}/${DRC}" -type l -exec echo \"{}\" \; -exec readlink -v {} \; | grep -iB1 "Proton" | grep -v "^\-\-" | sed 'N;s/\n/;\"/' | sed 's/$/\"/')"
			writelog "INFO" "${FUNCNAME[0]} - Stop Unsymlinking"
	else
		writelog "SKIP" "${FUNCNAME[0]} - Unsymlinking is not enabled"
	fi
}

function delPrefix {
	if [ "$DELPFX" -eq 1 ]; then
		if [ -d "$STEAM_COMPAT_DATA_PATH" ] ; then
			writelog "INFO" "${FUNCNAME[0]} - Removing the prefix was enabled - Creating a backup of steamuser before"
			BACKUPSTEAMUSER=1
			backupSteamUser "$AID"

			writelog "INFO" "${FUNCNAME[0]} - Removing the prefix '$GPFX' as requested"
			notiShow "$(strFix "$NOTY_DELPFX" "$GPFX")"
			rm -rf "$STEAM_COMPAT_DATA_PATH" 2>/dev/null
			mkProjDir "$STEAM_COMPAT_DATA_PATH"
		fi
	fi
}

function createOrUpdateSymDir {
	SYML="$1"
	ODIR="$2"
	if [ -d "$SYML" ] && [ ! -L "$SYML" ] ; then
		writelog "WARN" "${FUNCNAME[0]} - Renaming existing '$SYML' to '${SYML}_old'"
		mv "$SYML" "${SYML}_old"
	fi
	
	if [ -L "$SYML" ] && [ "$(readlink "$SYML")" != "$ODIR" ]; then
		writelog "WARN" "${FUNCNAME[0]} - Renaming existing symlink '$SYML' to '${SYML}_old'"
		writelog "WARN" "${FUNCNAME[0]} - because it points to '$(readlink "$SYML")'"
		mv "$SYML" "${SYML}_old"
	fi

	if [ ! -L "$SYML" ]; then
		writelog "INFO" "${FUNCNAME[0]} - Created symlink from '$ODIR' to '$SYML'"
		ln -s "$ODIR" "$SYML"
	fi
}

function gameFix {
	if [ "$AID" -eq 223220 ] || [ "$AID" -eq 246960 ]; then
		writelog "INFO" "${FUNCNAME[0]} - got '$AID' as STEAM_COMPAT_APP_ID - need to change pwd from '$PWD' to '${STEAM_COMPAT_INSTALL_PATH}/launcher'"
		cd "${STEAM_COMPAT_INSTALL_PATH}/launcher" || return
	fi
}

function updateMO2GlobConf {
	mkProjDir "$STLMO2DLDATDIR"
	MYGLOBDLDAT="${STLMO2DLDATDIR}/global.conf"
	writelog "INFO" "${FUNCNAME[0]} - Updating '$MYGLOBDLDAT' with up to date data"
	{
		echo "GMO2EXE=\"$MO2EXE\""
		echo "RUNPROTON=\"$MO2RUNPROT\""
		echo "STEAM_COMPAT_CLIENT_INSTALL_PATH=\"$STEAM_COMPAT_CLIENT_INSTALL_PATH\""
		echo "STEAM_COMPAT_DATA_PATH=\"$MO2CODA\""
	} > "$MYGLOBDLDAT"
}

function updateMO2PortConf {
	MONGURL="$(grep -i "\"$MO2GAM\"" "$MO2GAMES" | head -n1 | cut -d ';' -f4)"
	MONGURL="${MONGURL//\"}"

	mkProjDir "$STLMO2DLDATDIR"
	MYPORTDLDAT="${STLMO2DLDATDIR}/${MONGURL}.conf"

	if [ -z "${MONGURL}" ]; then
		writelog "WARN" "${FUNCNAME[0]} - extracting the gamename MONGURL from '$MO2GAMES' by looking for '$MO2GAM' failed - the file '$MYPORTDLDAT' won't be found"
	fi

	writelog "INFO" "${FUNCNAME[0]} - Updating '$MYPORTDLDAT' with up to date data"

	{
		echo "GMO2EXE=\"$GMO2EXE\""
		echo "RUNPROTON=\"$RUNPROTON\""
		echo "STEAM_COMPAT_CLIENT_INSTALL_PATH=\"$STEAM_COMPAT_CLIENT_INSTALL_PATH\""
		echo "STEAM_COMPAT_DATA_PATH=\"$STEAM_COMPAT_DATA_PATH\""
	} > "$MYPORTDLDAT"
}

function prepMO2 {
	function setBaseMO2RunCmd {
		unset RUNCMD
		while read -r arg; do
			mapfile -t -O "${#RUNCMD[@]}" RUNCMD <<< "$arg"
			if [ "$arg" == "$WFEAR" ]; then
				break
			fi
		done <<< "$(printf "%s\n" "$@")"
	}

	if [ "$ISGAME" -eq 2 ] && [ "$USEWINE" -ne 1 ]; then
		if [ "$MO2MODE" != "disabled" ]; then
			if [ "$MOINST" == "global" ]; then
				writelog "INFO" "${FUNCNAME[0]} - MO2MODE is '$MO2MODE' - preparing MO2 symlinks in '$GPFX' for '$MOINST' instance"

				GAMMO2DAT="$GPFX/$DRCU/$STUS/$ADLO/$MO"
				ORGMO2DAT="$MO2PFX/$DRCU/$STUS/$ADLO/$MO"
				createOrUpdateSymDir "$GAMMO2DAT" "$ORGMO2DAT"

				OMODDIR="$MO2PFX/$MORDIR"
				GMODDIR="$GPFX/$MORDIR"
				createOrUpdateSymDir "$GMODDIR" "$OMODDIR"
			else
				writelog "INFO" "${FUNCNAME[0]} - MO2MODE is '$MO2MODE' - preparing MO2 symlinks in '$GPFX' for '$MOINST' instance"
			fi
			
			setBaseMO2RunCmd "$@"
			GMO2EXE="$GPFX/$MOERPATH"
		fi

# silent mode doesn't work, feel free to create a PR
		if [ "$MO2MODE" == "silent" ]; then

MO2MODE="gui"

function disabledWIPSilentMode {
			if [ -n "$MO2GAM" ] && [ -f "$MO2EXE" ]; then
				if [ "$(grep -c "^+" "$MODLIST")" -eq 0 ]; then
					writelog "SKIP" "${FUNCNAME[0]} - Not starting $MO silent as requested, because no mod is enabled in '$MODLIST'"
					notiShow "$(strFix "$NOTY_NOMO" "$GN" "$AID")"
					MO2MODE="gui"
				else
					# both seem to work:
#					ZEXE="Z:${3//\//\\\\}"
#					ZEXE="$(grep "^1\\\binary" "$MOININI" | tr -d "\015" | cut -d '=' -f2)"
#					sed "/^MainWindow_modList_state/d" -i "$MOININI"
#					sed "/^MainWindow_downloadView_state/d" -i "$MOININI"
#					sed "/^MainWindow_geometry/d" -i "$MOININI"

					RUNCMD=("${RUNCMD[@]}" "$GMO2EXE" "moshortcut://$MO2GAM:$MO2GAMINI" "-p" "Default")
#					RUNCMD=("$1" "$2" "$GMO2EXE" "$ZEXE" "-i" "$MO2GAM")
#					RUNCMD=("$1" "$2" "$GMO2EXE" "-i" "$MO2GAM")

					writelog "INFO" "${FUNCNAME[0]} - Starting '$SGNAID' with $MO enabled mods with command '${RUNCMD[*]}'"
					notiShow "$(strFix "$NOTY_STARTSIMO" "$GN" "$AID")"
				fi
			else
				writelog "SKIP" "${FUNCNAME[0]} - Not starting $MO silent as requested, because MO2GAM ('$MO2GAM') or MO2EXE ('$MO2EXE') is empty"
				MO2MODE="gui"
			fi
}
		fi

		if [ "$MO2MODE" == "gui" ]; then
			if [ -n "$MO2GAM" ]; then
				if [ -n "$MOINST" ] && [ "$MOINST" == "portable" ]; then
				#XXXXXXXXXXXXXXXX
				# testing and not working because wabbajack wants to open a nexus url for authentication, which doesn't seem to work
					USEWABBAJACK=0

					WAB="wabbajack"
					if [ "$USEWABBAJACK" -eq 1 ]; then
						writelog "INFO" "${FUNCNAME[0]} - ${WAB^} is enabled - starting"
						WABINST="$MO2DLDIR/${WAB^}.exe"
						export DOTNET_ROOT="$VTX_DOTNET_ROOT"
						export DOTNET_BUNDLE_EXTRACT_BASE_DIR="$VTX_DOTNET_ROOT"
						installDotNet "$MO2PFX" "$MO2WINE" "48"
					#	WINEDEBUG="-all" WINEPREFIX="$MO2PFX" "$MO2WINE" "$WABINST" 2>&1 | tee "$STLSHM/${FUNCNAME[0]}_${WAB}.log"
						RUNCMD=("$MO2WINE" "$WABINST")
					else
						writelog "INFO" "${FUNCNAME[0]} - ${WAB^} MOINST $MOINST"

						writelog "INFO" "${FUNCNAME[0]} - Running $MOINST instance"
						RUNCMD=("${RUNCMD[@]}" "$MO2EXE")
					fi
				else
					RUNCMD=("${RUNCMD[@]}" "$MO2EXE" "-i" "${MO2GAM//\"}")
				fi

				writelog "INFO" "${FUNCNAME[0]} - Starting '$SGNAID' with $MO gui via '${RUNCMD[*]}'"
				notiShow "$(strFix "$NOTY_STARTVEMO" "$GN" "$AID")"
			else
				RUNCMD=("${RUNCMD[@]}" "$MO2EXE")
				writelog "INFO" "${FUNCNAME[0]} - Starting '$SGNAID' with $MO gui via '${RUNCMD[*]}'"
				notiShow "$(strFix "$NOTY_STARTVEMO" "$GN" "$AID")"
			fi

			if [ -n "$MOINST" ] && [ "$MOINST" == "portable" ]; then
				updateMO2PortConf
			else
				updateMO2GlobConf
			fi
		fi
	fi
}

function startGame {
	loadCfg "$GEMETA/$AID.conf"

	if [ "$STLPLAY" -eq 0 ]; then
		writelog "INFO" "${FUNCNAME[0]} - Getting the Game Window name:"
		getGameWindowName &
	fi

	touch "$PIDLOCK"
	startSBSVR &
	gameFix
	checkConty

	if [ "$BLOCKINTERNET" -eq 1 ]; then
		writelog "INFO" "${FUNCNAME[0]} - Starting game with blocked internet access"
		BLOCKCMD="unshare"
		BLOCKARGS="-n -r"
		unset BLOCKARGSARR
		mapfile -d " " -t -O "${#BLOCKARGSARR[@]}" BLOCKARGSARR < <(printf '%s' "$BLOCKARGS")
		RUNCMD=("$BLOCKCMD" "${BLOCKARGSARR[@]}" "${@}")
	else
		RUNCMD=("${@}")
	fi

	writelog "INFO" "${FUNCNAME[0]} - Full start command is '${*}'"

	prepMO2 "$@"

	if [ "$HAVESCTP" -eq 1 ] && [ "$ISGAME" -eq 2 ]; then
		writelog "INFO" "${FUNCNAME[0]} - Rebuilding STEAM_COMPAT_TOOL_PATHS variable:"
		writelog "INFO" "${FUNCNAME[0]} - Adding RUNPROTON '${RUNPROTON%/*}'"
		STEAM_COMPAT_TOOL_PATHS="${RUNPROTON%/*}"
		if [ "$HAVESCTP" -eq 1 ] && [ "$USESLR" -eq 1 ]; then
			RUNSLA="${RUNSLR[0]}"
			writelog "INFO" "${FUNCNAME[0]} - Adding '${RUNSLA%/*}' because USESLR is enabled"
			STEAM_COMPAT_TOOL_PATHS="$STEAM_COMPAT_TOOL_PATHS:${RUNSLA%/*}"
		fi
		writelog "INFO" "${FUNCNAME[0]} - Result: Set STEAM_COMPAT_TOOL_PATHS from '$ORG_STEAM_COMPAT_TOOL_PATHS' to '$STEAM_COMPAT_TOOL_PATHS'"
	elif [ "$RUNFORCESLR" -eq 1 ]; then
		writelog "INFO" "${FUNCNAME[0]} - Rebuilding STEAM_COMPAT_TOOL_PATHS variable, because SLR was forced"
		writelog "INFO" "${FUNCNAME[0]} - Adding RUNPROTON '${RUNPROTON%/*}'"
		STEAM_COMPAT_TOOL_PATHS="${RUNPROTON%/*}"
		LASTSLRPATH="${LASTSLR% --verb*}"
		STEAM_COMPAT_TOOL_PATHS="$STEAM_COMPAT_TOOL_PATHS:${LASTSLRPATH%/*}"
		writelog "INFO" "${FUNCNAME[0]} - Result: Updated STEAM_COMPAT_TOOL_PATHS to '$STEAM_COMPAT_TOOL_PATHS'"
	fi

	SECONDS=0

	if [ "$MO2MODE" != "disabled" ] && [ -n "$GMO2EXE" ]; then
		writelog "INFO" "${FUNCNAME[0]} - Changing pwd to '${GMO2EXE%/*}' for $MO launch"
		cd "${GMO2EXE%/*}" >/dev/null || return
	fi

	if ! command -v "$GAMESCOPE" >/dev/null && [ "$USEMANGOAPP" -eq 1 ]; then
		writelog "WARN" "${FUNCNAME[0]} - Disabling USEMANGOAPP because '$GAMESCOPE' wasn't found"
		USEMANGOAPP=0
	fi
	
	if [ -x "$RUNCONTY" ] && [ "$RUNCONTY" != "$NON" ]; then
		writelog "INFO" "${FUNCNAME[0]} - ## Starting game using Conty executable '$RUNCONTY'"
		"$RUNCONTY" "${RUNCMD[@]}"
	else
		writelog "INFO" "${FUNCNAME[0]} - ## ORIGINAL INCOMING LAUNCH COMMAND: '${INGCMD[*]}'"
		writelog "INFO" "${FUNCNAME[0]} - ## STL LAUNCH COMMAND: '${RUNCMD[*]}'"
		writelog "INFO" "${FUNCNAME[0]} - ## GAMESTART HERE ###"

		restoreOrgVars # restore original LC_ and friends for the game

		GRUNLOG="$STLGLLOGDIRID/${AID}.log"
		if [ "$ISORIGIN" -eq 1 ]; then
			writelog "INFO" "${FUNCNAME[0]} - ## ${L2EA}  LAUNCH COMMAND: '${RUNCMD[*]}'"

			function runEA {
				"${RUNCMD[@]}" 2>&1 | tee "$GRUNLOG"
			}

			unsetSTLvars		
			runEA &
		elif [ "$USEMANGOAPP" -eq 1 ]; then
			# mangoapp gamestart - COMMENTDEBUG:
			writelog "INFO" "${FUNCNAME[0]} - Using $MANGOAPP"
			MRSH="$STLSHM/maprun.sh"
			printf "\"%s\" " "${RUNCMD[@]}" > "$MRSH"
			sed -i "s/\\\/\\\\\\\/" "$STLSHM/maprun.sh"
			chmod +x "$MRSH"
			gameScopeArgs "$GAMESCOPE_ARGS"

			function runMA {
				function mappRun {
					"$MRSH" & "$MANGOAPP"
				}
				export MANGOAPP
				export MRSH
				export -f mappRun
				if [ -n "${GAMESCOPEARGSARR[0]}" ]; then
					writelog "INFO" "${FUNCNAME[0]} - ## ${MANGOAPP^^} GAMESCOPE LAUNCH COMMAND: '$(command -v "$GAMESCOPE") ${GAMESCOPEARGSARR[*]}'"
					"$(command -v "$GAMESCOPE")" "${GAMESCOPEARGSARR[@]}" bash -c mappRun 2>&1 | tee "$GRUNLOG"
				else
					"$(command -v "$GAMESCOPE")" -- bash -c mappRun 2>&1 | tee "$GRUNLOG"				
				fi
			}
			runMA &
		else
			# regular gamestart - COMMENTDEBUG:
			"${RUNCMD[@]}" 2>&1 | tee "$GRUNLOG"
		fi
	fi

	if [ "$MO2MODE" != "disabled" ]; then
		cd - >/dev/null || return
	fi

	emptyVars "O" "X" # clear original variables again (mostly for a continous log (date))
	createSymLink "${FUNCNAME[0]}" "$GRUNLOG" "${STLGLLOGDIRTI}/${GN}.log"

# this is broken - maybe later:
#	if [ "$ISGAME" -eq 2 ] && [ "$USEWINE" -eq 0 ] && { grep -qi "GE-" <<< "$USEPROTON" || grep -qi "\-TKG" <<< "$USEPROTON" || [ "$ISORIGIN" -eq 1 ];}; then
	if [ "$ISGAME" -eq 2 ] && [ "$USEWINE" -eq 0 ]; then
		if [ "$ISORIGIN" -eq 1 ]; then
			writelog "INFO" "${FUNCNAME[0]} - Waiting for $L2EA process to finish"		
			# TODO maybe add waitForOriginPid - the sleep is not too nice (but at least non blocking)
			sleep 10
			OE="Origin.exe"
			WSPID="$("$PGREP" -a "" | grep "$OE" | grep -v grep | cut -d ' ' -f1 | tail -n1)"
			writelog "INFO" "${FUNCNAME[0]} - $L2EA game launch pid is $WSPID"
		elif [ "$USEMANGOAPP" -eq 1 ]; then
			# could be used generally, but undecided yet if waitForGamePid should be used always by default
			waitForGamePid
			RLRUNWINESERVER="$(readlink -f "$RUNWINESERVER")"
			WSPID="$("$PGREP" -a "" | grep "$RLRUNWINESERVER" | grep -v grep | cut -d ' ' -f1 | tail -n1)"
			writelog "INFO" "${FUNCNAME[0]} - $MANGOAPP game launch pid is $WSPID"
		elif [ "$USECUSTOMCMD" -eq 1 ] && [ "$FORK_CUSTOMCMD" -eq 1 ] && [ "$ONLY_CUSTOMCMD" -eq 0 ] && [ "$WAITFORCUSTOMCMD" -ge 1 ] && [ -n "$(CUCOPID)" ];then
			WSPID="$(CUCOPID)"
			writelog "INFO" "${FUNCNAME[0]} - Custom program pid is $WSPID"
		else
			RLRUNWINESERVER="$(readlink -f "$RUNWINESERVER")"
			WSPID="$("$PGREP" -a "" | grep "$RLRUNWINESERVER" | grep -v grep | cut -d ' ' -f1 | tail -n1)"
		fi
		if [ -n "$WSPID" ] && [ "$WSPID" -eq "$WSPID" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Waiting for the process '$WSPID' to finish"
			tail --pid="$WSPID" -f /dev/null

			if [ "$USEMANGOAPP" -eq 1 ]; then
				writelog "INFO" "${FUNCNAME[0]} - $MANGOAPP game launch finished - closing"
				"$PKILL" -f "$MANGOAPP"
			else
				writelog "INFO" "${FUNCNAME[0]} - Process '$WSPID' finished - closing"
			fi
		else
			writelog "ERROR" "${FUNCNAME[0]} - Could not determine pid of '$RLRUNWINESERVER'"
		fi
	else
		writelog "WARN" "${FUNCNAME[0]} - Skipping Wait for any PID - ISGAME:'$ISGAME';USEWINE:'$USEWINE' - possible missing function!"
	fi

	duration=$SECONDS
	logPlayTime "$duration"
	writelog "INFO" "${FUNCNAME[0]} - ## GAMESTOP after '$duration' seconds playtime"

	# Continue steamwebhelper if requested
	StateSteamWebHelper cont
}

# Shellcheck doesn't like the sed commands here and wants parameter expansion, but I'm not sure that these sed actions are possible with it.
# The Shellcheck wiki says more complex sed examples can be ignored, so we ignore it
function gameScopeArgs {  # This implementation could be VASTLY improved!
	ARGSTRING="$1"
	unset GAMESCOPEARGSARR

	if [ "$1" != "$NON" ]; then
		# This removes paths from the GameScope args array as spaces in paths can cause issues, then builds the array, and then re-inserts the paths where it finds empty single-quotes which we wrap paths with in GameScopeGui.
		# When saving from the main menu, single quotes seem to get cleared, so we need to ensure paths are wrapped with them

		# Store paths from GameScope array string
		IFS_backup=$IFS
		IFS=$'\n'
		mapfile -t GAMESCOPE_ARGPATHS < <( echo "$ARGSTRING" | grep -oP "'/(.+?)'" )
		writelog "INFO" "${FUNCNAME[0]} - GameScope incoming args are '${ARGSTRING[*]}'"
		# If the above is empty, try and surround any existing paths with quotes and then grep for the file paths from the quotes - This means paths cannot contain quotes, but oh well. Compromise!
		if [ -z "${GAMESCOPE_ARGPATHS[*]}" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Could not find any paths from incoming GameScope arguments, checking if we need to surround any paths in quotes..."
			unset GAMESCOPE_ARGPATHS

			# shellcheck disable=SC2001
			ARGSTRING="$(echo "${ARGSTRING}" | sed "s:\(/\S* \S*\):'\1':g" )"  # Finds paths and surrounds them in single quotes so the below grep works!
			mapfile -t GAMESCOPE_ARGPATHS < <( echo "$ARGSTRING" | grep -oP "'/(.+?)'" )
			if [ -n "${GAMESCOPE_ARGPATHS[*]}" ]; then
				writelog "INFO" "${FUNCNAME[0]} - We found some paths we need to update - Updated GameScope args string is '$ARGSTRING'"
			else
				writelog "INFO" "${FUNCNAME[0]} - Still could not find any paths from incoming GameScope arguments, assuming we don't have any paths in our arguments"
			fi
		fi
		IFS=$IFS_backup

		# Remove all text between single quotes -- We assume all text between single quotes in this context will be a GameScope path arg
		writelog "INFO" "${FUNCNAME[0]} - GameScope arg paths are '${GAMESCOPE_ARGPATHS[*]}'"
		# shellcheck disable=SC2001
		ARGSTRING="$( echo "$ARGSTRING" | sed "s:'[^']*':'':g" )"
		mapfile -d " " -t -O "${#GAMESCOPEARGSARR[@]}" GAMESCOPEARGSARR < <(printf '%s' "$ARGSTRING")

		INSERTARG=$((0))  # Which path arg to insert from the `GAMESCOPE_ARGPATHS` array
		GAMESCOPEARGSARR_COPY=("${GAMESCOPEARGSARR[@]}")
		for i in "${!GAMESCOPEARGSARR_COPY[@]}"; do
			if [[ "${GAMESCOPEARGSARR_COPY[$i]}" == *"'"* ]]; then
				GAMESCOPEARGSARR_COPY[$i]="${GAMESCOPE_ARGPATHS[${INSERTARG}]}"
				INSERTARG=$((INSERTARG + 1))
			fi
		done

		unset GAMESCOPEARGSARR  # Reset array and re-assign it to copied array with updated argument values
		GAMESCOPEARGSARR=("${GAMESCOPEARGSARR_COPY[@]}")
	fi

	if [ "${#GAMESCOPEARGSARR[@]}" -ge 1 ]; then
		writelog "INFO" "${FUNCNAME[0]} - Using following gamescope arguments: '${GAMESCOPEARGSARR[*]}'"
	else
		writelog "INFO" "${FUNCNAME[0]} - gamescope doesn't have any command line arguments"
	fi
}

function gameArgs {
	ARGSTRING="$1"
	unset GAMEARGSARR

	if [ "$1" == "$GAMEARGS" ]; then
		if [ "$SORTGARGS" -eq 1 ]; then
			# add (originally "hardcoded", but now possibly modified) command line arguments coming directly from Steam/the game
			if [ "$HARDARGS" != "$NOPE" ] && [ "$HARDARGS" != "$NON" ]; then
				mapfile -d " " -t -O "${#GAMEARGSARR[@]}" GAMEARGSARR < <(printf '%s' "$HARDARGS")
			fi

			# now append those command line arguments coming from $SLO
			if [ "$SLOARGS" != "$NON" ]; then
				mapfile -d " " -t -O "${#GAMEARGSARR[@]}" GAMEARGSARR < <(printf '%s' "$SLOARGS")
			fi
		else
			if [ "${#ORGCMDARGS[@]}" -ge 1 ]; then
				GAMEARGSARR=("${ORGCMDARGS[@]}")
			fi
		fi
	fi 
	
	# finally add the own custom command line arguments
	if [ "$1" != "$NON" ]; then
		mapfile -d " " -t -O "${#GAMEARGSARR[@]}" GAMEARGSARR < <(printf '%s' "$ARGSTRING")
	fi

	if [ "${#GAMEARGSARR[@]}" -ge 1 ]; then
		writelog "INFO" "${FUNCNAME[0]} - Combined final game command line arguments: '${GAMEARGSARR[*]}'"
	else
		writelog "INFO" "${FUNCNAME[0]} - Game doesn't use any command line arguments"
	fi
}

function fixCustomMeta {
	if [ -f "$1" ] && grep -q "^GAMEDIR=" "$1"; then
		writelog "INFO" "${FUNCNAME[0]} - Renaming variable 'GAMEDIR' to 'MEGAMEDIR' in '$1', because 'GAMEDIR' also exists in the generic metadata, coming from steam" "E"
		sed "s:^GAMEDIR=:MEGAMEDIR=:" -i "$1"
	fi	
}

function initPlay {
	HAVESLR=0
	HAVESLRCT=0
	HAVEREAP=0
	HAVESCTP=0
	INCOPATH=0
	STLPLAY=1

	function setHaveConfs {
		if [ -n "$HAVID" ]; then
			if [ -z "$HAVCUME" ]; then
				HAVCUME="$CUMETA/$HAVID.conf"
			fi

			if [ -z "$HAVGEME" ]; then
				HAVGEME="$GEMETA/$HAVID.conf"
			fi
			
			if [ -z "$HAVGACO" ]; then
				HAVGACO="$STLGAMEDIRID/$HAVID.conf"
			fi
		fi	
	}

	function loadHaveConfs {
		if [ -f "$HAVGEME" ] && [ -z "$LOADEDHAVGEME" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Loading generic metadata found under '$HAVGEME'" "E"
			loadCfg "$HAVGEME"
			LOADEDHAVGEME=1
		fi

		if [ -f "$HAVCUME" ] && [ -z "$LOADEDHAVCUME" ]; then
			fixCustomMeta "$HAVCUME"
			writelog "INFO" "${FUNCNAME[0]} - Loading custom metadata found under '$HAVCUME'" "E"
			loadCfg "$HAVCUME"
			LOADEDHAVCUME=1
		fi

		if [ -f "$HAVGACO" ] && [ -z "$LOADEDHAVGACO" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Loading game config '$HAVGACO'" "E"
			loadCfg "$HAVGACO"
			LOADEDHAVGACO=1
		fi
	}

	function saveHaveCuMe {
		if [ -n "$HAVCUME" ] && [ ! -f "$HAVCUME" ]; then
			touch "$HAVCUME"
		fi
		
		if [ -n "$MEGAMEDIR" ]; then 
			touch "$FUPDATE"
			updateConfigEntry "MEGAMEDIR" "$MEGAMEDIR" "$HAVCUME"
		fi
	}

	function saveHaveGeMe {
		if [ -n "$HAVGEME" ] && [ ! -f "$HAVGEME" ]; then
			touch "$HAVGEME"
		fi

		if [ -n "$HAVID" ]; then
			touch "$FUPDATE"
			updateConfigEntry "GAMEID" "$HAVID" "$HAVGEME"
		elif [ -n "$AID" ] && [ "$AID" != "$PLACEHOLDERAID" ]; then
			touch "$FUPDATE"
			updateConfigEntry "GAMEID" "$AID" "$HAVGEME"
		fi
		
		if [ -n "$EXECUTABLE" ]; then 
			touch "$FUPDATE"
			updateConfigEntry "EXECUTABLE" "$EXECUTABLE" "$HAVGEME"	
			if [ -z "$GAMEEXE" ]; then
				GAMEEXE="${EXECUTABLE//.exe}"
			fi
		fi

		if [ -n "$GE" ] && [ -z "$GAMEEXE" ]; then
			GAMEEXE="$GE"
		fi

		if [ -n "$GAMEEXE" ]; then
			touch "$FUPDATE"
			updateConfigEntry "GAMEEXE" "$GAMEEXE" "$HAVGEME"
		fi

		if [ -z "$GAMENAME" ]; then
			GAMENAME="${EXECUTABLE//.exe}"
		fi
			
		if [ -n "$GAMENAME" ]; then
			touch "$FUPDATE"
			updateConfigEntry "GAMENAME" "$GAMENAME" "$HAVGEME"
		fi

		if [ -z "$KEEPGAMENAME" ]; then
			KEEPGAMENAME=1
			touch "$FUPDATE"
			updateConfigEntry "KEEPGAMENAME" "$KEEPGAMENAME" "$HAVGEME"
		fi	
	}

	if [ "$1" -eq "$1" ] 2>/dev/null; then
		writelog "INFO" "${FUNCNAME[0]} - Assuming incoming argument '$1' is a SteamAppId" "E"
		HAVID="$1"
	elif [ -f "$1" ]; then
		writelog "INFO" "${FUNCNAME[0]} - Assuming incoming argument '$1' is an absolute path to a game exe" "E"
		HAVPA="$1"
		INCOPATH=1
	else
		writelog "INFO" "${FUNCNAME[0]} - Assuming incoming argument '$1' is a game title" "E"
		HAVTI="$1"
	fi
	
	if [ -n "$HAVTI" ] || [ -n "$HAVID" ] && { [ -n "$2" ] && [ -f "$2" ];}; then
		HAVPA="$2"
	fi
	
	if [ -n "$HAVTI" ]; then
		CKHAVGEME="$(find "$TIGEMETA" -iname "$HAVTI.conf")"
		if [ -f "$CKHAVGEME" ]; then
			HAVGEME="$CKHAVGEME"
		fi

		CKHAVCUME="$(find "$TICUMETA" -iname "$HAVTI.conf")"
		if [ -f "$CKHAVCUME" ]; then
			HAVCUME="$CKHAVCUME"
		fi
		
		if [ -z "$HAVGEME" ]; then
			HAVGEMECFG="$(grep -Ri "NAME=\"$HAVTI" "$GEMETA/" | head -n1 | cut -d ':' -f1)"
			CKHAVGEME="$GEMETA/$HAVGEMECFG"
			if [ -f "$CKHAVGEME" ]; then
				HAVGEME="$CKHAVGEME"
			fi

			CKHAVCUME="$(find "$CUMETA" -iname "$HAVGEMECFG")"
			if [ -f "$CKHAVCUME" ]; then
				HAVCUME="$CKHAVCUME"
			fi
		fi
	fi
	
	setHaveConfs
	loadHaveConfs

	if [ -n "$GAMEID" ] && [ -z "$HAVID" ]; then
		HAVID="$GAMEID"
		writelog "INFO" "${FUNCNAME[0]} - Found SteamAppId '$HAVID'" "E"
	fi

	setHaveConfs
	loadHaveConfs

	if [ -z "$EXECUTABLE" ] && [ -f "$HAVPA" ]; then
		EXECUTABLE="${HAVPA##*/}"
	fi

	if [ -z "$EXECUTABLE" ] && [ -n "$GAMENAME" ]; then
		EXECUTABLE="$GAMENAME"
	fi

	if [ -z "$HAVPA" ] && [ -n "$MEGAMEDIR" ] && [ -n "$EXECUTABLE" ]; then
		CHKHAVPA="$MEGAMEDIR/$EXECUTABLE"
		if [ -f "$CHKHAVPA" ]; then
			HAVPA="$CHKHAVPA"
		fi
	fi
	
	if [ -n "$EXECUTABLE" ] && [ -n "$HAVPA" ] && [ "$EXECUTABLE" != "${HAVPA##*/}" ]; then
		EXECUTABLE="${HAVPA##*/}"
	fi

	if [ -n "$MEGAMEDIR" ]; then
		GFD="$MEGAMEDIR"
	fi

	if [ -z "$HAVID" ] &&  [ -z "$GAMEID" ] && [ -n "$HAVPA" ]; then
		HAVID="$(setGNID "${HAVPA##*/}")"
		if [ -z "$GFD" ]; then
			GFD="${HAVPA%/*}"
		fi
		if [ -z "$EFD" ]; then
			EFD="${HAVPA%/*}"
		fi
	fi

	if [ -n "$MEGAMEDIR" ] && [ -n "$HAVPA" ] && [ "$MEGAMEDIR" != "${HAVPA%/*}" ]; then
		MEGAMEDIR="${HAVPA%/*}"
	fi

	if [ -n "${HAVPA%/*}" ] && [ -z "$EFD" ]; then EFD="${HAVPA%/*}"; fi
	if [ -n "${HAVPA%/*}" ] && [ -z "$GFD" ]; then GFD="${HAVPA%/*}"; fi

	setHaveConfs
	loadHaveConfs

	if [ -n "$HAVID" ] &&  [ -z "$GAMEID" ] && { [ -z "$AID" ] || [ "$AID" == "$PLACEHOLDERAID" ];}; then
		writelog "INFO" "${FUNCNAME[0]} - Setting AID to '$HAVID'" "E"
		export AID="$HAVID"
	fi

	if [ -n "$GAMEID" ] && { [ -z "$AID" ] || [ "$AID" == "$PLACEHOLDERAID" ];}; then
		writelog "INFO" "${FUNCNAME[0]} - Setting AID to '$GAMEID'" "E"
		export AID="$GAMEID"
	fi
	saveHaveCuMe
	saveHaveGeMe
    # from here all required vars should be ready to launch
	if [ -n "$AID" ] && [ "$AID" != "$PLACEHOLDERAID" ]; then
		if [ -z "$HAVGACO" ]; then
			HAVGACO="$STLGAMEDIRID/$AID.conf"
		fi

		loadHaveConfs

		if [ -n "$GAMENAME" ] && [ "$GAMENAME" != "$NON" ]; then
			ICGN="$GAMENAME"
		elif [ -n "$GAMEEXE" ] && [ "$GAMEEXE" != "$NON" ]; then
			ICGN="$GAMEEXE"
		elif [ -n "$EXECUTABLE" ] && [ "$EXECUTABLE" != "$NON" ]; then
			ICGN="$GAMEEXE"
		else
			ICGN="$NON"
		fi

		createDesktopIconFile "$AID" "0" "$ICGN" "$HAVPA"

		if [ -f "$HAVPA" ]; then
			if [ -z "$GP" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Set 'GP' to '$HAVPA'" "E"
				GP="$HAVPA"
			else
				writelog "INFO" "${FUNCNAME[0]} - Already have 'GP' '$GP'" "E"
			fi

			if [ "$INCOPATH" -eq 1 ]; then
				while read -r INGARG; do
					mapfile -t -O "${#INGCMD[@]}" INGCMD <<< "$INGARG"
				done <<< "$(printf "%s\n" "$@")"

				FOUNDORGGCMD=0
				while read -r ORGARG; do
					if [ "$FOUNDORGGCMD" -eq 0 ]; then
						mapfile -t -O "${#ORGGCMD[@]}" ORGGCMD <<< "$ORGARG"
						if [[ "$ORGARG" =~ $GP ]]; then
							FOUNDORGGCMD=1
						fi
					else
						mapfile -t -O "${#ORGCMDARGS[@]}" ORGCMDARGS <<< "$ORGARG"
					fi
				done <<< "$(printf "%s\n" "${INGCMD[@]}")"
			else
				ORGGCMD=( "$HAVPA" )
			fi

			if [ -z "$GE" ] && [ -n "$HAVPA" ]; then
				GE="${HAVPA##*/}" 
			fi

			if [ -z "$GP" ] && [ -n "$HAVPA" ]; then
				GP="$HAVPA"
			fi

			if [ -z "$GN" ] && [ -n "$HAVPA" ]; then
				GN="${HAVPA##*/}" 
			fi

			writelog "INFO" "${FUNCNAME[0]} - Game executable used is '$HAVPA'" "E"

			if grep -q "shell script" <<< "$(file "$(realpath "$HAVPA")")" || grep -q "ELF.*.LSB" <<< "$(file "$(realpath "$HAVPA")")" ; then
				writelog "INFO" "${FUNCNAME[0]} - Assuming this is a linux binary" "E"
				ISGAME=3
				GPFX="$NON"
				cd "$MEGAMEDIR" || return
				prepareLaunch
				cd - || return
			else
				writelog "INFO" "${FUNCNAME[0]} - Assuming this is a windows binary" "E"

				if [ -z "$STEAM_COMPAT_INSTALL_PATH" ]; then
					if [ -n "$MEGAMEDIR" ]; then
						export STEAM_COMPAT_INSTALL_PATH="$MEGAMEDIR"
					elif [ -n "$EFD" ]; then
						export STEAM_COMPAT_INSTALL_PATH="$EFD"
					else
						writelog "INFO" "${FUNCNAME[0]} - STEAM_COMPAT_INSTALL_PATH (game dir) is unknown - setting it at least to '${STLDLDIR}'"
						export STEAM_COMPAT_INSTALL_PATH="$STLDLDIR"
					fi
				fi

				if [ -z "$STL_COMPAT_DATA_PATH" ]; then
					STL_COMPAT_DATA_PATH="$STLCOMPDAT/$AID"
				fi

				if [ -n "$STL_COMPAT_DATA_PATH" ]; then
					mkProjDir "$STL_COMPAT_DATA_PATH"
					writelog "INFO" "${FUNCNAME[0]} - Using '$STL_COMPAT_DATA_PATH' as STEAM_COMPAT_DATA_PATH" "E"
					export STEAM_COMPAT_DATA_PATH="$STL_COMPAT_DATA_PATH"
					export GPFX="${STL_COMPAT_DATA_PATH}/pfx"
					ISGAME=2
					cd "$STEAM_COMPAT_INSTALL_PATH" || return
					prepareLaunch
					cd - || return
				else
					writelog "ERROR" "${FUNCNAME[0]} - STEAM_COMPAT_DATA_PATH was not defined"
				fi
			fi
		fi
	else
		writelog "ERROR" "${FUNCNAME[0]} - Could not determine an AppID - can't continue" "E"
	fi
}

function standaloneGames {
	if [ -d "$GEMETA" ]; then
		while read -r line; do
			if [ -n "$1" ] && [ "$1" == "l" ]; then
				SAG="$(grep "^GAMENAME=" "$line" | cut -d '=' -f2)"
				if [ -n "$SAG" ]; then
					echo "${SAG//\"/}"
				fi
			elif [ -n "$1" ] && [ "$1" == "g" ]; then
				unset GAMENAME EXECUTABLE GAMEID
				loadCfg "$line"
				if [ -n "$GAMEID" ] && [ -n "$EXECUTABLE" ]; then
					echo "FALSE"

					if [ -n "$GAMENAME" ]; then
						echo "$GAMENAME"
					else
						echo "$EXECUTABLE"
					fi
					
					echo "$EXECUTABLE"
					echo "$GAMEID"
				else
					writelog "SKIP" "${FUNCNAME[0]} - Skipping config '$line', because at least one of GAMEID:'$GAMEID' EXECUTABLE:'$EXECUTABLE', GAMENAME:'$GAMENAME' is empty"
				fi
			else
				echo "$line"
			fi
		done <<< "$(find "$GEMETA" -name "${GETSTAID}.conf")"
	else
		writelog "ERROR" "${FUNCNAME[0]} - Directory GEMETA '$GEMETA' could not be found" "E"
 	fi
}

function standaloneDefGameIcon {
	if [ -x "$(command -v "$CONVERT" 2>/dev/null)" ]; then
		"$CONVERT" "$STLICON" -resize "128x128!" "$WANTGPNG"
	else
		cp "$STLICON" "$WANTGPNG"
	fi
}

function standaloneGameIcon {
	WANTGPNG="$1"
	AID="$2"
	GAMENAME="$3"
	HAVEPA="$4"
	if [ -f "$WANTGPNG" ]; then
		writelog "SKIP" "${FUNCNAME[0]} - Already have an icon: '$WANTGPNG'"
	else
		writelog "SKIP" "${FUNCNAME[0]} - Trying to find an icon for '$GAMENAME'"
		if grep -q "shell script" <<< "$(file "$(realpath "$HAVPA")")" || grep -q "ELF.*.LSB" <<< "$(file "$(realpath "$HAVPA")")" ; then
			# yes, quick&dirty!
			SYSICN="$(cut -d '=' -f2 <<< "$(grep "^Icon=" "$(find "/usr/share/applications/" -name "${HAVPA##*/}*.desktop" | head -n1)")")"
			if [ -n "$SYSICN" ]; then
				SYSICF="$(find "/usr/share/icons/" -name "${SYSICN}.png" | sort -nr | head -n1)"
				if [ -f "$SYSICF" ]; then
					if [ -x "$(command -v "$CONVERT" 2>/dev/null)" ]; then
						writelog "INFO" "${FUNCNAME[0]} - Creating a '$SYSICF' copy with fix size 128x128 at '$WANTGPNG'"
						"$CONVERT" "$SYSICF" -resize "128x128!" "$WANTGPNG"
					else
						writelog "INFO" "${FUNCNAME[0]} - Copying '$SYSICF' to '$WANTGPNG'"
						cp "$SYSICF" "$WANTGPNG"
					fi
				else
					writelog "INFO" "${FUNCNAME[0]} - Did not find a default icon for '$GAMENAME' using '$STLICON' as default for '$WANTGPNG'"
					standaloneDefGameIcon
				fi
			fi
		else
			PEVDSTI="$STLGPEVKD/$PERES/id/$AID"
			
			if [ -x "$(command -v "$PERES")" ] && { [ ! -d "$PEVDSTI" ] || [ "$(find "$PEVDSTI" -type f | wc -l)" -eq 0 ];}; then
				mkProjDir "$PEVDSTI"
				writelog "INFO" "${FUNCNAME[0]} - extracting data from '${HAVEPA##*/}' using '$PERES' to '$PEVDSTI'"
				cd "$PEVDSTI" >/dev/null || return
				notiShow "$(strFix "$NOTY_ANALYZE" "$HAVEPA" "$PERES")"
				"$PERES" -x "$HAVEPA" &
				cd - >/dev/null || return
			fi
			
			PRI="$PEVDSTI/resources/icons"
			if [ ! -d "$PRI" ]; then
				writelog "INFO" "${FUNCNAME[0]} - directory for alternative icon location not found - using '$STLICON' as default for '$WANTGPNG'"
				standaloneDefGameIcon
			else
				FIRSTICO="$(find "$PRI" -type f -name "*.ico" -printf "%s %p\n" | sort -nr | head -n1 | cut -d ' ' -f2)"
				if [ -f "$FIRSTICO" ]; then
					if [ -x "$(command -v "$CONVERT" 2>/dev/null)" ]; then
						writelog "INFO" "${FUNCNAME[0]} - Converting '$FIRSTICO', extracted from '${HAVEPA##*/}' to '$WANTGPNG'"
						"$CONVERT" "$FIRSTICO" -resize "128x128!" "$WANTGPNG"
					else
						writelog "INFO" "${FUNCNAME[0]} - Could not convert '$FIRSTICO', because '$CONVERT' was not found - using '$STLICON' as default for '$WANTGPNG'"
						cp "$STLICON" "$WANTGPNG"
					fi
				else
					writelog "INFO" "${FUNCNAME[0]} - Could not extract icon from '${HAVEPA##*/}' - using '$STLICON' as default for '$WANTGPNG'"
					standaloneDefGameIcon
				fi
			fi
		fi	
	fi
}

function standaloneDesktopFile {
	INTDTFILE="$1"
	WANTGPNG="$2"
	AID="$3"
	GAMENAME="$4"

	if [ -f "$INTDTFILE" ]; then
		writelog "SKIP" "${FUNCNAME[0]} - $INTDTFILE already exists"
	else
		if [ -n "$GAMENAME" ] && [ "$GAMENAME" != "$NON" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Creating '$INTDTFILE' for '$GAMENAME'"
			{
				echo "[Desktop Entry]"
				echo "Name=${GAMENAME//\"/}"
				echo "Comment=$(strFix "$DF_SLCOMMENT" "${GAMENAME//\"/}" "$PROGNAME")"
				echo "Exec=$(realpath "$0") play $AID"
				echo "Icon=$WANTGPNG"
				echo "Terminal=false"
				echo "Type=Application"
				echo "Categories=Game;"
			} >> "$INTDTFILE"
		fi
	fi
}

function standaloneLaunch {
	setShowPic
	STLA="Standalone-Launcher"
	export CURWIKI="$PPW/$STLA"
	TITLE="${PROGNAME}-$STLA"
	pollWinRes "$TITLE"
	echo "STLISLDFD $STLISLDFD"
	if [ -d "$STLISLDFD" ] && [ "$(find "$STLISLDFD" -name "*.desktop" | wc -l)" -ge 1 ]; then
		"$YAD" --f1-action="$F1ACTION" --icons --window-icon="$STLICON" --read-dir="$STLISLDFD" "$WINDECO" --title="$TITLE" --single-click --keep-icon-size --center --compact --sort-by-name "$GEOM"
	else
		writelog "SKIP" "${FUNCNAME[0]} - No games found in '$STLISLDFD' or directory itself not found"
	fi
}

function standaloneEd {
	if [ -z "$1" ]; then
		writelog "ERROR" "${FUNCNAME[0]} - Need a valid AppID or title for an installed standalone program" "E"
	else
		if [ "$1" -eq "$1" ] 2>/dev/null; then
			AID="$1"
			HAVID="$AID"
		else
			if [ -d "$STLISLDFD" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Looking for AppID for title '$1'" "E"
				TSTAID="$(grep "^Name=$1$" -h -A5 -R "$STLISLDFD" | grep -m1 "Exec=" | grep -o "$GETSTAID")"
				if [ -n "$TSTAID" ] && [ "$TSTAID" -eq "$TSTAID" ] 2>/dev/null; then
					AID="$TSTAID"
					HAVID="$AID"
				fi
			else
				writelog "ERROR" "${FUNCNAME[0]} - directory '$STLISLDFD' missing - can't search for '$1'" "E"
			fi
		fi
		
		if [ -n "$AID" ] && [ "$AID" != "$PLACEHOLDERAID" ]; then
			
			unset MEGAMEDIR GAMENAME KEEPGAMENAME STL_COMPAT_DATA_PATH 
			writelog "INFO" "${FUNCNAME[0]} - Looking for configs for AppID '$AID'" "E"
			HAVGEME="$GEMETA/${AID}.conf"
			if [ -f "$HAVGEME" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Loading found config '$HAVGEME'" "E"
				loadCfg "$HAVGEME"
			fi 

			HAVCUME="$CUMETA/${AID}.conf"
			if [ -f "$HAVCUME" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Loading found config '$HAVCUME'" "E"
				loadCfg "$HAVCUME"
			fi 
			
			WANTGPNG="$STLGPNG/${AID}.png"
			CPICKPROG="$MEGAMEDIR/$EXECUTABLE"

			STED="Standalone-Editor"
			STLA="Standalone-Launcher"
			export CURWIKI="$PPW/$STLA"
			TITLE="${PROGNAME}-$STED"
			pollWinRes "$TITLE"
			
			NEWSTDAT="$("$YAD" --f1-action="$F1ACTION" --image "$WANTGPNG" --window-icon="$STLICON" --form --center --on-top "$WINDECO" \
			--title="$TITLE" --separator="|" \
			--text="$STED" \
			--field=" ":LBL " " \
			--field="     $GUI_PICKPROG!$DESC_PICKPROG":FL "$CPICKPROG" \
			--field="     $GUI_GAMENAME!$DESC_GAMENAME" "${GAMENAME/#-/ -}" \
			--field="     $GUI_KEEPGAMENAME!$DESC_KEEPGAMENAME":CHK "${KEEPGAMENAME/#-/ -}" \
			--field="     $GUI_STL_COMPAT_DATA_PATH!$DESC_STL_COMPAT_DATA_PATH":DIR "${STL_COMPAT_DATA_PATH/#-/ -}" \
			--field="     $GUI_PICKICON!$DESC_PICKICON":FL "${WANTGPNG/#-/ -}" \
			--button="$BUT_DONE":0 --button="$BUT_CAN":2  "$GEOM")"
			case $? in
			0)  {
					writelog "INFO" "${FUNCNAME[0]} - Selected $BUT_DONE"
					unset NSTARR
					mapfile -d "|" -t -O "${#NSTARR[@]}" NSTARR < <(printf '%s' "$NEWSTDAT")
					NPICKPROG="${NSTARR[1]}"
					NGAMENAME="${NSTARR[2]}"
					NKEEPGAMENAME="${NSTARR[3]}"
					NSTL_COMPAT_DATA_PATH="${NSTARR[4]}"
					NPICKICON="${NSTARR[5]}"
					
					NEWIC=0
					
					if [ "$NPICKPROG" != "$CPICKPROG" ]; then
						NMEGAMEDIR="${NPICKPROG%/*}"
						NEXECUTABLE="${NPICKPROG##*/}"

						if [ "$NMEGAMEDIR" != "$MEGAMEDIR" ]; then
							touch "$FUPDATE"
							updateConfigEntry "MEGAMEDIR" "$NMEGAMEDIR" "$HAVCUME"
							NEWIC=1
						fi
						if [ "$NEXECUTABLE" != "$EXECUTABLE" ]; then
							touch "$FUPDATE"
							updateConfigEntry "EXECUTABLE" "$NEXECUTABLE" "$HAVGEME"
							NEWIC=1
						fi
					fi

					if [ "$NGAMENAME" != "$GAMENAME" ]; then
						touch "$FUPDATE"
						updateConfigEntry "GAMENAME" "$NGAMENAME" "$HAVGEME"
						NEWIC=1
					fi

					updateConfigEntry "KEEPGAMENAME" "$NKEEPGAMENAME" "$HAVGEME"	

					if [ "$NSTL_COMPAT_DATA_PATH" != "$STL_COMPAT_DATA_PATH" ]; then
						touch "$FUPDATE"
						updateConfigEntry "STL_COMPAT_DATA_PATH" "$NSTL_COMPAT_DATA_PATH" "$HAVGEME"
						NEWIC=1
					fi

					if [ "$NPICKICON" != "$WANTGPNG" ]; then
						if [ -x "$(command -v "$CONVERT" 2>/dev/null)" ]; then
							"$CONVERT" "$NPICKICON" -resize "128x128!" "$WANTGPNG"
						else
							cp "$NPICKICON" "$WANTGPNG"
						fi
						NEWIC=1
					fi

					if [ "$NEWIC" -eq 1 ]; then
						loadCfg "$HAVGEME"
						loadCfg "$HAVCUME"
						WANTGPNG="$STLGPNG/${AID}.png"
						HAVEPA="$MEGAMEDIR/$EXECUTABLE"
						INTDTFILE="$STLISLDFD/$AID.desktop"
						rm "$INTDTFILE"
						standaloneDesktopFile "$INTDTFILE" "$WANTGPNG" "$AID" "$GAMENAME" "$HAVEPA"
					fi
				}
			;;
			2) 	{
					writelog "INFO" "${FUNCNAME[0]} - Selected $BUT_CAN"

				}
			;;
			esac 
		else
			writelog "ERROR" "${FUNCNAME[0]} - No data found for '$1'" "E"
		fi
	fi
}

function createDLWineList {
	writelog "INFO" "${FUNCNAME[0]} - Generating list of online available Wine archives"
	WINEDLLIST="$STLSHM/WineDL.txt"
	MAXAGE=360

	if [ ! -f "$WINEDLLIST" ] || test "$(find "$WINEDLLIST" -mmin +"$MAXAGE")"; then
		rm "$WINEDLLIST" 2>/dev/null
		while read -r CWURL; do
		if grep -q "$GHURL" <<< "${!CWURL}"; then
			SRCURL="${!CWURL}"
			SRCURL="${SRCURL//\/releases}"
			SRCURL="${SRCURL//$GHURL/$AGHURL\/repos}"
			SRCURL="${SRCURL}/releases"
			"$WGET" -q "$SRCURL" -O - | "$JQ" -r '.[].assets[].browser_download_url' | grep "tar.gz\|tar.xz" >>  "$WINEDLLIST"
		fi
		done <<< "$(grep "^CW_" "$STLURLCFG" | cut -d '=' -f1)"
	fi

	unset WineDLList
	unset WineDLDispList
	while read -r CWVERS; do
		mapfile -t -O "${#WineDLList[@]}" WineDLList <<< "$CWVERS"
		mapfile -t -O "${#WineDLDispList[@]}" WineDLDispList <<< "${CWVERS##*/}"
	done < "$WINEDLLIST"
}

function dlWineGUI {
	createDLWineList

	writelog "INFO" "${FUNCNAME[0]} - Opening dialog to choose a download"

	DLWINELIST="$(printf "!%s\n" "${WineDLDispList[@]//\"/}" | tr -d '\n' | sed "s:^!::" | sed "s:!$::")"
	export CURWIKI="$PPW/Download-Custom-Wine"
	TITLE="${PROGNAME}-DownloadWine"
	pollWinRes "$TITLE"

	if [ -z "$DLWINE" ]; then
		DLWINE="${WineDLDispList[0]}"
	fi

	DLDISPWINE="$("$YAD" --f1-action="$F1ACTION" --window-icon="$STLICON" --form --center --on-top $WINDECO \
	--title="$TITLE" \
	--text="$(spanFont "$GUI_DLWINETEXT" "H")" \
	--field=" ":LBL " " \
	--field="$GUI_DLWINETEXT2!$GUI_DLWINETEXT":CBE "$(cleanDropDown "${DLWINE/#-/ -}" "$DLWINELIST")" \
	"$GEOM")"

	if [ -n "${DLDISPWINE//|/\"}" ]; then
		if grep -q "^http" <<< "${DLDISPWINE//|/\"}"; then  #"
			DLURL="${DLDISPWINE//|/\"}"
			writelog "INFO" "${FUNCNAME[0]} - The URL '$DLURL' was entered manually - downloading directly"
		else
			DLWINEVERSION="${DLDISPWINE//|/}"
			DLURL="$(printf "%s\n" "${WineDLList[@]}" | grep -m1 "${DLDISPWINE//|}")"
			writelog "INFO" "${FUNCNAME[0]} - '${DLDISPWINE//|}' was selected - downloading '$DLURL'"
		fi
		StatusWindow "$(strFix "$NOTY_DLCUSTOMPROTON" "Wine")" "dlWine ${DLURL//|/\"}" "DownloadWineStatus"
	fi
}

# currently unused:
function PickSpecificWine {
	export CURWIKI="$PPW/Download-Custom-Wine"
	TITLE="${PROGNAME}-${FUNCNAME[0]}"
	pollWinRes "$TITLE"

	SPECWINE="$("$YAD" --f1-action="$F1ACTION" --window-icon="$STLICON" --form --center --on-top $WINDECO \
	--title="$TITLE" --separator="|" \
	--text="$(spanFont "GUI_DLSPECWINE" "H")" \
	--field=" ":LBL " " \
	--field="Vanilla":CHK "TRUE" \
	--field="Staging":CHK "TRUE" \
	--field="Proton":CHK "TRUE" \
	--field="TkG":CHK "TRUE" \
	--field=" ":LBL " " \
	--field="x86":CHK "TRUE" \
	--field="amd64":CHK "TRUE" \
	"$GEOM")"

	unset SWINSEL
	mapfile -d "|" -t -O "${#SWINSEL[@]}" SWINSEL < <(printf '%s' "$SPECWINE")
	WANTVAN="${SWINSEL[1]}"
	WANTSTA="${SWINSEL[2]}"
	WANTPRO="${SWINSEL[3]}"
	WANTTKG="${SWINSEL[4]}"
	WANTX86="${SWINSEL[6]}"
	WANTA64="${SWINSEL[7]}"

	if [ "$WANTVAN" == "TRUE" ]; then
		GWI="[0-9]-[x,a]"
		GWO="$NON"
	else
		GWO="[0-9]-[x,a]"
		GWI="releases"
	fi

	if [ "$WANTSTA" == "TRUE" ]; then
		GWI="${GWI}\|staging"
	else
		GWO="${GWO}\|staging"
	fi

	if [ "$WANTPRO" == "TRUE" ]; then
		GWI="${GWI}\|proton"
	else
		GWO="${GWO}\|proton"
	fi

	if [ "$WANTTKG" == "TRUE" ]; then
		GWI="${GWI}\|tkg"
	else
		GWO="${GWO}\|tkg"
	fi

	if [ "$WANTX86" == "TRUE" ]; then
		GWI="${GWI}\|x86"
	else
		GWO="${GWO}\|x86"
	fi

	if [ "$WANTA64" == "TRUE" ]; then
		GWI="${GWI}\|amd64"
	else
		GWO="${GWO}\|amd64"
	fi
}

function dlWine {
	WURL="${1//\"/}"
	WURLFILE="${WURL##*/}"
	DSTDL="$WINEDLDIR/$WURLFILE"
	if [ ! -f "$DSTDL" ]; then
		writelog "INFO" "${FUNCNAME[0]} - Downloading '$WURL' to '$WINEDLDIR'"
		notiShow "$(strFix "$NOTY_DLCUSTOMPROTON" "$WURL")" "S"
		dlCheck "$WURL" "$DSTDL" "X" "Downloading '$WURLFILE'"
		notiShow "$(strFix "$NOTY_DLCUSTOMPROTON2" "$WURL")" "S"
	else
		writelog "INFO" "${FUNCNAME[0]} - File '$DSTDL' already exists - nothing to download"
		notiShow "$(strFix "$NOTY_DLCUSTOMPROTON4" "${WURL##*/}")" "S"
	fi
	extractWine "$DSTDL"
}

function dlWineGate {
	if [ -z "$1" ]; then
		dlWineGUI
	else
		if grep -q "^http" <<< "$1"; then
			writelog "INFO" "${FUNCNAME[0]} - '$1' is an URL - sending directly to dlWine"
			StatusWindow "$(strFix "$NOTY_DLCUSTOMPROTON" "Wine")" "dlWine $*" "DownloadWineStatus"
		elif [ "$1" == "latest" ] || [ "$1" == "l" ]; then
			createDLWineList
			writelog "INFO" "${FUNCNAME[0]} - Downloading latest custom Wine ${WineDLList[0]//\"/}" "E"
			StatusWindow "$(strFix "$NOTY_DLCUSTOMPROTON" "Wine")" "dlWine ${WineDLList[0]//\"/}" "DownloadWineStatus"
		else
			writelog "SKIP" "${FUNCNAME[0]} - Don't know what to do with argument '$1'"
		fi
	fi
}

function extractWine {
	if [ -f "$1" ]; then
		WURLFILE="${1##*/}"
		WDIRRAW="${WURLFILE//wine-/}"
		WDIR="${WDIRRAW//.tar.xz}"
		
		if [ -d "$WINEEXTDIR/$WDIR" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Directory '$WINEEXTDIR/$WDIR' already exists - nothing to extract"
		else
			writelog "INFO" "${FUNCNAME[0]} - Extracting archive '$WURLFILE' to '$WINEEXTDIR'"
			notiShow "$(strFix "$NOTY_DLCUSTOMPROTON3" "$1")" "S"
			"$TAR" xf "$1" -C "$WINEEXTDIR" 2>/dev/null
			notiShow "$GUI_DONE" "S"
		fi
	fi
}

function WineSelection {
	setShowPic
	export CURWIKI="$PPW/Wine-Support"
	TITLE="${PROGNAME}-ChooseWine"
	pollWinRes "$TITLE"

	writelog "INFO" "${FUNCNAME[0]} - Opening Wine Selection"

	 "$YAD" --f1-action="$F1ACTION" --image "$SHOWPIC" --image-on-top --center --window-icon="$STLICON" --form --center "$WINDECO" \
	--title="$TITLE" \
	--text="$(spanFont "$GUI_SELWINE" "H")" \
	--button="$BUT_DLDWINE":0 \
	--button="$BUT_SELWINE":2 \
	"$GEOM"
	
	case $? in
	0)  {
			writelog "INFO" "${FUNCNAME[0]} - Selected Wine Download"
			dlWineGUI
			if [ "$DLWINEVERSION" != "$NON" ]; then
				WINEVERSION="${DLWINEVERSION//|/}"
				writelog "INFO" "${FUNCNAME[0]} - Chose downloaded '$WINEVERSION'"
			fi
		}
	;;
	2) 	{
			writelog "INFO" "${FUNCNAME[0]} - Selected Ready Wine"
			createWineList
			export CURWIKI="$PPW/Wine-Support"
			TITLE="${PROGNAME}-SelectedWine"
			pollWinRes "$TITLE"
			WINSEL="$("$YAD" --f1-action="$F1ACTION" --window-icon="$STLICON" --form --center --on-top $WINDECO \
			--title="$TITLE" \
			--text="$(spanFont "$GUI_SELIWINE" "H")" \
			--field=" ":LBL " " \
			--field="     $GUI_WINEVERSION!$DESC_WINEVERSION ('WINEVERSION')":CBE "$(cleanDropDown "${WINEVERSION/#-/ -}" "$WINEYADLIST")" \
			"$GEOM")"
			WINEVERSION="${WINSEL//|/}"
			writelog "INFO" "${FUNCNAME[0]} - Chose available '$WINEVERSION'"
		}
	;;
	esac 

	writelog "INFO" "${FUNCNAME[0]} - Saving selected wine version '$WINEVERSION' into $STLGAMECFG"
	touch "$FUPDATE"
	updateConfigEntry "WINEVERSION" "$WINEVERSION" "$STLGAMECFG"

	if [ -n "$2" ]; then
		setWineVersion "$AID" "${FUNCNAME[0]}"
	fi
}

function setWineVersion {
	if [ "$USEWINE" -eq 1 ] && [ "$ISGAME" -eq 2 ]; then
		if [[ "$WINEVERSION" =~ ${DUMMYBIN}$ ]] || [ "$WINEVERSION" == "$NON" ]; then
			writelog "INFO" "${FUNCNAME[0]} - No current wine version configured yet"
			if [[ ! "$WINEDEFAULT" =~ ${DUMMYBIN}$ ]] && [ "$WINEDEFAULT" != "$NON" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Default wine version set to '$WINEDEFAULT' - using that as current wine"
				WINEVERSION="$WINEDEFAULT"
			else
				writelog "INFO" "${FUNCNAME[0]} - No current wine version configured and no default one set, so opening a requester"
				WineSelection "$AID" "${FUNCNAME[0]}"
				writelog "INFO" "${FUNCNAME[0]} - Chose '$WINEVERSION' via requester"
			fi
		else
			writelog "INFO" "${FUNCNAME[0]} - Using current wine version '$WINEVERSION'"
		fi
	
		WINEVERSION="${WINEVERSION%%.tar*}"

		if [ ! -d "$WINEEXTDIR/${WINEVERSION}" ]; then
		
			if ! grep -q "$WINEVERSION" "$WINEDLLIST"; then
				writelog "ERROR" "${FUNCNAME[0]} - Failed to set wineversion to something usable: '$WINEVERSION' - giving up"
				closeSTL " ######### STOP EARLY '$PROGNAME $PROGVERS' #########"
				exit
			else
				writelog "INFO" "${FUNCNAME[0]} - Configured wine version '$WINEVERSION' is not installed yet, but was found detected as downloadable - trying to install it automatically"
				DLURL="$(grep "$WINEVERSION" "$WINEDLLIST" | head -n1)"
				writelog "INFO" "${FUNCNAME[0]} - Downloading '$WINEVERSION' from '$DLURL'"
				StatusWindow "$(strFix "$NOTY_DLCUSTOMPROTON" "Wine")" "dlWine ${DLURL//|/\"}" "DownloadWineStatus"
				if [ -d "$WINEEXTDIR/$WINEVERSION" ]; then
					writelog "INFO" "${FUNCNAME[0]} - Downloading and extracting '$WINEVERSION' was successful"
				else
					writelog "ERROR" "${FUNCNAME[0]} - Downloading and extracting '$WINEVERSION' failed - giving up"
					closeSTL " ######### STOP EARLY '$PROGNAME $PROGVERS' #########"
					exit
				fi
			fi
		fi
	fi
	RUNWINEVERSION="$WINEVERSION"
	writelog "INFO" "${FUNCNAME[0]} - Selected wine version is '$RUNWINEVERSION'"
}

function createWineList {
	writelog "INFO" "${FUNCNAME[0]} - Updating the Wine Dropdown List"
	WINEYADLIST="$(printf "!%s\n" "$(find "$WINEEXTDIR" -mindepth 1 -maxdepth 1 -type d -printf '%P!')" | tr -d '\n' | sed "s:^!::" | sed "s:!$::")"
}

function setWineVars {
	WINEVERSION="${WINEVERSION%%.tar*}"

	if [ "$USEWINE" -eq 1 ] && [ "$ISGAME" -eq 2 ] && { [ -z "$RUNWINEVERSION" ] || [ "$RUNWINEVERSION" != "$WINEVERSION" ];}; then
		writelog "INFO" "${FUNCNAME[0]} - USEWINE is enabled. Creating some wine related variables"

		if [ -n "$RUNWINEVERSION" ] && [[ "$WINEVERSION" =~ ${DUMMYBIN}$ ]]; then
			WINEVERSION="$RUNWINEVERSION"
		else
			createDLWineList
		fi

		setWineVersion
		
		USEWINEBIN="$WINEEXTDIR/${WINEVERSION}/bin"
		writelog "INFO" "${FUNCNAME[0]} - Setting wine bin dir to '$USEWINEBIN'"

		RUNWINE="$USEWINEBIN/wine"
		writelog "INFO" "${FUNCNAME[0]} - Setting wine binary to '$RUNWINE'"

		RUNWINECFG="$USEWINEBIN/$WINECFG"
		writelog "INFO" "${FUNCNAME[0]} - Setting $WINECFG binary to '$RUNWINECFG'"

		RUNREGEDIT="$USEWINEBIN/regedit"
		writelog "INFO" "${FUNCNAME[0]} - Setting regedit binary to '$RUNREGEDIT'"

		RUNWICO="$USEWINEBIN/$WICO"
		writelog "INFO" "${FUNCNAME[0]} - Setting $WICO binary to '$RUNWICO'"

		if [ -n "$ARCHALTEXE" ] && [[ ! "$ARCHALTEXE" =~ ${DUMMYBIN}$ ]]; then
			CHARCH="$ARCHALTEXE"
		else
			CHARCH="$GP"
		fi

		if [ "$(getArch "$CHARCH")" == "32" ]; then
			RUNWINEARCH=win32
		else
			RUNWINEARCH=win64
		fi

		writelog "INFO" "${FUNCNAME[0]} - Game binary '${CHARCH##*/}' is $(getArch "$CHARCH")-bit so creating '$RUNWINEARCH' WINEPREFIX"
		GWFX="${GPFX//pfx/wfx}"
		writelog "INFO" "${FUNCNAME[0]} - Using WINEPREFIX '$GWFX'"
	fi
}

# Get path to 'require_tool_appid' specified in toolmanifest.vdf 
function getRequireToolAppidPath {
	COMPATTOOLPATH="$1"

	if [ -d "$COMPATTOOLPATH" ]; then
		TOMAPATH="${COMPATTOOLPATH}/$TOMA"
		if [ -f "$TOMAPATH" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Found tool manifest at '$TOMAPATH', attempting to get 'require_tool_appid' value..."
			
			REQUIRETOOLAID="$( getValueFromAppManifest "require_tool_appid" "$TOMAPATH" )"  # toolmanifest.vdf and some other files have identical structures to AppManifest files, so this works :-)
			if [ -n "$REQUIRETOOLAID" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Got 'require_tool_appid' from '$TOMAPATH' ('$REQUIRETOOLAID') - Returning path to tool"

				getGameDir "$REQUIRETOOLAID" "X"
			else
				writelog "INFO" "${FUNCNAME[0]} - Could not get 'require_tool_appid' from existing file '$TOMAPATH' - Assuming the key was not present"
			fi
		else
			writelog "SKIP" "${FUNCNAME[0]} - Could not get Steam Linux Runtime, could not find tool manifest at '$TOMAPATH'"
		fi
	else
		writelog "INFO" "${FUNCNAME[0]} - Could not find directory for specified compat tool '$COMPATTOOLPATH'"
	fi
}

function setSLRReap {
	if [ -n "$USESLR" ] && [ -n "$HAVESLR" ]; then
		if [ "$HAVESLRCT" -eq 1 ] && [ "$USESLR" -eq 1 ]; then
			writelog "INFO" "${FUNCNAME[0]} - ## SLR is enabled via USESLR=$USESLR - prepending SLR from Compatibility Tool to the current launch command"
			SLRCMD=("${RUNSLRCT[@]}")
		fi
		
		if [ "$HAVESLR" -eq 1 ] && [ "$USESLR" -eq 1 ]; then
			writelog "INFO" "${FUNCNAME[0]} - ## SLR is enabled via USESLR=$USESLR - prepending SLR from command line to the current launch command"
			SLRCMD=("${RUNSLR[@]}")
		fi

		if [ "$HAVESLR" -eq 1 ] && [ "$USESLR" -eq 0 ] ; then
			writelog "SKIP" "${FUNCNAME[0]} - USESLR is disabled, so skipping '$SLR' found in the commandline: '${RUNSLR[*]}'"
		fi
		RUNFORCESLR=0

		if [ "$HAVESLR" -eq 0 ] && [ "$USESLR" -eq 1 ] ; then
			if [ -n "$LASTSLR" ] && [ -f "${LASTSLR% --verb*}" ] && [ "$FORCESLR" -eq 1 ]; then
				writelog "INFO" "${FUNCNAME[0]} - ## No SLR provided from command line, but FORCESLR is $FORCESLR, so prepending LASTSLR '$LASTSLR' to the current launch command"
				mapfile -d " " -t -O "${#LASTSLRARR[@]}" LASTSLRARR < <(printf '%s' "$LASTSLR")
				SLRCMD=("${LASTSLRARR[@]}")
				RUNFORCESLR=1
			else
				# Steam usually does not pass the SLR in the start command anymore, and gets it from the `toolmanifest.vdf` with the `"require_tool_appid": "<app_id>"` for Proton games
				# For native games, on Steam Deck it seems Valve enforce the regular Steam Linux Runtime, so we have separate logic for fetching that
				writelog "INFO" "${FUNCNAME[0]} - No SLR provided from command line, attempting to fetch required SLR from current compatibility tool's '$TOMA'"

				SLR_PATH=""
				SLRENTRYPOINT=""
				SLRVERB=""
				PROTON_SLRCMD=("")
				NATIVE_SLRCMD=("")

				# Pressure Vessel Funtime 2nd Edition Ver. 2.31
				# Get SLR Paths
				if [ "$ISGAME" -eq 3 ]; then
					# Native games already have a hardcoded initial native SLR AppID, so we can get the path from this hardcoded AppID
					# However they need to get the required "nested" SLR from the toolmanifest from the hardcoded native SLR - This is the SLR that the regular native SLR runs inside of
					# This nested AppID is stored in the hardcoded SLR's toolmanifest
					writelog "INFO" "${FUNCNAME[0]} - Looks like we have a native Linux game here - Checking for plain SLR (AppID '$SLRAID')"
					REQUIRED_APPID="$SLRAID"  # AppID of native SLR

					NATIVE_SLR_PATH="$( getGameDir "$REQUIRED_APPID" "X" )"  # Native SLR
					if [ -d "$NATIVE_SLR_PATH" ]; then
						SLR_PATH="$( getRequireToolAppidPath "$NATIVE_SLR_PATH" )"  # Nested SLR path for native SLR to run inside of

						writelog "INFO" "${FUNCNAME[0]} - Nested Steam Linux Runtime for native game seems to be '$SLR_PATH'"

						NATIVE_SLR_ENTRYPOINT="${NATIVE_SLR_PATH}/scout-on-soldier-entry-point-v2"
						NATIVE_SLRCMD=("$NATIVE_SLR_ENTRYPOINT" "--")  # Extra part to pass for native CMD which needs to be appended to regular SLRCMD
					else
						writelog "WARN" "${FUNCNAME[0]} - Could not find Steam Linux Runtime with AppID '$SLRAID' for native Linux game - This will need to be installed manually!"
					fi
				else
					# Path to SLR based on AppID in Proton's `toolmanifest.vdf`
					SLR_PATH="$( getRequireToolAppidPath "$( dirname "$RUNPROTON" )" )"
				fi

				# Build SLRCMD
				if [ -d "$SLR_PATH" ]; then
					writelog "INFO" "${FUNCNAME[0]} - '$SLR_PATH' exists - Path gotten from specified AppID looks valid"
					
					SLRENTRYPOINT="${SLR_PATH}/_v2-entry-point"
					SLRVERB="--verb=$WFEAR"

					PROTON_SLRCMD=("$SLRENTRYPOINT" "$SLRVERB" "--")
				else
					writelog "WARN" "${FUNCNAME[0]} - Could not get path to Steam Linux Runtime - This will need to be installed manually!"
					writelog "WARN" "${FUNCNAME[0]} - Ignoring USESLR option since valid Steam Linux Runtime could not be found"
				fi

				# Passing even a blank `NATIVE_SLRCMD[@]` prevents games from launching, so we need this check
				if [ -n "${NATIVE_SLRCMD[*]}" ]; then
					writelog "INFO" "${FUNCNAME[0]} - Building Steam Linux Runtime command for native game"
					SLRCMD=("${PROTON_SLRCMD[@]}" "${NATIVE_SLRCMD[@]}")  # Not really "Proton" for native games, but naming is hard
				else
					writelog "INFO" "${FUNCNAME[0]} - Building Steam Linux Runtime command for Proton game"
					SLRCMD=("${PROTON_SLRCMD[@]}") 
				fi
			fi
		fi
	
		if [ "$HAVEREAP" -eq 1 ] && [ "$USEREAP" -eq 1 ]; then
			writelog "INFO" "${FUNCNAME[0]} - ## reaper command is enabled via USEREAP=$USEREAP - prepending to the current launch command"
			SLRCMD=("${REAPCMD[@]}" "${SLRCMD[@]}")
		elif [ "$HAVEREAP" -eq 0 ] && [ "$USEREAP" -eq 1 ] && [ -n "$LASTREAP" ] && [ -f "$LASTREAP" ] && [ "$FORCEREAP" -eq 1 ]; then
			writelog "INFO" "${FUNCNAME[0]} - ## No reaper command provided from command line, but FORCEREAP is $FORCEREAP, so prepending LASTREAP '$LASTREAP' to the current launch command"
			SLRCMD=("$LASTREAP" "SteamLaunch" "AppId=$AID" "--" "${SLRCMD[@]}")
		fi

		if [ -n "${SLRCMD[0]}" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Adding SLR '${SLRCMD[*]}' to the launch command"
		fi
	fi
}

function setBoxtronCmd {
	DOSEXE="$GP"
	if [ -x "$(command -v "$BOXTRONCMD" 2>/dev/null)" ]; then
		notiShow "$(strFix "$NOTY_BOXTRON" "$GN" "$AID")"
		# disable CHANGE_PULSE_LATENCY else audio gets stuck
		CHANGE_PULSE_LATENCY="0"
		EXTSTARTCMD=("$BOXTRONCMD" "$BOXTRONARGS" "$DOSEXE")
		writelog "INFO" "${FUNCNAME[0]} - Starting game '$SGNAID' with boxtron"
	else
		writelog "ERROR" "${FUNCNAME[0]} - boxtron command '$BOXTRONCMD' not found - exit"
		exit
	fi
}

function setRobertaCmd {
	VMEXE="$GP"
	if [ -x "$(command -v "$ROBERTACMD" 2>/dev/null)" ]; then
		EXTSTARTCMD=("$ROBERTACMD" "$ROBERTAARGS" "$VMEXE")
		writelog "INFO" "${FUNCNAME[0]} - Starting game '$AID' with roberta"
		notiShow "$(strFix "$NOTY_ROBERTA" "$GN" "$AID")"
	else
		writelog "ERROR" "${FUNCNAME[0]} - roberta command '$ROBERTACMD' not found - exit"
		exit
	fi
}

function setLuxtorpedaCmd {
	LUXEXE="$GP"
	if [ -x "$(command -v "$LUXTORPEDACMD" 2>/dev/null)" ]; then
		if [ "$USESLR" -eq 1 ]; then
			writelog "INFO" "${FUNCNAME[0]} - Using ${LUXTORPEDACMD^} (Runtime)"
			LUMADO="manual-download"
			LUXTORPEDAARGS="runtime_$LUXTORPEDAARGS"
		else
			LUMADO="manual-download"
		fi
		# skip download if engine_choice.txt exists already:
		if [ ! -f "$HOME"/.config/luxtorpeda/"$AID"/engine_choice.txt ]; then
			writelog "INFO" "${FUNCNAME[0]} - Downloading native game data for '$AID' with luxtorpeda: '$LUXTORPEDACMD' '$LUMADO' $AID"
			notiShow "$(strFix "$NOTY_LUXTORPEDA1" "$GN" "$AID")"
			"$LUXTORPEDACMD" "$LUMADO" "$AID"
		fi
		notiShow "$(strFix "$NOTY_LUXTORPEDA2" "$GN" "$AID")"
		EXTSTARTCMD=("$LUXTORPEDACMD" "$LUXTORPEDAARGS" "$LUXEXE")
		writelog "INFO" "${FUNCNAME[0]} - Starting game '$AID' with luxtorpeda"
	else
		writelog "ERROR" "${FUNCNAME[0]} - luxtorpeda command '$LUXTORPEDACMD' not found - exit"
		exit
	fi
}
		
function setLinuxCmd {
	# maybe limit this to custom linux commands
	if [ "${GAMESTARTCMD[0]}" == "$WFEAR" ]; then
		writelog "INFO" "${FUNCNAME[0]} - Removing '$WFEAR' from '${GAMESTARTCMD[*]}'"
		GAMESTARTCMD=( "${GAMESTARTCMD[@]:1}" )
		writelog "INFO" "${FUNCNAME[0]} - Result is '${GAMESTARTCMD[*]}'"
	fi

	# start with gamemoderun:
	if [ "$USEGAMEMODERUN" -eq 1 ]; then
		if [ "$USEGAMESCOPE" -eq 1 ]; then
			writelog "INFO" "${FUNCNAME[0]} - Starting native game '$SGNAID' with '$GAMEMODERUN' and '$GAMESCOPE'"
			notiShow "$(strFix "$NOTY_STARTNATGAMOSC" "$GN" "$AID")"
			gameScopeArgs "$GAMESCOPE_ARGS"
		else
			writelog "INFO" "${FUNCNAME[0]} - Starting native game '$SGNAID' with '$GAMEMODERUN' - ${GAMESTARTCMD[*]}"
			notiShow "$(strFix "$NOTY_STARTNATGAMO" "$GN" "$AID")"
		fi
	# start with gamescope:
	elif [ "$USEGAMESCOPE" -eq 1 ]; then
		writelog "INFO" "${FUNCNAME[0]} - Starting native game '$SGNAID' with $GAMESCOPE arguments '$GAMESCOPE_ARGS'"
		notiShow "$(strFix "$NOTY_STARTNATGAMSCO" "$GN" "$AID")"
		gameScopeArgs "$GAMESCOPE_ARGS"
	# regular start:
	else
		writelog "INFO" "${FUNCNAME[0]} - Starting native game '$SGNAID'"
		notiShow "$(strFix "$NOTY_STARTNAT" "$GN" "$AID")"
	fi
}

function setWineCmd {
	function startWineGame {
		writelog "INFO" "${FUNCNAME[0]} - Starting game '$GN' ($AID)' using Wine"
		extWine64Run "$@" "$RUNWINE" "${FINGAMECMD[*]}" &> "$WINE_LOG_DIR/${AID}.log" 
		WINEPID="$!"
	}

	writelog "INFO" "${FUNCNAME[0]} - Using Wine instead of Proton"
	setWineVars

	RUNGAMECMD="${GAMESTARTCMD[*]}"
	RAWGAMECMD="${RUNGAMECMD#*waitforexitandrun }"
	mapfile -d " " -t -O "${#FINGAMECMD[@]}" FINGAMECMD < <(printf '%s' "$RAWGAMECMD")
	
	writelog "INFO" "${FUNCNAME[0]} - Starting game $GN with '$("$RUNWINE" --version)' and waiting for its PID to exit"

	# start with gamemoderun:
	if [ "$USEGAMEMODERUN" -eq 1 ]; then
		if [ "$USEGAMESCOPE" -eq 1 ]; then
			gameScopeArgs "$GAMESCOPE_ARGS"
			notiShow "$(strFix "$NOTY_STARTPROTGAMOSC" "$RUNWINEVERSION" "$GN" "$AID")"
			startWineGame "$GMR" "$GSC" "${GAMESCOPEARGSARR[@]}"
			writelog "INFO" "${FUNCNAME[0]} - Started game $GN via wine using '$GAMEMODERUN' and '$GAMESCOPE' with PID '$WINEPID'"
		else
			notiShow "$(strFix "$NOTY_STARTPROTGAMO" "$RUNWINEVERSION" "$GN" "$AID")"
			startWineGame "$GMR"
			writelog "INFO" "${FUNCNAME[0]} - Started game $GN via wine using '$GAMEMODERUN' with PID '$WINEPID'"
		fi
	# start with gamescope:
	elif [ "$USEGAMESCOPE" -eq 1 ]; then
		gameScopeArgs "$GAMESCOPE_ARGS"
		notiShow "$(strFix "$NOTY_STARTPROTGAMSCO" "$RUNWINEVERSION" "$GN" "$AID")"
		startWineGame "$GSC" "${GAMESCOPEARGSARR[@]}"
		writelog "INFO" "${FUNCNAME[0]} - Started game $GN via wine using '$GAMESCOPE' with PID '$WINEPID'"
	# regular start:
	else
		notiShow "$(strFix "$NOTY_STARTPROT" "$RUNWINEVERSION" "$GN" "$AID")"
		startWineGame
		writelog "INFO" "${FUNCNAME[0]} - Started game $GN via wine with PID '$WINEPID'"
	fi

	wait "$WINEPID"
	writelog "INFO" "${FUNCNAME[0]} - game PID '$WINEPID' exited..."
}

function setProtonCmd {
	# proton variants start here:

	if [ "$RUN_GDB" -eq 1 ]; then
		GDBGAMESTARTCMD=("${ORGGCMD[@]}" "${GAMEARGSARR[@]}")
	elif [ "$HAVEINPROTON" -eq 1 ]; then
		writelog "INFO" "${FUNCNAME[0]} - Not overriding Proton and using Proton provided by steam commandline '${INPROTCMD[*]}'"
		PROTSTARTCMD=("${INPROTCMD[@]}" "$WFEAR")
	else
		writelog "INFO" "${FUNCNAME[0]} - Proton override enabled, so checking if it needs updated"

		if [ -z "$USEPROTON" ]; then
			writelog "INFO" "${FUNCNAME[0]} - No current Proton found"
			if [ "$AUTOLASTPROTON" -eq 1 ]; then
				writelog "INFO" "${FUNCNAME[0]} - Automatically selecting newest official one"
				setNOP
			fi
		fi

		# the last chance to set the Proton version before starting the game,
		setRunProtonFromUseProton

		# remove prefix if requested 
		delPrefix
		
		# so fixing outdated symlinks if requested
		fixSymlinks
		# and/or unsymlink any proton symlink found
		unSymlink

		if [ "$HAVEINPROTON" -eq 1 ] && [ "${INPROTCMD[*]}" == "$RUNPROTON" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Command line proton '${INPROTCMD[*]}' is identical to RUNPROTON '$RUNPROTON' - nothing to change"
			PROTSTARTCMD=("${INPROTCMD[@]}" "$WFEAR")
		else
			if [ ! -f "${RUNPROTON//\"/}" ]; then
				writelog "WARN" "${FUNCNAME[0]} - '$USEPROTON' seems outdated as the executable ${RUNPROTON//\"/} wasn't found"
				fixProtonVersionMismatch "USEPROTON" "$STLGAMECFG"
			fi

			if [ "${GAMESTARTCMD[0]}" == "$WFEAR" ]; then
				# removing first ORGGCMD element as it is '$WFEAR'
				unset "GAMESTARTCMD[0]"
			fi
			
			if [ -f "${RUNPROTON//\"/}" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Prepending Proton '$USEPROTON' (='${RUNPROTON//\"/}') to the command line '${GAMESTARTCMD[*]}'"
				PROTSTARTCMD=("${RUNPROTON//\"/}" "$WFEAR")
			else
				writelog "INFO" "${FUNCNAME[0]} - Still don't have a usable proton executable in RUNPROTON '{RUNPROTON//\"/}')"
				if [ "$HAVEINPROTON" -eq 1 ]; then
					writelog "INFO" "${FUNCNAME[0]} - Overriding Proton provided by steam commandline '${INPROTCMD[*]}' from command line with '$USEPROTON' (='${RUNPROTON//\"/}')"
					PROTSTARTCMD=("${INPROTCMD[@]}" "$WFEAR")
				else
					writelog "ERROR" "${FUNCNAME[0]} - Could not find any usable proton version - this will likely crash - please open an issue on '$PROJECTPAGE' with this log"
				fi
			fi
			writelog "INFO" "${FUNCNAME[0]} - UPDATED game start command is: ${GAMESTARTCMD[*]}"
		fi

		if [ "$USERAYTRACING" -eq 1 ]; then
			writelog "INFO" "${FUNCNAME[0]} - Raytracing is enabled with the variable 'USERAYTRACING' - exporting 'VKD3D_CONFIG=dxr11' and appending '-dx12' to the game command line parameters"
			export VKD3D_CONFIG=dxr11
			GAMEARGSARR=("${GAMEARGSARR[@]}" "-dx12")
		fi
	fi

############ 
	# set the definitive used versions, which are also stored into writeLastRun
	PROTONVERSION="$(setProtonPathVersion "$RUNPROTON")"

	# start with x64dbg:
	if [ "$RUN_X64DBG" -eq 1 ]; then
		checkX64dbgLaunch "${GAMESTARTCMD[@]}"
	elif [ "$RUN_GDB" -eq 1 ]; then
		if [ -f "$(command -v "$USETERM")" ]; then
			prepareGdb
			injectGdb &
			writelog "INFO" "${FUNCNAME[0]} - Starting '$SGNAID' using '$GDBGAMERUN' and attaching gdb to the running process"
			writelog "WARN" "${FUNCNAME[0]} - This function might not always work as expected - not sure yet if it is worth to maintain"
			notiShow "$(strFix "$NOTY_STARTPROTGDB" "$PROTONVERSION" "$GN" "$AID")"
			"$GDBGAMERUN"
		else
			writelog "ERROR" "${FUNCNAME[0]} - '$GDB' was enabled, but configured terminal '$USETERM' was not found"
		fi
	elif [ "$RUN_DEPS" -eq 1 ]; then
		checkDepsLaunch "${GAMESTARTCMD[@]}"
	# start with gamemoderun:
	elif [ "$USEGAMEMODERUN" -eq 1 ]; then
		if [ "$USEGAMESCOPE" -eq 1 ]; then
			writelog "INFO" "${FUNCNAME[0]} - Starting '$SGNAID' with Proton: '$PROTONVERSION' with '$GAMEMODERUN' and '$GAMESCOPE'"
			gameScopeArgs "$GAMESCOPE_ARGS"
			notiShow "$(strFix "$NOTY_STARTPROTGAMOSC" "$PROTONVERSION" "$GN" "$AID")"
		else
			writelog "INFO" "${FUNCNAME[0]} - Starting '$SGNAID' with Proton: '$PROTONVERSION' with '$GAMEMODERUN'"
			notiShow "$(strFix "$NOTY_STARTPROTGAMO" "$PROTONVERSION" "$GN" "$AID")"
		fi
	# start with gamescope:
	elif [ "$USEGAMESCOPE" -eq 1 ]; then
		writelog "INFO" "${FUNCNAME[0]} - Starting '$SGNAID' with Proton: '$PROTONVERSION' with $GAMESCOPE arguments '$GAMESCOPE_ARGS'"
		notiShow "$(strFix "$NOTY_STARTPROTGAMSCO" "$PROTONVERSION" "$GN" "$AID")"
		gameScopeArgs "$GAMESCOPE_ARGS"
	# regular start:
	else
		writelog "INFO" "${FUNCNAME[0]} - Starting '$SGNAID' with Proton: '$PROTONVERSION'"
		notiShow "$(strFix "$NOTY_STARTPROT" "$PROTONVERSION" "$GN" "$AID")"
	fi
}

function launchSteamGame {
########################
	steamdeckBeforeGame

	setCommandLaunchVars  # Re-usable function for Steam games and custom program launches

	writelog "INFO" "${FUNCNAME[0]} - Initial game command is '${INGCMD[*]}'"

	setSLRReap
	
	if [ "$USEBOXTRON" -eq 1 ] || [ "$USEROBERTA" -eq 1 ] || [ "$USELUXTORPEDA" -eq 1 ]; then
		ISGAME=3
	fi

	# game start command for both proton and linux native games:
	if [ "$USEBOXTRON" -eq 0 ] && [ "$USEROBERTA" -eq 0 ] && [ "$USELUXTORPEDA" -eq 0 ]; then
		# the actual game launch:
		gameArgs "$GAMEARGS"
		GAMESTARTCMD=("${ORGGCMD[@]}")
	fi

	# first start with non-proton games here:
	if [ "$ISGAME" -eq 3 ]; then
		if [ "$USEBOXTRON" -eq 1 ]; then
			writelog "INFO" "${FUNCNAME[0]} - Preparing boxtron command"
			setBoxtronCmd
		elif [ "$USEROBERTA" -eq 1 ]; then
			writelog "INFO" "${FUNCNAME[0]} - Preparing roberta command"
			setRobertaCmd
		elif [ "$USELUXTORPEDA" -eq 1 ]; then
			writelog "INFO" "${FUNCNAME[0]} - Preparing luxtorpeda command"
			setLuxtorpedaCmd
		else
			writelog "INFO" "${FUNCNAME[0]} - Preparing linux native game command"
			setLinuxCmd
		fi

	# now games using proton or wine:
	elif [ "$ISGAME" -eq 2 ]; then
		if [ "$USEWINE" -eq 1 ]; then
			writelog "INFO" "${FUNCNAME[0]} - Preparing wine command"
			setWineCmd
		else
			writelog "INFO" "${FUNCNAME[0]} - Preparing proton command"
			setProtonCmd
		fi
	else
		writelog "SKIP" "${FUNCNAME[0]} - With ISGAME '$ISGAME' the game failed to start"
	fi

	if [ "$USEWINE" -eq 0 ]; then
		# concatenate final game start command

		buildCustomCmdLaunch

		FINALSTARTCMD=( "${FINALOUTCMD[@]}" )  # Use FINALOUTCMD from buildCustomCmdLaunch

		if [ -n "${SLRCMD[0]}" ]; then
			if [ -n "${FINALSTARTCMD[0]}" ]; then
				FINALSTARTCMD=("${FINALSTARTCMD[@]}" "${SLRCMD[@]}")
			else
				FINALSTARTCMD=("${SLRCMD[@]}")
			fi
		fi
		
		if [ -n "${EXTSTARTCMD[0]}" ]; then
			if [ -n "${FINALSTARTCMD[0]}" ]; then
				FINALSTARTCMD=("${FINALSTARTCMD[@]}" "${EXTSTARTCMD[@]}")
			else
				FINALSTARTCMD=("${EXTSTARTCMD[@]}")
			fi
		else
			if [ -n "${PROTSTARTCMD[0]}" ]; then
				if [ -n "${FINALSTARTCMD[0]}" ]; then
					FINALSTARTCMD=("${FINALSTARTCMD[@]}" "${PROTSTARTCMD[@]}")
				else
					FINALSTARTCMD=("${PROTSTARTCMD[@]}")
				fi
			fi
			
			if [ -n "${GAMESTARTCMD[0]}" ]; then
				if [ -n "${FINALSTARTCMD[0]}" ]; then
					FINALSTARTCMD=("${FINALSTARTCMD[@]}" "${GAMESTARTCMD[@]}")
				else
					FINALSTARTCMD=("${GAMESTARTCMD[@]}")
				fi
			fi

			if [ -n "${GAMEARGSARR[0]}" ]; then
				if [ -n "${FINALSTARTCMD[0]}" ]; then
					FINALSTARTCMD=("${FINALSTARTCMD[@]}" "${GAMEARGSARR[@]}")
				else
					FINALSTARTCMD=("${GAMEARGSARR[@]}")
				fi	
			fi
		fi

		if [ "$STARTDEBUG" -eq 1 ]; then
			{
				echo "$(date) - $GN ($AID) - ======================"
				echo "GMR $GMR"
				echo "GSC $GSC"
				echo "SLRCMD '${SLRCMD[*]}'"
				echo "PROTSTARTCMD '${PROTSTARTCMD[*]}'"
				echo "GAMESTARTCMD '${GAMESTARTCMD[*]}'"
				echo "GAMEARGSARR '${GAMEARGSARR[*]}'"
				echo "-----------"
				echo "I '${INGCMD[*]}'"
				echo "X '${FINALSTARTCMD[*]}'"
				echo "$(date) - $GN ($AID) - ======================"
				if [ "$HAVESCTP" -eq 0 ] && [ "$HAVEREAP" -eq 0 ]; then
					echo "$(date) - $GN ($AID) - HAVESCTP='$HAVESCTP', and HAVEREAP='$HAVEREAP' - assuming ${PROGNAME,,} is used as compat tool - using regular base game command to continue"
				elif [ "$HAVESCTP" -eq 0 ] && [ "$HAVEREAP" -eq 1 ]; then
					echo "$(date) - $GN ($AID) - HAVESCTP='$HAVESCTP', but also HAVEREAP='$HAVEREAP' - assuming ${PROGNAME,,} is set to both command and compat tool (or compat tool is empty) - steam doesn't provide STEAM_COMPAT_TOOL_PATHS, so have to cut out the reaper line to continue; HAVESLR='$HAVESLR'"
				elif [ "$HAVESCTP" -eq 1 ] && [ "$HAVEREAP" -eq 1 ]; then
					echo "$(date) - $GN ($AID) - HAVESCTP='$HAVESCTP', and HAVEREAP='$HAVEREAP' - assuming $PROGCMD is used as command line tool - switching proton version is disabled"
				elif [ "$HAVESCTP" -eq 1 ] && [ "$HAVEREAP" -eq 0 ]; then
					echo "$(date) - $GN ($AID) - HAVESCTP='$HAVESCTP', but also HAVEREAP='$HAVEREAP' - something went wrong - never seen this in the wild"
				fi
				echo "$(date) - $GN ($AID) - ======================"
				echo "$(date) - $GN ($AID) - INITIAL LAUNCH COMAND '${INGCMD[*]}'"
				echo "$(date) - $GN ($AID) - HAVESCTP='$HAVESCTP';HAVEREAP='$HAVEREAP';HAVESLR='$HAVESLR';HAVESLRCT='$HAVESLRCT';HAVEINPROTON='$HAVEINPROTON'"
				echo "$(date) - $GN ($AID) - REAPCMD '${REAPCMD[*]}'"
				echo "$(date) - $GN ($AID) - RUNSLR '${RUNSLR[*]}'"
				echo "$(date) - $GN ($AID) - RUNSLRCT '${RUNSLRCT[*]}'"
				echo "$(date) - $GN ($AID) - ISGAME '$ISGAME'"
				echo "$(date) - $GN ($AID) - INPROTCMD '${INPROTCMD[*]}'"
				echo "$(date) - $GN ($AID) - INSTLCMD '${INSTLCMD[*]}'"
				echo "$(date) - $GN ($AID) - ORGGCMD '${ORGGCMD[*]}'"
				echo "$(date) - $GN ($AID) - ORG_STEAM_COMPAT_TOOL_PATHS '${ORG_STEAM_COMPAT_TOOL_PATHS[*]}'"
				echo "$(date) - $GN ($AID) - USEREAP='$USEREAP'; USESLR=$USESLR'"
				echo "$(date) - $GN ($AID) - FINAL LAUNCH RUNCMD '${RUNCMD[*]}'"
				echo "$(date) - $GN ($AID) - FINALSTARTCMD '${FINALSTARTCMD[*]}'"
				echo "$(date) - $GN ($AID) - ======================"
			} >> "$STLSHM/${PROGNAME,,}-${FUNCNAME[0]}-STARTDEBUG.txt"
		fi

		# might be also useful for starting custom commands generally
		if [ "$USECUSTOMCMD" -eq 1 ] && [ "$FORK_CUSTOMCMD" -eq 1 ] && [ "$ONLY_CUSTOMCMD" -eq 0 ] && [ "$WAITFORCUSTOMCMD" -ge 1 ]; then
			writelog "INFO" "${FUNCNAME[0]} - WAITFORCUSTOMCMD is enabled, so replacing $WFEAR with 'run' in'${FINALSTARTCMD[*]}'"
			for i in "${!FINALSTARTCMD[@]}"; do
				if [[ ${FINALSTARTCMD[$i]} == "$WFEAR" ]]; then
					FINALSTARTCMD[$i]="run"
				fi
			done
		fi

		writelog "INFO" "${FUNCNAME[0]} - Original incoming start command: '${INGCMD[*]}'"
		writelog "INFO" "${FUNCNAME[0]} - Final outgoing start command: '${FINALSTARTCMD[*]}'"

		startGame "${FINALSTARTCMD[@]}"

		writelog "STOP" "######### $PROGNAME $PROGVERS #########"
	fi
}

### CORE LAUNCH END ###

### COMMAND LINE START ###

function CompatTool {
	
	SCTS="$STEAMCOMPATOOLS/$PROGNAME"

	if [ "$1" == "add" ] ; then
		if [ -d "$SROOT" ]; then
			if [ ! -d "$STEAMCOMPATOOLS" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Initially creating dir '$STEAMCOMPATOOLS'"
				mkProjDir "$STEAMCOMPATOOLS"
				if [ ! -d "$SCTS" ]; then
					writelog "ERROR" "${FUNCNAME[0]} - Failed to create the directory '$STEAMCOMPATOOLS'"
				fi
			fi

			if [ "$ONSTEAMDECK" -eq 1 ]; then
				if [ -n "$2" ]; then
					STLBIN="$2"
				else
					STLBIN="$PREFIX/$PROGCMD"
				fi
			else
				STLBIN="$0"
			fi

			if [ ! -d "$SCTS" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Creating dir '$SCTS'"
				mkProjDir "$SCTS"

				if [ ! -d "$SCTS" ]; then
					writelog "ERROR" "${FUNCNAME[0]} - Failed to create the directory '$SCTS' - check your write priviledges on '$STEAMCOMPATOOLS'"
				fi

				CVDF="$SCTS/$CTVDF"
				writelog "INFO" "${FUNCNAME[0]} - Creating file '$CVDF'"
				{
				echo "\"compatibilitytools\""
				echo "{"
				echo "  \"compat_tools\""
				echo "  {"
				echo "	\"Proton-${SHOSTL}\" // Internal name of this tool"
				echo "	{"
				echo "	  \"install_path\" \".\""
				echo "	  \"display_name\" \"$NICEPROGNAME\""
				echo ""
				echo "	  \"from_oslist\"  \"windows\""
				echo "	  \"to_oslist\"    \"linux\""
				echo "	}"
				echo "  }"
				echo "}"
				} >> "$CVDF"

				if [ ! -f "$CVDF" ]; then
					writelog "ERROR" "${FUNCNAME[0]} - Failed to create the file '$CVDF' - check your write priviledges on '$SCTS'"
				fi

				TVDF="$SCTS/toolmanifest.vdf"
				writelog "INFO" "${FUNCNAME[0]} - Creating file '$TVDF'"
				{
				echo "\"manifest\""
				echo "{"
				echo "  \"commandline\" \"/$PROGCMD run\""
				echo "  \"commandline_$WFEAR\" \"/$PROGCMD $WFEAR\""
				echo "}"
				} >> "$TVDF"

				if [ ! -f "$CVDF" ]; then
					writelog "ERROR" "${FUNCNAME[0]} - Failed to create the file '$TVDF' - check your write priviledges on '$SCTS'"
				fi

				writelog "INFO" "${FUNCNAME[0]} - Creating symlink '$SCTS/$PROGCMD' pointing to '$STLBIN'" "E"
				ln -s "$(realpath "$STLBIN")" "$SCTS/$PROGCMD"
				
				if [ ! -L "$SCTS/$PROGCMD" ]; then
					writelog "ERROR" "${FUNCNAME[0]} - Failed to create the symlink '$SCTS/$PROGCMD' - check your write priviledges on '$SCTS'"
				fi
			else
				writelog "INFO" "${FUNCNAME[0]} - '$SCTS' already exists - checking if '$PROGCMD' symlink needs to be updated"
				if [ "$(readlink "$SCTS/$PROGCMD")" == "$(realpath "$STLBIN")" ]; then
					writelog "SKIP" "${FUNCNAME[0]} - Nothing to do the '$SCTS/$PROGCMD' symlink still points to '$STLBIN'" "E"
				else
					rm "$SCTS/$PROGCMD"
					ln -s "$(realpath "$STLBIN")" "$SCTS/$PROGCMD"
					writelog "SKIP" "${FUNCNAME[0]} - Updated the '$SCTS/$PROGCMD' symlink to '$STLBIN'" "E"
				fi
			fi
		else
			writelog "SKIP" "${FUNCNAME[0]} - Steam Home Dir '$SROOT' not found!"
		fi
	elif [ "$1" == "del" ]; then
		if [ ! -d "$SCTS" ]; then
			writelog "SKIP" "${FUNCNAME[0]} - Selected '$1' but '$SCTS' doesn't exist"
		else
			rm "$SCTS/$PROGCMD" 2>/dev/null
			find "$SCTS" -maxdepth 1 -type f -name "*.vdf" -exec rm {} \;
			rmdir "$SCTS"
			if [ ! -d "$SCTS" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Removed '$SCTS' successfully" "E"
			else
				writelog "SKIP" "${FUNCNAME[0]} - Tried to carefully remove '$SCTS', but it still exists - any files inside '$SCTS'?" "E"
			fi
		fi
	else
		if [ ! -d "$SCTS" ]; then
			writelog "INFO" "${FUNCNAME[0]} - '$PROGNAME' is not installed as Steam Compatibility Tool in '$STEAMCOMPATOOLS'" "E"
		else
			writelog "INFO" "${FUNCNAME[0]} - '$PROGNAME' is installed as Steam Compatibility Tool in '$STEAMCOMPATOOLS' and points to '$(readlink "$SCTS/$PROGCMD")'" "E"
		fi
	fi
}

function setRunProtonFromUseProton {
	if [ -n "$USEPROTON" ]; then
		NRUNPROTON="$(getProtPathFromCSV "$USEPROTON")"

		if [ -n "$RUNPROTON" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Setting ORUNPROTON to '$RUNPROTON'"
			ORUNPROTON="$RUNPROTON"
		fi

		if [ -n "$ORUNPROTON" ] && [ "$ORUNPROTON" == "$NRUNPROTON" ]; then
			writelog "SKIP" "${FUNCNAME[0]} - RUNPROTON '$RUNPROTON' hasn't changed"
		elif [ -n "$NRUNPROTON" ]; then
			if [ -z "$ORUNPROTON" ] || [ "$ORUNPROTON" == "" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Initially setting RUNPROTON for USEPROTON '$USEPROTON' to '$NRUNPROTON'"
			else
				writelog "INFO" "${FUNCNAME[0]} - Updating RUNPROTON for USEPROTON '$USEPROTON' from '$ORUNPROTON' to '$NRUNPROTON'"
			fi
			RUNPROTON="$NRUNPROTON"
			writelog "INFO" "${FUNCNAME[0]} - Set RUNPROTON to '$RUNPROTON'"
		fi
	else
		writelog "SKIP" "${FUNCNAME[0]} - USEPROTON is empty"
	fi
}

function checkStartMode {
	if [ -n "${ORGGCMD[0]}" ]; then

		writelog "INFO" "${FUNCNAME[0]} - LoadCfg: $STLGAMECFG"
		loadCfg "$STLGAMECFG"

		if [ "$ISGAME" -eq 2 ]; then
			if [ -n "$USEWINE" ] && [ "$USEWINE" -eq 1 ]; then
				writelog "SKIP" "${FUNCNAME[0]} - USEWINE is enabled - skipping this function"
			elif grep -q "USEWINE=\"1\"" "$STLGAMECFG" ; then
				writelog "SKIP" "${FUNCNAME[0]} - USEWINE is enabled in the to-be-loaded gameconfig '$STLGAMECFG' - skipping this function"
				EARLYUSEWINE=1
				# could still be enabled via steamcollections, but this would be an overkill here, as ${FUNCNAME[0]} is non-fatal
			else
				if [ "$HAVEINPROTON" -eq 1 ]; then
					writelog "INFO" "${FUNCNAME[0]} - Game was started via '$SLO' ('$PROGCMD %command%'),"
					writelog "INFO" "${FUNCNAME[0]} - because a Proton path was found in the command line provided by steam"
					writelog "INFO" "${FUNCNAME[0]} - Override Proton is disabled, when using $PROGCMD as '$SLO', so using it as-is: '${INPROTCMD[*]}'"
					writelog "INFO" "${FUNCNAME[0]} - (ignoring USEPROTON '$USEPROTON' from game config)"
					RUNPROTON="${INPROTCMD[*]}"
					writelog "INFO" "${FUNCNAME[0]} - Set RUNPROTON to '$RUNPROTON'"

					USEPROTON="$INPROTV"
					writelog "INFO" "${FUNCNAME[0]} - Set USEPROTON to '$USEPROTON'"
				else
					writelog "INFO" "${FUNCNAME[0]} - Game was started as Steam Compatibility Tool - automatically enabling override Proton,"
					writelog "INFO" "${FUNCNAME[0]} - as proton doesn't appear in the command line here"
					setRunProtonFromUseProton
				fi

				writelog "INFO" "${FUNCNAME[0]} - Continuing with RUNPROTON='$RUNPROTON'"

				if [ -n "$RUNPROTON" ]; then
					CHECKWINE="$(dirname "$RUNPROTON")/$DBW"

					if [ -f "$CHECKWINE" ]; then
						RUNWINE="$CHECKWINE"
						writelog "INFO" "${FUNCNAME[0]} - Set the wine binary for proton in path '$RUNPROTON' to '$RUNWINE'"
					else
						writelog "WARN" "${FUNCNAME[0]} - Couldn't find the wine binary for the proton in path '$RUNPROTON'"
					fi

					PROTONVERSION="$(setProtonPathVersion "$RUNPROTON")"
				fi
			fi
		fi
	fi
}

function getDefaultProton {
	if [ -n "$INPROTV" ]; then
		echo "$INPROTV"
	else
		getNOP "v"
	fi
}

function FUSEID {
	if [ -n "$1" ]; then
		USEID="$1"
	else
		USEID="$AID"
	fi

	if [ "$USEID" == "$PLACEHOLDERAID" ]; then
		if [ -f "$LASTRUN" ]; then
			PREVAID="$(grep "^PREVAID" "$LASTRUN" | cut -d '=' -f2)"
			if [ -n "$PREVAID" ]; then
				USEID="${PREVAID//\"}"
				PREVGAME="$(grep "^PREVGAME" "$LASTRUN" | cut -d '=' -f2)"
				if [ -n "$PREVGAME" ]; then
					GN="${PREVGAME//\"}"
				fi
			fi
		fi
	fi

	if [ -f "$LOGDIR/$USEID.log" ]; then
		rm "$LOGDIR/$USEID.log"
	fi
	resetAID "$USEID"
	setGN "$USEID"
}

function howto {
	echo "========================="
	echo "$PROGNAME $PROGVERS"
	echo "========================="
	echo "Usage: $PROGCMD [options]..."
	echo ""
	echo "where options include:"
	echo "    addcustomproton|acp <path>       Adds local custom Proton to"
	echo "                                       the internal list from dialog"
	echo "                                       or directly from <path>"
	echo "    addnonsteamgame|ansg <args>      Add a $NSGA to Steam"
	echo "                                       opens gui without args"
	echo "      <args>:                          for cli min arg is'-ep'"
	echo "      -an=|--appname=	                 App Name - optional"
	echo "      -ep=|--exepath=                  Full gamepath required"
	echo "      -sd=|--startdir=                 Start Dir - optional"
	echo "      -ip=|--iconpath=                 Icon Path - optional"
	echo "      -lo=|--launchoptions             Game Launch Options - optional"
	echo "      -hd=|--hide=                     Hide Game - optional*"
	echo "      -adc=|--allowdesktopconf=        Allow Desktop Conf - optional"
	echo "      -ao=|--allowoverlay=             Allow Overlay - optional"
	echo "      -vr=|--openvr=                   OpenVR - optional*"
	echo "      -t=|--tags=                      Tags - quoted, comma-separated"
	echo "      -stllo|--stllaunchoption         Use '${PROGCMD} %command%' as Launch Option"
	echo "    backup <value>                   Backup found '$STUS' files"
	echo "                                       (for 'SteamAppID' or 'all')"
	echo "    block                            Opens the category Block selection menu"
	echo "    compat <cmd>                     Will (add|del|get) ${PROGNAME,,} as" 
	echo "                                       Steam compatibility tool"
	echo "                                       under 'STEAMCOMPATOOLS'"
	echo "    createappinfo|cai <id|i|o>       Create raw appinfo for <id>"
	echo "                                      or for 'installed|i' or 'owned|o' games"
	echo "                                      Append any arg to update the raw file"
	echo "                                      (takes a long time for many games!)"
	echo "    createappinfometa|caim <id|i|o>  Read data from raw appinfo for <id>"
	echo "                                      or for 'installed|i' or 'owned|o' games"
	echo "                                      and write to game metadata."
	echo "                                      Append any arg to update the metadata"
	echo "                                      (takes a long time for many games!)"
	echo "    createcompatdata|ccd <gameid><gui> (Re-)create compatdata for <gameid>"
	echo "                                       open <gui> to configure custom programs"
	echo "    createdesktopicon|cdi <game><id> Create desktop icon for <game>"
	echo "                                       <game> is the gameid or"
	echo "                                       with available meta game title"
	echo "                                       0=only internally"
	echo "                                       1=on the desktop"
	echo "                                       2=for the application menu"
	echo "                                       3=for desktop and application menu"
	echo "    createfirstinstall|cfi <gameid>  Open gui to create a Steam First Time Setup" 
	echo "    <a|c|r|file> (see wiki)            file for game <gameid>"
	echo "    configdir                        Open the SteamTinkerLaunch config directory with xdg-open"
	echo "    ${DPRS,}|dprs                    Prepare/launch ${DPRS}"
	echo "    dlcustomproton|dcp <url|l>       Download/install custom Proton"
	echo "                                       - from filerequester"
	echo "                                       - directly from <url>"
	echo "                                       - the 'latest|l' GE version"
	echo "                                       - 'latestge|lge' for Proton-GE"
	echo "                                       - 'latesttkg|ltkg' for Proton-TKG"
	echo "    dlwine|dw <url or latest|l>      Download/install Wine archive"
	echo "                                       from filerequester or"
	echo "                                       automatically the latest|l version or"
	echo "                                       directly from <url>"
	echo "    editor <value>                   Opens the editor menu"
	echo "                                       (for 'SteamAppID' or 'last')"
	echo "    fav <value>                      Opens the favorite menu"
	echo "                                       (for 'SteamAppID' or 'last')"
	echo "    gamefiles|gf <gameid>            Opens menu for opening <gameid> files"
	echo "    gamescope|gs <gameid>            Gamescope config-menu for <gameid>"
	echo "    (get commands only for games known by ${PROGNAME,,}:)"
	echo "    getcompatdata|gc <gameid/title>  Print the Game compatdata path"
	echo "    getexe|ge <gameid>               Print the Game Exe for <gameid>"
	echo "    getgamedir|gg <gameid/title>     Print the Game install directory with game name and AppID"
	echo "                  only                 Only display install directory"
	echo "    getid|gi <gametitle>             Print the SteamAppId for <gametitle>"
	echo "    gettitle|gt <gameid>             Print the Game Title for <gameid>"
	echo "    hedgemodmanager|hmm              HedgeModManager"
	echo "            install|i                  install latest stable HedgeModManager"
	echo "            download|d <channel>       download latest HedgeModManager release (stable or nightly)"
	echo "                                        defaults to stable"
	echo "            start|s <channel>          start HedgeModManager"
	echo "                                        automatically downloads and installs latest stable if <channel>"
	echo "                                        is not provided"
	echo "            url|u <url>              Download a GameBanana mod using MineType URL"
	echo "                                      Note that this will *not* work with regular browser URLs"
	echo "            desktopfile|df           (Re-)create .desktop files for HedgeModManager"
	echo "            list-supported           List games supported by HedgeModManager"
	echo "            list-installed           List installed games with HedgeModManager support"
	echo "            list-owned               List owned games on Steam with HedgeModManager support"
	echo "            resetmime                (Re)set MimeType and application menu entries"   
	echo "            uninstall                Remove HedgeModManager downloads folder, desktop files and Wineprefix"
	echo "                                      Note that this will not remove your mods or installed Winetricks"
	echo "    lang=<option>                    Mostly to get translated configs on inital setup."
	echo "                                      <option> can be a language file name without suffix or an path to a valid language file"
 	echo "    launcher <args>                  Start the Game Launcher"
	echo "             COLLECTION                Show only installed games from Steam collection COLLECTION"
	echo "             menu                      Open Steam Collection Menu"
	echo "             last                      Open last Game as 'Menu'"
	echo "             auto                      Create/Download data for all installed games first"
	echo "             update                    ReCreate all Collection Menus"
	echo "                                       Can be combined with auto"
	echo "    list <owned|installed>           List ids of <owned|o,installed|i> games"
	echo "         <id|name|path|count|full>     Optionally specify whether you want to see"
	echo "                                        each game's <id|name|path|count|full>"
	echo "    meta                             Generates/Updates metadata"
	echo "                                       for all installed games"
	echo "    mo2                              Mod Organizer 2"
	echo "         install|i                   install MO2 (includes download)"
	echo "         download|d                  download latest MO2 release"
	echo "         start|s                     start MO2 (includes download+install)"
	echo "         list-supported|ls           list games supported by MO2"
	echo "         list-installed|li           list installed games supported by MO2"
	echo "         create-instance|ci <id>     create MO2 instance for <id>"
	echo "         url|u <url>                 open nxm url with MO2"
	echo "         resetmime                   (Re)set MimeType and application menu entries"
	echo "         winecfg                     Run Winecfg with MO2 Wine in MO2 prefix"
	echo "    opengridfolder|ogf               Open the Steam Grid folder where custom game artwork is stored using xdg-open"
	echo "    openissue|oi                     Opens issue tracker on GitHub in default browser"
	echo "    play <gameid>                    Start game with id <gameid> directly" 
 	echo "    proton|p <title> <X>             Start and/or create <title> with proton"
	echo "                                       without using steam."
	echo "                                       Optional <X> opens gui"
 	echo "    proton|p list                    Update the list of all available proton versions"
	echo "    set <var> <for> <value>          Change configuration settings"
	echo "                                       Example:"
	echo "      set RUN_REPLAY all 1               Set RUN_REPLAY for all games to 1"
	echo "    setgameart|sga <gameid> <args>   Set the artwork for various games by their AppID using absolute paths"
	echo "                                      Passing no args will open a GUI"
	echo "                                      By default, given artwork will be copied to the Steam Grid folder"
	echo "                                      Note that only ONE of the copy/link/move options should be used"
	echo "      <args>:                           "
	echo "      -hr=|--hero=                     Hero Art path    - Banner used on the Game Screen (3840x1240 recommended)"
	echo "      -lg=|--logo=                     Logo Art path    - Logo that gets displayed on Game Screen (16:9 recommended)"
	echo "      -ba=|--boxart=                   Box Art path     - Cover art used in the library (600x900 recommended)"
	echo "      -tf=|--tenfoot=                  Tenfoot Art path - Small banner used for recently played game in library (600x350 recommended)"
	echo "      --copy                            Copy art files to Steam Grid folder"
	echo "      --link                            Symlink art files to Steam Grid folder"
	echo "      --move                            Move art files to Steam Grid folder"
	echo "    settings <value>                 Opens the $SETMENU"
	echo "    src                              Shortcut '$STERECO'"
	echo "    steamdeckcompat <gameid>         Get information about Steam Deck compatibility for <gameid>"
	echo "                                       Will work offline if the information has been fetched before"
	echo "                                       (for 'SteamAppID' or 'last')"
	echo "    steamworksshared|sws <opts>      Steamworks Shared:"
	echo "      <opts>:                          Options:"
	echo "      <l>                              List packages - or"
	echo "      <i>                              Install package with options:"
	echo "      <packagename>                    - packagename"
	echo "      <SteamAppID or pfx>              - SteamAppID or pfx path"
	echo "      <wine binary>                    - Optional wine binary path"
	echo "    update <value>                   Updates <value>:"
	echo "           gamedata <SteamAppID>       Updates missing desktopfiles"
	echo "                                       and pictures of installed games"
	echo "                                       or only from <SteamAppID>"
	echo "           grid <SteamAppID>         Update Steam Grid for installed game(s)"
	echo "                                       optional argument either a SteamAppID,"
	echo "                                       'owned' or 'installed'"
	echo "                                       (default is 'installed')"
	echo "           allgamedata                 The same as above for"
	echo "                                       all games in $SCV"
	echo "           shaders <shadername>        all enabled shaders or <shadername>"
	echo "                                       'list' to list shaders"
	echo "                                       'repos' to update used shader repos"
	echo "           gameshaders <opt1> <opt2|3> open shader selection for dir <opt1>,"
	echo "                                       for last gamedir when <opt1> is empty"
	echo "                                       enable repo <opt1> for dir <opt2>"
	echo "                                        with empty <opt3> or <opt3>=enable"
	echo "                                       disable repo <opt1> for dir <opt2>"
	echo "                                        with  <opt3>=disable"
	echo "                                       block repo <opt1> with <opt2>=block"
	echo "                                       unblock repo <opt1> with <opt2>=unblock"
	echo "           reshade <version>           (re)-download ReShade (version)"
	echo "    version                          Output the program version"
	echo "    ${VTX} <value>                   ${VTX^} commandline options"
	echo "           install                     Installs ${VTX^}"
	echo "           list-supported|ls           List all ${VTX^}-supported Steam Game IDs"
	echo "                                       (offline - ${VTX^} needs to be installed)"
	echo "           list-online|lo              List ${VTX^}-supported games found online"
	echo "           list-owned|low              List owned games with ${VTX^} support"
	echo "           list-installed|li           List installed Games with ${VTX^} support"
	echo "           games                       Gui to en/disable ${VTX^} for supported game"
	echo "           symlinks                    Gui showing ${VTX^} symlinks"
	echo "           start                       Starts ${VTX^}"
	echo "           url|u <url>                 Open nxm url with ${VTX^}"
	echo "           getset                      Show config of installed ${VTX^}"
	echo "           reset                       Reset all autodetected settings in ${VTX^}"
	echo "           stage <path>                Add ${VTX^} stage via dialog"
	echo "           resetmime                   (Re)set MimeType and application menu entries"
	echo "           winecfg                     Run Winecfg with ${VTX^} Wine in ${VTX^} prefix"
    echo "                                        or directly the one given in <path>"
	echo "    vr <windowname> <SteamAppID> <s> Start SBS-VR mode for <windowname>"
	echo "                                       and game <SteamAppID>"
	echo "                                       's'ave windowname for the game"
	echo "    waitrequester|wr e|s|u           <e>nable the waitrequester for the launched game"
	echo "                                       (no effect if already enabled)"
	echo "                                     <s>kip the waitrequester temporarily"
	echo "                                     <u>nskip the temporary waitrequester skip"
	echo "    wiki <page>                      Opens the wiki <page> in yad"
	echo "    yad <yad binary> <opt>           Configure the used Yad binary"
	echo "                                       <yad binary> can be either"
	echo "                                       <absolute/path>"
	echo "                                       <conty>"
	echo "                                       <ai> or <appimage> plus optional <opt>:"
	echo "                                       <opt> can be either"
	echo "                                         <absolute/path/to/a/yad/appimage>"
	echo "                                         <http/s/yad/appimage/download/url>"
	echo "                                       (see Wiki for details)"
}

#STARTCMDLINE
function commandline {
	if [ "$1" == "addcustomproton" ] || [ "$1" == "acp" ]; then
		addCustomProton "$2" "$3"
	elif [ "$1" == "addnonsteamgame" ] || [ "$1" == "ansg" ] ; then
		if [ -z "$2" ]; then
			addNonSteamGameGui "$NON"
		else
			if grep -q "ep=\|--exepath=" <<< "$*"; then
				if grep -q "gui" <<< "$*"; then
					addNonSteamGameGui "$@"
				else
					addNonSteamGame "$@"
				fi
			else
				writelog "INFO" "${FUNCNAME[0]} - Command line parameters insufficent - starting the Gui"
				addNonSteamGameGui "$NON"
			fi
		fi
	elif [ "$1" == "backup" ]; then
		if [ "$2" == "all" ]; then
			backupSteamUserGate "$2"
		else
			FUSEID "$2"
			backupSteamUserGate "$USEID"
		fi
	elif [ "$1" == "block" ]; then
		FUSEID "$2"
		setGuiBlockSelection "$USEID"
	elif [ "$1" == "sort" ]; then
		setGuiSortOrder
	elif [ "$1" == "compat" ]; then
		if [ -n "$2" ]; then
			if [ "$2" == "add" ] || [ "$2" == "del" ] || [ "$2" == "get" ]; then
				CompatTool "$2"
			else
				howto
			fi
		else
			CompatTool "get"
		fi
	elif [ "$1" == "conty" ]; then
		if [ -n "$2" ]; then
			if [ "$2" == "up" ] || [ "$2" == "update" ]; then
				updateConty
			fi
		fi
	elif [ "$1" == "createcompatdata" ] || [ "$1" == "ccd" ]; then
		FUSEID "$2"
		writelog "INFO" "${FUNCNAME[0]} - Starting Install via command: reCreateCompatdata \"$1\" \"$USEID\" \"$3\""
		reCreateCompatdata "$1" "$USEID" "$3"
	elif [ "$1" == "createdesktopicon" ] || [ "$1" == "cdi" ]; then
		if [ "$2" == "all" ]; then
			if [ "$(listInstalledGameIDs | wc -l)" -eq 0 ]; then
				writelog "SKIP" "${FUNCNAME[0]} - No installed games found!" "E"
			else
				while read -r CATAID; do
					createDesktopIconFile "$CATAID" "$3"
				done <<< "$(listInstalledGameIDs)"
			fi
		else
			FUSEID "$2"
			createDesktopIconFile "$USEID" "$3"
		fi
	elif [ "$1" == "createappinfo" ] || [ "$1" == "cai" ]; then
		if [ "$2" == "installed" ] || [ "$2" == "i" ]; then
			if [ "$(listInstalledGameIDs | wc -l)" -eq 0 ]; then
				writelog "SKIP" "${FUNCNAME[0]} - No installed games found!" "E"
			else
				while read -r CATAID; do
					getRawAppIDInfo "$CATAID" "$3"
				done <<< "$(listInstalledGameIDs)"
			fi
		elif [ "$2" == "owned" ] || [ "$2" == "o" ]; then
			while read -r CATAID; do
				getRawAppIDInfo "$CATAID" "$3"
			done <<< "$(getOwnedAids)"
		else
			FUSEID "$2"
			getRawAppIDInfo "$USEID" "$3"
		fi
	elif [ "$1" == "createappinfometa" ] || [ "$1" == "caim" ]; then
		if [ -n "$2" ]; then
			if [ "$2" == "installed" ] || [ "$2" == "i" ]; then
				if [ "$(listInstalledGameIDs | wc -l)" -eq 0 ]; then
					writelog "SKIP" "${FUNCNAME[0]} - No installed games found!" "E"
				else
					while read -r CATAID; do
						writeAllAIMeta "$CATAID" "$3"
					done <<< "$(listInstalledGameIDs)"
				fi
			elif [ "$2" == "owned" ] || [ "$2" == "o" ]; then
				while read -r CATAID; do
					writeAllAIMeta "$CATAID" "$3"
				done <<< "$(getOwnedAids)"
			else
				if [ "$2" -eq "$2" ]; then
					FUSEID "$2"
					writeAllAIMeta "$USEID" "$3"
				fi
			fi
		else
			writelog "INFO" "${FUNCNAME[0]} - need at least 'installed|i' or 'owned|o' or a SteamAppId as arg2" "E"
		fi
	elif [ "$1" == "createfirstinstall" ] || [ "$1" == "cfi" ]; then
		FUSEID "$2"
		CreateCustomEvaluatorScript "$USEID"
	elif [ "$1" == "configdir" ]; then
		"$XDGO" "$STLCFGDIR"
	elif [ "$1" == "${DPRS,}" ] || [ "$1" == "dprs" ]; then
		startDepressurizer
	elif [ "$1" == "dlcustomproton" ] || [ "$1" == "dcp" ]; then
		dlCustomProtonGate "$2"
	elif [ "$1" == "dlwine" ] || [ "$1" == "dw" ]; then
		dlWineGate "$2"
	elif [ "$1" == "dxvkhud" ] || [ "$1" == "dxh" ]; then
		FUSEID "$2"
		DxvkHudPick "$USEID"
	elif [ "$1" == "dotnet" ]; then
		if [ -n "$3" ]; then
			installDotNet "$2" "$3" "$4"
		else
			writelog "INFO" "${FUNCNAME[0]} - need at least a winepfx as arg2 '$2' and a wine binary as arg3" "E"
			#howto
		fi
	elif [ "$1" == "editor" ]; then
		FUSEID "$2"
		EditorDialog "$USEID"		
	elif [ "$1" == "fav" ]; then
		FUSEID "$2"
		if [ -n "$3" ] && [ "$3" == "set" ]; then
			setGuiFavoritesSelection "$USEID"
		else
			openTrayIcon
			favoritesMenu "$USEID"
			cleanYadLeftOvers
		fi
	elif [ "$1" == "gamefiles" ] || [ "$1" == "gf" ]; then
		FUSEID "$2"
		GameFilesMenu "$USEID"	
	elif [ "$1" == "gamescope" ] || [ "$1" == "gs" ]; then
		FUSEID "$2"
		GameScopeGui "$USEID" "$3"
	elif [ "$1" == "getexe" ] || [ "$1" == "ge" ]; then
		getExeFromID "$2"
	elif [ "$1" == "getid" ] || [ "$1" == "gi" ]; then
		getIDFromTitle "$2"
	elif [ "$1" == "gettitle" ] || [ "$1" == "gt" ]; then
		getTitleFromID "$2"
	elif [ "$1" == "getcompatdata" ] || [ "$1" == "gc" ]; then
		getCompatData "$2"
	elif [ "$1" == "getgamedir" ] || [ "$1" == "gg" ]; then
		if [ "$3" == "only" ]; then
			getGameDir "$2" "X"
		else
			getGameDir "$2"
		fi
	elif [ "$1" == "help" ] || [ "$1" == "--help" ] || [ "$1" == "-h" ]; then
		howto
	elif [ "$1" == "helpurl" ] || [ "$1" == "hu" ]; then
		FUSEID "$2"
		HelpUrlMenu "$USEID"
		if [ -z "$3" ]; then
			rm "$STLSHM/KillBrowser-$AID.txt" 2>/dev/null
		fi
	elif [ "$1" == "launcher" ]; then
		openGameLauncher "$2" "$3"
	elif [ "$1" == "list" ]; then
		if [ -z "$2" ]; then
			echo "invalid usage - must pass one additional argument to 'list' command, either 'owned' or 'installed'"
		else
			listSteamGames "$2" "$3" # 3rd parameter is optional
		fi
	elif [ "$1" == "meta" ]; then
		createMetaData "yes"
	elif [ "$1" == "mo2" ]; then
		if [ -n "$2" ]; then
			if [ "$2" == "download" ] || [ "$2" == "d" ]; then
				dlLatestMO2
			elif [ "$2" == "install" ] || [ "$2" == "i" ]; then
				StatusWindow "$(strFix "$NOTY_INSTSTART" "$MO")" "installMO2" "InstallMO2Status"
			elif [ "$2" == "start" ] || [ "$2" == "s" ]; then
				startMO2
			elif [ "$2" == "list-supported" ] || [ "$2" == "ls" ]; then
				listMO2Games
			elif [ "$2" == "list-installed" ] || [ "$2" == "li" ]; then
				# Output installed MO2 games in format "Name (AppID) -> /path/to/prefix"
				setMO2Vars
				mapfile -t -O "${#CMDINSTMO2GAMS}" CMDINSTMO2GAMS <<< "$( prepAllMO2Games "li" )"
				for IMO2G in "${CMDINSTMO2GAMS[@]}"; do
					IMO2GAID="$( echo "$IMO2G" | cut -d ";" -f 1 )"
					IMO2GN="$( echo "$IMO2G" | cut -d ";" -f 2 )"
					IMO2GPA="$( echo "$IMO2G" | cut -d ";" -f 3 )"

					printf "%s (%s) -> %s\n" "$IMO2GN" "$IMO2GAID" "$IMO2GPA"
				done 
			elif [ "$2" == "create-instance" ] || [ "$2" == "ci" ]; then
				if [ -z "$3" ] || [ "$3" == "all" ]; then
					createAllMO2Instances
				else
					manageMO2GInstance "$3"
				fi
			elif [ "$2" == "url" ] || [ "$2" == "u" ]; then
				if [ -z "$3" ]; then
					writelog "ERROR" "${FUNCNAME[0]} - No URL was passed for ('$3') -- Maybe this is being incorrectly launched from the XDG menu?"
					warnInvalidModToolLaunch "ModOrganizer 2"
				else
					writelog "INFO" "${FUNCNAME[0]} - URL passed is '$3'"
					dlMod2nexurl "$3"
				fi
			elif [ "$2" == "winecfg" ]; then
				mo2Winecfg
			elif [ "$2" == "resetmime" ]; then
				writelog "INFO" "${FUNCMAME[0]} - (Re)setting MO2 .desktop file entries and MimeType associations"
				echo "(Re)setting MO2 .desktop file entries and MimeType associations"
				setMO2DLMime
			else
				writelog "INFO" "${FUNCNAME[0]} - arg2 '$2' is no valid command"
				howto
			fi
		else
			echo "need arg2"
			howto
		fi
	elif [ "$1" == "hedgemodmanager" ] || [ "$1" == "hmm" ]; then
		if [ -n "$2" ]; then
			if [ -n "$3" ]; then
				CMDHMMDLVER="$3"
			fi

			if [ "$2" == "download" ] || [ "$2" == "d" ]; then
				dlLatestHMM "$CMDHMMDLVER"
			elif [ "$2" == "install" ] || [ "$2" == "i" ]; then
				dlLatestHMM "$CMDHMMDLVER"
				installHMM
			elif [ "$2" == "start" ] || [ "$2" == "s" ]; then
				if [ "$4" == "--force" ] || [ "$4" == "-f" ]; then
					# This will force dotnet48 to be reinstalled for each installed 64bit HMM game if `--force` or `-f` is passed to `steamtinkerlaunch hmm start` 
					startHMM "$CMDHMMDLVER" "X"
				else
					startHMM "$CMDHMMDLVER"
				fi
			elif [ "$2" == "list-supported" ] || [ "$2" == "ls" ]; then
				listSupportedHMMGames
			elif [ "$2" == "list-installed" ] || [ "$2" == "li" ]; then
				listInstalledHMMGames
			elif [ "$2" == "list-owned" ] || [ "$2" == "lo" ]; then
				listOwnedHMMGames
			elif [ "$2" == "desktopfile" ] || [ "$2" == "df" ]; then
				createHMMDesktopFile
			elif [ "$2" == "uninstall" ]; then
				uninstallHMM
			elif [ "$2" == "url" ] || [ "$2" == "u" ]; then
				if [ -z "$3" ]; then
					writelog "ERROR" "${FUNCNAME[0]} - No URL was passed for ('$3') -- Maybe this is being incorrectly launched from the XDG menu?"
					warnInvalidModToolLaunch "Hedge Mod Manager"
				else 
					dlHedgeMod "$3"
				fi
			elif [ "$2" == "resetmime" ]; then
				writelog "INFO" "${FUNCMAME[0]} - (Re)setting HMM .desktop file entries and MimeType associations"
				echo "(Re)setting HMM .desktop file entries and MimeType associations"
				createHMMDesktopFile
			else
				echo "Need to input a valid arg2 '$2' to run a HedgeModManager command"
				howto
			fi
		else
			writelog "INFO" "arg2 '$2' is no valid command"
			howto
		fi
	elif [ "$1" == "opengridfolder" ] || [ "$1" == "ogf" ]; then
		openSteamGridDir
	elif [ "$1" == "setgameart" ] || [ "$1" == "sga" ]; then
		if [ -n "$2" ]; then
			if [ -z "$3" ]; then
				setGameArtGui "$2"  # Don't think this function needs to take any arguments
			else
				setGameArt "${@:2}"  # Pass all arguments except the first which is the command name e.g. `setgameart`
			fi
		else
			echo "At least one argument (AppID) must be provided"
		fi
	elif [ "$1" == "noty" ]; then
		if [ -n "$2" ]; then
			NTEXT="$2"
		else
			NTEXT="notifier test"
		fi
		notiShow "$NTEXT"
	elif [ "$1" == "onetimerun" ] || [ "$1" == "otr" ]; then
		FUSEID "$2"
		OneTimeRunGui "$USEID"
	elif [ "$1" == "pdb" ]; then
		getProtonDBRating "$2"
	elif [ "$1" == "steamdeckcompat" ] || [ "$1" == "sdc" ]; then
		mapfile -d ";" -t -O "${#DECKCOMPATARR[@]}" DECKCOMPATARR <<< "$( getSteamDeckCompatInfo "$( echo "$2" | xargs )" )"
		unset "DECKCOMPATARR[-1]"

		if [ "${#DECKCOMPATARR[@]}" -eq "0" ]; then
			echo "Could not get Steam Deck compatibility information got AppID '$2' - Is this definitely correct?"
			echo "You can check get the AppID for a game by running 'steamtinkerlaunch getid <name>'"
		else
			echo "Valve's testing indicates that this game is ${DECKCOMPATARR[0]} on Steam Deck"
			if ! [ "${#DECKCOMPATARR[@]}" -eq "1" ]; then  # Only take a newline if there is compatibility information to show
				echo ""
				for COMPATSTR in "${DECKCOMPATARR[@]:1}"; do
					echo "$COMPATSTR"
				done
			fi
		fi
	elif [ "$1" == "pickwin" ] || [ "$1" == "pw" ]; then
		pickGameWindowNameMeta "$2" "$3"
	elif [ "$1" == "play" ]; then
		if [ -z "$2" ]; then
			writelog "INFO" "${FUNCNAME[0]} - need at a valid game name or SteamAppId of an installed game or an absolute path to a game exe as arg2 '$2' or 'gui' for a menu" "E"
		else
			if [ "$2" == "gui" ]; then
				standaloneLaunch
			elif [ "$2" == "ed" ]; then
				standaloneEd "${@:3}"
			elif [ "$2" == "list" ]; then
				standaloneGames l
			else
				initPlay "${@:2}"
			fi
		fi
	elif [ "$1" == "proton" ] || [ "$1" == "p" ]; then
		if [ -n "$2" ] && [ "$2" == "list" ]; then
			getAvailableProtonVersions "up" X
		else
			StandaloneProtonGame "$2" "$3"
		fi
	elif [ "$1" == "set" ]; then
		if [ -n "$2" ]; then
				ENTLIST="$(sed -n "/#STARTsaveCfgdefault_template/,/#ENDsaveCfgdefault_template/p;/#ENDsaveCfgdefault_template/q" "$0" | grep "echo" | grep "=" | cut -d '"' -f2 | cut -d '=' -f1 | sed 's/^#//')"
				if ! grep "$2" <<< "$ENTLIST" >/dev/null; then
					writelog "INFO" "${FUNCNAME[0]} - '$2' is no valid entry - valid are:" "E"
					writelog "INFO" "${FUNCNAME[0]} ------------------------" "E"
					writelog "INFO" "${FUNCNAME[0]} - $ENTLIST" "E"
					writelog "INFO" "${FUNCNAME[0]} ------------------------" "E"
					exit
				fi
			if [ -n "$3" ]; then
				if [ -z "$4" ]; then
					writelog "INFO" "${FUNCNAME[0]} - argument 4 is missing - exit" "E"
					exit
				else
					if [ "$3" == "all" ]; then
						writelog "INFO" "${FUNCNAME[0]} - arg3 is all - updating all config files in '$STLGAMEDIRID':" "E"
						while read -r file; do
							writelog "INFO" "${FUNCNAME[0]} - updating entry '$2' to value '$4' in config $file" "E"
							touch "$FUPDATE"
							updateConfigEntry "$2" "$4" "$file"
						done <<< "$(find "$STLGAMEDIRID" -name "*.conf")"
					else
						if [ -f "$STLGAMEDIRID/$3.conf" ]; then
							writelog "INFO" "${FUNCNAME[0]} - updating entry '$2' to value '$4' in config '$STLGAMEDIRID/$3.conf'" "E"
							touch "$FUPDATE"
							updateConfigEntry "$2" "$4" "$STLGAMEDIRID/$3.conf"
						else
							writelog "INFO" "${FUNCNAME[0]} - config file '$STLGAMEDIRID/$3.conf' does not exist - nothing to do - exit" "E"
							exit
						fi
					fi
				fi
			else
				writelog "INFO" "${FUNCNAME[0]} - arg3 is missing, you need to provide either the SteamAppId of the game or 'all' to batch update all game configs with the chosen entry!" "E"
				exit
			fi
		else
			writelog "INFO" "${FUNCNAME[0]} - arg2 is missing, you need to provide a valid config entry which should be updated!" "E"
			exit
		fi
	elif [ "$1" == "settings" ]; then
		startSettings "$2"
	elif [ "$1" == "src" ]; then
			"$STEAM" "${STEAM}://${RECO}"
	elif [ "$1" == "steamworksshared" ] || [ "$1" == "sws" ]; then
		if [ -n "$2" ]; then
			if [ "$2" == "install" ] || [ "$2" == "i" ]; then
				if [ -n "$4" ]; then
				installSteWoShPak "$3" "$4" "$5"
				else
					writelog "INFO" "${FUNCNAME[0]} - Need at least package name as arg 3 and a wineprefix OR a SteamAppID as arg 4" E
					writelog "INFO" "${FUNCNAME[0]} - and optionally an absolute path to to a wine binary as arg 5" E
				fi
			elif [ "$2" == "list" ] || [ "$2" == "l" ]; then
				listSteWoShPaks
			else	
				writelog "INFO" "${FUNCNAME[0]} - arg2 '$2' is no valid command"
				howto
			fi
		else
			echo "need arg2"
			howto
		fi
	elif [ "$1" == "${SPEK,,}" ]; then
		if [ -n "$2" ]; then
			if [ "$2" == "download" ] || [ "$2" == "dl" ]; then
				dlSpecialK "$3"
			else
				howto
			fi
		else
			howto
		fi
	elif [ "$1" == "update" ]; then
		if [ -n "$2" ]; then
			if [ "$2" == "gamedata" ]; then
				if [ -z "$3" ]; then
					getGameDataForInstalledGames
				else
					echo getGameData "$3"
					getGameData "$3"
				fi
			elif [ "$2" == "grid" ]; then
				if [ -z "$3" ]; then
					getGridsForOwnedGames
				elif [ "$3" == "owned" ]; then
					getGridsForOwnedGames
				elif [ "$3" == "installed" ]; then
					getGridsForInstalledGames				
				else
					getGrids "$3"
				fi
			elif [ "$2" == "allgamedata" ]; then
				getDataForAllGamesinSharedConfig
			elif [ "$2" == "shader" ] || [ "$2" == "shaders" ]; then
				if [ -n "$3" ] && { [ "$3" == "repos" ] || [ "$3" == "list" ]; }; then
					dlShaders "$3"
				else
					StatusWindow "$GUI_DLSHADER" "dlShaders $3"  "DownloadShadersStatus"
				fi
			elif [ "$2" == "gameshader" ] || [ "$2" == "gameshaders" ]; then
				if [ -z "$3" ]; then
					writelog "INFO" "${FUNCNAME[0]} - No game directory in argument 3 provided - using last game!"
					GameShaderDialog
				else
					if [ -d "$3" ]; then
						writelog "INFO" "${FUNCNAME[0]} - command line: GameShaderDialog \"$3\""
						GameShaderDialog "$3"
					else
						if [ -n "$4" ]; then
							if [ -d "$4" ]; then
								if [ -n "$5" ] && [ "$5" == "disable" ]; then
									disableThisGameShaderRepo "$3" "$4"
								else
									enableThisGameShaderRepo "$3" "$4"
								fi
							elif [ "$4" == "block" ]; then
								echo "$3" >> "$SHADERREPOBLOCKLIST"
								sort -u "$SHADERREPOBLOCKLIST" -o "$SHADERREPOBLOCKLIST"
								unblockrssub
							elif [ "$4" == "unblock" ]; then
								grep -v "^${3}$" "$SHADERREPOBLOCKLIST" > "$STLSHM/SHADERREPOBLOCKLIST_tmp.txt"
								mv "$STLSHM/SHADERREPOBLOCKLIST_tmp.txt" "$SHADERREPOBLOCKLIST"
							else
								writelog "SKIP" "${FUNCNAME[0]} - Invalid argument '$4' - exit"
							fi
						else
							writelog "SKIP" "${FUNCNAME[0]} - Game directory '$3' does not exist - exit"
						fi
					fi
				fi
			elif [ "$2" == "reshade" ]; then
				dlReShade "$3"
			else
				howto
			fi
		else
			howto
		fi
	elif [ "$1" == "version" ] || [ "$1" == "--version" ] || [ "$1" == "-v" ]; then
		echo "${PROGNAME,,}-${PROGVERS}"
	elif [ "$1" == "$VTX" ]; then
		USEVORTEX=1
		if [ -n "$2" ]; then
			if [ "$2" == "install" ] || [ "$2" == "i" ]; then
				if [ -n "$3" ] && [ "$3" == "gui" ]; then
					installVortexGui
				else
					StatusWindow "$(strFix "$NOTY_DLCUSTOMPROTON" "${VTX^}")" "dlLatestVortex S" "DownloadVortexStatus"
					StatusWindow "$(strFix "$NOTY_INSTSTART" "${VTX^}")" "installVortex" "InstallVortexStatus"
				fi
			elif [ "$2" == "start" ]; then
				startVortex "noask" "$3"
			elif [ "$2" == "url" ] || [ "$2" == "u" ]; then
				if [ -z "$3" ]; then
					writelog "ERROR" "${FUNCNAME[0]} - No URL was passed for ('$3') -- Maybe this is being incorrectly launched from the XDG menu?"
					warnInvalidModToolLaunch "Vortex"
				else
					startVortex "noask" "url" "$3"
				fi
			elif [ "$2" == "getset" ]; then
				startVortex "noask" "$2"
			elif [ "$2" == "gui" ]; then
				VortexOptions
			elif [ "$2" == "reset" ]; then
				resetVortexSettings
			elif [ "$2" == "stage" ]; then
				addVortexStage "$3"
			elif [ "$2" == "list-supported" ] || [ "$2" == "ls" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Games With ${VTX^} Support found in the ${VTX^} installation:" "E"
				# getVortexSupported X
				getVortexSupportedNames
			elif [ "$2" == "list-online" ] || [ "$2" == "lo" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Games With ${VTX^} Support listed online:" "E"
				dlVortexSupportedList
			elif [ "$2" == "list-owned" ] || [ "$2" == "low" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Games owned with ${VTX^} Support:" "E"
				VORTEXGAMES="$GLOBALMISCDIR/$VOGAT"
				while read -r line; do
					# TODO speed this up somehow?
					OWNEDVTXGAMELINE="$( grep "\"$line\"" "$VORTEXGAMES" )"
					OWNEDVTXGAMENAME="$( echo "$OWNEDVTXGAMELINE" | cut -d ";" -f2 | cut -d '"' -f 2 )"
					OWNEDVTXGAMEAID="$( echo "$OWNEDVTXGAMELINE" | cut -d ";" -f3 | cut -d '"' -f 2 )"

					if [ -n "$OWNEDVTXGAMENAME" ] && [ -n "$OWNEDVTXGAMEAID" ]; then
						printf "%s (%s)\n" "$OWNEDVTXGAMENAME" "$OWNEDVTXGAMEAID"
					fi
				done <<< "$(getOwnedAids)"
			elif [ "$2" == "list-installed" ] || [ "$2" == "li" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Installed Games With ${VTX^} Support"
				setVortexVars
				VORTEXGAMES="$GLOBALMISCDIR/$VOGAT"
				while read -r INSTALLEDVTXAID; do
					INSTALLEDVTXNAME="$( grep "$INSTALLEDVTXAID" "$VORTEXGAMES" | cut -d ";" -f 2 | cut -d '"' -f 2 )"

					# Bit hacky but fixes an instance where two games (on newlines) are returned but only one AppID is returned
					# Get rid of the newlines and replace with a semicolon, then cut and get the second game name which should be the matching AppID
					INSTALLEDVTXNAME="$( echo "${INSTALLEDVTXNAME//$'\n'/;}" | cut -d ";" -f 2 )"
					printf "%s (%s)\n" "$INSTALLEDVTXNAME" "$INSTALLEDVTXAID"
				done <<< "$(getInstalledGamesWithVortexSupport X)"
			elif [ "$2" == "games" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Opening Gui for en/disabling ${VTX^} for installed and supported games"
				VortexGamesDialog
			elif [ "$2" == "symlinks" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Opening Gui showing Symlinks in the ${VTX^} WINEPREFIX"
				VortexSymDialog
			elif [ "$2" == "download" ] || [ "$2" == "d" ]; then
				StatusWindow "$(strFix "$NOTY_DLCUSTOMPROTON" "${VTX^}")" "dlLatestVortex S" "DownloadVortexStatus"
			elif [ "$2" == "activate" ] && { [ -n "$3" ]  && [ "$3" -eq "$3" ] 2>/dev/null;}; then
				startVortex "activate" "$3"
			elif [ "$2" == "winecfg" ]; then
				vtxWinecfg
			elif [ "$2" == "resetmime" ]; then
				writelog "INFO" "${FUNCMAME[0]} - (Re)setting ${VTX^} .desktop file entries and MimeType associations"
				echo "(Re)setting ${VTX^} .desktop file entries and MimeType associations"
				setVortexDLMime
			else	
				writelog "INFO" "${FUNCNAME[0]} - arg2 '$2' is no valid command"
				howto
			fi
		else
			echo "need arg2"
			howto
		fi
	elif [ "$1" == "vr" ]; then
		if [ -n "$3" ]; then
			GAMEWINDOW="$2"
			AID="$3"
			setAIDCfgs
			if [ -n "$4" ] && [ "$4" == "s" ]; then
				storeGameWindowNameMeta "$(getGameWinNameFromXid "$2")"
			fi
			checkSBSVRLaunch "$2" 
		else
			howto
		fi
	elif [ "$1" == "waitrequester" ] || [ "$1" == "wr" ]; then
		if [ -n "$2" ] && { [ "$2" == "e" ] || [ "$2" == "s" ] || [ "$2" == "u" ];}; then
			if [ "$2" == "e" ]; then
				writelog "INFO" "${FUNCNAME[0]} - enabling the Wait Requester for the next launched game"
				touch "$EWRF"
			elif [ "$2" == "s" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Skipping the Wait Requester temporarily for the next launched games"
				touch "$SWRF"
			elif [ "$2" == "u" ]; then
				if [ -f "$SWRF" ]; then
					writelog "INFO" "${FUNCNAME[0]} - Disabling the temporary Wait Requester skipping"
					touch "$UWRF"
				else
					writelog "SKIP" "${FUNCNAME[0]} - The temporary Wait Requester skipping is not enabled, nothing to do"
				fi
			fi
		else
			writelog "INFO" "${FUNCNAME[0]} ------------------------"
			writelog "INFO" "${FUNCNAME[0]} - need either e,s or u as arg2"
			howto
		fi
	elif [ "$1" == "wiki" ]; then
		OpenWikiPage "$2"
	elif [ "$1" == "winetricks" ] || [ "$1" == "wt" ]; then
		FUSEID "$2"
		chooseWinetricksPrefix "$USEID"
	elif [ "$1" == "runwinecfg" ] || [ "$1" == "onetimewinecfg" ] || [ "$1" == "otwcfg" ]; then
		# Assumes that if `runwinecfg` is called without any arguments that it's an internal call
		# Otherwise we assume if *any* arguments are passed that we're a user calling it from the command-line
		if [ -n "$2" ]; then 
			# Always assume second argument is the AppID
			#
			# Could be improved in future by trying to find a matching game based on an entered game name
			# In the case of multiple matches we could just take the first match
			#
			# (Maybe AppID should be checked for first, on the off-chance that a game's names is the same as an AppID? 
			writelog "INFO" "${FUNCNAME[0]} - Looks like we're a user calling this from the command line -- User passed '$2'"
			oneTimeWinecfg "$2"
		else
			writelog "INFO" "${FUNCNAME[0]} - Looks like we're getting an internal One-Time Winecfg call"
			oneTimeWinecfg
		fi
	elif [ "$1" == "runwinetricks" ] || [ "$1" == "onetimewinetricks" ] || [ "$1" == "otwt" ]; then
		# All of the above comments about Winecfg apply to this Winetricks logic as well
		if [ -n "$2" ]; then 
			writelog "INFO" "${FUNCNAME[0]} - Looks like we're a user calling this from the command line -- User passed '$2'"
			oneTimeWinetricks "$2"
		else
			writelog "INFO" "${FUNCNAME[0]} - Looks like we're getting an internal One-Time Winetricks call"
			oneTimeWinetricks
		fi
	elif [ "$1" == "winedebugchannel" ] || [ "$1" == "wdc" ]; then
		FUSEID "$2"
		SetWineDebugChannels "$USEID"
	elif [ "$1" == "yad" ]; then
		if [ -n "$2" ]; then
			setYadBin "$2" "$3"
		else
			writelog "INFO" "${FUNCNAME[0]} ------------------------"
			writelog "INFO" "${FUNCNAME[0]} - arg2 '$2' needs to be a valid yad parameter"
			howto
		fi
	elif [ "$1" == "openissue" ] || [ "$1" == "oi" ]; then
		writelog "INFO" "${FUNCNAME[0]} - Opening issue tracker in user's default browser"
		"$XDGO" "$PROJECTPAGE/issues/new/choose"
	elif echo "$@" | grep -owq '\-q'; then
		writelog "INFO" "${FUNCNAME[0]} - Quiet mode enabled with '-q', suppressing notifier for this execution"
		export STLQUIET=1
		USENOTIFIER=0
	else
		if ! grep -q "lang=\|run" <<< "$@"; then
			writelog "INFO" "${FUNCNAME[0]} ------------------------"
			writelog "INFO" "${FUNCNAME[0]} - arg1 '$1' is no valid command"
			howto
		fi
	fi
}
#ENDCMDLINE


### COMMAND LINE END ###

function writeLastRun {
	writelog "INFO" "${FUNCNAME[0]} - Recreating $LASTRUN"
	{
	echo "RUNPROTON=\"$RUNPROTON\""
	echo "RUNWINE=\"$RUNWINE\""
	echo "PROTONVERSION=\"$PROTONVERSION\""
	echo "PREVAID=\"$AID\""
	echo "PREVGAME=\"$GN\""
	echo "PREVABSGAMEEXEPATH=\"$ABSGAMEEXEPATH\""
	} >	"$LASTRUN"
}

function storeMetaData {
	MAID="$1"
	MGNA1="${2//\//_}"
	MGNA="${MGNA1//\"/}"
	MPFX="$3"
	GDIR="$4"

	writelog "INFO" "${FUNCNAME[0]} - Saving metadata for game '$MGNA ($MAID)'"

	if [ ! -f "$GEMETA/$MAID.conf" ]; then
		if [ "$SGDBAUTODL" == "no_meta" ] ; then
			writelog "INFO" "${FUNCNAME[0]} - Automatic Grid Update Check '$SGDBAUTODL'"
			getGrids "$MAID"
		fi
		touch "$GEMETA/$MAID.conf"
	fi
	
	loadCfg "$GEMETA/$MAID.conf" X
	updateConfigEntry "GAMEID" "$MAID" "$GEMETA/$MAID.conf"

	if [ -z "$KEEPGAMENAME" ] || [ "$KEEPGAMENAME" -eq 0 ] || [ "$GAMENAME" == "$NON" ]; then
		updateConfigEntry "GAMENAME" "$MGNA" "$GEMETA/$MAID.conf"
	fi

	if [ -n "$GE" ] && [ -z "$GAMEEXE" ]; then
		GAMEEXE="$GE"
	fi

	if [ -n "$GAMEEXE" ]; then
		updateConfigEntry "GAMEEXE" "$GAMEEXE" "$GEMETA/$MAID.conf"
	fi

	if [ -n "$GP" ]; then
		updateConfigEntry "GAMEARCH" "$(getArch "$GP")" "$GEMETA/$MAID.conf"
	fi
	
	if [ ! -f "$CUMETA/$MAID.conf" ]; then
		touch "$CUMETA/$MAID.conf"
	fi
	loadCfg "$CUMETA/$MAID.conf" X

	if [ "$MPFX" != "$NON" ]; then
		updateConfigEntry "WINEPREFIX" "$MPFX" "$CUMETA/$MAID.conf"
	fi

	updateConfigEntry "MEGAMEDIR" "$GDIR" "$CUMETA/$MAID.conf"

	if [ "$STLPLAY" -eq 1 ]; then
		touch "$FUPDATE"
		updateConfigEntry "STL_COMPAT_DATA_PATH" "$STEAM_COMPAT_DATA_PATH" "$CUMETA/$MAID.conf"
	fi
	createSymLink "${FUNCNAME[0]}" "$GEMETA/$MAID.conf" "$TIGEMETA/${MGNA}.conf" X
	createSymLink "${FUNCNAME[0]}" "$CUMETA/$MAID.conf" "$TICUMETA/${MGNA}.conf" X

	if [ "$STLPLAY" -eq 0 ]; then
		createSymLink "${FUNCNAME[0]}" "$EVMETAID/${EVALSC}_${MAID}.vdf" "$EVMETATITLE/${EVALSC}_${MGNA}.vdf"
	fi
}

function delMenuTemps {
	find "$STLSHM" -maxdepth 1 -type f -regextype posix-extended -regex '^.*menu.[A-Z,a-z,0-9]{8}' -exec rm {} \;	
}

function delWinetricksTemps {
	# cosmetics - GE leaves empty winetricks directories back, removing them
	find "/tmp" -maxdepth 1 -type d -regextype posix-extended -regex '^.*winetricks.[A-Z,a-z,0-9]{8}' -exec rmdir {} \;	2>/dev/null
}

function cleanSUTemp {
	if [ "$ISGAME" -eq 2 ] && [ "$CLEANPROTONTEMP" -eq 1 ]; then
		PFXSUTEMP="$GPFX/$DRCU/$STUS/Temp"
		if [ -d "$PFXSUTEMP" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Cleaning up Temp directory '$PFXSUTEMP'"
			rm -rf "${PFXSUTEMP:?}" 
		else
			writelog "SKIP" "${FUNCNAME[0]} - Temp directory '$PFXSUTEMP' exists, but is empty"
		fi
	fi
}

function restoreSteamUser {

	function startRestore {
		writelog "INFO" "${FUNCNAME[0]} - Restoring backup from '$BACKUPSRC' to '$SteamUserDir'"
		notiShow "$(strFix "$NOTY_STARTRESTORE" "$BACKUPSRC" "$AID")"
		mkProjDir "$SteamUserDir"
		"$RSYNC" -am "$BACKUPSRC" "$SteamUserDir" 
		notiShow "$(strFix "$NOTY_STOPRESTORE" "$SteamUserDir")"
	}
	
	function startRestoreBecause {
		writelog "INFO" "${FUNCNAME[0]} - Restoring, because '$RSTUS' is set"
		startRestore
	}

	function askRestore {
		writelog "INFO" "${FUNCNAME[0]} - Asking if $STUS data from '$BACKUPSRC' shall be restored to '$SteamUserDir'"

		export CURWIKI="$PPW/Backup Support"
		TITLE="${PROGNAME}-Ask_Restore_SteamUser_data"
		pollWinRes "$TITLE"

		"$YAD" --f1-action="$F1ACTION" --image "$SHOWPIC" --image-on-top --window-icon="$STLICON" --center --on-top "$WINDECO" \
		--title="$TITLE" \
		--text="$(spanFont "$(strFix "$GUI_AR" "$BACKUPSRC" "$SteamUserDir")" "H")\n<i>$1</i>" $GEOM
		case $? in
			0) 	{
					writelog "INFO" "${FUNCNAME[0]} - Restoring '$SteamUserDir' from '$BACKUPSRC' confirmed"
					startRestore
				}
			;;
			1)	{
					writelog "INFO" "${FUNCNAME[0]} - Selected CANCEL - Not restoring '$BACKUPSRC' to '$SteamUserDir'"
				}
			;;
		esac
	}

	if [ -n "$1" ] && [ "$1" != "$NON" ]; then
		writelog "INFO" "${FUNCNAME[0]} - Using value '$1' from argument for RESTORESTEAMUSER"
		RSTUS="$1"
	else
		writelog "INFO" "${FUNCNAME[0]} - Using configured value '$RESTORESTEAMUSER' for RESTORESTEAMUSER"
		RSTUS="$RESTORESTEAMUSER"
	fi

	SteamUserDir="$GPFX/$DRCU/$STUS"
	BACKUPSRC="$SUBADIRID/$AID/$STUS/"
	
	if [ "$RSTUS" == "$NON" ] ; then
		writelog "INFO" "${FUNCNAME[0]} - Restoration of $STUS data is disabled with RESTORESTEAMUSER being '$RSTUS"
	else
		if [ -n "$AID" ] && [ -d "$BACKUPSRC" ] && [ -d "$GPFX" ]; then
			if [ "$RSTUS" == "ask-always" ] ; then
				askRestore "$GUI_AR_ALWAYSASK"
			elif [ "$RSTUS" == "restore-always" ] ; then
				startRestoreBecause
			elif [ ! -f "$SteamUserDir/$BTS" ] ; then
				if [ "$RSTUS" == "ask-if-dst-has-no-backup-timestamp" ] ; then
					askRestore "$GUI_AR_ASKNODSTTS"
				elif [ "$RSTUS" == "restore-if-dst-has-no-backup-timestamp" ] ; then
					startRestoreBecause
				elif [ "$RSTUS" == "restore-if-dst-is-empty" ]; then
					if [ ! -d "$SteamUserDir" ] || [ "$(find "$SteamUserDir" -type f | wc -l)" -eq 0 ]; then
						startRestoreBecause
					elif [ "$RSTUS" == "ask-if-unsure" ] ; then
						askRestore "$GUI_AR_ALWAYSASK"	
					fi
				elif [ "$RSTUS" == "ask-if-unsure" ] ; then
					askRestore "$GUI_AR_ASKUNSURE"
				fi
			elif [ -f "$BACKUPSRC/$BTS" ] && [ -f "$SteamUserDir/$BTS" ]; then
				if [ "$(cat "$BACKUPSRC/$BTS")" -gt "$(cat "$SteamUserDir/$BTS")" ]; then
					writelog "INFO" "${FUNCNAME[0]} - Data in '$BACKUPSRC' is newer than in '$SteamUserDir'"
					if [ "$RSTUS" == "restore-if-backup-timestamp-is-newer" ] ; then
						startRestoreBecause
					elif [ "$RSTUS" == "ask-if-unsure" ] ; then
						askRestore "$GUI_AR_ALWAYSASK"
					fi
				else
					writelog "INFO" "${FUNCNAME[0]} - Data in '$BACKUPSRC' is older than in '$SteamUserDir'"
					if [ "$RSTUS" == "ask-if-unsure" ]; then
						askRestore "$GUI_AR_ASKUNSURE"
					elif [ "$RSTUS" == "restore-always" ]; then
						startRestoreBecause
					fi
				fi
			elif [ "$RSTUS" == "ask-if-unsure" ] ; then
				askRestore "$GUI_AR_ASKUNSURE"
			else
				writelog "SKIP" "${FUNCNAME[0]} - Have to skip - this should never happen. RESTORESTEAMUSER is '$RSTUS'"
			fi
		else
			writelog "SKIP" "${FUNCNAME[0]} - At least one of AID '$AID', BACKUPSRC '$BACKUPSRC', SteamUserDir '$SteamUserDir' is missing - can't start restoration of $STUS data"
		fi
	fi
}

function backupSteamUser {
	if [ "$BACKUPSTEAMUSER" -eq 1 ]; then
		BAID="$1"

		if [ -n "$GN" ]; then
			BACKTI="$GN"
		else
			getGameName "$BAID"
			if [ -n "$GAMENAME" ] && [ "$GAMENAME" != "$NON" ]; then
				BACKTI="$GAMENAME"
			fi
		fi

		if [ -n "$2" ]; then
			if [ -d "$2" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Using argument 2 '$2' as WINEPREFIX'"
				GPFX="$2"
			else
				writelog "SKIP" "${FUNCNAME[0]} - Directory in argument 2 '$2' does not exist"
				GPFX=""
			fi
		fi

		setGPfxFromAppMa "$BAID"

		if [ -z "$GPFX" ]; then
			if [ -f "$CUMETA/$BAID.conf" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Loading metadata config '$CUMETA/$BAID.conf'"
				loadCfg "$CUMETA/$BAID.conf" X
				if [ -d "$WINEPREFIX" ]; then
					writelog "INFO" "${FUNCNAME[0]} - Searching in stored metadata WINEPREFIX '$WINEPREFIX' for files to backup"
					GPFX="$WINEPREFIX"
				else
					writelog "SKIP" "${FUNCNAME[0]} - Stored metadata WINEPREFIX '$WINEPREFIX' does not exist"
				fi
			else
				writelog "SKIP" "${FUNCNAME[0]} - No metadata config '$CUMETA/$BAID.conf' found to search for the WINEPREFIX"
				GPFX=""
			fi
		fi

		if [ -z "$GPFX" ]; then
			if [ -z "$BACKTI" ]; then
				writelog "SKIP" "${FUNCNAME[0]} - Game pfx unknown for '$BAID'"
			else
				writelog "SKIP" "${FUNCNAME[0]} - Game pfx unknown for '$BACKTI ($BAID)'"
			fi
		else
			if [ -z "$2" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Backup enabled for Game '$BACKTI ($BAID)'"
			fi
			mkProjDir "$SUBADIRID/$BAID"
			mkProjDir "$SUBADIRTI"
			SteamUserDir="$GPFX/$DRCU/$STUS"
			
			if [ -d "$SteamUserDir" ]; then
				writelog "INFO" "${FUNCNAME[0]} - backing up directory '$SteamUserDir' to '$SUBADIRID/$BAID'"
				if [ -z "$2" ]; then
					notiShow "$(strFix "$NOTY_STARTBACKUP" "$BACKTI" "$BAID")"
				fi
				mkProjDir "$BACKEX"
				
				EXID="$BACKEX/exclude-${BAID}.txt"
				touch "$EXGLOB" "$EXID"
				"$RSYNC" -am --exclude-from="$EXGLOB" --exclude-from="$EXID" "$SteamUserDir" "$SUBADIRID/$BAID"
				date +%s > "$SUBADIRID/$BAID/$STUS/$BTS"

				if [ -z "$2" ]; then
					notiShow "$(strFix "$NOTY_STOPBACKUP" "$BACKTI" "$BAID")"
				fi
			else
				writelog "SKIP" "${FUNCNAME[0]} - directory '$SteamUserDir' does not exist - nothing to backup"
			fi

			if [ -z "$BACKTI" ]; then
				if [ -z "$2" ]; then
					writelog "SKIP" "${FUNCNAME[0]} - Skipping symlinking backup - no valid game name found"
				fi
			else
				createSymLink "${FUNCNAME[0]}" "$SUBADIRID/$BAID" "$SUBADIRTI/$BACKTI"
			fi
		fi
	fi
}

function backupSteamUserGate {
	BACKUPSTEAMUSER=1
	if [ "$1" != "all" ]; then
		backupSteamUser "$1"
	else
		LOGFILE="$TEMPLOG"
		writelog "INFO" "${FUNCNAME[0]} - Selected to backup all '$STUS' files from all found pfxes"

		while read -r APPMA; do
			AMF="${APPMA##*/}"
			BAID="$(cut -d'_' -f2 <<< "$AMF" | cut -d'.' -f1)"
			BPFX="$(dirname "$APPMA")/$CODA/$BAID/pfx"
			if [ -d "$BPFX" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Backup all '$STUS' files for pfx '$BPFX'"
				backupSteamUser "$BAID" "$BPFX"
			fi
		done <<< "$(listAppManifests)"
	fi
}

function createMetaData {
	LASTMETAUP="$METADIR/lastmeta.txt"
	MAXMETAAGE=1440
	
	if [ -n "$1" ] && [ "$1" == "yes" ]; then
		writelog "INFO" "${FUNCNAME[0]} - Updating metadata requested via command line"
		rm "$LASTMETAUP"
	fi
	
	if [ ! -f "$LASTMETAUP" ] || test "$(find "$LASTMETAUP" -mmin +"$MAXMETAAGE")"; then
		writelog "INFO" "${FUNCNAME[0]} - Creating/Updating metadata for all installed games found"

		while read -r APPMA; do
			AMF="${APPMA##*/}"
			MAID="$(cut -d'_' -f2 <<< "$AMF" | cut -d'.' -f1)"

			GNRAW="$(grep "\"name\"" "$APPMA" | awk -F '"name"' '{print $NF}')"
			GNAM="$(awk '{$1=$1};1' <<< "$GNRAW")"
			GDIR="$(getGameDirFromAM "$APPMA")"
			MPFX="$(dirname "$APPMA")/$CODA/$MAID/pfx"

			storeMetaData "$MAID" "$GNAM" "$MPFX" "$GDIR"
		done <<< "$(listAppManifests)"
		writelog "INFO" "${FUNCNAME[0]} - Done with Creating/Updating metadata"
		date +%y-%m-%d > "$LASTMETAUP"
	fi
}

function getLatestX64dbgSnap {
	basename "$("$WGET" -q "$X64DBGURL" -O - 2> >(grep -v "SSL_INIT") | grep -E 'releases.*download.*snapshot.*zip' | cut -d '"' -f2 | head -n1)"
}

function dlX64Dbg {
	DLDST="$X64DBGDLDIR"
	DLCH="$DLDST/commithash.txt"
	if [ -f "$DLCH" ]; then
		writelog "SKIP" "${FUNCNAME[0]} - '$X64D' is already ready"
	else	
		mkProjDir "$DLDST"
		X64ZIP="$(getLatestX64dbgSnap)"

		if [ ! -f "$DLDST/$X64ZIP" ]; then
			notiShow "$(strFix "$NOTY_DLCUSTOMPROTON" "$X64ZIP")" "S"
			dlCheck "${X64DBGURL//tag/download}/$X64ZIP" "$DLDST/$X64ZIP" "X" "Downloading '$X64ZIP'"
			notiShow "$(strFix "$NOTY_DLCUSTOMPROTON2" "$X64ZIP")" "S"
		fi
	
		if [ ! -s "$DLDST/$X64ZIP" ]; then
			writelog "SKIP" "${FUNCNAME[0]} - Downloaded file '$DLDST/$X64ZIP' is empty - removing"
			rm "$DLDST/$X64ZIP" 2>/dev/null
		else
			notiShow "$(strFix "$NOTY_DLCUSTOMPROTON3" "$X64ZIP")" "S"
			writelog "INFO" "${FUNCNAME[0]} - Download of '$X64ZIP' to '$DLDST' was successful"
			"$UNZIP" -q "$DLDST/$X64ZIP" -d "$DLDST" 2>/dev/null
			notiShow "$GUI_DONE" "S"
			if [ -f "$DLCH" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Extracted '$X64ZIP' to '$DLDST'"
			else
				writelog "SKIP" "${FUNCNAME[0]} - Extracting of file '$DLDST/$X64ZIP' failed"
			fi
		fi
	fi
}

# start x64dbg
function checkX64dbgLaunch {
	if [ "$RUN_X64DBG" -eq 1 ] && [ "$ISGAME" -eq 2 ] && [ "$USEWINE" -eq 0 ]; then
		writelog "INFO" "${FUNCNAME[0]} - Starting '$X64D' for '$GE ($AID)'"

		if [ "$(getArch "$GP")" == "32" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Using '$X32D' as '$GE' is 32bit" 
			XDBGEXE="$X32D"
		elif [ "$(getArch "$GP")" == "64" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Using '$X64D' as '$GE' is 64bit" 
			XDBGEXE="$X64D"
		else
			writelog "INFO" "${FUNCNAME[0]} - Could not get architecture of '$GP' - using '$X64D'" 
			XDBGEXE="$X64D"	
		fi
		
		XDBFPATH="$X64DBGDLDIR/release/${XDBGEXE//dbg/}/${XDBGEXE}.exe"
		
		if [ ! -f "$XDBFPATH" ]; then
			writelog "INFO" "${FUNCNAME[0]} - File '$X64EXE' does not exit - starting installer"
			StatusWindow "$(strFix "$NOTY_DLCUSTOMPROTON" "$X64D")" "dlX64Dbg" "DownloadX64DbgStatus"
		fi

		if [ ! -f "$XDBFPATH" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Installing failed - can't start '$XDBFPATH' - skipping"
			RUN_X64DBG=0
		else
			writelog "INFO" "${FUNCNAME[0]} - Applying registry '${X64D}.reg'"
			regEdit "$GLOBALMISCDIR/${X64D}.reg"

			WGP="$(extWine64Run "$RUNWINE" winepath -w "$GP")"
			writelog "INFO" "${FUNCNAME[0]} - Starting '$XDBFPATH' using extWine64Run for the game '$WGP'"
			extWine64Run "$RUNWINE" "$XDBFPATH" "$WGP"
		fi
	fi
}

function prepareGdb {
	GDBOPTS="$STLSHM/gdb.conf"
	WIREPY="WineReload.py"
	WINEREL="$STLSHM/$WIREPY"
	WIREURL="$WINERELOADURL/$WIREPY"
	GST10="gstreamer-1.0"

	if [ ! -f "$WINEREL" ]; then
		dlCheck "$WIREURL" "$WINEREL" "X" "Downloading '$DLSRC' to '$DLDST'"
	fi
	
	if [ ! -f "$GDBOPTS" ]; then
		{
		echo "set confirm off"
		echo "set pagination off"
		echo "handle SIGUSR1 noprint nostop"
		echo "handle SIGSYS noprint nostop"
		echo "source $WINEREL"
		} > "$GDBOPTS"
	fi

	if [ -z "$RUNPROTON" ]; then
		setRunProtonFromUseProton
	fi

	PROTONBASEPATH="$(dirname "$RUNPROTON")/files"
	if [ ! -d "$PROTONBASEPATH" ]; then
		PROTONBASEPATH="$(dirname "$RUNPROTON")/dist"
	fi

	setRunWineServer "${FUNCNAME[0]}"

	PBIPA="$PROTONBASEPATH/bin"
	PLIPA="$PROTONBASEPATH/lib"
	PLIPA64="$PROTONBASEPATH/lib64"


	if [ -n "$(GETALTEXEPATH)" ]; then
		WORKDIR="$(GETALTEXEPATH)"
	else
		WORKDIR="$EFD"
	fi

	{
	head -n1 "$0"
	echo "PATH=\"$PATH=:$PBIPA\" WINEDEBUG=\"-all\" WINEDLLPATH=\"${PLIPA64}/wine:${PLIPA}/wine:$WINEDLLPATH\" LD_LIBRARY_PATH=\"$LD_LIBRARY_PATH:${PLIPA64}:${PLIPA}:$WORKDIR\" \
	WINEPREFIX=\"$GPFX\" WINEESYNC=1 WINEFSYNC=1 WINEDLLOVERRIDES=\"$WINEDLLOVERRIDES;steam.exe=b;dotnetfx35.exe=b;dxvk_config=n;d3d11=n;d3d10=n;d3d10core=n;d3d10_1=n;d3d9=n;dxgi=n\" \
	WINE_LARGE_ADDRESS_AWARE=1 GST_PLUGIN_SYSTEM_PATH_1_0=\"${PLIPA64}/${GST10}:${PLIPA}/${GST10}:$GST_PLUGIN_SYSTEM_PATH_1_0\" WINE_GST_REGISTRY_DIR=\"${WINEPREFIX}/${GST10}/\" \
	\"$RUNWINE\" \"steam.exe\" \"${GDBGAMESTARTCMD[*]}\""
	} > "$GDBGAMERUN"	
	chmod +x "$GDBGAMERUN"
}

#start gdb
function injectGdb {
	function setgampi {
		GAMPI="$("$PGREP" -a "" | grep -i "${GP##*/}"  | grep "Z:" | grep -v "$PROGCMD" | cut -d ' ' -f1 | tail -n1)"
	}
	
	MAXWAIT=5
	COUNTER=0
	
	while ! [ "$GAMPI" -eq "$GAMPI" ] 2>/dev/null; do
		writelog "INFO" "${FUNCNAME[0]} - setgampi"
		setgampi
		if [[ "$COUNTER" -ge "$MAXWAIT" ]]; then
			writelog "ERROR" "${FUNCNAME[0]} - Timeout waiting for game pid $GAMPI - Skipping '$GDB'"
			return 
		fi
		COUNTER=$((COUNTER+1))
		sleep 1
	done

	if [ -n "$GAMPI" ]; then
		writelog "INFO" "${FUNCNAME[0]} - Found GamePid '$GAMPI' - Starting '$GDB'"
		{
		head -n1 "$0"
		echo "\"$GDB\" \"-x\" \"$GDBOPTS\" \"-p\" \"$GAMPI\""
		} > "$GDBRUN"
		chmod +x "$GDBRUN"
		"$USETERM" "$TERMARGS" "bash -c \"$GDBRUN\""
	fi
}

function startSettings {
	FUSEID "$1"

	writelog "INFO" "${FUNCNAME[0]} - createProtonList:"
	createProtonList X

	writelog "INFO" "${FUNCNAME[0]} - openTrayIcon:"
	openTrayIcon

	writelog "INFO" "${FUNCNAME[0]} - MainMenu:"
	MainMenu "$USEID"

	writelog "INFO" "${FUNCNAME[0]} - cleanYadLeftOvers:"
	cleanYadLeftOvers	
}

function retBool {
	if [ "$1" == "TRUE" ]; then
		echo "1"
	else
		echo "0"
	fi	
}

function SteamCatSelect {
	writelog "INFO" "${FUNCNAME[0]} - Steam Collection Selection"
	export CURWIKI="$PPW/Steam-Collections"
	TITLE="${PROGNAME}-SteamCollectionSelection"
	pollWinRes "$TITLE"

	setShowPic
	unset VALTAGS
	mapfile -d "\n" -t -O "${#VALTAGS[@]}" VALTAGS <<< "$(getActiveSteamCollections | grep -v "^rt[A-Z]")"
	SCATSELOUT="$(while read -r f; do if [[ ! "${SCATSEL[*]}" =~ $f ]]; then 	echo FALSE ; echo "$f"; else echo TRUE ; echo "$f" ;fi ; done <<< "$(printf "%s\n" "${VALTAGS[@]}")" | \
	"$YAD" --f1-action="$F1ACTION" --image "$SHOWPIC" --image-on-top --window-icon="$STLICON" --center $WINDECO --list --checklist --column="" --column="Steam Collection" --separator="\n" --print-column="2" \
	--text="$(spanFont "$GUI_STEAMCATSEL" "H")" --title="$TITLE" --button="$BUT_SEL":0 --button="$BUT_CAN":2 "$GEOM")"

	case $? in
		0)  {
		writelog "INFO" "${FUNCNAME[0]} - Selected Select"
				if [ -n "$SCATSELOUT" ]; then
					writelog "INFO" "${FUNCNAME[0]} - Selected following Collections: '$(sort -u <<< "$SCATSELOUT" | sed '/^$/d' | tr '\n' ',')'"
					unset SCATSEL
					mapfile -d "\n" -t -O "${#SCATSEL[@]}" SCATSEL <<< "$(sort -u <<< "$SCATSELOUT" | sed '/^$/d')"
				fi
			}
		;;
		2)  writelog "INFO" "${FUNCNAME[0]} - Selected CANCEL"
		;;
	esac

	goBackToPrevFunction "${FUNCNAME[0]}" "$2"
}

function AutoMarkSCat {
	writelog "INFO" "${FUNCNAME[0]} - Auto-marking specific Steam Collections"

	if ! grep -q "$DESC_NOST" <<< "$(printf "%s" "${SCATSEL[@]}" | tr '\n' ',')" && grep -q "$DESC_NOST" <<< "$(getActiveSteamCollections | tr '\n' ',')"; then
		writelog "INFO" "${FUNCNAME[0]} - Marking '$DESC_NOST' as Collection"
		mapfile -d "\n" -t -O "${#SCATSEL[@]}" SCATSEL <<< "$DESC_NOST"
	fi
	
	function maybeLater {
		if [ -f "$AUTOADDSCATLIST" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Marking everything found in '$AUTOADDSCATLIST' as Steam Collection"
			while read -r line; do
				mapfile -d "\n" -t -O "${#SCATSEL[@]}" SCATSEL <<< "$line"
			done < "$AUTOADDSCATLIST"
		else
			writelog "INFO" "${FUNCNAME[0]} - No file '$AUTOADDSCATLIST' containing Steam Collections found for adding"
		fi
	}
}

function filterUnwantedSteamCategories {
	FILTEREDTAGS="$(grep -v "^rt[A-Z]" <<< "$1")"
	printf "%s" "${FILTEREDTAGS[@]}" | tr '\n' '!' | sed 's/\!*$//g'
}

function addNonSteamGameGui {
	writelog "INFO" "${FUNCNAME[0]} - Starting the Gui for adding a $NSGA to Steam"

	# defaults
	if [ -n "$1" ]; then
		for i in "$@"
		do
		case $i in
			-ep=*|--exepath=*)
			NOSTGEXEPATH="${i#*=}";
			shift
			;;
		esac
		done

		NOSTGAPPNAME="${NOSTGEXEPATH##*/}"
		NOSTGSTDIR="${NOSTGEXEPATH%/*}"
	fi
	
	if grep -q "^NOSTEAMSTLDEF=\"1\"" "$STLDEFGLOBALCFG"; then
		NOSTGICONPATH="$STLICON"
	else
		NOSTGICONPATH=""
	fi
	NOSTGHIDE=0
	NOSTGADC=1
	NOSTGAO=1
	NOSTGVR=0
	unset VALTAGS
	mapfile -d "\n" -t -O "${#VALTAGS[@]}" VALTAGS <<< "$(getActiveSteamCollections | sed '/^$/d')"
	VALIDTAGS="$(filterUnwantedSteamCategories "${VALTAGS[@]}")"

	AutoMarkSCat

	if [[ -v SCATSEL[@] ]]; then
		NOSTTAGS="$(filterUnwantedSteamCategories "${SCATSEL[@]}")"
	fi 
	export CURWIKI="$PPW/Add-Non-Steam-Game"
	TITLE="${PROGNAME}-$NSGA"
	pollWinRes "$TITLE"

	NSGSET="$("$YAD" --f1-action="$F1ACTION" --window-icon="$STLICON" --form --center --on-top "$WINDECO" \
	--title="$TITLE" --separator="|" \
	--text="$(spanFont "$GUI_ADDNSG" "H")\n<i>$(strFix "$GUI_WARNNSG1" "$STERECO")\n\n$(strFix "$GUI_WARNNSG2" "$STERECO"))</i>" \
	--field=" ":LBL " " \
	--field="     $GUI_NOSTGAPPNAME!$DESC_NOSTGAPPNAME ('NOSTGAPPNAME')" "${NOSTGAPPNAME/#-/ -}" \
	--field="     $GUI_NOSTGEXEPATH!$DESC_NOSTGEXEPATH ('NOSTGEXEPATH')":FL "${NOSTGEXEPATH/#-/ -}" \
	--field="     $GUI_NOSTGSTDIR!$DESC_NOSTGSTDIR ('NOSTGSTDIR')":DIR "${NOSTGSTDIR/#-/ -}" \
	--field="     $GUI_NOSTGICONPATH!$DESC_NOSTGICONPATH ('NOSTGICONPATH')":FL "${NOSTGICONPATH/#-/ -}" \
	--field="     $GUI_NOSTGLAOP!$DESC_NOSTGLAOP ('NOSTGLAOP')" "${NOSTGLAOP/#-/ -}" \
	--field="     $GUI_NOSTGHIDE!$DESC_NOSTGHIDE ('NOSTGHIDE')":CHK "${NOSTGHIDE/#-/ -}" \
	--field="     $GUI_NOSTGADC!$DESC_NOSTGADC ('NOSTGADC')":CHK "${NOSTGADC/#-/ -}" \
	--field="     $GUI_NOSTGAO!$DESC_NOSTGAO ('NOSTGAO')":CHK "${NOSTGAO/#-/ -}" \
	--field="     $GUI_NOSTGVR!$DESC_NOSTGVR ('NOSTGVR')":CHK "${NOSTGVR/#-/ -}" \
	--field="     $GUI_NOSTTAGS!$DESC_NOSTTAGS ('NOSTTAGS')":CBE "$(cleanDropDown "${NOSTTAGS/#-/ -}" "$VALIDTAGS")" \
	--button="$BUT_CAN":0 --button="$BUT_TAGS":2 --button="$BUT_CREATE":4 "$GEOM")"

	case $? in
		0)  writelog "INFO" "${FUNCNAME[0]} - Selected '$BUT_CAN'"
		;;
		2)  writelog "INFO" "${FUNCNAME[0]} - Selected '$BUT_TAGS"
			SteamCatSelect "$NON" "${FUNCNAME[0]}"
		;;
		4)  writelog "INFO" "${FUNCNAME[0]} - Selected '$BUT_CREATE'"
			if [ -n "$NSGSET" ]; then
				mapfile -d "|" -t -O "${#NSGSETARR[@]}" NSGSETARR < <(printf '%s' "$NSGSET")
				NOSTGAPPNAME="${NSGSETARR[1]}"
				NOSTGEXEPATH="${NSGSETARR[2]}"
				NOSTGSTDIR="${NSGSETARR[3]}"
				NOSTGICONPATH="${NSGSETARR[4]}"
				NOSTGLAOP="${NSGSETARR[5]}"
				NOSTGHIDE="$(retBool "${NSGSETARR[6]}")"
				NOSTGADC="$(retBool "${NSGSETARR[7]}")"
				NOSTGAO="$(retBool "${NSGSETARR[8]}")"
				NOSTGVR="$(retBool "${NSGSETARR[9]}")"
				NOSTTAGS="${NSGSETARR[10]}"
				writelog "INFO" "${FUNCNAME[0]} - Launching command: addNonSteamGame -an=\"$NOSTGAPPNAME\" -ep=\"$NOSTGEXEPATH\" -sd=\"$NOSTGSTDIR\" -ip=\"$NOSTGICONPATH\" -lo=\"$NOSTGLAOP\" -hd=\"$NOSTGHIDE\" -adc=\"$NOSTGADC\" -ao=\"$NOSTGAO\" -vr=\"$NOSTGVR\" -t=\"$NOSTTAGS\""
				addNonSteamGame	-an="$NOSTGAPPNAME" -ep="$NOSTGEXEPATH" -sd="$NOSTGSTDIR" -ip="$NOSTGICONPATH" -lo="$NOSTGLAOP" -hd="$NOSTGHIDE" -adc="$NOSTGADC" -ao="$NOSTGAO" -vr="$NOSTGVR" -t="$NOSTTAGS"
			fi
		;;
	esac
}

function addNonSteamGame {
	if [ -z "$SUSDA" ] || [ -z "$STUIDPATH" ]; then
		setSteamPaths
	fi
	SCPATH="$STUIDPATH/config/$SCVDF"

	function getCRC {
		echo -n "$1" | gzip -c | tail -c 8 | od -An -N 4 -tx4
	}

	function dec2hex {
		 printf '%x\n' "$1"
	}

	function hex2dec {
		printf "%d\n" "0x${1#0x}"
	}

	function splitTags {
		mapfile -d "," -t -O "${#TAGARR[@]}" TAGARR < <(printf '%s' "$1")
		for i in "${!TAGARR[@]}"; do
			if grep -q "${TAGARR[$i]}" <<< "$(getActiveSteamCollections)"; then
				printf '\x01%s\x00%s\x00' "$i" "${TAGARR[i]}"
			fi
		done
	}

	NOSTHIDE=0
	NOSTADC=1
	NOSTAO=1
	NOSTVR=0
	NOSTSTLLO=0

	for i in "$@"; do
		case $i in
			-an=*|--appname=*)
				NOSTAPPNAME="${i#*=}"
				shift ;;
			-ep=*|--exepath=*)
				QEP="${i#*=}"; NOSTEXEPATH="\"$QEP\""
				shift ;;
			-sd=*|--startdir=*)
				QSD="${i#*=}"; NOSTSTDIR="\"$QSD\""
				shift ;;
			-ip=*|--iconpath=*)
				NOSTICONPATH="${i#*=}"
				shift ;;
			-lo=*|--launchoptions=*)
				NOSTLAOP="${i#*=}"
				shift ;;
			-hd=*|--hide=*)
				NOSTHIDE="${i#*=}"
				shift ;;
			-adc=*|--allowdesktopconf=*)
				NOSTADC="${i#*=}"
				shift ;;
			-ao=*|--allowoverlay=*)
				NOSTAO="${i#*=}"
				shift ;;
			-vr=*|--openvr=*)
				NOSTVR="${i#*=}"
				shift ;;
			-t=*|--tags=*)
				NOSTTAGS="${i#*=}"
				shift ;;
			-stllo=*|--stllaunchoption=*)
				NOSTSTLLO="${i#*=}"
				shift ;;
			*) ;;
		esac
	done

	if [ -n "${NOSTEXEPATH}" ]; then
		if [ -z "${NOSTAPPNAME}" ]; then
			NOSTAPPNAME="${QEP##*/}"
		fi

		if [ -z "${NOSTSTDIR}" ]; then
			QSD="$(dirname "$QEP")"; NOSTSTDIR="\"$QSD\""
		fi

		if [ "$NOSTSTLLO" -eq 1 ]; then
			NOSTGICONPATH="$STLICON"
		fi

		# AppID for Non-Steam Games in shortcuts.vdf is stored as 4-byte little endian integer by Steam
		# No idea how to extract it using Bash, but there are various working Python implementations

		NOSTAIDRHX="$(printf "%03x%03x%02x\n" $((RANDOM%4096)) $((RANDOM%4096)) $((RANDOM%256)))"
		NOSTAID="$(hex2dec "$NOSTAIDRHX")"
		NOSTAIDHX="\x$(awk '{$1=$1}1' FPAT='.{2}' OFS="\\\x" <<< "$NOSTAIDRHX")"

		writelog "INFO" "${FUNCNAME[0]} - === Adding new $NSGA ==="
		writelog "INFO" "${FUNCNAME[0]} - AppID: '${NOSTAID}'"
		writelog "INFO" "${FUNCNAME[0]} - App Name: '${NOSTAPPNAME}'"
		writelog "INFO" "${FUNCNAME[0]} - Exe Path: '${NOSTEXEPATH}'"
		writelog "INFO" "${FUNCNAME[0]} - Start Dir: '${NOSTSTDIR}'"
		writelog "INFO" "${FUNCNAME[0]} - Icon Path: '${NOSTICONPATH}'"
		writelog "INFO" "${FUNCNAME[0]} - Launch options: '${NOSTLAOP}'"
		writelog "INFO" "${FUNCNAME[0]} - Is Hidden: '${NOSTHIDE}'"
		writelog "INFO" "${FUNCNAME[0]} - Allow Desktop Config: '${NOSTADC}'"
		writelog "INFO" "${FUNCNAME[0]} - Allow Overlay: '${NOSTAO}'"
		writelog "INFO" "${FUNCNAME[0]} - OpenVR: '${NOSTVR}'"
		writelog "INFO" "${FUNCNAME[0]} - Tags: '${NOSTTAGS}'"

		if [ -f "$SCPATH" ]; then
			writelog "INFO" "${FUNCNAME[0]} - The file '$SCPATH' already exists, creating a backup, then removing the 2 closing backslashes at the end"
			cp "$SCPATH" "${SCPATH//.vdf}_${PROGNAME}_backup.vdf" 2>/dev/null
			truncate -s-2 "$SCPATH"
			OLDSET="$(grep -aPo '\x00[0-9]\x00\x02appid' "$SCPATH" | tail -n1 | tr -dc '0-9')"
			NEWSET=$((OLDSET + 1))
			writelog "INFO" "${FUNCNAME[0]} - Last set in file has ID '$OLDSET', so continuing with '$OLDSET'"
		else
			writelog "INFO" "${FUNCNAME[0]} - Creating new $SCPATH"
			printf '\x00%s\x00' "shortcuts" > "$SCPATH"
			NEWSET=0
		fi

		writelog "INFO" "${FUNCNAME[0]} - Adding new set '$NEWSET'"

		{
		printf '\x00%s\x00' "$NEWSET"
		printf '\x02%s\x00%b' "appid" "$NOSTAIDHX"
		printf '\x01%s\x00%s\x00' "appname" "$NOSTAPPNAME"
		printf '\x01%s\x00%s\x00' "Exe" "$NOSTEXEPATH"
		printf '\x01%s\x00%s\x00' "StartDir" "$NOSTSTDIR"

		if [ -n "$NOSTICONPATH" ]; then
			printf '\x01%s\x00%s\x00' "icon" "$NOSTICONPATH"
		else
			printf '\x01%s\x00\x00' "icon"
		fi

		printf '\x01%s\x00\x00' "ShortcutPath"

		if [ -n "$NOSTLAOP" ]; then
			printf '\x01%s\x00%s\x00' "LaunchOptions" "$NOSTLAOP"
		else
			printf '\x01%s\x00\x00' "LaunchOptions"
		fi
		
		if [ "$NOSTHIDE" -eq 1 ]; then
			printf '\x02%s\x00\x01\x00\x00\x00' "IsHidden"
		else
			printf '\x02%s\x00\x00\x00\x00\x00' "IsHidden"
		fi

		if [ "$NOSTADC" -eq 1 ]; then
			printf '\x02%s\x00\x01\x00\x00\x00' "AllowDesktopConfig"
		else
			printf '\x02%s\x00\x00\x00\x00\x00' "AllowDesktopConfig"
		fi

		if [ "$NOSTAO" -eq 1 ]; then
			printf '\x02%s\x00\x01\x00\x00\x00' "AllowOverlay"
		else
			printf '\x02%s\x00\x00\x00\x00\x00' "AllowOverlay"
		fi

		if [ "$NOSTVR" -eq 1 ]; then
			printf '\x02%s\x00\x01\x00\x00\x00' "openvr"
		else
			printf '\x02%s\x00\x00\x00\x00\x00' "openvr"
		fi

		printf '\x02%s\x00\x00\x00\x00\x00' "Devkit"
		printf '\x01%s\x00\x00' "DevkitGameID"

		printf '\x02%s\x00\x00\x00\x00\x00' "LastPlayTime"
		printf '\x00%s\x00' "tags"
		splitTags "$NOSTTAGS"
		printf '\x08'
		printf '\x08'

		#file end:
		printf '\x08'
		printf '\x08'
		} >> "$SCPATH"
		
		writelog "INFO" "${FUNCNAME[0]} - Finished adding new $NSGA"
	fi
}

function setCloseVars {
# yes, ugly... ¯\_(ツ)_/¯
	if [ ! -f "$CLOSEVARS" ]; then
		writelog "INFO" "${FUNCNAME[0]} - Storing all variables used in closeSTL into '$CLOSEVARS'"
		{
		echo BROWSER
		echo LOGLEVEL
		echo MO2MODE
		echo ONLY_CUSTOMCMD
		echo RUN_NYRNA
		echo RUN_REPLAY
		echo RUNSBSVR
		echo TOGSTEAMWEBHELPER
		echo USECUSTOMCMD
		echo USEMANGOAPP
		echo USENETMON
		echo USEPROTON
		echo USEWINE
		echo WAITFORTHISPID
		} >> "$CLOSEVARS"
		# should be sorted above already, but better safe
		sort "$CLOSEVARS" -o "$CLOSEVARS"
	fi
}

#STARTCLOSESTL ###
function closeSTL {
	writelog "INFO" "${FUNCNAME[0]} - closing STL"

	updateConfigEntry "CUSTOMCMD" "$DUMMYBIN" "$STLDEFGAMECFG"
	
	# dummy file which could be used to stop possible while loops
	writelog "INFO" "${FUNCNAME[0]} - Creating '$CLOSETMP'"
	touch "$CLOSETMP"

	setPrevRes
	customUserScriptStop	# USERSTOP

	if [ -f "$MO2INSTFAIL" ]; then
		rm "$MO2INSTFAIL" 2>/dev/null
	fi

	if [ "$USEMANGOAPP" -eq 1 ] && "$PGREP" -f "$MANGOAPP" >/dev/null; then
		writelog "INFO" "${FUNCNAME[0]} - Killing '$MANGOAPP'"
		"$PKILL" -f "$MANGOAPP"
	fi

	checkPlayTime "$duration"

	steamdeckClose

	if [ -f "$STLSHM/KillBrowser-$AID.txt" ]; then
		writelog "INFO" "${FUNCNAME[0]} - '$BROWSER' instance was created, so closing it now, to exit the game session"
		"$PKILL" -f "$BROWSER"
		rm "$STLSHM/KillBrowser-$AID.txt"
	fi

	cleanSUTemp
	backupSteamUser "$AID"

	if [ "$SGDBAUTODL" == "after_game" ] ; then
		writelog "INFO" "${FUNCNAME[0]} - Automatic Grid Update Check '$SGDBAUTODL'"
		getGrids "$AID"
	fi

	if [ "$ISGAME" -eq 2 ] && [ "$PROTON_LOG" -eq 1 ]; then
		createSymLink "${FUNCNAME[0]}" "$STLPROTONIDLOGDIR/steam-${AID}.log" "$STLPROTONTILOGDIR//steam-${GN}.log"
	fi

	writelog "INFO" "${FUNCNAME[0]} - Game '$SGNAID' exited - cleaning up custom processes if necessary"

# all variables in closeSTL are blocked from being unset before gamestart - dirty list with variables to keep which are not used here:
#DXVK_HUD DXVK_LOG_LEVEL ENABLE_VKBASALT LOGDIR LOGLEVEL MANGOHUD NETOPTS PROTON_DEBUG_DIR PROTON_DUMP_DEBUG_COMMANDS PROTON_FORCE_LARGE_ADDRESS_AWARE
#PROTON_LOG PROTON_LOG_DIR PROTON_NO_D3D10 PROTON_NO_D3D11 PROTON_NO_ESYNC PROTON_NO_FSYNC PROTON_ENABLE_NVAPI PROTON_HIDE_NVIDIA_GPU PROTON_USE_WINED3D
#USESLR WINEDLLOVERRIDES WINE_FULLSCREEN_INTEGER_SCALING WINE_FULLSCREEN_FSR WINE_FULLSCREEN_FSR_STRENGTH WINE_FULLSCREEN_FSR_MODE WINE_FULLSCREEN_FSR_CUSTOM_MODE

	# kill $VRVIDEOPLAYER in case it wasn't closed before
	if [ -n "$RUNSBSVR" ]; then
		if [ "$RUNSBSVR" -eq 1 ]; then
			if "$PGREP" -f "$VRVIDEOPLAYER" >/dev/null; then
				"$PKILL" -f "$VRVIDEOPLAYER"
				writelog "INFO" "${FUNCNAME[0]} - $VRVIDEOPLAYER killed"
			fi
		fi
	fi
	
	# kill $NYRNA if running
	if [ -n "$RUN_NYRNA" ]; then
		if [ "$RUN_NYRNA" -eq 1 ]; then
			if "$PGREP" -f "$NYRNA" >/dev/null; then
				"$PKILL" -f "$NYRNA"
				# also remove systray created in /tmp/ ("systray_" with 6 random chars should be save enough)
				find /tmp -maxdepth 1 -type f -regextype posix-extended -regex '^.*systray_[A-Z,a-z,0-9]{6}' -exec rm {} \;
				writelog "INFO" "${FUNCNAME[0]} - $NYRNA killed"
			fi
		fi
	fi

	# kill $REPLAY if running
	if [ -n "$RUN_REPLAY" ]; then
		if [ "$RUN_REPLAY" -eq 1 ]; then
			if "$PGREP" -f "$REPLAY" >/dev/null; then
				"$PKILL" -f "$REPLAY"
				writelog "INFO" "${FUNCNAME[0]} - $REPLAY killed"
			fi
		fi
	fi
	
	# stop network monitor if running

	if [ "$USENETMON" -eq 1 ]; then
		if "$PGREP" "$NETMON" >/dev/null; then
			"$PKILL" -f "$NETMON"
			writelog "INFO" "${FUNCNAME[0]} - $NETMON killed"
			# remove duplicate lines to make reading easier
			rmDupLines "$NETMONDIR/$AID-$NETMON.log"
		fi
	fi

	togWindows windowraise	# TOGGLEWINDOWS

	getHexAidForAid "$AID" X

	cleanYadLeftOvers

	notiShow "$(strFix "$NOTY_STLSTOP" "$GN" "$AID" "$PROGNAME")"

	sleep 1 # so any while loop still running gets the chance to see it
	writelog "INFO" "${FUNCNAME[0]} - Removing '$CLOSETMP'"
	rm "$CLOSETMP" 2>/dev/null
	writelog "STOP" "######### ${FUNCNAME[0]} $PROGNAME $PROGVERS #########"
	rm "$UPWINTMPL" 2>/dev/null
	rm "$KILLSWITCH" 2>/dev/null
	rm "$GWXTEMP" 2>/dev/null
	rm "$STLSHM/lola-*.txt" 2>/dev/null

	# only useful for win games or games started outside steam:
	if [ "$STLPLAY" -eq 1 ] || { [ "$ISGAME" -eq 2 ] || [ "$ISGAME" -eq 3 ] && [ "$USEWINE" -eq 0 ];}; then
		writeLastRun
		storeMetaData "$AID" "$GN" "$GPFX" "$EFD"
	fi

	delMenuTemps
	delWinetricksTemps
	if [ "$AID" != "$PLACEHOLDERAID" ]; then
		echo "log can be found under: '$TEMPLOG' and '$LOGFILE'"
	else
		echo "log can be found under: '$TEMPLOG'"
	fi
}
#ENDCLOSESTL ###

# main:#################

function saveOrgVars {
	writelog "INFO" "${FUNCNAME[0]} - Storing some original variables to restore them later" "P"

	env | grep "=" | sort -o "$VARSIN"

	ORG_LD_PRELOAD="$LD_PRELOAD"
	ORG_LD_LIBRARY_PATH="$LD_LIBRARY_PATH"
	ORG_LC_ALL="$LC_ALL"
	ORG_PATH="$PATH"
}

function emptyVars {
	# clear "original" variables

	if [ "$1" == "O" ] ; then
		LC_ALL="" 
		STLPATH="$(tr ':' '\n' <<< "$PATH" | grep -v "$STERU" | tr '\n' ':')"
		PATH="$STLPATH"

		FPPATH="/app/utils/bin/"
		if [ -d "$FPPATH" ]; then
			PATH="$STLPATH:$FPPATH"
		else
			PATH="$STLPATH"
		fi
		LD_LIBRARY_PATH=""
		LD_PRELOAD=""
		if [ -z "$2" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Emptied some original variables as they slowdown several system calls when started from steam" "P"
			writelog "INFO" "${FUNCNAME[0]} - Set \$PATH to '$PATH'" "P"
		fi
#	# empty "some" internal variables created by ${PROGNAME,,} (before starting the game)
	elif [ "$1" == "S" ]; then
		writelog "INFO" "${FUNCNAME[0]} - Clearing some '${PROGNAME,,}' internal variables before the game starts"

		TIEXV="$STLSHM/TrayIconVars.txt"
		TIEXF="$STLSHM/TrayIconFuncs.txt"

		if [ ! -f "$TIEXV" ]; then
			sed -n "/^#STARTIEX/,/^#ENDIEX/p;/^#ENDIEX/q" "$0" | grep export | grep -v "export \-f" | cut -d '=' -f1 | awk -F 'export ' '{print $2}' > "$TIEXV"
		fi

		if [ ! -f "$TIEXF" ]; then
			sed -n "/^#STARTIEX/,/^#ENDIEX/p;/^#ENDIEX/q" "$0" | grep "export \-f" | awk -F '-f ' '{print $2}' > "$TIEXF"
		fi

		while read -r intvar; do
			if [ -n "$intvar" ]; then
				if [[ "$intvar" =~ "BASH_FUNC" ]]; then
					BAFU1="${intvar#BASH_FUNC_*}"
					BAFU="${BAFU1%%\%}"
					if grep -q "${BAFU%%\%}" "$STLSHM/TIEXF"; then
						writelog "INFO" "${FUNCNAME[0]} - Skipping TrayIcon function '${BAFU%%\%}'"
					else
						if grep -q "function ${BAFU%%\%}" "$0"; then
							writelog "INFO" "${FUNCNAME[0]} - Clearing function '${BAFU%%\%}'"
							unset -f "${BAFU%%\%}"
						else
							writelog "INFO" "${FUNCNAME[0]} - Skipping unknown function '${BAFU%%\%}'"
						fi
					fi
				else
					if grep -q "$intvar" "$STLSHM/TIEXV"; then
						writelog "INFO" "${FUNCNAME[0]} - Skipping TrayIcon variable '$intvar'"
					else
						if ! grep -q "\$${intvar}" "$0" ; then
							writelog "INFO" "${FUNCNAME[0]} - Skipping unknown variable '$intvar'"
						else
							if grep -q "$intvar" <<< "$(sed -n "/^#STARTCLOSESTL/,/^#ENDCLOSESTL/p;/^#ENDCLOSESTL/q" "$0")"; then
								writelog "INFO" "${FUNCNAME[0]} - Skipping variable in closeSTL '$intvar'"
							else
								writelog "INFO" "${FUNCNAME[0]} - Clearing variable '$intvar'"
								unset "$intvar"
							fi
						fi
					fi
				fi
			fi
		done <<< "$(comm -32 <(cut -d '=' -f1 < "$STLSHM/${FUNCNAME[0]}-in") <(cut -d '=' -f1 < "$VARSIN"))"
	fi
}

function unsetSTLvars {
	setCloseVars
	writelog "INFO" "${FUNCNAME[0]} - Unsetting $PROGNAME internal variables"
	sort "$STLSETENTRIES" -o "${STLSETENTRIES}s"
	while read -r line; do
		unset "$line"
	done <<< "$(comm -3 "${STLSETENTRIES}s" "$CLOSEVARS")" 
}

function restoreOrgVars {
	writelog "INFO" "${FUNCNAME[0]} - Restoring previously cleared Variables"
	LD_PRELOAD="$ORG_LD_PRELOAD"
	LD_LIBRARY_PATH="$ORG_LD_LIBRARY_PATH"
	LC_ALL="$ORG_LC_ALL"
	PATH="$ORG_PATH"
}

function rmOldLog {
	# restart $LOGFILE only if older than 3 minutes # TODO minutes configurable?
	setAIDCfgs
	if [ -f "$LOGFILE" ]; then
		if test "$(find "$LOGFILE" -mmin -3 2>/dev/null)"; then
			rm "$LOGFILE" 2>/dev/null
		fi
	fi
}

function CreateCustomEvaluatorScript {
	# create temporary '$TEVALSC'
	function createTempEvals {

		# first the correct install order:
		OCNT=0

		echo "\"$EVALSC\"" > "$TEVALSC"
		echo "{" >> "$TEVALSC"
		while read -r ordline; do
			if grep -q "$ordline" <<< "$EVALSCFILES"; then
				echo "	\"$OCNT\"" >> "$TEVALSC"
				if [ -f "${GLOBSTLEVPACKS}/$ordline" ]; then
					cat "${GLOBSTLEVPACKS}/$ordline" >> "$TEVALSC"
				else
					cat "${GLOBEVPACKS}/$ordline" >> "$TEVALSC"
				fi				
				OCNT=$((OCNT+1))
			fi
		done < "$GLOBEVPACKORDER"

		# then append those packages which are not in the order list:
		while read -r wantevascs; do
			if ! grep -q "$wantevascs" "$GLOBEVPACKORDER"; then
				echo "	\"$OCNT\"" >> "$TEVALSC"
				if [ -f "${GLOBSTLEVPACKS}/$wantevascs" ]; then
					cat "${GLOBSTLEVPACKS}/$wantevascs" >> "$TEVALSC"
				else
					cat "${GLOBEVPACKS}/$wantevascs" >> "$TEVALSC"
				fi
				OCNT=$((OCNT+1))
			fi
		done <<< "$EVALSCFILES"
		
		while read -r intpak; do
			if [ -n "$intpak" ] ; then
				IPFDIR="$(awk -F'"' '{print $4}' <<< "$intpak")"
				IPDIR="${IPFDIR##*/}"
				INTPAKWA="$STLSHM/intpak"
				# dirty workaround - proper fix?
				echo "tac \"$OEVALSC\" | awk '/$IPDIR/,/appid/' | tac" > "$INTPAKWA"
				chmod +x "$INTPAKWA"
				{
					echo "	\"$OCNT\""
					echo "	{"
					"$INTPAKWA"
					echo "	}" 
				} >> "$TEVALSC"
				OCNT=$((OCNT+1))
				rm "$INTPAKWA" 2>/dev/null
			fi
		done <<< "$(grep "$LIINPA" "$OEVALSC" | grep -v "${STEWOS}\|${STLDLDIR}\|STESHA\|STLDLDIR")"
		
		echo "}" >> "$TEVALSC"
		writelog "INFO" "${FUNCNAME[0]} - Created temporary '$TEVALSC'"
	}

	mkProjDir "$EVMETACUSTOMID"
	mkProjDir "$EVMETAADDONID"
	
	writelog "INFO" "${FUNCNAME[0]} - Starting Gui for Creating a custom '$EVALSC'"
	export CURWIKI="$PPW/Steam-First-Time-Setup"
	TITLE="${PROGNAME}-${FUNCNAME[0]}"
	pollWinRes "$TITLE"
	setShowPic

	EUNID="$1"

	REVALSC="$EVMETAID/${EVALSC}_${EUNID}.vdf"
	CEVALSC="$EVMETACUSTOMID/${EVALSC}_${EUNID}.vdf"
	AEVALSC="$EVMETAADDONID/${EVALSC}_${EUNID}.vdf"
	TEVALSC="${STLSHM}/${EVALSC}_${EUNID}_temp.vdf"

	REVP="packages"
	SEVP="stlpackages"
	GLOBEVPACKS="${GLOBALEVALDIR}/$REVP"
	GLOBSTLEVPACKS="${GLOBALEVALDIR}/$SEVP"

	GLOBEVPACKORDER="${GLOBALEVALDIR}/order.txt"
	TEVALSCSEL="$NON"

	if [ -f "$REVALSC" ]; then
		FOUNDEVALSC="Original"
		OEVALSC="$REVALSC"
		TEVALSCSEL="Original"
	fi
	
	if [ -f "$CEVALSC" ]; then
		if [ -n "$FOUNDEVALSC" ]; then
			FOUNDEVALSC="${FOUNDEVALSC}, Custom"
		else
			FOUNDEVALSC="Custom"
		fi
		OEVALSC="$CEVALSC"
		TEVALSCSEL="Custom"
	fi
	
	if [ -f "$AEVALSC" ]; then
		if [ -n "$FOUNDEVALSC" ]; then
			FOUNDEVALSC="${FOUNDEVALSC}, Addon"
		else
			FOUNDEVALSC="Addon"
		fi
		OEVALSC="$AEVALSC"
		TEVALSCSEL="Addon"
	fi

	if [ -f "$OEVALSC" ]; then
		writelog "INFO" "${FUNCNAME[0]} - Pre-Selection is based on packages enabled in '$OEVALSC'"
	else
		TEVALSCSEL="$NON"
	fi

	GUITEXT1="$(strFix "$GUI_FOUNDEVALSC" "$FOUNDEVALSC")"
	GUITEXT2="$(strFix "$GUI_TEVALSCSEL" "$TEVALSCSEL")"
	GUITEXT3="$(strFix "$GUI_ADDEVALSC" "$SHADDESTDIR")"

	EVALSCFILES="$(
	while read -r EPACK; do
		if [ -f "$OEVALSC" ]; then
			PACKPROC="$(grep "process 1" "$EPACK")"
			if [ -n "$PACKPROC" ]; then
				writelog "INFO" "${FUNCNAME[0]} - Searching in '$PACKPROC' '$OEVALSC'"
				if grep -Fq "$PACKPROC" "$OEVALSC"; then
					echo TRUE ; echo "${EPACK##*/}"
				else
					echo FALSE ; echo "${EPACK##*/}"
				fi
			else
				echo FALSE ; echo "${EPACK##*/}"
			fi
		else
			echo FALSE ; echo "${EPACK##*/}"
		fi
	done <<< "$(find "${GLOBALEVALDIR}" \( -type f -and -path "*/$REVP/*" -or -path "*/$SEVP/*" \))" | \
		"$YAD" --f1-action="$F1ACTION" --image "$SHOWPIC" --image-on-top --window-icon="$STLICON" --center "$WINDECO" \
		--list --checklist --column="$GUI_ADD" --column=Script --separator="" --print-column="2" \
		--text="${GUITEXT1}\n$GUITEXT2\n$GUITEXT3" \
		--title="$TITLE" \
		--button="$BUT_SAEVALSC":2 --button="$BUT_SCEVALSC":4 --button="$BUT_ONLYINSTALL":6 --button="$BUT_CAN":8 \
		"$GEOM"
	)"
	case $? in
		2) 	{
				createTempEvals
				writelog "INFO" "${FUNCNAME[0]} - Selected Saving as Addon '$EVALSC': '$AEVALSC'"
				if [ -f "$AEVALSC" ]; then
					mv "$AEVALSC" "${AEVALSC//.vdf/_back.vdf}"
				fi
				mv "$TEVALSC" "$AEVALSC"
			}
		;;
		4)	{
				createTempEvals
				writelog "INFO" "${FUNCNAME[0]} - Selected Saving as Custom '$EVALSC': '$CEVALSC'"
				if [ -f "$CEVALSC" ]; then
					mv "$CEVALSC" "${CEVALSC//.vdf/_back.vdf}"
				fi
				mv "$TEVALSC" "$CEVALSC"
			}
		;;
		6)	{
				writelog "INFO" "${FUNCNAME[0]} - Selected to only install the packages without saving"
				createTempEvals
				writelog "INFO" "${FUNCNAME[0]} - Starting Install via command: reCreateCompatdata \"$EUNID\" \"${FUNCNAME[0]}\" \"$TEVALSC\""
				reCreateCompatdata "$EUNID" "${FUNCNAME[0]}" "$TEVALSC"
			}
		;;
		8)	{
				writelog "INFO" "${FUNCNAME[0]} - Selected CANCEL"
			}
		;;
	esac
}

function reCreateCompatdata {
	function runEvalsc {
		unset LEV
		mapfile -d " " -t -O "${#LEV[@]}" LEV <<< "run ${ISCEXE} ${LECO}\\${EVALSC}_${1}.vdf"
		rm "$EVALISRUN" 2>/dev/null
		touch "$EVALISRUN"
		checkFirstTimeRun "${LEV[@]}" >/dev/null 2>/dev/null
		rm "$EVALISRUN"	"$FRSTATE" "${FRSTATE}-prev" 2>/dev/null
		doneEvacInstall
	}
	
	function getCurStep {
		unset GCS
		mapfile -d " " -t -O "${#GCS[@]}" GCS <<< "run ${ISCEXE} --${GECUST} ${1}"
		checkFirstTimeRun "${GCS[@]}" >/dev/null 2>/dev/null
		PRFRSTATE="${FRSTATE}-prev"

		if [ -f "$FRSTATE" ]; then
			if ! cmp -s -- "$FRSTATE" "$PRFRSTATE"; then
				cp "$FRSTATE" "$PRFRSTATE"
				notiShow "$(strFix "$NOTY_FRSTATE" "$(cat "$FRSTATE")")" "X"
				writelog "INFO" "${FUNCNAME[0]} - $(strFix "$NOTY_FRSTATE" "$(cat "$FRSTATE")")"
			fi
		fi
	}

	WANTGUI=0
	if [ "$1" == "ccd" ] || [ "$1" == "createcompatdata" ]; then
		writelog "INFO" "${FUNCNAME[0]} - Started from command-line"
		EUNID="$2"
		if [ -n "$3" ]; then
			WANTGUI=1
		fi
	else
		writelog "INFO" "${FUNCNAME[0]} - Started from gui"
		EUNID="$1"
		WANTGUI=1
		BACKFUNC="$2"
	fi

	SCCILECO="$STEAM_COMPAT_CLIENT_INSTALL_PATH/$LECO"
	ISCEXE="$SCCILECO/$ISCRI.exe"
	
	if [ -n "$EUNID" ]; then
		SRCORIGEVSC="$EVMETAID/${EVALSC}_${EUNID}.vdf"
		SRCCUSTEVSC="$EVMETACUSTOMID/${EVALSC}_${EUNID}.vdf"

		if [ "$EUNID" == "$DPRS" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Starting '$DPRS' Installation"
			SRCORIGEVSC="${GLOBALEVALDIR}/sets/${EVALSC}_${DPRS,}.vdf"
			SRCEVSC="$SRCORIGEVSC"
			DESTCODA="$DPRSCOMPDATA"
			EARLYPROT="$DPRSPROTON"
			export STEAM_COMPAT_APP_ID="$DPRS"
			STEAM_COMPAT_INSTALL_PATH="$DPRSCOMPDATA"
		fi	
		
		if [ ! -f "$ISCEXE" ]; then
			writelog "ERROR" "${FUNCNAME[0]} - '$ISCEXE' not found"
		else		
			if [ ! -f "$SRCORIGEVSC" ] && [ ! -f "$SRCCUSTEVSC" ]; then
				if [ "$WANTGUI" -eq 0 ]; then
					writelog "ERROR" "${FUNCNAME[0]} - Neither '$SRCORIGEVSC' nor '$SRCCUSTEVSC' found (see wiki if the reason for not being able to continue is unknown)"
					writelog "ERROR" "${FUNCNAME[0]} - Alternatively start the same command with an additional 'gui' parameter, to create a '$SRCCUSTEVSC' via gui"
					HAVEEVSC=0
				else
					writelog "INFO" "${FUNCNAME[0]} - Requester to create a custom Install file via Gui"
					CreateCustomEvaluatorScript "$EUNID"
					if [ -f "$SRCCUSTEVSC" ]; then
						HAVEEVSC=1
					else
						HAVEEVSC=0
					fi
				fi
			else
				HAVEEVSC=1
			fi
			
			if [ "$HAVEEVSC" -eq 1 ]; then
				if [ -f "$CUMETA/${EUNID}.conf" ]; then
					writelog "INFO" "${FUNCNAME[0]} - Loading Metadata '$CUMETA/${EUNID}.conf'"
					loadCfg "$CUMETA/${EUNID}.conf"
				fi

				if [ -z "$DESTCODA" ]; then
					if [ -n "$WINEPREFIX" ]; then
						DESTCODA="${WINEPREFIX%/*}"
					elif [ -n "$STEAM_COMPAT_DATA_PATH" ]; then
						DESTCODA="$STEAM_COMPAT_DATA_PATH"
					elif [ -n "$GPFX" ]; then
						DESTCODA="${GPFX%/*}"
					else
						getCompatData "${EUNID}" >/dev/null
						DESTCODA="$(cut -d ';' -f2 <<< "$FCOMPDAT")"
					fi
				fi

				if [ -n "$DESTCODA" ]; then
					export STEAM_COMPAT_DATA_PATH="$DESTCODA"
					writelog "INFO" "${FUNCNAME[0]} - Destination $CODA is '$STEAM_COMPAT_DATA_PATH'"

					if [ -z "$STEAM_COMPAT_INSTALL_PATH" ]; then
						if [ -n "$MEGAMEDIR" ]; then
							export STEAM_COMPAT_INSTALL_PATH="$MEGAMEDIR"
						elif [ -n "$EFD" ]; then
							export STEAM_COMPAT_INSTALL_PATH="$EFD"
						else
							writelog "INFO" "${FUNCNAME[0]} - STEAM_COMPAT_INSTALL_PATH (game dir) is unknown - setting it at least to '${STLDLDIR}'"
							export STEAM_COMPAT_INSTALL_PATH="$STLDLDIR"
						fi
					fi

					RECRECODA=1

					find "$DESTCODA" -maxdepth 0 -empty -exec rmdir {} \; 2>/dev/null

					if [ -d "$DESTCODA" ]; then
						if [ "$3" == "s" ]; then
							RCSEL="$(confirmReq "Ask_Recreate_Compatdata" "$(strFix "$GUI_RECRECODA" "$EUNID" "${EUNID}_${PROGNAME,,}")")"
							if [ "$RCSEL" -eq 0 ]; then
							{
								writelog "INFO" "${FUNCNAME[0]} - Confirmed recreating the wineprefix"
								RECRECODA=1
							}
							else
								writelog "INFO" "${FUNCNAME[0]} - Selected CANCEL - Not recreating the wineprefix"
								RECRECODA=0
							fi
						fi

						if [ "$RECRECODA" -eq 1 ]; then
							if [ -d "${DESTCODA}_${PROGNAME,,}" ]; then
								writelog "INFO" "${FUNCNAME[0]} - Removing previous backup $CODA backup '${DESTCODA}_${PROGNAME,,}'"
								rm -rf "${DESTCODA}_${PROGNAME,,}" 2>/dev/null
							fi
							
							find "$DESTCODA" -maxdepth 0 -empty -exec rmdir {} \;

							if [ -d "$DESTCODA" ]; then
								writelog "INFO" "${FUNCNAME[0]} - Moving existing $CODA to '${DESTCODA}_${PROGNAME,,}'"
								mv "$DESTCODA" "${DESTCODA}_${PROGNAME,,}"
							fi
						fi
					fi

					if [ "$RECRECODA" -eq 1 ]; then
						if [ -z "$STEAM_COMPAT_APP_ID" ]; then
							export STEAM_COMPAT_APP_ID="${EUNID}"
						fi

						mkProjDir "$DESTCODA"
						EVALISRUN="$STLSHM/evalisrun.txt"
						
						cd "$STEAM_COMPAT_CLIENT_INSTALL_PATH" >/dev/null || return
						
						writelog "INFO" "${FUNCNAME[0]} - Launching First Run Installer"

						runEvalsc "${EUNID}" &

						while [ ! -f "$EVALISRUN" ];do
							sleep 0.1
						done
						
						while [ -f "$EVALISRUN" ];do
							getCurStep "${EUNID}"
							sleep 1
						done
						
						cd - >/dev/null || return
					fi
				else
					writelog "SKIP" "${FUNCNAME[0]} - No destination $CODA determined"
				fi
			fi

			if [ -n "$BACKFUNC" ]; then
				"$BACKFUNC" "$AID" "${FUNCNAME[0]}"
			fi
		fi
	else
		writelog "SKIP" "${FUNCNAME[0]} - Need SteamAppId as argument"
	fi
}

function createModifiedEvalsc {
	if [ -z "$ISCRILOG" ]; then
		ISCRILOG="$STLSHM/${PROGNAME,,}-${ISCRI}-temp_$RANDOM.log"
	fi 

	STESHA="$STEAM_COMPAT_CLIENT_INSTALL_PATH/$SAC/$STEWOS"
	if [ ! -d "$STESHA" ]; then
		writelog "WARN" "${FUNCNAME[0]} - '$STESHA' not found - packages expected there won't be found" "X" "$ISCRILOG"
		writelog "WARN" "${FUNCNAME[0]} - '$STESHA' is concatenated from '$STEAM_COMPAT_CLIENT_INSTALL_PATH', '$SAC', '$STEWOS'" "X" "$ISCRILOG"
	fi

	SOURCEEVALSC="$1"
	DSTEVALSC="$2"

	if [ ! -f "$SOURCEEVALSC" ]; then
		writelog "SKIP" "${FUNCNAME[0]} - '$SOURCEEVALSC' does not exists" "X" "$ISCRILOG"
	elif [ ! -f "$DSTEVALSC" ]; then
		SCCILECO="$STEAM_COMPAT_CLIENT_INSTALL_PATH/$LECO"

		# creating a temporary copy of the evaluatorscript in $SCCILECO:
		writelog "INFO" "${FUNCNAME[0]} - Copying '$SOURCEEVALSC' to '$SCCILECO'" "X" "$ISCRILOG"
		cp "$SOURCEEVALSC" "$DSTEVALSC"
		
		# replace placeholders with real paths
		writelog "INFO" "${FUNCNAME[0]} - Replacing placeholders with real paths in '$DSTEVALSC'" "X" "$ISCRILOG"
		sed "s:STESHA:$STESHA:g" -i "$DSTEVALSC"
		sed "s:STLDLDIR:$STLDLDIR:g" -i "$DSTEVALSC"
	else
		writelog "SKIP" "${FUNCNAME[0]} - '$DSTEVALSC' already exists" "X" "$ISCRILOG"
	fi
}

function cleanupOutdatedEvals {
	writelog "INFO" "${FUNCNAME[0]} - Cleaning up outdated files in '$EVMETAID'"

	mkProjDir "$EVMETAOLD"
	while read -r oldfile; do
		if [ -f "$oldfile" ]; then
			mv "$oldfile" "$EVMETAOLD"
		fi
	done <<< "$(grep -Rl "foreign_install_path" "$EVMETAID")"
	
	while read -r oldfile; do
		if [ -f "$oldfile" ]; then
			while read -r lipent; do
				ABSLIINPA="$(cut -d \" -f4 <<< "$lipent")" # too weak?
				if [ ! -d "${ABSLIINPA//\"}" ] && [ "${ABSLIINPA//\"}" != "STLDLDIR" ] && [ "${ABSLIINPA//\"}" != "STESHA" ]; then
					mv "$oldfile" "$EVMETAOLD"
				fi
			done <<< "$(grep "$LIINPA" "$oldfile")"
		fi
	done <<< "$(grep -Rl "$LIINPA" "$EVMETAID")"
	writelog "INFO" "${FUNCNAME[0]} - Finished cleaning up '$EVMETAID'"
}

function doneEvacInstall {
	notiShow "$(strFix "$NOTY_FRDONE" "$EUNID")" "X"
	writelog "INFO" "${FUNCNAME[0]} - $(strFix "$NOTY_FRDONE" "$EUNID")" "E"	
}

function runEvacInstall {
	INSTPROT="$1"
	# call $ISCRI via proton with the modified evaluatorscript as parameter:
	writelog "INFO" "${FUNCNAME[0]} - '$EVALSC' - START - STEAM_COMPAT_DATA_PATH=\"$STEAM_COMPAT_DATA_PATH\" '$INSTPROT run $ISCEXE $EVSC'" "X" "$ISCRILOG"
	STEAM_COMPAT_DATA_PATH="$STEAM_COMPAT_DATA_PATH" "$INSTPROT" run "$ISCEXE" "$EVSC"
	# move the temporary modified evaluatorscript into '$STMSHM'
	mv "$DSTEVSC" "$STLSHM/${DSTEVSC##*/}_$RANDOM"
}

function findEarlyProt {
	FEPLOG="$2"
	writelog "INFO" "${FUNCNAME[0]} - Trying to get a proton version from '$1'" "X" "$FEPLOG"
	if grep -q "^USEPROTON" "$1"; then
		CONFPROTRAW="$(grep "^USEPROTON" "$1" | cut -d '=' -f2)"
		CONFPROT="${CONFPROTRAW//\"}"

		if [ -z "$SUSDA" ]; then
			setSteamPaths
		fi
		
		createProtonList
		
		if [ -f "$PROTONCSV" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Searching '$CONFPROT' in '$PROTONCSV'" "X" "$FEPLOG"

			if grep -q "^${CONFPROT}" "$PROTONCSV"; then
				writelog "INFO" "${FUNCNAME[0]} - Found '$CONFPROT' in '$PROTONCSV'" "X" "$FEPLOG"
				EARLYPROT="$(grep "^${CONFPROT}" "$PROTONCSV" | cut -d ';' -f2)"
				export EARLYPROT
			else
				writelog "INFO" "${FUNCNAME[0]} - '$CONFPROT' not found in '$PROTONCSV'" "X" "$FEPLOG"
				# if configured USEPROTON proton binary was not found, try to find a minor version bump instead:
				TESTEARLYPROT="$(fixProtonVersionMismatch "CONFPROT" "$STLGAMECFG" "X")"
				if [ -f "$TESTEARLYPROT" ]; then
					writelog "INFO" "${FUNCNAME[0]} - Found a minor version mismatch binary for '$CONFPROT':'$TESTEARLYPROT'" "X" "$FEPLOG"
					EARLYPROT="$TESTEARLYPROT"
					export EARLYPROT
				else
					if [ -n "$TESTEARLYPROT" ]; then
						writelog "SKIP" "${FUNCNAME[0]} - Found '$TESTEARLYPROT' does not exist" "X" "$FEPLOG"
					else
						writelog "SKIP" "${FUNCNAME[0]} - No minor version mismatch binary for '$CONFPROT' found'" "X" "$FEPLOG"
					fi
				fi
			fi
		else
			writelog "ERROR" "${FUNCNAME[0]} - Could not create '$PROTONCSV'" "X" "$FEPLOG"
		fi
	else
		writelog "SKIP" "${FUNCNAME[0]} - No USEPROTON entry found in '$1'" "X" "$FEPLOG"
	fi
}

function checkFirstTimeRun {
	ISCRILOG="$STLSHM/${PROGNAME,,}-${ISCRI}-${STEAM_COMPAT_APP_ID}.log"
	GPFX="$STEAM_COMPAT_DATA_PATH/pfx"
	SCCILECO="$STEAM_COMPAT_CLIENT_INSTALL_PATH/$LECO"
	ISCEXE="$SCCILECO/$ISCRI.exe"
	EVALPROTCONF="$STLSHM/evalprot-${STEAM_COMPAT_APP_ID}.conf"
	
	function waitForEvaluatorscript {
		mkProjDir "$EVMETAID"
		mkProjDir "$EVMETATITLE"
		
		ISCRILOG="$2"
		EVALVDF="$SCCILECO/$1"
		writelog "INFO" "${FUNCNAME[0]} - Waiting for '$EVALVDF' to appear" "X" "$ISCRILOG"
		while [ ! -f "$EVALVDF" ]; do 
			sleep 0.1
		done
		cp "$EVALVDF" "$EVMETAID"
		writelog "INFO" "${FUNCNAME[0]} - Copied '$EVALVDF' to '$EVMETAID/$1'" "X" "$ISCRILOG"
	}

	rmOldLog

	if [ -n "$STEAM_RUNTIME_LIBRARY_PATH" ]; then
		touch "$STLSHM/SteamStart_${STEAM_COMPAT_APP_ID}.txt"
	fi
	
	if [ -f "$(find "$LOGFILE" -not -newermt '-5 seconds' 2>/dev/null)" ]; then
		if ! grep -q "$ISCRI" <<< "$(tail -n1 "$LOGFILE")"; then
			writelog "START" "######### '$ISCRI' #########" "X" "$ISCRILOG"
		fi
	fi
	# skip $ISCRI completely if a SKIP file exists for $STEAM_COMPAT_APP_ID
	if [ -f "$EVMETASKIPID/${EVALSC}_${STEAM_COMPAT_APP_ID}.vdf" ]; then
		writelog "SKIP" "${FUNCNAME[0]} - Skipping '$ISCRI' line '$*' because '$EVMETASKIPID/${EVALSC}_${STEAM_COMPAT_APP_ID}.vdf' exists" "X" "$ISCRILOG"
	else
		# filter evaluatorscript command
		if grep -q "$EVALSC" <<< "$@"; then
			# shellcheck disable=SC1003
			EVSC="$(awk -F 'legacycompat\\\' '{print $NF}' <<< "$@")"
		fi

		if [ -d "$EVMETAID" ]; then
			cleanupOutdatedEvals
		fi

		# check if evaluatorscript should be started:
		if [ ! -d "$GPFX" ] || [ ! -f "$EVMETAID/$EVSC" ]; then
			# get a proton version for the install process:
			if grep -q "$EVALSC" <<< "$@"; then

				# first check if the game has a ${PROGNAME,,} config and use the corresponding proton version:
				if [ -z "$EARLYPROT" ] && [ ! -f "$EVALPROTCONF" ] && [ -f "$STLGAMEDIRID/$STEAM_COMPAT_APP_ID.conf" ]; then
					findEarlyProt "$STLGAMEDIRID/$STEAM_COMPAT_APP_ID.conf" "$ISCRILOG"
				fi
				# as fallback check if the game template ${PROGNAME,,} config has a usable proton version:
				if [ -z "$EARLYPROT" ] && [ ! -f "$EVALPROTCONF" ] && [ -f "$STLDEFGAMECFG" ]; then
					findEarlyProt "$STLDEFGAMECFG" "$ISCRILOG"
				fi

				# if everything else failed, check for a "static proton version" just for the base install - either from file or from system variable:
				if [ -z "$EARLYPROT" ] && [ ! -f "$EVALPROTCONF" ] && [ -f "$STLEARLYPROTCONF" ]; then
					writelog "INFO" "${FUNCNAME[0]} - Trying to get a proton version from '$STLEARLYPROTCONF'" "X" "$ISCRILOG"
					source "$STLEARLYPROTCONF"
				fi

				# fallback if for whatever reason USEPROTON is empty everywhere - trying to get NOP
				if [ -z "$EARLYPROT" ]; then
					if [ -z "$SUSDA" ]; then
						setSteamPaths
					fi
					writelog "INFO" "${FUNCNAME[0]} - Last try - trying to get Newest Official Proton" "X" "$ISCRILOG"
					CONFPROT="$(getDefaultProton)"
					createProtonList
					EARLYPROT="$(grep "^${CONFPROT}" "$PROTONCSV" | cut -d ';' -f2)"
				fi
				
				# write found protonversion into temp config, so below GECUST runs can use it as well:
				if [ -n "$EARLYPROT" ]; then
					writelog "INFO" "${FUNCNAME[0]} - Writing 'EARLYPROT=$EARLYPROT' into '$EVALPROTCONF'" "X" "$ISCRILOG"
					echo "EARLYPROT=\"$EARLYPROT\"" > "$EVALPROTCONF"
					echo "TEVSC=\"$EVSC\"" >> "$EVALPROTCONF"
				fi			
			fi

			# reload proton version from above EVALSC run:
			TEVSC="$NON"
			if [ -z "$EARLYPROT" ] && [ -f "$EVALPROTCONF" ]; then
				source "$EVALPROTCONF"
			fi
			# only continue with proton being available:
			if [ -n "$EARLYPROT" ] && [ -f "$EARLYPROT" ]; then
					# filter evaluatorscript command
					if grep -q "$EVALSC" <<< "$@"; then
						mapfile -d " " -t -O "${#RUNISCCMD[@]}" RUNISCCMD < <(printf '%s' "$(awk -F 'run ' '{print $NF}' <<< "$*")")
						# no evaluatorscript for the started game yet in the metadata - so starting the collector:
						
						SRCCUSTEVSC="$EVMETACUSTOMID/$EVSC"
						SRCORIGEVSC="$EVMETAID/$EVSC"
						
						TEVALSC="${STLSHM}/${EVALSC}_${STEAM_COMPAT_APP_ID}_temp.vdf"
						if [ -f "$TEVALSC" ]; then
							SRCEVSC="$TEVALSC"
							writelog "INFO" "${FUNCNAME[0]} - Using '$SRCEVSC' as source" "X" "$ISCRILOG"
						fi
						
						if [ -z "$SRCEVSC" ]; then
							if [ ! -f "$SRCORIGEVSC" ] && [ ! -f "$SRCCUSTEVSC" ]; then
								SRCEVSC="$SRCORIGEVSC"
								writelog "INFO" "${FUNCNAME[0]} - Both the copy '$SRCORIGEVSC' of the original and a custom '$SRCCUSTEVSC' are missing - trying to get the original'" "X" "$ISCRILOG"
							elif [ -f "$SRCORIGEVSC" ] && [ ! -f "$SRCCUSTEVSC" ]; then
								SRCEVSC="$SRCORIGEVSC"
								writelog "INFO" "${FUNCNAME[0]} - Using '$SRCEVSC' as source" "X" "$ISCRILOG"
							elif [ -f "$SRCORIGEVSC" ] && [ -f "$SRCCUSTEVSC" ]; then
								SRCEVSC="$SRCCUSTEVSC"
								writelog "INFO" "${FUNCNAME[0]} - Using custom '$SRCCUSTEVSC' as source, as it overrides the original '$SRCORIGEVSC' which also does exist" "X" "$ISCRILOG"
							elif [ ! -f "$SRCORIGEVSC" ] && [ -f "$SRCCUSTEVSC" ]; then
								SRCEVSC="$SRCCUSTEVSC"
								writelog "INFO" "${FUNCNAME[0]} - Using custom '$SRCCUSTEVSC' as source, and the original '$SRCORIGEVSC' does not exist" "X" "$ISCRILOG"
							fi
						fi
					
						if [ -n "$EVSC" ] && [ ! -f "$SRCEVSC" ] && [ "$SRCEVSC" == "$SRCORIGEVSC" ]; then
							waitForEvaluatorscript "$EVSC" "$ISCRILOG" &
							writelog "INFO" "${FUNCNAME[0]} - '$EVALSC' START - '$EARLYPROT run ${RUNISCCMD[*]}'" "X" "$ISCRILOG"
							"$EARLYPROT" run "${RUNISCCMD[@]}"
							while [ ! -f "$SRCEVSC" ]; do 
								sleep 0.1
							done
						fi

						# have a evaluatorscript to work with:
						if [ -f "$SRCEVSC" ]; then
							DSTEVSC="$STEAM_COMPAT_CLIENT_INSTALL_PATH/$EVSC"
							createModifiedEvalsc "$SRCEVSC" "$DSTEVSC"

							if grep -q "$EVMETACUSTOMID" <<< "$SRCEVSC" ; then
								notiShow "$(strFix "$NOTY_FRSTART" "Custom")" "X"
							elif grep -q "$STLSHM" <<< "$SRCEVSC" ; then
								notiShow "$(strFix "$NOTY_FRSTART" "Live")" "X"			
							else
								notiShow "$(strFix "$NOTY_FRSTART" "Regular")" "X"
							fi

							runEvacInstall "$EARLYPROT"
							SRCADDONEVSC="$EVMETAADDONID/$EVSC"
							if [ -f "$SRCADDONEVSC" ]; then
								writelog "INFO" "${FUNCNAME[0]} - Found additional install script in '$SRCADDONEVSC'" "X" "$ISCRILOG"
								
								DSTEVSC="$STEAM_COMPAT_CLIENT_INSTALL_PATH/$EVSC"
								createModifiedEvalsc "$SRCADDONEVSC" "$DSTEVSC"
								notiShow "$(strFix "$NOTY_FRSTART" "Addon")" "X"
								runEvacInstall "$EARLYPROT"
							fi
				
							if [ "$SRCEVSC" == "$TEVALSC" ]; then
								rm "$TEVALSC" 2>/dev/null
								writelog "INFO" "${FUNCNAME[0]} - Removed temporary '$TEVALSC'" "X" "$ISCRILOG"
							fi

							writelog "INFO" "${FUNCNAME[0]} - '$EVALSC' - STOP - '$EARLYPROT run $ISCEXE $EVSC'" "X" "$ISCRILOG"
						else
							writelog "INFO" "${FUNCNAME[0]} - '$EVALSC' - SKIP - '$SRCEVSC' not found" "X" "$ISCRILOG"
						fi
					# filter get-current-step command - this only updates the steam install gui process.
					elif grep -q "$GECUST" <<< "$@"; then
						"$EARLYPROT" "$@" | tee "$FRSTATE" | tee -a "$ISCRILOG"
						echo "" >> "$ISCRILOG"
						STINFO="$(date +%H:%M:%S) $NICEPROGNAME running"
						if [ -f "$TEVSC" ]; then
							# shellcheck disable=SC1003
							while read -r COMRED; do
								if "$PGREP" -a "" | grep "$STEWOS" | grep -v "runasadmin" | grep "${COMRED//\"}" >/dev/null ; then
										writelog "INFO" "${FUNCNAME[0]} - Installation of '${COMRED//\"}' running" | tee -a "$ISCRILOG"
									STINFO="$(date +%H:%M:%S) $NICEPROGNAME sees ${COMRED//\"}"
									break
								fi
							done <<< "$(grep "process 1" "$TEVSC" | awk -F'\\' '{print $NF}')"
						fi
						printf '\n%s\n' "$STINFO"	# heh, hello Steam Gui
					# should not happen, but better log it anyway just in case:
					else
						writelog "SKIP" "${FUNCNAME[0]} - Skipping '$ISCRI' command '$*' - Neither '$EVALSC' nor '$GECUST' found in command exiting" "X" "$ISCRILOG"
					fi
			else
				if ! grep -q "$GECUST" <<< "$@"; then
					writelog "SKIP" "${FUNCNAME[0]} - No usable Proton version found - ignoring '$ISCRI' command '$*' - Exiting" "X" "$ISCRILOG"
				fi
			fi
		else
			if [ -d "$GPFX" ]; then
				writelog "SKIP" "${FUNCNAME[0]} - Skipping '$ISCRI' command '$*', because '$GPFX' already exists - Exiting" "X" "$ISCRILOG"
			elif [ -f "$EVMETAID/$EVSC" ]; then
				writelog "SKIP" "${FUNCNAME[0]} - Skipping '$ISCRI' command '$*', because '$EVMETAID/$EVSC' already exists - Exiting" "X" "$ISCRILOG"
			fi
		fi
	fi
}

function verbRun {
	VERBLOG="$STLSHM/${PROGNAME,,}-VERB-${STEAM_COMPAT_APP_ID}.log"
	GPFX="$STEAM_COMPAT_DATA_PATH/pfx"
	SCCILECO="$STEAM_COMPAT_CLIENT_INSTALL_PATH/$LECO"
	EVALPROTCONF="$STLSHM/evalprot-${STEAM_COMPAT_APP_ID}.conf"

	writelog "INFO" "${FUNCNAME[0]} - 'verb' command detected '${*}'" "X" "$VERBLOG"
	writelog "INFO" "${FUNCNAME[0]} - Settings variable SteamAppId to '$STEAM_COMPAT_APP_ID' to make verb command happy"
	export SteamAppId="$STEAM_COMPAT_APP_ID"

	# first check if the game has a ${PROGNAME,,} config and use the corresponding proton version:
	if [ -z "$EARLYPROT" ] && [ -f "$STLGAMEDIRID/$STEAM_COMPAT_APP_ID.conf" ]; then
		findEarlyProt "$STLGAMEDIRID/$STEAM_COMPAT_APP_ID.conf" "$VERBLOG"
	fi
	# as fallback check if the game template ${PROGNAME,,} config has a usable proton version:
	if [ -z "$EARLYPROT" ] && [ -f "$STLDEFGAMECFG" ]; then
		findEarlyProt "$STLDEFGAMECFG" "$VERBLOG"
	fi

	# if everything else failed, check for a "static proton version" just for the base install - either from file or from system variable:
	if [ -z "$EARLYPROT" ] && [ -f "$STLEARLYPROTCONF" ]; then
		writelog "INFO" "${FUNCNAME[0]} - Trying to get a proton version from '$STLEARLYPROTCONF'" "X" "$VERBLOG"
		source "$STLEARLYPROTCONF"
	fi

	# fallback if for whatever reason USEPROTON is empty everywhere - trying to get NOP
	if [ -z "$EARLYPROT" ]; then
		if [ -z "$SUSDA" ]; then
			setSteamPaths
		fi
		writelog "INFO" "${FUNCNAME[0]} - Last try - trying to get Newest Official Proton" "X" "$VERBLOG"
		CONFPROT="$(getDefaultProton)"
		createProtonList
		if [ -n "$CONFPROT" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Picking '^${CONFPROT}' from '$PROTONCSV'" "X" "$VERBLOG"
			EARLYPROT="$(grep "^${CONFPROT}" "$PROTONCSV" | cut -d ';' -f2)"
		else
			writelog "WARN" "${FUNCNAME[0]} - Could not determine default Proton" "X" "$VERBLOG"
		fi
	fi
	
	# write found protonversion into temp config, so below GECUST runs can use it as well:
	if [ -f "$EARLYPROT" ]; then
		writelog "INFO" "${FUNCNAME[0]} - Running verb command '${*}' using proton '$EARLYPROT'" "X" "$VERBLOG"
		"$EARLYPROT" "$WFEAR" "$@" >> "$VERBLOG" 2>&1
	else
		writelog "INFO" "${FUNCNAME[0]} - Skipping verb command '${*}', because no usable proton '$EARLYPROT' was found" "X" "$VERBLOG"
	fi
}

function getCurrentCommandline {
	echo "$@" >> "${STLSHM}/cmdline.txt"
	# filter $ISCRI commands
	if grep -q "$ISCRI" <<< "$@"; then
		while read -r IARG; do
			mapfile -t -O "${#ISCRICMD[@]}" ISCRICMD <<< "$IARG"
		done <<< "$(printf "%s\n" "$@")"
		if [ "${ISCRICMD[0]}" == "%verb%" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Cutting '%verb%' from arguments '${*}'" "P"
			ISCRICMD=( "${ISCRICMD[@]:1}" )
		fi
		writelog "INFO" "${FUNCNAME[0]} - Running checkFirstTimeRun with arguments '${ISCRICMD[*]}'" "P"
		checkFirstTimeRun "${ISCRICMD[@]}"
	elif grep -q "%verb%" <<< "$@"; then
		echo "${FUNCNAME[0]} - Found '%verb%' in the command line '${*}'" >> "$STLSHM/DEBUG-verb.txt"
		while read -r IARG; do
			IARG="${IARG//steamservice.exe/SteamService.exe}"
			mapfile -t -O "${#VERBCMD[@]}" VERBCMD <<< "$IARG"
		done <<< "$(printf "%s\n" "$@")"
		VERBCMD=( "${VERBCMD[@]:1}" )
		echo "${FUNCNAME[0]} - Executing 'verb' command '${VERBCMD[*]}' through verbRun" >> "$STLSHM/DEBUG-verb.txt"
		verbRun "${VERBCMD[@]}" # >> "$STLSHM/DEBUG-verb.txt" 2>&1
		exit
	else
		INPROSTR="proton $WFEAR"
		if grep -q "$INPROSTR" <<< "$@"; then
			HAVEINPROTON=1
			writelog "INFO" "${FUNCNAME[0]} - Found Proton in command line arguments '${*}'" "P"
		else
			HAVEINPROTON=0
			writelog "INFO" "${FUNCNAME[0]} - No Proton in command line arguments '${*}'" "P"
		fi
	fi
}

function initShmStl {  # TODO can shorten?
	mkProjDir "$MTEMP"
	SHMVERS="$STLSHM/version"
	
	if [ -f "$SHMVERS" ]; then
		if [ "$PROGVERS" != "$(cat "$SHMVERS")" ]; then
			mv "${STLSHM}" "${STLSHM}-$((100 + RANDOM % 100))"
			mkProjDir "$MTEMP"
			echo "$PROGVERS" > "$SHMVERS"
		fi	
	else
		echo "$PROGVERS" > "$SHMVERS"
	fi
}

### STEAM DECK BEGIN

function steamdeckClose {
	if [ "$ONSTEAMDECK" -eq 1 ]; then
		GTKCSSFILE="$HOME/.config/gtk-3.0/gtk.css"
		if [ -f "${GTKCSSFILE}_ORIGNAL" ] ; then
			writelog "INFO" "${FUNCNAME[0]} - recovering original gtk.css from '${GTKCSSFILE}_ORIGNAL'"
			mv "${GTKCSSFILE}_ORIGNAL" "$GTKCSSFILE"
		fi
		
		if [ -n "$STLCTLID" ] && [ "$STLCTLID" != "$PLACEHOLDERAID" ]; then
			VTAPP="769"
			writelog "INFO" "${FUNCNAME[0]} - Loading controller configuration of ValveTestApp769 '$VTAPP' to map the controller to the default Steam Deck settings via 'steam steam://forceinputappid/$VTAPP'"
			steam steam://forceinputappid/"$VTAPP"
		fi
	fi
}

function steamdeckBeforeGame {
	if [ "$ONSTEAMDECK" -eq 1 ]; then
		if [ "$FIXGAMESCOPE" -eq 1 ]; then
			writelog "INFO" "${FUNCNAME[0]} - Final Deck Check: Looks like we're in Game Mode (FIXGAMESCOPE is '$FIXGAMESCOPE')"
		else
			writelog "INFO" "${FUNCNAME[0]} - Final Deck Check: Looks like we're in Desktop Mode (FIXGAMESCOPE is '$FIXGAMESCOPE')"
		fi

		if [ "$USEGAMESCOPE" -eq 1 ] && [ "$FIXGAMESCOPE" -eq 1 ]; then
			writelog "SKIP" "${FUNCNAME[0]} - Disabling own GameScope on SteamDeck Game Mode" "X"
			USEGAMESCOPE=0
		else
			writelog "INFO" "${FUNCNAME[0]} - Allowing GameScope enabled on SteamDeck in Desktop Mode" "X"
		fi

		if [ "$USEGAMEMODERUN" -eq 1 ] && [ "$FIXGAMESCOPE" -eq 1 ]; then
			writelog "SKIP" "${FUNCNAME[0]} - Disabling own Feral GameMode tool (gamemoderun) on SteamDeck Game Mode" "X"
			USEGAMEMODERUN=0
		else
			writelog "INFO" "${FUNCNAME[0]} - Allowing Feral GameMode tool (gamemoderun) enabled on SteamDeck in Desktop Mode" "X"
		fi
		
		if [ -n "$STLCTLID" ] && [ "$STLCTLID" != "$PLACEHOLDERAID" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Loading controller configuration for the current game via 'steam steam://forceinputappid/$AID'"
			steam steam://forceinputappid/"$AID"
		fi
	fi
}

function steamdeckControl {
	if [ "$ONSTEAMDECK" -eq 1 ]; then
		setSDCfg
		export STLCTLID="$PLACEHOLDERAID"

		if [ ! -f "$STLSDLCFG" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Creating initial '$STLSDLCFG'"
			touch "$STLSDLCFG"
			echo "STLCTLID=\"$PLACEHOLDERAID\"" > "$STLSDLCFG"
		fi
		
		if [ -f "$STLSDLCFG" ]; then
			loadCfg "$STLSDLCFG" X
		fi
	
		if [ "$STLCTLID" != "$PLACEHOLDERAID" ]; then
			writelog "WARN" "${FUNCNAME[0]} - As documented you're on your own if mappings fail and you need to fix it manually via ssh"
			STLCNTRLD="$DEFSTEAMAPPSCOMMON/Steam Controller Configs/${STEAMUSERID}/config/${STLCTLID}"
			STLCNTRLF="$STLCNTRLD/controller_neptune.vdf"

			if [ -f "$STLCNTRLF" ] && ! grep -q "$NICEPROGNAME" "$STLCNTRLF"; then
				writelog "INFO" "${FUNCNAME[0]} - Good - found an original controller config under '$STLCNTRLF' - creating backup under ${STLCNTRLF}_ORG"
				mv "$STLCNTRLF" "${STLCNTRLF}_ORG"
			fi

			if  [ -f "$STLCNTRLF" ] && grep -q "$NICEPROGNAME" "$STLCNTRLF"; then
				if [ "$(grep -m1 "revision" "$SRCCTRLF" | grep -oE "[0-9]")" -gt "$(grep -m1 "revision" "$STLCNTRLF" | grep -oE "[0-9]")" ]; then
					writelog "INFO" "${FUNCNAME[0]} - Updating '$STLCNTRLF'"
					cp "$SRCCTRLF" "$STLCNTRLF"
				else
					writelog "INFO" "${FUNCNAME[0]} - '$STLCNTRLF' is already up-to-date"
				fi
			fi
			
			if [ -f "${STLCNTRLF}_ORG" ] && [ ! -f "$STLCNTRLF" ]; then
				SRCCTRLF="${PREFIX}/misc/stl-steamdeck-control.vdf"
				mkProjDir "$STLCNTRLD"
				writelog "INFO" "${FUNCNAME[0]} - Copying $NICEPROGNAME '$SRCCTRLF' to '$STLCNTRLF'"
				cp "$SRCCTRLF" "$STLCNTRLF"
				# might not be even required, but the data is ready anyway, so make it as complete as possible
				sed "s:XXXXXX:$STEAMUSERID:g" -i "$STLCNTRLF"
				sed "s:YYYYYY:$STLCTLID:g" -i "$STLCNTRLF"
			fi

			if grep -q "$NICEPROGNAME" "$STLCNTRLF"; then
				writelog "INFO" "${FUNCNAME[0]} - Loading controller configuration of SteamAppId '$STLCTLID' to allow joypad controls in $PROGNAME via 'steam steam://forceinputappid/$STLCTLID'"
				steam steam://forceinputappid/"$STLCTLID" > "$STLSHM/${FUNCNAME[0]}_stdout.txt" 2> "$STLSHM/${FUNCNAME[0]}_stderr.txt"
				writelog "INFO" "${FUNCNAME[0]} - controller settings for '$STLCTLID' loaded "
			else
				writelog "SKIP" "${FUNCNAME[0]} - Found controller config '', but it doesn't contain '$NICEPROGNAME' - not loading"
			fi
		else
			writelog "SKIP" "${FUNCNAME[0]} - Skipping loading controller mapping for Steam Deck, because STLCTLID is not configured: '$STLCTLID'"
		fi
	fi
}

# NOTE: More may be added here in future to handle install failure
function steamDeckInstallFail {
	printf "\n%s\n" "$NOTY_STEAMDECK_INSTALLFAIL"
	notiShow "$NOTY_STEAMDECK_INSTALLFAIL" "X"
	exit 1;
}

# Generic function to download dependency from URL (mainly intended for fetching from package repos)
function fetchAndExtractDependency {
	function removeFileExtension {
		local FNAME="$1"
		local LASTFNAME=""
		while ! [ "$FNAME" = "$LASTFNAME" ]; do
			LASTFNAME="$FNAME"
			FNAME="${FNAME%.*}"
		done
		echo "$FNAME"
	}

	# Return dependency name stripped of version, architecture, file extension
	function getPrettyDependencyName {
		removeFileExtension "$( echo "$1" | sed -E 's:(\-[0-9]\.[0-9])+(.+)::g;s:^[^A-Za-z0-9]+::g' )"
	}

	# Takes dependency filename and strips:
	# - any non-letters-or-numbers from start of string
	# - the architecture string and everything after it
	# - any remaining letters or numbers
	# - any remaining non-numbers from the end of the string
	function getDependencyVersion {
		echo "$1" | sed -E 's:^[^A-Za-z0-9]::g;s:x86+(.*)::g;s:[a-zA-Z]::g;s:[^0-9]+$::g' | grep -oE "[0-9]\.[0-9]+(.+)"
	}

	# Variables used to build URL
	local ARCHIVEURL
	local EXTRACTPATH
	local ARCHIVENAME

	ARCHIVEURL="$1"
	EXTRACTPATH="$2"
	ARCHIVENAME="${3:-${1##*/}}"  # If no extract name passed, take filename from end of archive URL

	local CURLCMD
	local EXTRACTCMD
	local EXTRACTCMDFLAGS

	CURLCMD="curl"
	EXTRACTCMD="tar"
	EXTRACTCMDFLAGS="xf"

	local LOCALVERS
	local STLVERS

	# Download dependency
	mkdir -p "$EXTRACTPATH"
	if ! [ -f "$EXTRACTPATH/$ARCHIVENAME" ]; then
		if ! [ "$INTERNETCONNECTION" -eq 0 ]; then
			writelog "INFO" "${FUNCNAME[0]} - Installing '$ARCHIVENAME' from '$ARCHIVEURL' to installation directory '$EXTRACTPATH'"
			echo "Downloading dependency '$ARCHIVENAME'..."
			if "$CURLCMD" -Lq "$ARCHIVEURL" -o "$EXTRACTPATH/$ARCHIVENAME"; then  # Not showing notifier to reduce notifier spam
				writelog "INFO" "${FUNCNAME[0]} - Successfully downloaded dependency '$ARCHIVENAME'"
				echo "Successfully downloaded $ARCHIVENAME!"
			else  # Download failure
				writelog "WARN" "${FUNCNAME[0]} - Failed to download dependency '$ARCHIVENAME', will attempt to continue with installation in case dependency archives already exist at '$EXTRACTPATH'"
				notiShow "$(strFix "$NOTY_STEAMDECK_DEPINSTALLFAIL" "$ARCHIVENAME")" "X"
				strFix "$NOTY_STEAMDECK_DEPINSTALLFAIL" "$ARCHIVENAME"
			fi
		else  # No internet connection
			writelog "WARN" "${FUNCNAME[0]} - No internet connection, can't download dependency '$ARCHIVENAME' - Will check for locally installed dependencies later on (should be located at '$EXTRACTPATH/$ARCHIVENAME')"
			echo "WARNING: No Internet Connection, cannot download dependency '$ARCHIVENAME'. For offline installation, manually place the file in '$EXTRACTPATH'."
			notiShow "$(strFix "$NOTY_STEAMDECK_NOINTERNETDEPSWARN" "$ARCHIVENAME" "$EXTRACTPATH")"
		fi
	else
		writelog "INFO" "${FUNCNAME[0]} - Dependency '$ARCHIVENAME' already exists at installation directory '$EXTRACTPATH', skipping redownload..."
		echo "Dependency '$ARCHIVENAME' already exists at installation directory '$EXTRACTPATH', nothing to download"
	fi

	# Extracting dependencies - If we can't find an exact match for the downloaded file, try to find a fuzzy match based on 'real' package name
	if ! [ -f "$EXTRACTPATH/$ARCHIVENAME" ]; then
		# -----
		# Get list of files and remove version string from it, then check if this name is inside our target archive file
		# This basically tries to find any archives that have the 'actual' package name e.g. 'innoextract' from 'innoextract-1.1-1.pkg.tar.zst', then tries to search if any files in the directory match
		# the archive we passed in to try to download but couldn't and try to extract them. This lets us extract dependencies for a potential archive match if the name is not exact
		# -----
		local DEPMATCHFOUND=0
		mapfile -t DEPFILES < <( find "$EXTRACTPATH" -maxdepth 1 -type f -iname \*"*.*"\* -exec basename {} \; )
		if ! [[ "${#DEPFILES[@]}" -eq 0 ]]; then
			writelog "INFO" "${FUNCNAME[0]} - Found archive in '$EXTRACTPATH' that is potential match for '$ARCHIVENAME'"
			for file in "${DEPFILES[@]}"; do
				# Removes version number, anything before the first space, and removes anything that isn't a sequence of letters or numbers from the beginning of the filename
				# Attempts to be as generous as possible in matching *any* match for the dependency name
				PRETTYFILENAME="$( getPrettyDependencyName "$file" )"
				PRETTYARCHIVENAME="$( getPrettyDependencyName "$ARCHIVENAME" )"

				if [[ ( "$ARCHIVENAME" =~ $PRETTYFILENAME || "$PRETTYFILENAME" =~ $PRETTYARCHIVENAME ) ]]; then
					writelog "INFO" "${FUNCNAME[0]} - Found potential existing dependency '$file', assuming dependency '$ARCHIVENAME' is already satisfied."
					echo "Found potential matching dependency archive for '$ARCHIVENAME' at '$file'"

					LOCALVERS="$( getDependencyVersion "$file" )"
					STLVERS="$( getDependencyVersion "$ARCHIVENAME" )"
					# Check local archive version vs. what STL asked for
					if [ -z "$LOCALVERS" ]; then
						# Could not get version string from archive
						writelog "WARN" "${FUNCNAME[0]} - Could not get version from archive - This dependency version may not work if is newer than '$STLVERS'"
						echo "Could not get version from archive - This dependency version may not work if is newer than '$STLVERS'!"
					else
						if [ "$LOCALVERS" = "$STLVERS" ]; then  # Version match
							writelog "INFO" "${FUNCNAME[0]} - Archive version appears to be the same version that SteamTinkerLaunch asked for - Should be ok to install this version"
							echo "Dependency version looks ok"
						else  # Version newer/older (might still work, but warn the user anyway)
							writelog "WARN" "${FUNCNAME[0]} - Archive version '${LOCALVERS}' does not match the version that SteamTinkerLaunch asked for ('$STLVERS') - This may cause problems with the installation!"
							echo "Dependency version does not match what SteamTinkerLaunch was looking for - This may cause problems with your installation!"
						fi
					fi

					ARCHIVENAME="$file"
					DEPMATCHFOUND=1					
					break
				fi
			done
		fi

		# Abort if we couldn't match a dependency
		if [[ "$DEPMATCHFOUND" -eq 0 ]]; then
			writelog "INFO" "${FUNCNAME[0]} - Could not find any matching dependency archives in '$EXTRACTPATH' for '$ARCHIVENAME' - Assuming this dependency is missing and installation cannot continue"
			echo "Could not find any archive in '$EXTRACTPATH' for '$ARCHIVENAME', aborting install..."
			return 1;
		fi
	fi

	# Extract archive now that we know we should have *something* to extract
	writelog "INFO" "${FUNCNAME[0]} - Extracting dependency '$ARCHIVENAME' at '$EXTRACTPATH/$ARCHIVENAME'"
	echo "Extracting dependency '$ARCHIVENAME'..."
	if "$EXTRACTCMD" "$EXTRACTCMDFLAGS" "$EXTRACTPATH/$ARCHIVENAME" -C "$EXTRACTPATH"; then
		# Succes extraction
		writelog "INFO" "${FUNCNAME[0]} - Successfully extracted dependency to '$EXTRACTPATH/$ARCHIVENAME'"
		echo "Successfully extracted '$ARCHIVENAME' to '$EXTRACTPATH'"
	else
		# Failed extraction
		writelog "ERROR" "${FUNCNAME[0]} - Failed to extract dependency '$ARCHIVENAME' to '$EXTRACTPATH' - Consider checking file/folder permissions"
		notiShow "$(strFix "$NOTY_STEAMDECK_EXTRACTFAIL" "$ARCHIVENAME" "$EXTRACTPATH")" "X"
		strFix "$NOTY_STEAMDECK_EXTRACTFAIL" "$ARCHIVENAME" "$EXTRACTPATH"
		return 1;
	fi
}

function checkSteamDeckDependencies {
	
	function installDependencyVersionFromURL {
		local DEPCMD="$1"
		local DEPFILENAME="$2"
		local DEPDIR="$3"
		local REPOURL="$4"

		if [ -f "$(command -v "$DEPCMD")" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Using '$DEPCMD' binary found in path: '$(command -v "$DEPCMD")'"
			echo "Dependency '$DEPCMD' already installed, nothing to do."
		else
			writelog "INFO" "${FUNCNAME[0]} - Downloading $DEPCMD version automatically from URL '$REPOURL'"
			writelog "INFO" "${FUNCNAME[0]} - curl -Lq \"$REPOURL\" -o \"$DEPDIR/$DEPFILENAME\""

			notiShow "$(strFix "$NOTY_STEAMDECK_DEPSDOWNLOAD" "$DEPCMD")" "X"
			strFix "$NOTY_STEAMDECK_DEPSDOWNLOAD" "$DEPCMD"

			fetchAndExtractDependency "$REPOURL" "$DEPDIR" "$DEPFILENAME" || steamDeckInstallFail

			STEAMDECKWASUPDATE=1
		fi
	}

	# if this really changes, it could be grepped directly from /etc/pacman.d/mirrorlist as well: (was previously used for wget, keeping commented in case we need it in future)
	#SDREPO="https://steamdeck-packages.steamos.cloud/archlinux-mirror/extra/os/x86_64/"
	# ARCHURL="https://archlinux.org/packages/community/x86_64"
	ARCHARCHIVEURL="https://archive.archlinux.org/packages"

	INNOEXTRACTVERS="1.9-7"
	INNOEXTRACTFILE="$INNOEXTRACT-$INNOEXTRACTVERS-x86_64.pkg.tar.zst"
	INNOEXTRACTURL="$ARCHARCHIVEURL/i/$INNOEXTRACT/$INNOEXTRACTFILE"

	CABEXTRACTVERS="1.9.1-2"
	CABEXTRACTFILE="$CABEXTRACT-$CABEXTRACTVERS-x86_64.pkg.tar.zst"
	CABEXTRACTURL="$ARCHARCHIVEURL/c/$CABEXTRACT/$CABEXTRACTFILE"

	printf '\n'

	installDependencyVersionFromURL "$INNOEXTRACT" "$INNOEXTRACTFILE" "$STLDEPS" "$INNOEXTRACTURL" || steamDeckInstallFail
	installDependencyVersionFromURL "$CABEXTRACT" "$CABEXTRACTFILE" "$STLDEPS" "$CABEXTRACTURL" || steamDeckInstallFail

	if [ -f "$(command -v "yad")" ]; then
		writelog "INFO" "${FUNCNAME[0]} - Using yad binary found in path: '$(command -v "yad")'"
		echo "Dependency 'yad' already installed, nothing to do."
		# Force update of global config file to add Yad path if it exists in $HOME/stl/deps/yad/bin
		touch "$FUPDATE"
		updateConfigEntry "YAD" "$( command -v "yad" )" "$STLDEFGLOBALCFG"
	else
		printf '\n'
		writelog "INFO" "${FUNCNAME[0]} - Using yad app image"
		setYadBin "ai" "sd" || steamDeckInstallFail
	fi
}

function installFilesSteamDeck {	
	local INSTALLEDPROGVERS
	local SCRIPTDIR

	if [[ "$INTERNETCONNECTION" -eq 1 ]]; then
		# Notification for either updating or downloading STL on Deck
		if [ -d "$SYSTEMSTLCFGDIR/.git" ]; then
			notiShow "$NOTY_STEAMDECK_UPDATE" "X"
			echo "$NOTY_STEAMDECK_UPDATE"
			STEAMDECKWASUPDATE=1
		else
			notiShow "$NOTY_STEAMDECK_DOWNLOAD" "X"
			echo "$NOTY_STEAMDECK_DOWNLOAD"
		fi

		# Attempt to get update files from Git
		if ! gitUpdate "$PREFIX" "$PROJECTPAGE"; then
			writelog "WARN" "${FUNCNAME[0]} - Could not clone/pull changes from git repo, doing some checks"
			if ! ping -q -c1 archlinux.org &>/dev/null; then
				writelog "WARN" "${FUNCNAME[0]} - Could not ping Arch Linux website, maybe there is a connectivity problem - Install / Update may fail"
			else
				writelog "WARN" "${FUNCNAME[0]} - Looks like GitHub is ok, attempting to update via a fresh clone to '${PREFIX}-temp'"
			fi

			if ! gitUpdate "${PREFIX}-temp" "$PROJECTPAGE"; then
				writelog "WARN" "${FUNCNAME[0]} - Still failed to download from GitHub, though it should be up -Not trying to update again, maybe something is wrong with install files"
				echo "Could not pull down changes from Git, even though GitHub should be up. Not attempting another update right now, maybe try again later or try a fresh install if the issue persists."
			else
				# TODO clean this up

				# Currently we assume the removal of the existing files and moving of the new files will succeed ok
				# There could be a very rare instance where due to permission faults or somethimg, this fails
				# We aren't worried about this for now, but a PR might be welcome on this in future :-)
				writelog "INFO" "${FUNCNAME[0]} - Fresh clone succeeded ok, overwriting existing installation with fresh clone"
			
				# This was disabled because I thought it caused issues on Steam Deck
				# It needs testing before it can be safely enabled, if we even want to re-enable this functionality

				# rm -rf "$PREFIX"
				# mv "${PREFIX}-temp" "$PREFIX"
				# rm -rf "${PREFIX}-temp"
			
				writelog "INFO" "${FUNCNAME[0]} - Successfully pulled updated changes!"
			fi
		else
			writelog "INFO" "${FUNCNAME[0]} - Fetching from git seems to have succeeded ok."
		fi
	else
		# Get version of existing STL install, if present, and compare with our version
		writelog "WARN" "${FUNCNAME[0]} - No Internet Connection detected, cannot clone Git repo - Attempting to manually install"

		SCRIPTDIR="$( realpath "$0" )"
		SCRIPTDIR="${SCRIPTDIR%/*}"

		# Offline installation of STL was previously installed/attempted - With check to try and ensure scriptdir is a valid STL install and not a standalone script
		if ! [ -d "$SCRIPTDIR/lang" ] && ! [ -d "$SCRIPTDIR/misc" ] && ! [ -d "$SCRIPTDIR/guicfgs" ]; then
			writelog "WARN" "${FUNCNAME[0]} - Script dir '$SCRIPTDIR' does not look like a valid SteamTinkerLaunch installation directory! Not copying files in case this script is not in a proper STL folder"
			echo "WARNING: Not updating offline filees - It looks like you're trying to install SteamTinkerLaunch as a standalone script outside of its downloaded files."
		elif [ -f "$PREFIX/steamtinkerlaunch" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Found existing SteamTinkerLaunch files at '$PREFIX', checking if we need to update"
			INSTALLEDPROGVERS="$( grep -i "^PROGVERS=.*." "$PREFIX/steamtinkerlaunch" | cut -d '"' -f 2 )"
			writelog "INFO" "${FUNCNAME[0]} - Currently installed STL version: $INSTALLEDPROGVERS"
			writelog "INFO" "${FUNCNAME[0]} - This script's STL version: $PROGVERS"
			# Check if we actually need to update (running script ver > currently installed script ver)
			# Not a fool-proof test, sometimes PROGVERS isn't bumped, but a user can always manually copy the files if they want to - We'll assume they downloaded the latest version ahead of time and want to manually install that
			if [[ "$PROGVERS" > "$INSTALLEDPROGVERS" ]]; then 
				writelog "INFO" "${FUNCNAME[0]} - Existing SteamTinkerLaunch installation is older than current version - Installation will continue by copying downloaded files at '$SCRIPTDIR' to '$PREFIX'"
				echo "Updating SteamTinkerLaunch to '$PROGVERS' by copying installation files to '$PREFIX' for offline installation..." 
				cp -R "$SCRIPTDIR"/* "$PREFIX"
				STEAMDECKWASUPDATE=1
			else
				writelog "INFO" "${FUNCNAME[0]} - Existing SteamTinkerLaunch installation is newer than or same as current version - No code to update"
				echo "Existing SteamTinkerLaunch install is up-to-date, verifying dependencies..."
				STEAMDECKDIDINSTALL=0
			fi
		else
			# No existing STL installation - Let's create one using the files downloaded with the script currently running!
			writelog "INFO" "${FUNCNAME[0]} - No existing STL installation found - Installation will continue by copying downloaded files at '$SCRIPTDIR' to '$PREFIX'"
			echo "No existing STL installation found, so copying installation files to '$PREFIX' for offline installation..." 
			cp -R "$SCRIPTDIR"/* "$PREFIX"
		fi
	fi
}

function steamdedeckt {
	if [ -f "/etc/os-release" ] && grep -q "steamdeck" "/etc/os-release"; then		
		ONSTEAMDECK=1

		export STEAMDECKWASUPDATE=0
		export STEAMDECKDIDINSTALL=1
		export STEAMDECKSTEAMRUN=0  # Stores if we're running STL when Steam opens on Steam Deck

		writelog "INFO" "${FUNCNAME[0]} - Seems like we have a Steam Deck here - making some specific settings"

		STLBASE="/home/deck/$SHOSTL"
		export PREFIX="$STLBASE/prefix"
		SYSTEMSTLCFGDIR="$PREFIX"
		STLDEPS="$STLBASE/deps"

		mkProjDir "$PREFIX"
		mkProjDir "$STLDEPS"

		if [ -z "$SUSDA" ]; then
			setSteamPaths
		fi

		# Show icon and title for notifier
		if ! [ -f "$STLICON" ]; then
			SCRIPTDIR="$( realpath "$0" )"
			SCRIPTDIR="${SCRIPTDIR%/*}"
			STLICON="$SCRIPTDIR/misc/steamtinkerlaunch.svg"
		fi
		export NOTYARGS="-i $STLICON -a $PROGNAME"

		# Differentiate between Game Mode and Desktop Mode on Steam Deck
		if grep -q "generate-drm-mode" <<< "$(pgrep -a "$GAMESCOPE")"; then
			writelog "INFO" "${FUNCNAME[0]} - Detected '$GAMESCOPE' running 'forced' - assuming we're running in Game Mode"
			FIXGAMESCOPE=1
		else
			writelog "INFO" "${FUNCNAME[0]} - Did not detect a running '$GAMESCOPE' process - assuming we're running in Desktop Mode"

			SMALLDESK=1
		fi

		writelog "INFO" "${FUNCNAME[0]} - Set 'FIXGAMESCOPE' to '$FIXGAMESCOPE'"
		writelog "INFO" "${FUNCNAME[0]} - Set 'SMALLDESK' to '$SMALLDESK'"

		INTERNETCONNECTION=1

		# Check if we're running STL on a Steam first launch
		# Assume Steam if all of these are true:
		# - We already have an STL installation (assume install if script in prefix)
		# - The AppID is a placeholder ID (not running a game)
		# - The script is running from CompatibilityTools.d 
		if [ -f "$PREFIX/steamtinkerlaunch" ] && [ "$AID" = "$PLACEHOLDERAID" ] && [[ ${0^^} == *"${CTD^^}"* ]]; then
			writelog "INFO" "${FUNCNAME[0]} - Looks like we're running through Steam on a Steam Deck, we don't want to do any updating here!"
			STEAMDECKSTEAMRUN=1
		elif [[ ${0^^} == *"${PREFIX^^}"* ]] && ! [ "$AID" = "$PLACEHOLDERAID" ]; then
			# Launching a game proper through Steam would mean the dir we're launching from (${0}) would be the compattool dir
			#
			# The check for the AID != PlaceholderAID means we can update if we're just running the script from the prefix (i.e., we double clicked it) 
			# But if we have an actual game AppID and we're running from the prefix, we're probably being called from an extra dialog on the main menu, which means we don't want to update (and this stops notifier spam too)
			writelog "INFO" "${FUNCNAME[0]} - Looks like we have a game but we're running from the Steam Deck install Prefix, not doing any updating here!"
			STEAMDECKSTEAMRUN=1
		else
			notiShow "$NOTY_STEAMDECK_INSTALL" "X"
			echo "$NOTY_STEAMDECK_INSTALL on Steam Deck"

			if ! (ping -q -c1 archlinux.org &>/dev/null || ping -q -c1 google.com &>/dev/null); then
				INTERNETCONNECTION=0
				writelog "WARN" "${FUNCNAME[0]} - No Internet Connection detected, attempting to install SteamTinkerLaunch offline - This may not succeed!"
				writelog "WARN" "${FUNCNAME[0]} - Make sure you have either manually installed all dependencies, or added all manual dependency archives to '$STLDEPS'"
				notiShow "$NOTY_STEAMDECK_NOINTERNET" "X"
				echo "$NOTY_STEAMDECK_NOINTERNET"
			fi
		fi
		
		export STLSDPATH="${STLDEPS}/usr/bin"
		export PATH="$PATH:$STLSDPATH"

		if [ "$STEAMDECKSTEAMRUN" -eq 0 ]; then
			installFilesSteamDeck
			checkSteamDeckDependencies

			# Don't remove dependencies offline
			if [ "$INTERNETCONNECTION" -eq 1 ]; then
				find "$STLDEPS" -type f \( -name "*.zst" -o -name "*.gz" -o -name ".*" \) -exec rm {} \;
			fi

			# update/set compatibility tool to git stl:
			if [ "$INFLATPAK" -eq 0 ]; then
				notiShow "$NOTY_STEAMDECK_ADDCOMPAT" "X"
				CompatTool "add" "$PREFIX/$PROGCMD" >/dev/null
			fi
			
			GTKCSSFILE="$HOME/.config/gtk-3.0/gtk.css"

			if [ ! -f "$GTKCSSFILE" ] ; then
				writelog "SKIP" "${FUNCNAME[0]} - '$GTKCSSFILE' does not exist - skipping"
			else
				if grep -q "scrollbar" "$GTKCSSFILE"; then
					writelog "SKIP" "${FUNCNAME[0]} - found a scrollbar entry in '$GTKCSSFILE'"
				else
					writelog "INFO" "${FUNCNAME[0]} - backup '$GTKCSSFILE' to '${GTKCSSFILE}_ORIGNAL'"
					cp "$GTKCSSFILE" "${GTKCSSFILE}_ORIGNAL"

					# NOTE: This styles most, but not all, UI elements on Steam Deck
					# It makes the scrollbar wider and easier to grab, and it adds a right margin so UI elements aren't covered by the scollbar
					# However currently the UI is not as uniform on Steam Deck, because file choosers and text fields don't have this margin
					# PRs are welcome to apply styling to these elements :-)
					writelog "INFO" "${FUNCNAME[0]} - adding bigger scrollbar and customising some other UI elements using '$GTKCSSFILE'"
					{
						echo ".scrollbar.vertical slider,"
						echo "scrollbar.vertical slider {"
						echo "min-width: 15px;"
						echo "}"
						echo "spinbutton, combobox button {"
						echo "margin-right: 20px;"
						echo "}"
					} >> "$GTKCSSFILE"
				fi
			fi
		else
			writelog "INFO" "${FUNCNAME[0]} - Seems like we're being run by Steam here, not doing any installation steps"
		fi
	fi
}

function restoreGtkCss {
	if [ "$ONSTEAMDECK" -eq 1 ]; then
		GTKCSSFILE="$HOME/.config/gtk-3.0/gtk.css"
		if [ -f "${GTKCSSFILE}_ORIGNAL" ] ; then
			writelog "INFO" "${FUNCNAME[0]} - recovering original gtk.css from '${GTKCSSFILE}_ORIGNAL'"
			mv "${GTKCSSFILE}_ORIGNAL" "$GTKCSSFILE"
		fi
	fi
} 

function prepareSteamDeckCompatInfo {
	if [ ! -x "$(command -v "$JQ")" ]; then
		writelog "WARN" "${FUNCNAME[0]} - Can't get Steam Deck compatibility information because '$JQ' is not installed"
		return 1
	fi

	mapfile -d ";" -t -O "${#DECKCOMPATARR[@]}" DECKCOMPATARR <<< "$( getSteamDeckCompatInfo "$AID" )"
	unset "DECKCOMPATARR[-1]"

	if [ "${#DECKCOMPATARR[@]}" -eq "0" ]; then
		writelog "INFO" "${FUNCNAME[0]} - No compatibility information available for '$AID' - Is this AppID definitely correct?"
	else
		# HTML symbols for Verified (checkmark), Playable (circled question mark) and Unsupported (no-entry sign) 
		COMPATMARK=""
		case ${DECKCOMPATARR[0]} in
			*"Verified"*) COMPATMARK="&#10003;" ;;
			*"Playable"*) COMPATMARK="&#128712;" ;;
			*"Unsupported"*) COMPATMARK="&#128683;" ;;
		esac
		STEAMDECKCOMPATRATING="${DECKCOMPATARR[0]} ${COMPATMARK}"
	fi
}

# Fetches compatibility information about a game directly from the Steam store endpoint
# TODO maybe store `display_type` to differentiate what each string refers to, e.g.:
#    - 4 means Verified
#    - 3 means Playable
#    - ???
#    - 1 is the grey subtext for small notes about controllers and internet access
function getSteamDeckCompatInfo {
	if [ ! -x "$(command -v "$JQ")" ]; then
		writelog "WARN" "${FUNCNAME[0]} - Can't get Steam Deck compatibility information because '$JQ' is not installed"
		return 1
	fi

	if [ -z "$1" ]; then
		echo "No AppID given, you need to pass the AppID of the game you want to check the compatibility of"
		writelog "ERROR" "${FUNCNAME[0]} - Need a valid AppID to check the Steam Deck compatibility information"
		return 1
	fi

    AID="$1"
	mkProjDir "$STLGDECKCOMPAT"

	# Unofficial documentation for this endpoint is available here: https://github.com/Revadike/InternalSteamWebAPI/wiki/Get-Deck-Compatibility-Report
    DECKCOMPATENDPOINT="https://store.steampowered.com/saleaction/ajaxgetdeckappcompatibilityreport?nAppID="
    COMPATFILE="$STLGDECKCOMPAT/${AID}-deckcompatrating.json"

	# Check if we can access Steam before fetching the Deck compatibility info
    COMPATINFO=""
	if ! ping -q -c1 store.steampowered.com &>/dev/null; then
		writelog "INFO" "${FUNCNAME[0]} - Looks like we can't access Steam, not removing any Steam Deck compatibility files"

		# No existing file and offline, so skip
		if ! [ -f "$COMPATFILE" ]; then
			writelog "WARN" "${FUNCNAME[0]} - Looks like we can't contact Steam and there is no known Steam Deck compatibility information file at '$COMPATFILE' - Skipping this step since we won't be able to retrieve any useful data"
			return 1
		else
			writelog "INFO" "${FUNCNAME[0]} - Existing file found at '$COMPATFILE', Steam Deck compatibility information will be taken from this since we can't contact Steam - The information here could be outdated depending on when it was fetched!"
		fi
	else 
		# Remove existing file
		if [ -f "$COMPATFILE" ]; then			
			if ! "$JQ" -e '.success' "$COMPATFILE" 1>/dev/null; then
				writelog "INFO" "${FUNCNAME[0]} - File '$COMPATFILE' containing Steam Deck compatibility information already exists, however it looks like it failed last time - Removing it so we can attempt to redownload it"
				rm "$COMPATFILE"
			elif [ "$(( $(date +"%s") - $(stat -c "%Y" "$COMPATFILE") ))" -gt "86400" ]; then  # Todo maybe let the user define this in the Global Menu
				writelog "INFO" "${FUNCNAME[0]} - File '$COMPATFILE' is older than 1 day - Removing it so we can update in case the compatibility rating has changed"
				rm "$COMPATFILE"
			fi
		fi

		# If the file doesn't exist at all and we can connect to Steam, create it from the response
		if ! [ -f "$COMPATFILE" ]; then
			writelog "INFO" "${FUNCNAME[0]} - Fetching Steam Deck compatibility information for '$AID' from Steam store endpoint with '${DECKCOMPATENDPOINT}${AID}'"
			if ! "$WGET" -q "${DECKCOMPATENDPOINT}${AID}" -O "$COMPATFILE" 2> >(grep -v "SSL_INIT"); then
				# Failed to fetch for some reason, skip getting Deck compat info
				writelog "INFO" "${FUNCNAME[0]} - Failed to fetch Steam Deck compatibility information from Steam store endpoint with '${DECKCOMPATENDPOINT}${AID}'"
				return 1
			fi
		else
			# File exists, don't redownload
			writelog "INFO" "${FUNCNAME[0]} - Steam Deck compatibility rating file '$COMPATFILE' already exists - not redownloading"
		fi
	fi

	# We were able to hit the endpoint successfully, but check if the response success is valid!
	RESULTSLENGTH="$( "$JQ" -e '.results | length' "$COMPATFILE" )"
    if (( RESULTSLENGTH > 0 )); then 
        writelog "INFO" "${FUNCNAME[0]} - Successfully retrieved Steam Deck compatility information - Stored to '$COMPATFILE'"

        # Get Verified/Playable/Unsupported/Unknown
        DECKCOMPATRATING="$( "$JQ" -e '.results.resolved_category' "$COMPATFILE" )"
        case $DECKCOMPATRATING in
            1) COMPATTEXT="$STEAMDECKCOMPAT_UNSUPPORTED" ;;
            2) COMPATTEXT="$STEAMDECKCOMPAT_PLAYABLE" ;;
            3) COMPATTEXT="$STEAMDECKCOMPAT_VERIFIED" ;;
            *) COMPATTEXT="$STEAMDECKCOMPAT_UNKNOWN" ;;
        esac
        COMPATINFO+="${COMPATTEXT};"

		writelog "INFO" "${FUNCNAME[0]} - Successfully retrieved Steam Deck compatibility rating of '$COMPATTEXT' for '$AID'"
		writelog "INFO" "${FUNCNAME[0]} - Converting language tokens for Steam Deck compatibility criteria into SteamTinkerLaunch translated strings"

		# Turn language tokens like '#SteamDeckVerified_TestResult_blah' into an actual translated string from the translation files
		# Language strings credited to: https://github.com/SteamDatabase/SteamTracking
        for LANGTOKEN in $( "$JQ" -r '.results.resolved_items[].loc_token' "$COMPATFILE" ); do
            LANGTOKEN="$( echo "$LANGTOKEN" | xargs )"
            if [ -n "$LANGTOKEN" ]; then
				OGLANGTOKEN="$LANGTOKEN"
				# Convert token to uppercase and remove hash at beginning
                LANGTOKEN="${LANGTOKEN^^}"
                LANGTOKEN="${LANGTOKEN//#/}"

				# Get associated translation variable from translation files to match this translated string
				STLLANGTOKEN="${!LANGTOKEN}"
				if [ -n "$STLLANGTOKEN" ]; then
					COMPATINFO+="\"$STLLANGTOKEN\";"
				else
					writelog "WARN" "${FUNCNAME[0]} - Could not find translation string for returned language token '$OGLANGTOKEN' - Seems like we need to update the translation files to include a new string!"
				fi
            else
                writelog "INFO" "${FUNCNAME[0]} - Skipping blank LANGTOKEN '$LANGTOKEN' - though this should probably not happen!"
            fi
        done

		DEVELOPERCOMMENTSURL="$( "$JQ" -e '.results.steam_deck_blog_url' "$COMPATFILE" )"
		if [ "${#DEVELOPERCOMMENTSURL}" -gt 2 ]; then  # DEVELOPERCOMMENTSURL will always have quotes around it (e.g. `""` for blank), so the minimum length will always be 2 since it will be 2 for a blank entry because of the set of quotes 
			writelog "INFO" "${FUNCNAME[0]} - Seems like the developer has a blog post with some comments on this game's compatibility, appending it... (length is ${#DEVELOPERCOMMENTSURL}"
			COMPATINFO+="$( strFix "$STEAMDECKVERIFIED_CUSTOMRESULT_DEVPOST" "$DEVELOPERCOMMENTSURL" );"
		else
			writelog "INFO" "${FUNCNAME[0]} - Seems like no developer comments were left for this game - This is fine as most games don't have this, so skipping"
		fi
		writelog "INFO" "${FUNCNAME[0]} - Finished setting Steam Deck compatibility criteria strings"
    else
		# We were able to get a response from the endpoint, but the results body was blank so we can't get any response information - Not sure when this would happen outside of Non-Steam Games
		writelog "WARN" "${FUNCNAME[0]} - No compatibility information available for '$AID' - Maybe the AppID is invalid?"
		rm "$COMPATFILE"
		return 1
    fi

	echo "$COMPATINFO"
}

### STEAM DECK END

function setflatpak {
	if [ -n "$FLATPAK_ID" ] && [ "$FLATPAK_ID" == "com.valvesoftware.Steam" ]; then
		writelog "INFO" "${FUNCNAME[0]} - seems like flatpak is used, because variable 'FLATPAK_ID' exists and points to 'com.valvesoftware.Steam'"
		INFLATPAK=1
		CompatTool "add" "$FPBIN/$PROGCMD"
	else
		writelog "INFO" "${FUNCNAME[0]} - started $PROGNAME from ${0}"
	fi
}

# This has the side effect of being called everytime on a local install run, but since the scriptdir of a local install can change, It Has To Be This Way
function setLocalInstall {
	SCRIPTDIR="$( realpath "$0" )"
	SCRIPTDIR="${SCRIPTDIR%/*}"
	# If not on Steam Deck or Flatpak, and we don't have a system config directory, assume we have a non-root local install and set/update config folder structure to match
	if [ "$ONSTEAMDECK" -eq 0 ] && [ ! -d "$SYSTEMSTLCFGDIR" ] && [ "$INFLATPAK" -eq 0 ]; then  # Check if "$SYSTEMSTLCFGDIR" doesn't exist because the user could be running the script for testing but have a global install
		writelog "INFO" "${FUNCNAME[0]} - Looks like we have a non-root local install here - Updating paths..."
		# If no "$SYSTEMSTLCFGDIR" directory, assume it was looking in `/usr/something` for configs (where they would be on a root install) - but since that folder doesn't exist, set it to the scriptdir 
		SYSTEMSTLCFGDIR="$SCRIPTDIR"
	else
		writelog "INFO" "${FUNCNAME[0]} - Looks like we don't have a local non-root install"
	fi

	# Only update if we have an existing config file, don't call `updateConfigEntry` on non-existent file
	# Running this block here means we can update existing configs if the user installs system-wide again later or switches between
	if [ -f "$STLDEFGLOBALCFG" ]; then
		touch "$FUPDATE"
		updateConfigEntry "GLOBALCOLLECTIONDIR" "$SYSTEMSTLCFGDIR/collections" "$STLDEFGLOBALCFG"
		updateConfigEntry "GLOBALMISCDIR" "$SYSTEMSTLCFGDIR/misc" "$STLDEFGLOBALCFG"
		updateConfigEntry "GLOBALSBSTWEAKS" "$SYSTEMSTLCFGDIR/sbstweaks" "$STLDEFGLOBALCFG"
		updateConfigEntry "GLOBALTWEAKS" "$SYSTEMSTLCFGDIR/tweaks" "$STLDEFGLOBALCFG"
		updateConfigEntry "GLOBALEVALDIR" "$SYSTEMSTLCFGDIR/eval" "$STLDEFGLOBALCFG"
		updateConfigEntry "GLOBALSTLLANGDIR" "$SYSTEMSTLCFGDIR/lang" "$STLDEFGLOBALCFG"
		updateConfigEntry "GLOBALSTLGUIDIR" "$SYSTEMSTLCFGDIR/guicfgs" "$STLDEFGLOBALCFG"
	fi
}

function removeEmptyFiles {
	REFCHECKDIR="$1"
	writelog "INFO" "${FUNCNAME[0]} - Removing empty files from '$REFCHECKDIR'"
	for STLFILE in "$REFCHECKDIR/"*; do
		if ! [ -s "$STLFILE" ]; then
			rm "$STLFILE" &>/dev/null
		fi
	done
}

##################

function main {
	initShmStl
	restoreGtkCss
	rm "$TEMPLOG" "$WINRESLOG" "$PRELOG" "$APPMALOG" "$GGDLOG" 2>/dev/null
	touch "$PRELOG"
	mkProjDir "$LOGDIRID"
	setflatpak

	USS="${PREFIX}/share/steam"
	if [ "$INFLATPAK" -eq 1 ]; then
		USS="/app/share/steam"
	fi
	SYSSTEAMCOMPATOOLS="$USS/$CTD"

	SCRIPTDIR="$( realpath "$0" )"
	SCRIPTDIR="${SCRIPTDIR%/*}"

	initAID "$@"
	setAIDCfgs

	# Respect language choice asap in running (uses correct language during Steam Deck install)
	# Try and load either from langfile directory or `lang=` argument (prioritising lang arguments) - Default if we don't get a valid `$STLLANG`
	loadLanguage "$@"
	if [ -z "$STLLANG" ]; then
		loadLangFile "$STLDEFLANG"
	fi

	# Check quiet mode to hide notifier
	STLQUIET=0
	if echo "$@" | grep -qow '\-q'; then
		writelog "INFO" "${FUNCNAME[0]} - Quiet mode enabled with '-q', suppressing notifier for this execution"
		export STLQUIET=1
		USENOTIFIER=0
	fi

	steamdedeckt
	setLocalInstall
	getCurrentCommandline "$@"  # Maybe pass args with removed '-q' flag in the above if block
	saveOrgVars
	emptyVars "O"

    # Notify success on Steam Deck
	if [ "$ONSTEAMDECK" -eq 1 ] && [ "$STEAMDECKSTEAMRUN" -eq 0 ]; then
		printf '\n'
		if [ "$STEAMDECKDIDINSTALL" -eq 1 ]; then
			INSTALLEDPROGVERS="$( grep -i "^PROGVERS=.*." "$PREFIX/steamtinkerlaunch" | cut -d '"' -f 2 )"
			if [ "$STEAMDECKWASUPDATE" -eq 1 ]; then
				strFix "$NOTY_STEAMDECK_UPDATE_SUCCESS!" "$INSTALLEDPROGVERS"  # Update success w/ version
				notiShow "$(strFix "$NOTY_STEAMDECK_UPDATE_SUCCESS" "$INSTALLEDPROGVERS")" "X"
			else
				strFix "$NOTY_STEAMDECK_INSTALL_SUCCESS!" "$INSTALLEDPROGVERS"  # Install success w/ version
				notiShow "$(strFix "$NOTY_STEAMDECK_INSTALL_SUCCESS" "$INSTALLEDPROGVERS")" "X"
			fi
		else
			# Show install finished if no STL install files were modified (currently only for offline installs where existing install == install files)
			echo "$NOTY_STEAMDECK_INSTALL_FINISH!"
			notiShow "$NOTY_STEAMDECK_INSTALL_FINISH" "X"
		fi
	fi

	writelog "START" "######### Initializing Game Launch $AID using $PROGNAME $PROGVERS #########" "P"

	if [ -f "$STLDEFGLOBALCFG" ] && grep -q "^RESETLOG=\"1\"" "$STLDEFGLOBALCFG"; then
		if [ -f "$PRELOG" ]; then
			mv "$PRELOG" "$LOGFILE"
		else
			rmOldLog
			rm "$PRELOG" 2>/dev/null
		fi
		writelog "INFO" "${FUNCNAME[0]} - Starting with a clean log"  # from here the '$LOGFILE' is written directly
	fi

	writelog "INFO" "${FUNCNAME[0]} - Start creating default configs"
	createDefaultCfgs "$@"

	listSteamLibraries
	setSteamLibraryPaths

	writelog "INFO" "${FUNCNAME[0]} - Checking internal dependencies:"
	checkIntDeps "$@"

	writelog "INFO" "${FUNCNAME[0]} - Initializing first Proton:"
	initFirstProton

	writelog "INFO" "${FUNCNAME[0]} - Initializing default window resolution"
	setInitWinXY

	GREETING="$( getSeasonalGreeting )"
	writelog "INFO" "${FUNCNAME[0]} - ${GREETING:-Welcome to SteamTinkerLaunch}"

	removeEmptyFiles "$STLAPPINFOIDDIR"  # Remove appinfo files that are 0 bytes (i.e. Non-Steam Games)
	removeEmptyFiles "$STLGHEADD"  # Remove appinfo files that are 0 bytes (i.e. Non-Steam Games)

	if [ -z "$1" ]; then
		writelog "INFO" "${FUNCNAME[0]} - No arguments provided. See '$PROGCMD --help' for possible command line parameters" "E"
	else
		writelog "INFO" "${FUNCNAME[0]} - Checking command line: incoming arguments '${*}'"

		if [ -n "$SteamAppId" ] && [ "$SteamAppId" -eq "0" ]; then
			if grep -q "\"$1\"" <<< "$(sed -n "/^#STARTCMDLINE/,/^#ENDCMDLINE/p;/^#ENDCMDLINE/q" "$0" | grep if)"; then
				writelog "INFO" "${FUNCNAME[0]} - Seems like a '$PROGCMD'-internal command was started - checking the command line"
				commandline "$@"
			else
				setCustomGameVars "$@"
				if [ -n "$ISGAME" ]; then
					if [ "$ISGAME" -eq 2 ] || [ "$ISGAME" -eq 3 ]; then
						prepareLaunch
					fi
				else
					writelog "ERROR" "${FUNCNAME[0]} - Unknown command '$*'" "E"
				fi
			fi
		elif grep -q "$SAC" <<< "$@" || grep -q "$L2EA" <<< "$@"; then
			if grep -q "update" <<< "$@" || grep -q "^play" <<< "$@" ; then
				commandline "$@"
			else
				setGameVars "$@"
				if [ "$ISGAME" -eq 2 ] || [ "$ISGAME" -eq 3 ]; then
					prepareLaunch
				else
					writelog "INFO" "${FUNCNAME[0]} - Unknown parameter '${ORGGCMD[*]}'" "E"
				fi
			fi
		else
			commandline "$@"
		fi
	fi

	restoreGtkCss
}

if [ "$EUID" = 0 ]; then
	echo "'$PROGCMD' is not meant to be run as root - Exiting"
else
	main "$@"
fi
