summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKurt Himebauch <136133082+xXJSONDeruloXx@users.noreply.github.com>2025-07-17 00:28:42 -0400
committerGitHub <noreply@github.com>2025-07-17 00:28:42 -0400
commit74ac6e7b7a18c2ae969b08242a5919f903d294e2 (patch)
treee6d48b345c4933ea21a83ef6e2dc315ba9a990f3
parente905b94fe5b40b438f2ce63caad90760fea7fc9a (diff)
downloadDecky-Framegen-74ac6e7b7a18c2ae969b08242a5919f903d294e2.tar.gz
Decky-Framegen-74ac6e7b7a18c2ae969b08242a5919f903d294e2.zip
v0.10.0 initial implementation of proper optiscaler nightly statically linked (#113)
* initial implementation of proper optiscaler nightly statically linked * default ini to nukems on mod dir install * description tweaks
-rwxr-xr-xdefaults/assets/fgmod-uninstaller.sh95
-rwxr-xr-xdefaults/assets/fgmod.sh130
-rwxr-xr-xdefaults/assets/prepare.sh47
-rw-r--r--justfile11
-rw-r--r--main.py269
-rw-r--r--package.json108
-rw-r--r--plugin.json2
-rwxr-xr-xsrc/index.tsx12
8 files changed, 359 insertions, 315 deletions
diff --git a/defaults/assets/fgmod-uninstaller.sh b/defaults/assets/fgmod-uninstaller.sh
index dd5f198..93f279f 100755
--- a/defaults/assets/fgmod-uninstaller.sh
+++ b/defaults/assets/fgmod-uninstaller.sh
@@ -1,15 +1,16 @@
#!/usr/bin/env bash
-set -x # Enable debugging
-exec > >(tee -i /tmp/prepare.log) 2>&1 # Log output and errors
+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"
+ zenity --error --text "$1" || echo "Zenity failed to display error"
fi
+ logger -t fgmod-uninstaller "โŒ ERROR: $1"
exit 1
}
@@ -18,10 +19,8 @@ if [ "$#" -lt 1 ]; then
exit 1
fi
-game_path=""
-mod_path="/usr/share/fgmod"
-
-# Locate the game folder based on the first argument
+# === Resolve Game Path ===
+exe_folder_path=""
if [[ "$1" == *.exe ]]; then
exe_folder_path=$(dirname "$1")
else
@@ -44,9 +43,7 @@ else
fi
# Fallback to STEAM_COMPAT_INSTALL_PATH when no path was found
-if [[ ! -d $exe_folder_path ]] && [[ -n ${STEAM_COMPAT_INSTALL_PATH} ]]; then
- exe_folder_path=${STEAM_COMPAT_INSTALL_PATH}
-fi
+[[ -z "$exe_folder_path" && -n "$STEAM_COMPAT_INSTALL_PATH" ]] && exe_folder_path="$STEAM_COMPAT_INSTALL_PATH"
# Check for Unreal Engine game paths
if [[ -d "$exe_folder_path/Engine" ]]; then
@@ -55,51 +52,65 @@ if [[ -d "$exe_folder_path/Engine" ]]; then
fi
# Verify the game folder exists
-if [[ ! -d $exe_folder_path ]]; then
- error_exit "Unable to locate the game folder. Ensure the game is installed and the path is correct."
-fi
+[[ ! -d "$exe_folder_path" ]] && error_exit "Unable to locate the game folder: $exe_folder_path"
# Avoid operating on the uninstaller's own directory
script_dir=$(dirname "$(realpath "$0")")
-if [[ "$(realpath "$exe_folder_path")" == "$script_dir" ]]; then
- error_exit "The target directory matches the script's directory. Aborting to prevent accidental deletion."
-fi
+[[ "$(realpath "$exe_folder_path")" == "$script_dir" ]] && error_exit "The target directory matches the script's directory. Aborting to prevent accidental deletion."
# Change to the game directory
cd "$exe_folder_path" || error_exit "Failed to change directory to $exe_folder_path"
# Verify current directory before proceeding
-if [[ "$(pwd)" != "$exe_folder_path" ]]; then
- error_exit "Unexpected working directory: $(pwd)"
-fi
-
-# Log the resolved exe_folder_path for debugging
-echo "Resolved exe_folder_path: $exe_folder_path" >> /tmp/fgmod-uninstaller.log
-
-# Perform uninstallation
-rm -f "dlss-enabler.dll" "dxgi.dll" "nvngx-wrapper.dll" "_nvngx.dll"
-rm -f "dlssg_to_fsr3_amd_is_better.dll" "dlssg_to_fsr3_amd_is_better-3.0.dll"
-rm -f "dlss-enabler-upscaler.dll" "nvngx.ini"
-rm -f "d3dcompiler_47.dll" "amd_fidelityfx_dx12.dll" "amd_fidelityfx_vk.dll"
-rm -f "nvapi64.dll" "fakenvapi.ini" "OptiScaler.log"
-rm -f "dlss-enabler.log" "dlssg_to_fsr3.log" "fakenvapi.log"
-
-# Restore original DLLs if they exist
-mv -f "libxess.dll.b" "libxess.dll" 2>/dev/null # keeping this for legacy patched games to successfully revert changes with newer builds of plugin
-mv -f "d3dcompiler_47.dll.b" "d3dcompiler_47.dll" 2>/dev/null
-mv -f "amd_fidelityfx_dx12.dll.b" "amd_fidelityfx_dx12.dll" 2>/dev/null
-mv -f "amd_fidelityfx_vk.dll.b" "amd_fidelityfx_vk.dll" 2>/dev/null
+[[ "$(pwd)" != "$exe_folder_path" ]] && error_exit "Unexpected working directory: $(pwd)"
+
+logger -t fgmod-uninstaller "๐ŸŸข Uninstalling from: $exe_folder_path"
+
+# === Remove 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..."
+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"
+rm -f "amdxcffx64.dll"
+
+# === Remove Supporting Libraries ===
+echo "๐Ÿงน Removing supporting libraries..."
+rm -f "libxess.dll" "nvngx.dll" "nvngx.ini"
+
+# === Remove 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..."
+original_dlls=("d3dcompiler_47.dll" "amd_fidelityfx_dx12.dll" "amd_fidelityfx_vk.dll" "nvapi64.dll" "amdxcffx64.dll" "libxess.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"
+ fi
+done
-# Self-remove uninstaller (now optional for safety)
-echo "Uninstaller self-removal skipped for safety. Remove manually if needed."
+# === Self-remove uninstaller ===
+echo "๐Ÿ—‘๏ธ Removing uninstaller..."
+rm -f "fgmod-uninstaller.sh"
-echo "fgmod removed from this game."
+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 "$@"
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 026d546..134ded0 100755
--- a/defaults/assets/fgmod.sh
+++ b/defaults/assets/fgmod.sh
@@ -1,42 +1,41 @@
#!/usr/bin/env bash
-set -x # Enable debugging
-exec > >(tee -i /tmp/prepare.log) 2>&1 # Log output and errors
+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"
+ zenity --error --text "$1" || echo "Zenity failed to display error"
fi
+ logger -t fgmod "โŒ ERROR: $1"
exit 1
}
-mod_path="/usr/share/fgmod"
+# === CONFIG ===
+fgmod_path="$HOME/fgmod"
+dll_name="${DLL:-dxgi.dll}"
+preserve_ini="${PRESERVE_INI:-true}"
-if [ "$#" -lt 1 ]; then
- echo "Usage: $0 program [program_arguments...]"
- exit 1
+# === Resolve Game Path ===
+if [[ "$#" -lt 1 ]]; then
+ error_exit "Usage: $0 program [program_arguments...]"
fi
-# One arg means the command is ran standalone
+exe_folder_path=""
if [[ $# -eq 1 ]]; then
- if [[ "$1" == *.exe ]]; then
- exe_folder_path=$(dirname "$1")
- else
- exe_folder_path=$1
- fi
+ [[ "$1" == *.exe ]] && exe_folder_path=$(dirname "$1") || exe_folder_path="$1"
else
for arg in "$@"; do
if [[ "$arg" == *.exe ]]; then
- # Special cases, only FG-supported games
[[ "$arg" == *"Cyberpunk 2077"* ]] && arg=${arg//REDprelauncher.exe/bin/x64/Cyberpunk2077.exe}
[[ "$arg" == *"Witcher 3"* ]] && arg=${arg//REDprelauncher.exe/bin/x64_dx12/witcher3.exe}
[[ "$arg" == *"HITMAN 3"* ]] && arg=${arg//Launcher.exe/Retail/HITMAN3.exe}
[[ "$arg" == *"HITMAN World of Assassination"* ]] && arg=${arg//Launcher.exe/Retail/HITMAN3.exe}
- [[ "$arg" == *"SYNCED"* ]] && arg=${arg//Launcher\/sop_launcher.exe/SYNCED.exe} # UE with a launcher
- [[ "$arg" == *"2KLauncher"* ]] && arg=${arg//2KLauncher\/LauncherPatcher.exe/DoesntMatter.exe} # 2K launcher games
+ [[ "$arg" == *"SYNCED"* ]] && arg=${arg//Launcher\/sop_launcher.exe/SYNCED.exe}
+ [[ "$arg" == *"2KLauncher"* ]] && arg=${arg//2KLauncher\/LauncherPatcher.exe/DoesntMatter.exe}
[[ "$arg" == *"Warhammer 40,000 DARKTIDE"* ]] && arg=${arg//launcher\/Launcher.exe/binaries/Darktide.exe}
[[ "$arg" == *"Warhammer Vermintide 2"* ]] && arg=${arg//launcher\/Launcher.exe/binaries_dx12/vermintide2_dx12.exe}
[[ "$arg" == *"Satisfactory"* ]] && arg=${arg//FactoryGameSteam.exe/Engine/Binaries/Win64/FactoryGameSteam-Win64-Shipping.exe}
@@ -46,65 +45,70 @@ else
done
fi
-# Fallback to STEAM_COMPAT_INSTALL_PATH when no path was found
-if [[ ! -d $exe_folder_path ]] && [[ -n ${STEAM_COMPAT_INSTALL_PATH} ]]; then
- echo "Trying the path from STEAM_COMPAT_INSTALL_PATH"
- exe_folder_path=${STEAM_COMPAT_INSTALL_PATH}
-fi
+[[ -z "$exe_folder_path" && -n "$STEAM_COMPAT_INSTALL_PATH" ]] && exe_folder_path="$STEAM_COMPAT_INSTALL_PATH"
-# Check for UE games
if [[ -d "$exe_folder_path/Engine" ]]; then
- ue_exe_path=$(find "$exe_folder_path" -maxdepth 4 -mindepth 4 -path "*Binaries/Win64/*.exe" -not -path "*/Engine/*" | head -1)
- exe_folder_path=$(dirname "$ue_exe_path")
+ ue_exe=$(find "$exe_folder_path" -maxdepth 4 -mindepth 4 -path "*Binaries/Win64/*.exe" -not -path "*/Engine/*" | head -1)
+ exe_folder_path=$(dirname "$ue_exe")
fi
-if [[ -d $exe_folder_path ]]; then
- if [[ ! -w $exe_folder_path ]]; then
- error_exit "No write permission to the game folder!"
- 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!"
- original_dlls=("d3dcompiler_47.dll" "amd_fidelityfx_dx12.dll" "amd_fidelityfx_vk.dll")
+logger -t fgmod "๐ŸŸข Target directory: $exe_folder_path"
+logger -t fgmod "๐Ÿงฉ Using DLL name: $dll_name"
+logger -t fgmod "๐Ÿ“„ Preserve INI: $preserve_ini"
- # Assume that the mod is not installed when dlss-enabler.dll is not present
- if [[ ! -f "$exe_folder_path/dlss-enabler.dll" ]]; then
- [[ -f "$exe_folder_path/dxgi.dll" ]] && error_exit 'dxgi.dll is already present in the game folder!\nThis script uses dxgi.dll to load required files.\nRemove the mod using dxgi.dll or install DLSS Enabler manually.'
- for dll in "${original_dlls[@]}"; do
- if [[ ! -f "$exe_folder_path/${dll}.b" ]]; then
- mv -f "$exe_folder_path/$dll" "$exe_folder_path/${dll}.b" 2>/dev/null
- fi
- done
- fi
+# === Cleanup Old Injectors ===
+rm -f "$exe_folder_path"/{dxgi.dll,winmm.dll,nvngx.dll,_nvngx.dll,nvngx-wrapper.dll,dlss-enabler.dll,OptiScaler.dll}
- cp -f "$mod_path/fgmod-uninstaller.sh" "$exe_folder_path" ||
- error_exit "Couldn't copy the uninstaller!"
+# === Optional: Backup Original DLLs ===
+original_dlls=("d3dcompiler_47.dll" "amd_fidelityfx_dx12.dll" "amd_fidelityfx_vk.dll" "nvapi64.dll" "amdxcffx64.dll")
+for dll in "${original_dlls[@]}"; do
+ [[ -f "$exe_folder_path/$dll" && ! -f "$exe_folder_path/$dll.b" ]] && mv -f "$exe_folder_path/$dll" "$exe_folder_path/$dll.b"
+done
- cp -f "$mod_path/dlss-enabler.dll" "$exe_folder_path" &&
- cp -f "$mod_path/dxgi.dll" "$exe_folder_path" &&
- cp -f "$mod_path/nvngx-wrapper.dll" "$exe_folder_path" ||
- error_exit "Couldn't copy DLSS Enabler files!"
+# === 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"
+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"
+fi
- # File is not preset on Nvidia installs so will fail on some setups on purpose
- cp -f "$mod_path/nvapi64.dll" "$exe_folder_path" 2>/dev/null
+# === 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"
+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"
+fi
- cp -f "$mod_path/_nvngx.dll" "$exe_folder_path" ||
- error_exit "Couldn't copy _nvngx.dll!"
+# === Supporting Libraries ===
+cp -f "$fgmod_path/libxess.dll" "$exe_folder_path/" || true
+cp -f "$fgmod_path/amd_fidelityfx_dx12.dll" "$exe_folder_path/" || true
+cp -f "$fgmod_path/amd_fidelityfx_vk.dll" "$exe_folder_path/" || true
+cp -f "$fgmod_path/nvngx.dll" "$exe_folder_path/" || true
- cp -f "$mod_path/dlssg_to_fsr3_amd_is_better.dll" "$exe_folder_path" &&
- cp -f "$mod_path/dlssg_to_fsr3_amd_is_better-3.0.dll" "$exe_folder_path" ||
- error_exit "Couldn't copy dlssg-to-fsr3!"
+# === Nukem FG Mod Files (now in fgmod directory) ===
+cp -f "$fgmod_path/dlssg_to_fsr3_amd_is_better.dll" "$exe_folder_path/" || true
+cp -f "$fgmod_path/dlssg_to_fsr3.ini" "$exe_folder_path/" || true
+cp -f "$fgmod_path/nvapi64.dll" "$exe_folder_path/" || true
+cp -f "$fgmod_path/fakenvapi.ini" "$exe_folder_path/" || true
+cp -f "$fgmod_path/amdxcffx64.dll" "$exe_folder_path/" || true
- cp -f "$mod_path/dlss-enabler-upscaler.dll" "$exe_folder_path" &&
- cp -f "$mod_path/amd_fidelityfx_dx12.dll" "$exe_folder_path" &&
- cp -f "$mod_path/amd_fidelityfx_vk.dll" "$exe_folder_path" &&
- cp -f "$mod_path/d3dcompiler_47.dll" "$exe_folder_path" ||
- error_exit "Couldn't copy Optiscaler files!"
+# === Additional Support Files ===
+cp -f "$fgmod_path/d3dcompiler_47.dll" "$exe_folder_path/" || true
- cp -n "$mod_path/nvngx.ini" "$exe_folder_path"
- cp -n "$mod_path/fakenvapi.ini" "$exe_folder_path"
-else
- error_exit "Path doesn't exist!"
-fi
+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
# Log to both file and system journal
logger -t fgmod "=================="
@@ -119,7 +123,7 @@ if [[ $# -gt 1 ]]; then
# Execute the original command
export SteamDeck=0
export WINEDLLOVERRIDES="$WINEDLLOVERRIDES,dxgi=n,b"
- "$@"
+ exec "$@"
else
echo "Done!"
echo "----------------------------------------"
diff --git a/defaults/assets/prepare.sh b/defaults/assets/prepare.sh
deleted file mode 100755
index 65f92e1..0000000
--- a/defaults/assets/prepare.sh
+++ /dev/null
@@ -1,47 +0,0 @@
-#!/usr/bin/env bash
-
-set -x # Enable debugging
-exec > >(tee -i /tmp/prepare.log) 2>&1 # Log output and errors
-
-mod_path="$HOME/fgmod"
-bin_path="$(dirname "$(realpath "$0")")/../bin"
-assets_path="$(dirname "$(realpath "$0")")"
-
-standalone=1
-
-if [[ -d "$mod_path" ]] && [[ ! $mod_path == . ]]; then
- rm -r "$mod_path"
-fi
-
-mkdir -p "$mod_path"
-cd "$mod_path" || exit 1
-
-# Copy all files from bin directory into the current directory
-cp "$bin_path"/* .
-
-# # Unzip assets.zip so that all files are in the modpath root, then remove the zip file
-# unzip -j -o assets.zip && rm assets.zip
-
-# Copy fgmod.sh and fgmod-uninstaller.sh from defaults/assets
-# cp "$assets_path/fgmod.sh" "$mod_path/fgmod" || exit 1
-# cp "$assets_path/fgmod-uninstaller.sh" "$mod_path" || exit 1
-
-# Update paths in scripts
-sed -i 's|mod_path="/usr/share/fgmod"|mod_path="'"$mod_path"'"|g' fgmod
-chmod +x fgmod
-
-sed -i 's|mod_path="/usr/share/fgmod"|mod_path="'"$mod_path"'"|g' fgmod-uninstaller.sh
-chmod +x fgmod-uninstaller.sh
-
-echo ""
-
-# Flatpak compatibility
-if flatpak list | grep "com.valvesoftware.Steam" 1>/dev/null; then
- echo "Flatpak version of Steam detected, adding access to fgmod's folder"
- echo "Please restart Steam!"
- flatpak override --user --filesystem="$mod_path" com.valvesoftware.Steam
-fi
-
-echo "For Steam, add this to the launch options: \"$mod_path/fgmod\" %COMMAND%"
-echo "For Heroic, add this as a new wrapper: \"$mod_path/fgmod\""
-echo "All done!" \ No newline at end of file
diff --git a/justfile b/justfile
new file mode 100644
index 0000000..07aa118
--- /dev/null
+++ b/justfile
@@ -0,0 +1,11 @@
+default:
+ echo "Available recipes: build, test, clean"
+
+build:
+ rm -rf node_modules && .vscode/build.sh
+
+test:
+ scp "/Users/kurt/Developer/FG-plugins/Decky-Framegen/out/Decky-Framegen.zip" deck@192.168.0.6:~/Desktop
+
+clean:
+ rm -rf node_modules dist \ No newline at end of file
diff --git a/main.py b/main.py
index 39aaf71..12aa702 100644
--- a/main.py
+++ b/main.py
@@ -2,6 +2,8 @@ import decky # Old-style Decky import
import os
import subprocess
import json
+import shutil
+import re
from pathlib import Path
class Plugin:
@@ -11,84 +13,240 @@ class Plugin:
async def _unload(self):
decky.logger.info("Framegen plugin unloaded.")
- async def run_uninstall_fgmod(self) -> dict:
+ async def extract_static_optiscaler(self) -> dict:
+ """Extract OptiScaler from the plugin's bin directory."""
try:
- result = subprocess.run(
- ["/bin/bash", Path(decky.DECKY_PLUGIN_DIR) / "assets" / "fgmod-remover.sh"],
+ # Set up paths
+ bin_path = Path(decky.DECKY_PLUGIN_DIR) / "bin"
+ extract_path = Path(decky.HOME) / "fgmod"
+
+ # Find the OptiScaler archive in the bin directory
+ optiscaler_archive = None
+ for file in bin_path.glob("*.7z"):
+ if "OptiScaler" in file.name:
+ optiscaler_archive = file
+ break
+
+ if not optiscaler_archive:
+ return {"status": "error", "message": "OptiScaler archive not found in plugin bin directory"}
+
+ # Clean up existing directory
+ if extract_path.exists():
+ shutil.rmtree(extract_path)
+
+ extract_path.mkdir(exist_ok=True)
+
+ decky.logger.info(f"Extracting {optiscaler_archive.name} to {extract_path}")
+
+ # Extract the 7z file
+ extract_cmd = [
+ "7z",
+ "x",
+ "-y",
+ "-o" + str(extract_path),
+ str(optiscaler_archive)
+ ]
+
+ extract_result = subprocess.run(
+ extract_cmd,
capture_output=True,
text=True,
- check=True
+ check=False
)
- return {"status": "success", "output": result.stdout}
- except subprocess.CalledProcessError as e:
- decky.logger.error(e.output)
- return {"status": "error", "message": str(e), "output": e.output}
-
- async def run_install_fgmod(self) -> dict:
- try:
- assets_dir = Path(decky.DECKY_PLUGIN_DIR) / "assets"
- prepare_script = assets_dir / "prepare.sh"
-
- if not prepare_script.exists():
- decky.logger.error(f"prepare.sh not found: {prepare_script}")
+
+ if extract_result.returncode != 0:
+ decky.logger.error(f"Extraction failed: {extract_result.stderr}")
return {
"status": "error",
- "message": f"prepare.sh not found in plugin assets."
+ "message": f"Failed to extract OptiScaler archive: {extract_result.stderr}"
}
+
+ # Create renamed copies of OptiScaler.dll
+ try:
+ renames_dir = extract_path / "renames"
+ renames_dir.mkdir(exist_ok=True)
+
+ source_file = extract_path / "OptiScaler.dll"
+
+ rename_files = [
+ "dxgi.dll",
+ "winmm.dll",
+ "dbghelp.dll",
+ "version.dll",
+ "wininet.dll",
+ "winhttp.dll",
+ "OptiScaler.asi"
+ ]
+
+ if source_file.exists():
+ for rename_file in rename_files:
+ dest_file = renames_dir / rename_file
+ shutil.copy2(source_file, dest_file)
+ decky.logger.info(f"Created renamed copy: {dest_file}")
+ else:
+ decky.logger.error(f"Source file {source_file} does not exist")
+
+ except Exception as e:
+ decky.logger.error(f"Failed to create renamed copies: {e}")
+
+ # Copy launcher scripts from assets
+ try:
+ assets_dir = Path(decky.DECKY_PLUGIN_DIR) / "assets"
+
+ # Copy fgmod script
+ fgmod_script_src = assets_dir / "fgmod.sh"
+ fgmod_script_dest = extract_path / "fgmod"
+ if fgmod_script_src.exists():
+ shutil.copy2(fgmod_script_src, fgmod_script_dest)
+ fgmod_script_dest.chmod(0o755)
+ decky.logger.info(f"Copied fgmod script to {fgmod_script_dest}")
+
+ # Copy uninstaller script
+ uninstaller_src = assets_dir / "fgmod-uninstaller.sh"
+ uninstaller_dest = extract_path / "fgmod-uninstaller.sh"
+ if uninstaller_src.exists():
+ shutil.copy2(uninstaller_src, uninstaller_dest)
+ uninstaller_dest.chmod(0o755)
+ decky.logger.info(f"Copied uninstaller script to {uninstaller_dest}")
+
+ except Exception as e:
+ decky.logger.error(f"Failed to copy launcher scripts: {e}")
+
+ # Extract version from filename
+ version_match = optiscaler_archive.name.replace('.7z', '')
+ if '_v' in version_match:
+ version = 'v' + version_match.split('_v')[1]
+ else:
+ version = version_match
+
+ # Create version file
+ version_file = extract_path / "version.txt"
+ try:
+ with open(version_file, 'w') as f:
+ f.write(version)
+ decky.logger.info(f"Created version file: {version}")
+ except Exception as e:
+ decky.logger.error(f"Failed to create version file: {e}")
+
+ # Modify OptiScaler.ini to set FGType=nukems
+ try:
+ ini_file = extract_path / "OptiScaler.ini"
+ if ini_file.exists():
+ with open(ini_file, 'r') as f:
+ content = f.read()
+
+ # Replace FGType=auto with FGType=nukems
+ updated_content = re.sub(r'FGType\s*=\s*auto', 'FGType=nukems', content)
+
+ with open(ini_file, 'w') as f:
+ f.write(updated_content)
+
+ decky.logger.info("Modified OptiScaler.ini to set FGType=nukems")
+ else:
+ decky.logger.warning(f"OptiScaler.ini not found at {ini_file}")
+ except Exception as e:
+ decky.logger.error(f"Failed to modify OptiScaler.ini: {e}")
+
+ return {
+ "status": "success",
+ "message": f"Successfully extracted OptiScaler {version} to ~/fgmod",
+ "version": version
+ }
+
+ except Exception as e:
+ decky.logger.error(f"Extract failed: {str(e)}")
+ return {"status": "error", "message": f"Extract failed: {str(e)}"}
- # Ensure prepare.sh has execution permissions
- prepare_script.chmod(0o755)
-
- # Run prepare.sh directly from the plugin's assets folder
- process = subprocess.run(
- ["/bin/bash", str(prepare_script)],
- cwd=str(assets_dir), # Run in assets directory to use correct paths
- capture_output=True,
- text=True,
- timeout=300
- )
-
- decky.logger.info(f"Script output:\n{process.stdout}")
- decky.logger.error(f"Script errors:\n{process.stderr}")
+ async def run_uninstall_fgmod(self) -> dict:
+ try:
+ # Remove fgmod directory
+ fgmod_path = Path(decky.HOME) / "fgmod"
+
+ if fgmod_path.exists():
+ shutil.rmtree(fgmod_path)
+ decky.logger.info(f"Removed directory: {fgmod_path}")
+ return {
+ "status": "success",
+ "output": "Successfully removed fgmod directory"
+ }
+ else:
+ return {
+ "status": "success",
+ "output": "No fgmod directory found to remove"
+ }
+
+ except Exception as e:
+ decky.logger.error(f"Uninstall error: {str(e)}")
+ return {
+ "status": "error",
+ "message": f"Uninstall failed: {str(e)}",
+ "output": str(e)
+ }
- if "All done!" not in process.stdout:
- decky.logger.error("Installation did not complete successfully")
+ async def run_install_fgmod(self) -> dict:
+ try:
+ decky.logger.info("Starting OptiScaler installation from static bundle")
+
+ # Extract the static OptiScaler bundle
+ extract_result = await self.extract_static_optiscaler()
+
+ if extract_result["status"] != "success":
return {
"status": "error",
- "message": process.stdout + process.stderr
+ "message": f"OptiScaler extraction failed: {extract_result.get('message', 'Unknown error')}"
}
-
+
+ # Handle Flatpak compatibility
+ try:
+ fgmod_path = Path(decky.HOME) / "fgmod"
+
+ # Check if Flatpak Steam is installed
+ flatpak_check = subprocess.run(
+ ["flatpak", "list"],
+ capture_output=True,
+ text=True,
+ check=False
+ )
+
+ if flatpak_check.returncode == 0 and "com.valvesoftware.Steam" in flatpak_check.stdout:
+ decky.logger.info("Flatpak Steam detected, adding filesystem access")
+
+ subprocess.run([
+ "flatpak", "override", "--user",
+ f"--filesystem={fgmod_path}",
+ "com.valvesoftware.Steam"
+ ], check=False)
+
+ decky.logger.info("Added Flatpak filesystem access")
+
+ except Exception as e:
+ decky.logger.warning(f"Flatpak setup had issues (this is OK): {e}")
+
return {
"status": "success",
- "output": "You can now replace DLSS with FSR Frame Gen!"
+ "output": "Successfully installed OptiScaler with all necessary components! You can now replace DLSS with FSR Frame Gen!"
}
- except subprocess.TimeoutExpired:
- decky.logger.error("Installation script timed out")
- return {
- "status": "error",
- "message": "Installation timed out"
- }
- except subprocess.CalledProcessError as e:
- decky.logger.error(f"Script error: {e.stderr}")
- return {
- "status": "error",
- "message": e.stderr
- }
except Exception as e:
- decky.logger.error(f"Unexpected error: {str(e)}")
+ decky.logger.error(f"Unexpected error during installation: {str(e)}")
return {
"status": "error",
- "message": str(e)
+ "message": f"Installation failed: {str(e)}"
}
async def check_fgmod_path(self) -> dict:
path = Path(decky.HOME) / "fgmod"
required_files = [
- "amd_fidelityfx_dx12.dll", "amd_fidelityfx_vk.dll", "d3dcompiler_47.dll", "DisableNvidiaSignatureChecks.reg",
- "dlss-enabler.dll", "dlss-enabler-upscaler.dll", "dlssg_to_fsr3_amd_is_better-3.0.dll", "dlssg_to_fsr3_amd_is_better.dll",
- "dlssg_to_fsr3.ini", "dxgi.dll", "dxvk.conf", "fakenvapi.ini", "fgmod", "fgmod-uninstaller.sh",
- "libxess.dll", "nvapi64.dll", "nvngx.ini", "nvngx-wrapper.dll", "_nvngx.dll", "RestoreNvidiaSignatureChecks.reg"
+ "OptiScaler.dll",
+ "dlssg_to_fsr3_amd_is_better.dll",
+ "fakenvapi.ini",
+ "nvapi64.dll",
+ "amdxcffx64.dll",
+ "amd_fidelityfx_dx12.dll",
+ "amd_fidelityfx_vk.dll",
+ "libxess.dll",
+ "fgmod",
+ "fgmod-uninstaller.sh"
]
if path.exists():
@@ -103,6 +261,7 @@ class Plugin:
try:
steam_root = Path(decky.HOME) / ".steam" / "steam"
library_file = Path(steam_root) / "steamapps" / "libraryfolders.vdf"
+
if not library_file.exists():
return {"status": "error", "message": "libraryfolders.vdf not found"}
@@ -121,7 +280,7 @@ class Plugin:
continue
for appmanifest in steamapps_path.glob("appmanifest_*.acf"):
- game_info = {"appid": None, "name": None}
+ game_info = {"appid": "", "name": ""}
try:
with open(appmanifest, "r", encoding="utf-8") as file:
diff --git a/package.json b/package.json
index 1d9c1d9..6d7f0d2 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "decky-framegen",
- "version": "0.9.1",
- "description": "plugin to swap DLSS with FSR, to enable upscaling and framegen in games without built in FSR.",
+ "version": "0.10.0",
+ "description": "plugin to install OptiScaler bleeding-edge and enable upscaling and framegen in a large variety of games.",
"type": "module",
"scripts": {
"build": "rollup -c",
@@ -49,108 +49,14 @@
]
}
},
- "remote_binary_bundling" : false,
+ "remote_binary_bundling" : true,
"remote_binary":
[
{
- "name": "DisableNvidiaSignatureChecks.reg",
- "url": "https://github.com/xXJSONDeruloXx/Decky-Framegen/releases/download/binaries-DLSS-Enabler-3.02-Stable/DisableNvidiaSignatureChecks.reg",
- "sha256hash": "0db810f38303fc82b6fbd0cebd7f073bf0271d3bc5f065b7584598c4eda670f7"
- },
- {
- "name": "RestoreNvidiaSignatureChecks.reg",
- "url": "https://github.com/xXJSONDeruloXx/Decky-Framegen/releases/download/binaries-DLSS-Enabler-3.02-Stable/RestoreNvidiaSignatureChecks.reg",
- "sha256hash": "c096400b3106fcab37ac98fd33f8c7483af0f85b118d16133ee268aa122ddc68"
- },
- {
- "name": "_nvngx.dll",
- "url": "https://github.com/xXJSONDeruloXx/Decky-Framegen/releases/download/binaries-DLSS-Enabler-3.02-Stable/_nvngx.dll",
- "sha256hash": "52a68acc4e477eeff598b5ca01f26215dc5aa487c8f150b02c27ad099c11de0b"
- },
- {
- "name": "amd_fidelityfx_dx12.dll",
- "url": "https://github.com/xXJSONDeruloXx/Decky-Framegen/releases/download/binaries-DLSS-Enabler-3.02-Stable/amd_fidelityfx_dx12.dll",
- "sha256hash": "77809405a0ff464b63654f1264f0ec0fcf8f243dac7c15b5f5c032615520d143"
- },
- {
- "name": "amd_fidelityfx_vk.dll",
- "url": "https://github.com/xXJSONDeruloXx/Decky-Framegen/releases/download/binaries-DLSS-Enabler-3.02-Stable/amd_fidelityfx_vk.dll",
- "sha256hash": "29d6c8c5088f6442f915d4b895dfffe09a2b5f0f1d36ab46b59d6b08c8a37b05"
- },
- {
- "name": "d3dcompiler_47.dll",
- "url": "https://github.com/xXJSONDeruloXx/Decky-Framegen/releases/download/binaries-DLSS-Enabler-3.02-Stable/d3dcompiler_47.dll",
- "sha256hash": "4432bbd1a390874f3f0a503d45cc48d346abc3a8c0213c289f4b615bf0ee84f3"
- },
- {
- "name": "dlss-enabler-upscaler.dll",
- "url": "https://github.com/xXJSONDeruloXx/Decky-Framegen/releases/download/binaries-DLSS-Enabler-3.02-Stable/dlss-enabler-upscaler.dll",
- "sha256hash": "9449350177f64b9be5a97440417b4c8c4b5c648a4ab41b057cad17134fe4b401"
- },
- {
- "name": "dlss-enabler.dll",
- "url": "https://github.com/xXJSONDeruloXx/Decky-Framegen/releases/download/binaries-DLSS-Enabler-3.02-Stable/dlss-enabler.dll",
- "sha256hash": "00a880facebf5380cd9630f259fc28dd5e6f17875cdced958a2c3e38bed51b4e"
- },
- {
- "name": "dlssg_to_fsr3.ini",
- "url": "https://github.com/xXJSONDeruloXx/Decky-Framegen/releases/download/binaries-DLSS-Enabler-3.02-Stable/dlssg_to_fsr3.ini",
- "sha256hash": "30bd3c459e4db2159db0fd5f22d42a049153bab86ece7fad2febef145181ecbf"
- },
- {
- "name": "dlssg_to_fsr3_amd_is_better-3.0.dll",
- "url": "https://github.com/xXJSONDeruloXx/Decky-Framegen/releases/download/binaries-DLSS-Enabler-3.02-Stable/dlssg_to_fsr3_amd_is_better-3.0.dll",
- "sha256hash": "ce794bd6489068bd316e38aceb6db323766a2172ecada0e868913526c8c06ab0"
- },
- {
- "name": "dlssg_to_fsr3_amd_is_better.dll",
- "url": "https://github.com/xXJSONDeruloXx/Decky-Framegen/releases/download/binaries-DLSS-Enabler-3.02-Stable/dlssg_to_fsr3_amd_is_better.dll",
- "sha256hash": "bc0255ca9de9fe760fec38d91a6793b4ceb45684385a5085306edb8e74ae174d"
- },
- {
- "name": "dxgi.dll",
- "url": "https://github.com/xXJSONDeruloXx/Decky-Framegen/releases/download/binaries-DLSS-Enabler-3.02-Stable/dxgi.dll",
- "sha256hash": "9ae73670c5dbb80f40d98176cb4426992f0cb0b9d0143b1d8083838d03b7d6fc"
- },
- {
- "name": "dxvk.conf",
- "url": "https://github.com/xXJSONDeruloXx/Decky-Framegen/releases/download/binaries-DLSS-Enabler-3.02-Stable/dxvk.conf",
- "sha256hash": "fb4b28b38fa5d36e95f76498416f7875815e94d2914878b70599cd6d87a98e12"
- },
- {
- "name": "fakenvapi.ini",
- "url": "https://github.com/xXJSONDeruloXx/Decky-Framegen/releases/download/binaries-DLSS-Enabler-3.02-Stable/fakenvapi.ini",
- "sha256hash": "672d65665cddb21a10b525daa987179871ddf97f328861a3e4b6a76671457e28"
- },
- {
- "name": "fgmod",
- "url": "https://github.com/xXJSONDeruloXx/Decky-Framegen/releases/download/binaries-DLSS-Enabler-3.02-Stable/fgmod",
- "sha256hash": "70bcf240e160cf5f75f861e40032cbc788889fd81bf3ca836466b8be1e561d58"
- },
- {
- "name": "libxess.dll",
- "url": "https://github.com/xXJSONDeruloXx/Decky-Framegen/releases/download/binaries-DLSS-Enabler-3.02-Stable/libxess.dll",
- "sha256hash": "703ab8debc05ae209f6e4622cc06edf9f95a241f7ce68ee75c8955564d36ad70"
- },
- {
- "name": "nvapi64.dll",
- "url": "https://github.com/xXJSONDeruloXx/Decky-Framegen/releases/download/binaries-DLSS-Enabler-3.02-Stable/nvapi64.dll",
- "sha256hash": "8c9d602442d291a6c51db7cdd9f79a0617de5742af42a56fcb918e4f9ca3ba52"
- },
- {
- "name": "nvngx-wrapper.dll",
- "url": "https://github.com/xXJSONDeruloXx/Decky-Framegen/releases/download/binaries-DLSS-Enabler-3.02-Stable/nvngx-wrapper.dll",
- "sha256hash": "6bb7f36f7dc3fffd588f2c6d2341c13f2a690ade0a7ef6c74ccdb2387cd5952e"
- },
- {
- "name": "nvngx.ini",
- "url": "https://github.com/xXJSONDeruloXx/Decky-Framegen/releases/download/binaries-DLSS-Enabler-3.02-Stable/nvngx.ini",
- "sha256hash": "3e083428c87054235aedb61cb4cc5afa1716a540146b978ddcd3ce2d590292a8"
- },
- {
- "name": "fgmod-uninstaller.sh",
- "url": "https://github.com/xXJSONDeruloXx/Decky-Framegen/releases/download/binaries-DLSS-Enabler-3.02-Stable/fgmod-uninstaller.sh",
- "sha256hash": "6a61ee21f587ad1976522a36adfa610140f2b486fbc812ca334b55ce50fcd395"
+ "sha256hash": "e902c99be8a2501fac8ba636f79ed681964367a104e7e2e441d4bf4f894b2879",
+ "name": "BUNDLED_OptiScaler_v0.7.7-pre12_20250702.7z",
+ "url": "https://github.com/xXJSONDeruloXx/OptiScaler-Bleeding-Edge/releases/download/OptiScaler_v0.7.7-pre12_20250702_unsigned_dll-20250704-021155/BUNDLED_OptiScaler_v0.7.7-pre12_20250702.7z",
+ "size": 60721676
}
]
}
diff --git a/plugin.json b/plugin.json
index 426f835..125d5ad 100644
--- a/plugin.json
+++ b/plugin.json
@@ -5,7 +5,7 @@
"api_version": 1,
"publish": {
"tags": ["DLSS", "Framegen","upscaling","FSR"],
- "description": "Allows using FSR for upscaling and frame generation in games with DLSS support. Uses DLSS Enabler and Optiscaler.",
+ "description": "Allows using FSR for upscaling and frame generation in games with DLSS support. Uses the latest OptiScaler bleeding-edge build with static linking.",
"image": "https://raw.githubusercontent.com/xXJSONDeruloXx/Decky-Framegen/main/assets/decky_framegen.jpeg"
}
}
diff --git a/src/index.tsx b/src/index.tsx
index eeb95ea..64dabdb 100755
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -111,21 +111,21 @@ function FGModInstallerSection() {
{pathExists !== null ? (
<PanelSectionRow>
<div style={{ color: pathExists ? "green" : "red" }}>
- {pathExists ? "Mod Is Installed" : "Mod Not Installed"}
+ {pathExists ? "OptiScaler Mod Is Installed" : "OptiScaler Mod Not Installed"}
</div>
</PanelSectionRow>
) : null}
{pathExists === false ? (
<PanelSectionRow>
<ButtonItem layout="below" onClick={handleInstallClick} disabled={installing}>
- {installing ? "Installing..." : "Install FG Mod"}
+ {installing ? "Installing..." : "Install OptiScaler FG Mod"}
</ButtonItem>
</PanelSectionRow>
) : null}
{pathExists === true ? (
<PanelSectionRow>
<ButtonItem layout="below" onClick={handleUninstallClick} disabled={uninstalling}>
- {uninstalling ? "Uninstalling..." : "Uninstall FG Mod"}
+ {uninstalling ? "Uninstalling..." : "Uninstall OptiScaler FG Mod"}
</ButtonItem>
</PanelSectionRow>
) : null}
@@ -171,7 +171,7 @@ function FGModInstallerSection() {
) : null}
<PanelSectionRow>
<div>
- Install the mod above, then select and patch a game below to enable DLSS in the game's menu.
+ Install the OptiScaler-based mod above, then select and patch a game below to enable DLSS replacement with FSR Frame Generation. Map a button to "insert" key to bring up the OptiScaler menu in-game.
</div>
</PanelSectionRow>
</PanelSection>
@@ -222,7 +222,7 @@ function InstalledGamesSection() {
onOK={async () => {
try {
await SteamClient.Apps.SetAppLaunchOptions(selectedGame.appid, '~/fgmod/fgmod %COMMAND%');
- setResult(`Launch options set for ${selectedGame.name}. You can now select DLSS in the game's menu.`);
+ setResult(`Launch options set for ${selectedGame.name}. You can now select DLSS in the game's menu, and access OptiScaler with Insert key.`);
} catch (error) {
logError('handlePatchClick: ' + String(error));
setResult(error instanceof Error ? `Error setting launch options: ${error.message}` : 'Error setting launch options');
@@ -237,7 +237,7 @@ function InstalledGamesSection() {
try {
await SteamClient.Apps.SetAppLaunchOptions(selectedGame.appid, '~/fgmod/fgmod-uninstaller.sh %COMMAND%');
- setResult(`DLSS mods will uninstall on next launch of ${selectedGame.name}.`);
+ setResult(`OptiScaler will uninstall on next launch of ${selectedGame.name}.`);
} catch (error) {
logError('handleUnpatchClick: ' + String(error));
setResult(error instanceof Error ? `Error clearing launch options: ${error.message}` : 'Error clearing launch options');