diff options
| author | xXJSONDeruloXx <danielhimebauch@gmail.com> | 2026-05-19 11:43:14 -0400 |
|---|---|---|
| committer | xXJSONDeruloXx <danielhimebauch@gmail.com> | 2026-05-19 11:43:14 -0400 |
| commit | ef0b58b8836e6e53b0a32d569159f769853413e5 (patch) | |
| tree | e130ab8779b72e80094476322b2a912cc4e74517 | |
| parent | 94d1f366e5d7c7f8860000cce73643b2b8cfb0dd (diff) | |
| download | Decky-Framegen-fix/proxy-backup-idempotency.tar.gz Decky-Framegen-fix/proxy-backup-idempotency.zip | |
fix: preserve proxy dll backups on repatchfix/proxy-backup-idempotency
| -rwxr-xr-x | defaults/assets/fgmod-uninstaller.sh | 4 | ||||
| -rwxr-xr-x | defaults/assets/fgmod.sh | 62 | ||||
| -rw-r--r-- | main.py | 101 |
3 files changed, 144 insertions, 23 deletions
diff --git a/defaults/assets/fgmod-uninstaller.sh b/defaults/assets/fgmod-uninstaller.sh index 5e5143c..3d59eda 100755 --- a/defaults/assets/fgmod-uninstaller.sh +++ b/defaults/assets/fgmod-uninstaller.sh @@ -150,8 +150,8 @@ rm -f "dlssg_to_fsr3_amd_is_better-3.0.dll" # === Restore 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 +restorable_dlls=("dxgi.dll" "winmm.dll" "dbghelp.dll" "version.dll" "wininet.dll" "winhttp.dll" "OptiScaler.asi" "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 "${restorable_dlls[@]}"; do if [[ -f "${dll}.b" ]]; then mv "${dll}.b" "$dll" echo " Restored original $dll" diff --git a/defaults/assets/fgmod.sh b/defaults/assets/fgmod.sh index 8d0b77b..ed8aaf5 100755 --- a/defaults/assets/fgmod.sh +++ b/defaults/assets/fgmod.sh @@ -96,8 +96,66 @@ 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} +proxy_backup_files=( + "dxgi.dll" + "winmm.dll" + "dbghelp.dll" + "version.dll" + "wininet.dll" + "winhttp.dll" + "OptiScaler.asi" +) + +cleanup_files=( + "${proxy_backup_files[@]}" + "OptiScaler.dll" + "nvngx.dll" + "_nvngx.dll" + "nvngx-wrapper.dll" + "nvngx.ini" + "dlss-enabler.dll" + "dlss-enabler-upscaler.dll" + "fakenvapi.log" + "OptiScaler.log" + "dlssg_to_fsr3.log" + "dlssg_to_fsr3_amd_is_better-3.0.dll" +) + +is_bundled_proxy_copy() { + local existing_file="$1" + local bundled_copy="$fgmod_path/renames/$(basename "$existing_file")" + [[ -f "$existing_file" && -f "$bundled_copy" ]] && cmp -s "$existing_file" "$bundled_copy" +} + +has_patch_fingerprint() { + local fingerprint + for fingerprint in "FRAMEGEN_PATCH" "OptiScaler.ini" "fakenvapi.dll" "fakenvapi.ini" "dlssg_to_fsr3_amd_is_better.dll" "D3D12_Optiscaler"; do + [[ -e "$exe_folder_path/$fingerprint" ]] && return 0 + done + return 1 +} + +# === Backup Pre-existing Proxy DLLs Before Cleanup === +for dll in "${proxy_backup_files[@]}"; do + existing_path="$exe_folder_path/$dll" + backup_path="$exe_folder_path/$dll.b" + if [[ -f "$existing_path" && ! -f "$backup_path" ]]; then + if has_patch_fingerprint || is_bundled_proxy_copy "$existing_path"; then + logger -t fgmod "Skipping backup for managed/stale proxy copy: $dll" + else + mv -f "$existing_path" "$backup_path" + echo " Backed up pre-existing $dll" + logger -t fgmod "Backed up pre-existing proxy file: $dll" + fi + fi +done +unset existing_path backup_path fingerprint + +# === Cleanup Old Injectors / Legacy OptiScaler Artifacts === +for cleanup_file in "${cleanup_files[@]}"; do + rm -f "$exe_folder_path/$cleanup_file" +done +unset cleanup_file # === Optional: Backup 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") @@ -4,6 +4,7 @@ import subprocess import json import shutil import re +import filecmp from datetime import datetime, timezone from pathlib import Path @@ -11,7 +12,7 @@ from pathlib import Path # Set to False or comment out this constant to skip the overwrite by default. UPSCALER_OVERWRITE_ENABLED = True -VALID_DLL_NAMES = { +PROXY_DLL_BACKUPS = [ "dxgi.dll", "winmm.dll", "dbghelp.dll", @@ -19,11 +20,12 @@ VALID_DLL_NAMES = { "wininet.dll", "winhttp.dll", "OptiScaler.asi", -} +] + +VALID_DLL_NAMES = set(PROXY_DLL_BACKUPS) INJECTOR_FILENAMES = [ - "dxgi.dll", - "winmm.dll", + *PROXY_DLL_BACKUPS, "nvngx.dll", "_nvngx.dll", "nvngx-wrapper.dll", @@ -31,6 +33,27 @@ INJECTOR_FILENAMES = [ "OptiScaler.dll", ] +PATCH_CLEANUP_FILES = [ + *INJECTOR_FILENAMES, + "nvapi64.dll", + "nvapi64.dll.b", + "nvngx.ini", + "dlss-enabler-upscaler.dll", + "fakenvapi.log", + "OptiScaler.log", + "dlssg_to_fsr3.log", + "dlssg_to_fsr3_amd_is_better-3.0.dll", +] + +PATCH_FINGERPRINT_FILES = [ + "FRAMEGEN_PATCH", + "OptiScaler.ini", + "fakenvapi.dll", + "fakenvapi.ini", + "dlssg_to_fsr3_amd_is_better.dll", + "D3D12_Optiscaler", +] + ORIGINAL_DLL_BACKUPS = [ "d3dcompiler_47.dll", "amd_fidelityfx_dx12.dll", @@ -39,6 +62,11 @@ ORIGINAL_DLL_BACKUPS = [ "amd_fidelityfx_vk.dll", ] +RESTORABLE_BACKUP_FILES = [ + *PROXY_DLL_BACKUPS, + *ORIGINAL_DLL_BACKUPS, +] + SUPPORT_FILES = [ "libxess.dll", "libxess_dx11.dll", @@ -81,6 +109,7 @@ LEGACY_FILES = [ "dlss-enabler.dll", "dlss-enabler-upscaler.dll", "dlss-enabler.log", + "nvngx.ini", "nvngx-wrapper.dll", "_nvngx.dll", "dlssg_to_fsr3_amd_is_better-3.0.dll", @@ -157,6 +186,33 @@ class Plugin: decky.logger.error(f"Failed to copy launcher scripts: {e}") return False + def _files_match(self, file_a: Path, file_b: Path) -> bool: + try: + return file_a.exists() and file_b.exists() and filecmp.cmp(file_a, file_b, shallow=False) + except Exception: + return False + + def _is_bundled_proxy_copy(self, file_path: Path, fgmod_path: Path) -> bool: + bundled_copy = fgmod_path / "renames" / file_path.name + return self._files_match(file_path, bundled_copy) + + def _has_patch_fingerprint(self, directory: Path) -> bool: + return any((directory / filename).exists() for filename in PATCH_FINGERPRINT_FILES) + + def _backup_preexisting_proxy_files(self, directory: Path, fgmod_path: Path) -> list[str]: + backed_up: list[str] = [] + already_patched = self._has_patch_fingerprint(directory) + for filename in PROXY_DLL_BACKUPS: + source = directory / filename + backup = directory / f"{filename}.b" + if not source.exists() or backup.exists(): + continue + if already_patched or self._is_bundled_proxy_copy(source, fgmod_path): + continue + shutil.move(source, backup) + backed_up.append(filename) + return backed_up + def _migrate_optiscaler_ini(self, ini_file): """Migrate pre-v0.9-final OptiScaler.ini: replace FGType with FGInput + FGOutput. @@ -575,13 +631,24 @@ class Plugin: try: decky.logger.info(f"Manual patch started for {directory}") - removed_injectors = [] - for filename in INJECTOR_FILENAMES: + backed_up_proxies = self._backup_preexisting_proxy_files(directory, fgmod_path) + decky.logger.info( + f"Backed up pre-existing proxy files: {backed_up_proxies}" + if backed_up_proxies + else "No pre-existing proxy files required backup" + ) + + removed_patch_files = [] + for filename in dict.fromkeys(PATCH_CLEANUP_FILES): path = directory / filename if path.exists(): path.unlink() - removed_injectors.append(filename) - decky.logger.info(f"Removed injector DLLs: {removed_injectors}" if removed_injectors else "No injector DLLs found to remove") + removed_patch_files.append(filename) + decky.logger.info( + f"Removed stale patch files: {removed_patch_files}" + if removed_patch_files + else "No stale patch files found to remove" + ) backed_up_originals = [] for dll in ORIGINAL_DLL_BACKUPS: @@ -590,15 +657,11 @@ class Plugin: if source.exists() and not backup.exists(): shutil.move(source, backup) backed_up_originals.append(dll) - decky.logger.info(f"Backed up original DLLs: {backed_up_originals}" if backed_up_originals else "No original DLLs required backup") - - removed_legacy = [] - for legacy in ["nvapi64.dll", "nvapi64.dll.b"]: - legacy_path = directory / legacy - if legacy_path.exists(): - legacy_path.unlink() - removed_legacy.append(legacy) - decky.logger.info(f"Removed legacy files: {removed_legacy}" if removed_legacy else "No legacy files to remove") + decky.logger.info( + f"Backed up original game DLLs: {backed_up_originals}" + if backed_up_originals + else "No original game DLLs required backup" + ) renamed = fgmod_path / "renames" / dll_name destination_dll = directory / dll_name @@ -704,7 +767,7 @@ class Plugin: decky.logger.info(f"Removed D3D12_Optiscaler directory from {d3d12_dir}") restored_backups = [] - for dll in ORIGINAL_DLL_BACKUPS: + for dll in dict.fromkeys(RESTORABLE_BACKUP_FILES): backup = directory / f"{dll}.b" original = directory / dll if backup.exists(): @@ -1131,7 +1194,7 @@ class Plugin: if result["status"] != "success": return result - backed_up = [dll for dll in ORIGINAL_DLL_BACKUPS if (target_dir / f"{dll}.b").exists()] + backed_up = [dll for dll in dict.fromkeys(RESTORABLE_BACKUP_FILES) if (target_dir / f"{dll}.b").exists()] marker_path = target_dir / MARKER_FILENAME self._write_marker( marker_path, |
