1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
|
import decky # Old-style Decky import
import os
import subprocess
import json
from pathlib import Path
class Plugin:
async def _main(self):
decky.logger.info("Framegen plugin loaded")
async def _unload(self):
decky.logger.info("Framegen plugin unloaded.")
async def run_uninstall_fgmod(self) -> dict:
try:
result = subprocess.run(
["/bin/bash", Path(decky.DECKY_PLUGIN_DIR) / "assets" / "fgmod-remover.sh"],
capture_output=True,
text=True,
check=True
)
return {"status": "success", "output": result.stdout}
except subprocess.CalledProcessError as e:
return {"status": "error", "message": str(e), "output": e.output}
except Exception as e:
return {"status": "error", "message": f"Unexpected error: {str(e)}"}
async def run_install_fgmod(self) -> dict:
try:
defaults_dir = Path(decky.DECKY_PLUGIN_DIR) / "assets"
fgmod_dir = Path(decky.HOME) / "fgmod"
if not defaults_dir.exists():
decky.logger.error(f"Defaults directory not found: {defaults_dir}")
return {"status": "error", "message": f"Defaults directory not found: {defaults_dir}"}
fgmod_dir.mkdir(parents=True, exist_ok=True)
files_to_copy = [
"amd_fidelityfx_dx12.dll", "dlssg_to_fsr3_amd_is_better.dll", "libxess.dll",
"amd_fidelityfx_vk.dll", "dlssg_to_fsr3.ini",
"d3dcompiler_47.dll", "dxgi.dll", "nvapi64.dll",
"DisableNvidiaSignatureChecks.reg", "dxvk.conf", "_nvngx.dll",
"dlss-enabler.dll", "fakenvapi.ini", "nvngx.ini",
"dlss-enabler-upscaler.dll", "fgmod", "nvngx-wrapper.dll",
"dlssg_to_fsr3_amd_is_better-3.0.dll", "fgmod-uninstaller.sh", "RestoreNvidiaSignatureChecks.reg"
]
for file_name in files_to_copy:
src = defaults_dir / file_name
dest = fgmod_dir / file_name
if not src.exists():
decky.logger.error(f"Required file missing: {src}")
return {"status": "error", "message": f"Required file missing: {file_name}"}
dest.write_bytes(src.read_bytes())
dest.chmod(0o755)
# Ensure the uninstaller script is executable
uninstaller_script = fgmod_dir / "fgmod-uninstaller.sh"
uninstaller_script.chmod(0o755)
# Verify all files exist in fgmod directory
missing_files = [file for file in files_to_copy if not (fgmod_dir / file).exists()]
if missing_files:
return {"status": "error", "message": f"Missing files: {', '.join(missing_files)}"}
return {"status": "success", "output": "You can now replace DLSS with FSR Frame Gen!"}
except Exception as e:
return {"status": "error", "message": f"Unexpected error: {str(e)}"}
async def check_fgmod_path(self) -> dict:
fgmod_dir = Path(decky.HOME) / "fgmod"
required_files = [
"amd_fidelityfx_dx12.dll", "dlssg_to_fsr3_amd_is_better.dll", "libxess.dll",
"amd_fidelityfx_vk.dll", "dlssg_to_fsr3.ini",
"d3dcompiler_47.dll", "dxgi.dll", "nvapi64.dll",
"DisableNvidiaSignatureChecks.reg", "dxvk.conf", "_nvngx.dll",
"dlss-enabler.dll", "fakenvapi.ini", "nvngx.ini",
"dlss-enabler-upscaler.dll", "fgmod", "nvngx-wrapper.dll",
"dlssg_to_fsr3_amd_is_better-3.0.dll", "fgmod-uninstaller.sh", "RestoreNvidiaSignatureChecks.reg"
]
if not fgmod_dir.exists():
return {"exists": False}
missing_files = [file for file in required_files if not (fgmod_dir / file).exists()]
return {"exists": not missing_files, "missing_files": missing_files}
async def list_installed_games(self) -> dict:
try:
steam_root = Path(decky.HOME) / ".steam" / "steam"
library_file = steam_root / "steamapps" / "libraryfolders.vdf"
if not library_file.exists():
return {"status": "error", "message": "libraryfolders.vdf not found"}
library_paths = []
with open(library_file, "r", encoding="utf-8") as file:
for line in file:
if '"path"' in line:
path = line.split('"path"')[1].strip().strip('"').replace("\\\\", "/")
library_paths.append(path)
games = []
for library_path in library_paths:
steamapps_path = Path(library_path) / "steamapps"
if not steamapps_path.exists():
continue
for appmanifest in steamapps_path.glob("appmanifest_*.acf"):
with open(appmanifest, "r", encoding="utf-8") as file:
game_info = {"appid": None, "name": None}
for line in file:
if '"appid"' in line:
game_info["appid"] = line.split('"appid"')[1].strip().strip('"')
if '"name"' in line:
game_info["name"] = line.split('"name"')[1].strip().strip('"')
if game_info["appid"] and game_info["name"]:
games.append(game_info)
# Filter out games whose name contains "Proton" or "Steam Linux Runtime"
filtered_games = [g for g in games if "Proton" not in g["name"] and "Steam Linux Runtime" not in g["name"]]
return {"status": "success", "games": filtered_games}
except Exception as e:
return {"status": "error", "message": str(e)}
|