diff options
Diffstat (limited to 'defaults')
| -rwxr-xr-x | defaults/assets/fgmod-uninstaller.sh | 54 | ||||
| -rwxr-xr-x | defaults/assets/fgmod.sh | 112 | ||||
| -rw-r--r-- | defaults/assets/update-optiscaler-config.py | 110 |
3 files changed, 224 insertions, 52 deletions
diff --git a/defaults/assets/fgmod-uninstaller.sh b/defaults/assets/fgmod-uninstaller.sh index 38abcf4..5e5143c 100755 --- a/defaults/assets/fgmod-uninstaller.sh +++ b/defaults/assets/fgmod-uninstaller.sh @@ -4,13 +4,13 @@ set -x exec > >(tee -i /tmp/fgmod-uninstaller.log) 2>&1 error_exit() { - echo "โ $1" + echo " $1" if [[ -n $STEAM_ZENITY ]]; then $STEAM_ZENITY --error --text "$1" else zenity --error --text "$1" || echo "Zenity failed to display error" fi - logger -t fgmod-uninstaller "โ ERROR: $1" + logger -t fgmod-uninstaller "ERROR: $1" exit 1 } @@ -101,66 +101,78 @@ cd "$exe_folder_path" || error_exit "Failed to change directory to $exe_folder_p # Verify current directory before proceeding [[ "$(pwd)" != "$exe_folder_path" ]] && error_exit "Unexpected working directory: $(pwd)" -logger -t fgmod-uninstaller "๐ข Uninstalling from: $exe_folder_path" +logger -t fgmod-uninstaller "Uninstalling from: $exe_folder_path" # === Remove OptiScaler Files === -echo "๐งน Removing OptiScaler files..." +echo " Removing OptiScaler files..." rm -f "OptiScaler.dll" "dxgi.dll" "winmm.dll" "dbghelp.dll" "version.dll" "wininet.dll" "winhttp.dll" "OptiScaler.asi" rm -f "OptiScaler.ini" "OptiScaler.log" # === Remove Nukem FG Mod Files === -echo "๐งน Removing Nukem FG Mod files..." +echo " Removing Nukem FG Mod files..." rm -f "dlssg_to_fsr3_amd_is_better.dll" "dlssg_to_fsr3.ini" "dlssg_to_fsr3.log" rm -f "nvapi64.dll" "fakenvapi.ini" "fakenvapi.log" # === Remove Supporting Libraries === -echo "๐งน Removing supporting libraries..." -rm -f "libxess.dll" "libxess_dx11.dll" "libxess_fg.dll" "libxell.dll" "nvngx.dll" "nvngx.ini" -rm -f "amd_fidelityfx_dx12.dll" "amd_fidelityfx_framegeneration_dx12.dll" "amd_fidelityfx_upscaler_dx12.dll" "amd_fidelityfx_vk.dll" +echo " Removing supporting libraries..." +rm -f "nvngx.dll" "nvngx.ini" +# Only remove files if backups exist (to avoid removing restored originals) +[[ -f "libxess.dll.b" ]] && rm -f "libxess.dll" +[[ -f "libxess_dx11.dll.b" ]] && rm -f "libxess_dx11.dll" +[[ -f "libxess_fg.dll.b" ]] && rm -f "libxess_fg.dll" +[[ -f "libxell.dll.b" ]] && rm -f "libxell.dll" +[[ -f "amd_fidelityfx_dx12.dll.b" ]] && rm -f "amd_fidelityfx_dx12.dll" +[[ -f "amd_fidelityfx_framegeneration_dx12.dll.b" ]] && rm -f "amd_fidelityfx_framegeneration_dx12.dll" +[[ -f "amd_fidelityfx_upscaler_dx12.dll.b" ]] && rm -f "amd_fidelityfx_upscaler_dx12.dll" +[[ -f "amd_fidelityfx_vk.dll.b" ]] && rm -f "amd_fidelityfx_vk.dll" # === Remove FG Mod Files === -echo "๐งน Removing frame generation mod files..." +echo " Removing frame generation mod files..." rm -f "dlssg_to_fsr3_amd_is_better.dll" "dlssg_to_fsr3.ini" # === Remove NVAPI Files (Current and Legacy) === -echo "๐งน Removing NVAPI files..." -rm -f "fakenvapi.dll" "fakenvapi.ini" # Current v0.9.0-pre4 approach +echo " Removing NVAPI files..." +rm -f "fakenvapi.dll" "fakenvapi.ini" # v0.9.0-final rm -f "nvapi64.dll" "nvapi64.dll.b" # Legacy cleanup for older versions and backups # === Remove ASI Plugins === -echo "๐งน Removing ASI plugins directory..." +echo " Removing ASI plugins directory..." rm -rf "plugins" +# === Remove D3D12_Optiscaler directory (required by v0.9.0-final) === +rm -rf "D3D12_Optiscaler" + # === Remove Legacy Files === -echo "๐งน Removing legacy files..." +echo " Removing legacy files..." rm -f "dlss-enabler.dll" "dlss-enabler-upscaler.dll" "dlss-enabler.log" rm -f "nvngx-wrapper.dll" "_nvngx.dll" rm -f "dlssg_to_fsr3_amd_is_better-3.0.dll" # === Restore Original DLLs === -echo "๐ Restoring original DLLs..." +echo " Restoring original DLLs..." original_dlls=("d3dcompiler_47.dll" "amd_fidelityfx_dx12.dll" "amd_fidelityfx_framegeneration_dx12.dll" "amd_fidelityfx_upscaler_dx12.dll" "amd_fidelityfx_vk.dll" "libxess.dll" "libxess_dx11.dll" "libxess_fg.dll" "libxell.dll") for dll in "${original_dlls[@]}"; do if [[ -f "${dll}.b" ]]; then mv "${dll}.b" "$dll" - echo "โ
Restored original $dll" - logger -t fgmod-uninstaller "โ
Restored original $dll" + echo " Restored original $dll" + logger -t fgmod-uninstaller "Restored original $dll" fi done # === Self-remove uninstaller === -echo "๐๏ธ Removing uninstaller..." +echo " Removing uninstaller..." rm -f "fgmod-uninstaller.sh" -echo "โ
fgmod removed from this game successfully!" -logger -t fgmod-uninstaller "โ
fgmod removed from $exe_folder_path" +echo " fgmod removed from this game successfully!" +logger -t fgmod-uninstaller "fgmod removed from $exe_folder_path" # === Execute original command if provided === if [[ $# -gt 1 ]]; then - echo "๐ Launching the game..." + echo " Launching the game..." export SteamDeck=0 export WINEDLLOVERRIDES="${WINEDLLOVERRIDES},dxgi=n,b" + exec >/dev/null 2>&1 exec "$@" else - echo "โ
Uninstallation complete. No game specified to run." + echo " Uninstallation complete. No game specified to run." fi
\ No newline at end of file diff --git a/defaults/assets/fgmod.sh b/defaults/assets/fgmod.sh index d48856d..decb981 100755 --- a/defaults/assets/fgmod.sh +++ b/defaults/assets/fgmod.sh @@ -4,13 +4,13 @@ set -x exec > >(tee -i /tmp/fgmod-install.log) 2>&1 error_exit() { - echo "โ $1" + echo " $1" if [[ -n $STEAM_ZENITY ]]; then $STEAM_ZENITY --error --text "$1" else zenity --error --text "$1" || echo "Zenity failed to display error" fi - logger -t fgmod "โ ERROR: $1" + logger -t fgmod "ERROR: $1" exit 1 } @@ -68,7 +68,7 @@ for arg in "$@"; do fi # Extract executable path from YAML - exe_path=$(grep -E '^\s*exe:' "$config_file" | sed 's/.*exe:[[:space:]]*//') + exe_path=$(grep -E '^\s*exe:' "$config_file" | sed 's/.*exe:[[:space:]]*//' ) if [[ -n "$exe_path" ]]; then exe_folder_path=$(dirname "$exe_path") @@ -89,12 +89,12 @@ if [[ -d "$exe_folder_path/Engine" ]]; then exe_folder_path=$(dirname "$ue_exe") fi -[[ ! -d "$exe_folder_path" ]] && error_exit "โ Could not resolve game directory!" -[[ ! -w "$exe_folder_path" ]] && error_exit "๐ No write permission to the game folder!" +[[ ! -d "$exe_folder_path" ]] && error_exit " Could not resolve game directory!" +[[ ! -w "$exe_folder_path" ]] && error_exit " No write permission to the game folder!" -logger -t fgmod "๐ข Target directory: $exe_folder_path" -logger -t fgmod "๐งฉ Using DLL name: $dll_name" -logger -t fgmod "๐ Preserve INI: $preserve_ini" +logger -t fgmod "Target directory: $exe_folder_path" +logger -t fgmod "Using DLL name: $dll_name" +logger -t fgmod "Preserve INI: $preserve_ini" # === Cleanup Old Injectors === rm -f "$exe_folder_path"/{dxgi.dll,winmm.dll,nvngx.dll,_nvngx.dll,nvngx-wrapper.dll,dlss-enabler.dll,OptiScaler.dll} @@ -107,34 +107,71 @@ done # === Remove nvapi64.dll and its backup (conflicts from previous fakenvapi versions) === rm -f "$exe_folder_path/nvapi64.dll" "$exe_folder_path/nvapi64.dll.b" -echo "๐งน Cleaned up nvapi64.dll and backup (legacy fakenvapi conflicts)" +echo " Cleaned up nvapi64.dll and backup (legacy fakenvapi conflicts)" # === Core Install === if [[ -f "$fgmod_path/renames/$dll_name" ]]; then - echo "โ
Using pre-renamed $dll_name" - cp "$fgmod_path/renames/$dll_name" "$exe_folder_path/$dll_name" || error_exit "โ Failed to copy $dll_name" + echo " Using pre-renamed $dll_name" + cp "$fgmod_path/renames/$dll_name" "$exe_folder_path/$dll_name" || error_exit " Failed to copy $dll_name" else - echo "โ ๏ธ Pre-renamed $dll_name not found, falling back to OptiScaler.dll" - cp "$fgmod_path/OptiScaler.dll" "$exe_folder_path/$dll_name" || error_exit "โ Failed to copy OptiScaler.dll as $dll_name" + echo " Pre-renamed $dll_name not found, falling back to OptiScaler.dll" + cp "$fgmod_path/OptiScaler.dll" "$exe_folder_path/$dll_name" || error_exit " Failed to copy OptiScaler.dll as $dll_name" fi # === OptiScaler.ini Handling === if [[ "$preserve_ini" == "true" && -f "$exe_folder_path/OptiScaler.ini" ]]; then - echo "๐ Preserving existing OptiScaler.ini (user settings retained)" - logger -t fgmod "๐ Existing OptiScaler.ini preserved in $exe_folder_path" + echo " Preserving existing OptiScaler.ini (user settings retained)" + logger -t fgmod "Existing OptiScaler.ini preserved in $exe_folder_path" else - echo "๐ Installing OptiScaler.ini from plugin defaults" - cp "$fgmod_path/OptiScaler.ini" "$exe_folder_path/OptiScaler.ini" || error_exit "โ Failed to copy OptiScaler.ini" - logger -t fgmod "๐ OptiScaler.ini installed to $exe_folder_path" + echo " Installing OptiScaler.ini from plugin defaults" + cp "$fgmod_path/OptiScaler.ini" "$exe_folder_path/OptiScaler.ini" || error_exit " Failed to copy OptiScaler.ini" + logger -t fgmod "OptiScaler.ini installed to $exe_folder_path" fi +# === OptiScaler env variables Handling === +if [[ -f "$fgmod_path/update-optiscaler-config.py" ]]; then + python "$fgmod_path/update-optiscaler-config.py" "$exe_folder_path/OptiScaler.ini" +fi + +# OptiScaler 0.9.0-pre11 can assert on Proton when HQ font auto mode tries to load +# an external TTF that is not present. Only normalize the default auto value. +sed -i 's/^UseHQFont[[:space:]]*=[[:space:]]*auto$/UseHQFont=false/' "$exe_folder_path/OptiScaler.ini" || true + +# === Migrate FGType โ FGInput/FGOutput (pre-v0.9-final INIs) === +# v0.9-final split the single FGType key into FGInput + FGOutput. Games that were +# patched with an older build will have FGType=<value> with no FGInput/FGOutput, +# causing the new DLL to silently use nofg. Fix that here on every launch. +_fgtype_ini="$exe_folder_path/OptiScaler.ini" +if grep -q '^FGType=' "$_fgtype_ini" 2>/dev/null; then + _fgtype_val=$(sed -n 's/^FGType=\(.*\)/\1/p' "$_fgtype_ini") + echo " Migrating FGType=$_fgtype_val โ FGInput/FGOutput in OptiScaler.ini" + logger -t fgmod "Migrating FGType=$_fgtype_val โ FGInput/FGOutput" + if grep -q '^FGInput=' "$_fgtype_ini"; then + # FGInput already present โ INI already in v0.9-final format; just drop FGType + sed -i '/^FGType=/d' "$_fgtype_ini" || true + else + # Replace FGType=X with FGInput=X + FGOutput=X + sed -i "s/^FGType=.*$/FGInput=$_fgtype_val\nFGOutput=$_fgtype_val/" "$_fgtype_ini" || true + fi +fi +unset _fgtype_ini _fgtype_val + # === ASI Plugins Directory === if [[ -d "$fgmod_path/plugins" ]]; then - echo "๐ Installing ASI plugins directory" + echo " Installing ASI plugins directory" cp -r "$fgmod_path/plugins" "$exe_folder_path/" || true - logger -t fgmod "๐ ASI plugins directory installed to $exe_folder_path" + logger -t fgmod "ASI plugins directory installed to $exe_folder_path" else - echo "โ ๏ธ No plugins directory found in fgmod" + echo " No plugins directory found in fgmod" +fi + +# === D3D12_Optiscaler Directory (required for FSR4/FidelityFX DX12 path) === +if [[ -d "$fgmod_path/D3D12_Optiscaler" ]]; then + echo " Installing D3D12_Optiscaler directory" + cp -r "$fgmod_path/D3D12_Optiscaler" "$exe_folder_path/" || true + logger -t fgmod "D3D12_Optiscaler directory installed to $exe_folder_path" +else + echo " No D3D12_Optiscaler directory found in fgmod" fi # === Supporting Libraries === @@ -150,27 +187,27 @@ cp -f "$fgmod_path/nvngx.dll" "$exe_folder_path/" || true # === Nukem FG Mod Files (now in fgmod directory) === cp -f "$fgmod_path/dlssg_to_fsr3_amd_is_better.dll" "$exe_folder_path/" || true -# Note: dlssg_to_fsr3.ini is not included in v0.9.0-pre4 archive +# Note: dlssg_to_fsr3.ini is not included in v0.9.0-final archive # === FakeNVAPI Files === # Remove legacy nvapi64.dll to avoid conflicts # rm -f "$exe_folder_path/nvapi64.dll" -# echo "๐งน Removed legacy nvapi64.dll" +# echo " Removed legacy nvapi64.dll" # Copy fakenvapi.dll with original name (v1.3.8.1) cp -f "$fgmod_path/fakenvapi.dll" "$exe_folder_path/" || true cp -f "$fgmod_path/fakenvapi.ini" "$exe_folder_path/" || true -echo "๐ฆ Installed fakenvapi.dll and fakenvapi.ini" +echo " Installed fakenvapi.dll and fakenvapi.ini" # === Additional Support Files === # cp -f "$fgmod_path/d3dcompiler_47.dll" "$exe_folder_path/" || true -# Note: d3dcompiler_47.dll is not included in v0.9.0-pre4 archive +# Note: d3dcompiler_47.dll is not included in v0.9.0-final archive -echo "โ
Installation completed successfully!" -echo "๐ For Steam, add this to the launch options: \"$fgmod_path/fgmod\" %COMMAND%" -echo "๐ For Heroic, add this as a new wrapper: \"$fgmod_path/fgmod\"" -logger -t fgmod "๐ข Installation completed successfully for $exe_folder_path" +echo " Installation completed successfully!" +echo " For Steam, add this to the launch options: \"$fgmod_path/fgmod\" %COMMAND%" +echo " For Heroic, add this as a new wrapper: \"$fgmod_path/fgmod\"" +logger -t fgmod "Installation completed successfully for $exe_folder_path" # === Execute original command === if [[ $# -gt 1 ]]; then @@ -186,8 +223,21 @@ if [[ $# -gt 1 ]]; then # Execute the original command export SteamDeck=0 - export WINEDLLOVERRIDES="$WINEDLLOVERRIDES,dxgi=n,b" - exec "$@" + # Build WINEDLLOVERRIDES from the actual proxy DLL name (strip extension to get the stem) + if [[ "$dll_name" == *.dll ]]; then + _wine_dll="${dll_name%.dll}" + export WINEDLLOVERRIDES="$WINEDLLOVERRIDES,${_wine_dll}=n,b" + unset _wine_dll + fi + # .asi files are loaded by an ASI loader โ no WINEDLLOVERRIDES entry needed + + # Filter out leading -- separators (from Steam launch options) + while [[ $# -gt 0 && "$1" == "--" ]]; do + shift + done + + exec >/dev/null 2>&1 + "$@" else echo "Done!" echo "----------------------------------------" diff --git a/defaults/assets/update-optiscaler-config.py b/defaults/assets/update-optiscaler-config.py new file mode 100644 index 0000000..f4a65de --- /dev/null +++ b/defaults/assets/update-optiscaler-config.py @@ -0,0 +1,110 @@ +import os +import sys +import re +from configparser import ConfigParser + +def update_optiscaler_config(file_path): + if not os.path.exists(file_path): + print(f"Error: File '{file_path}' not found.") + return + + with open(file_path, 'r') as f: + lines = f.readlines() + + config = ConfigParser() + config.optionxform = str # Preserve case for keys (otherwise PATH could match Path) + config.read(file_path) + + # Because we want to support unprefixed env variables, we need to count key occurrences across all sections of the ini file + # Keys that appear multiple times should be prefixed like Section_Key by the user for them to be targeted properly + + # Normalize section names: strip - and . so V-Sync becomes VSync + # This allows env vars like VSync_Key to match INI section [V-Sync] + def normalize_section(section_name): + return section_name.replace('-', '').replace('.', '') + + key_occurrences = {} + key_to_sections = {} + section_normalized_to_actual = {} # Maps normalized section name to actual section name + + for section in config.sections(): + normalized = normalize_section(section) + section_normalized_to_actual[normalized] = section + + for key in config.options(section): + key_occurrences[key] = key_occurrences.get(key, 0) + 1 + if key not in key_to_sections: + key_to_sections[key] = [] + key_to_sections[key].append(section) + + env_updates = [] + + # Handle OptiScaler_Section_Key format + optiscaler_vars = {k: v for k, v in os.environ.items() if k.startswith("OptiScaler_")} + for env_name, env_value in optiscaler_vars.items(): + parts = env_name.split('_', 2) + if len(parts) >= 3: + env_updates.append(('optiscaler', parts[1], parts[2], env_value, env_name)) + + # Handle Section_Key and Key formats + other_vars = {k: v for k, v in os.environ.items() if not k.startswith("OptiScaler_")} + for env_name, env_value in other_vars.items(): + # Try Section_Key format + if '_' in env_name: + parts = env_name.split('_', 1) + section_from_env = parts[0] + key = parts[1] + + # Try exact section match first + if config.has_section(section_from_env) and config.has_option(section_from_env, key): + env_updates.append(('section_key', section_from_env, key, env_value, env_name)) + continue + + # Try section match with normalized section names + if section_from_env in section_normalized_to_actual: + actual_section = section_normalized_to_actual[section_from_env] + if config.has_option(actual_section, key): + env_updates.append(('section_key', actual_section, key, env_value, env_name)) + continue + + # Try Key format (only if key appears exactly once across all sections) + if env_name in key_occurrences and key_occurrences[env_name] == 1: + section = key_to_sections[env_name][0] + env_updates.append(('key', section, env_name, env_value, env_name)) + + print(f"Found {len(env_updates)} updates to apply") + for entry in env_updates: + print(f"> {entry}") + + for update_type, section_target, key_target, env_value, env_name in env_updates: + found_section = False + + # Regex to match [Section] and Key=Value (case-sensitive) + section_pattern = re.compile(rf'^\s*\[{re.escape(section_target)}]\s*') + key_pattern = re.compile(rf'^(\s*{re.escape(key_target)}\s*)=.*') + + for i, line in enumerate(lines): + # Track if we are inside the correct section + if section_pattern.match(line): + found_section = True + continue + + # If we hit a new section before finding the key, the key doesn't exist in the target section + if found_section and line.strip().startswith('[') and not section_pattern.match(line): + break + + # Replace the value if the key is found within the correct section + if found_section and key_pattern.match(line): + lines[i] = key_pattern.sub(r'\1=' + env_value, line) + print(f"Updated: [{section_target}] {key_target} = {env_value} (from {env_name})") + break + + # Write the modified content back + with open(file_path, 'w') as f: + f.writelines(lines) + +if __name__ == "__main__": + if len(sys.argv) < 2: + print("Usage: python update-optiscaler-config.py <path_to_ini>") + else: + update_optiscaler_config(sys.argv[1])
\ No newline at end of file |
