Skip to content

Commit 484f9d5

Browse files
Merge pull request #3 from xXJSONDeruloXx/ini-edit
Ini edit
2 parents dce5395 + dbf8b2a commit 484f9d5

File tree

3 files changed

+242
-41
lines changed

3 files changed

+242
-41
lines changed

defaults/assets/opti.sh

Lines changed: 32 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ set -x
44
exec > >(tee -i /tmp/opti-install.log) 2>&1
55

66
error_exit() {
7-
echo "$1"
7+
echo "$1"
88
if [[ -n $STEAM_ZENITY ]]; then
99
$STEAM_ZENITY --error --text "$1"
1010
else
@@ -14,30 +14,6 @@ error_exit() {
1414
exit 1
1515
}
1616

17-
safe_copy() {
18-
local src="$1"
19-
local dest="$2"
20-
local opts="${3:-}"
21-
cp $opts "$src" "$dest" 2>/dev/null
22-
23-
if [[ $? -ne 0 && -d "$(dirname "$dest")" ]]; then
24-
echo "Limited permissions detected, trying alternative methods..."
25-
26-
if command -v bwrap >/dev/null 2>&1; then
27-
echo "Using bubblewrap to copy files..."
28-
bwrap --dev-bind / / cp $opts "$src" "$dest" 2>/dev/null
29-
fi
30-
31-
if [[ $? -ne 0 && "$(whoami)" == "deck" && -x "$(command -v sudo)" ]]; then
32-
echo "Using sudo to copy files..."
33-
sudo cp $opts "$src" "$dest"
34-
fi
35-
fi
36-
37-
[[ -e "$dest" ]] || return 1
38-
return 0
39-
}
40-
4117
# === CONFIG ===
4218
optipath="$HOME/opti"
4319
fgmodpath="$HOME/fgmod"
@@ -77,6 +53,7 @@ if [[ -d "$exe_folder_path/Engine" ]]; then
7753
fi
7854

7955
[[ ! -d "$exe_folder_path" ]] && error_exit "❌ Could not resolve game directory!"
56+
[[ ! -w "$exe_folder_path" ]] && error_exit "🛑 No write permission to the game folder!"
8057

8158
logger -t optiscaler "🟢 Target directory: $exe_folder_path"
8259
logger -t optiscaler "🧩 Using DLL name: $dll_name"
@@ -85,35 +62,37 @@ logger -t optiscaler "🧩 Using DLL name: $dll_name"
8562
rm -f "$exe_folder_path"/{dxgi.dll,winmm.dll,nvngx.dll,_nvngx.dll,nvngx-wrapper.dll,dlss-enabler.dll,OptiScaler.dll}
8663

8764
# === Optional: Backup Original DLLs ===
88-
for f in dxgi.dll d3dcompiler_47.dll nvapi64.dll; do
89-
[[ -f "$exe_folder_path/$f" ]] && mv -n "$exe_folder_path/$f" "$exe_folder_path/$f.bak"
65+
original_dlls=("d3dcompiler_47.dll" "amd_fidelityfx_dx12.dll" "amd_fidelityfx_vk.dll" "nvapi64.dll")
66+
for dll in "${original_dlls[@]}"; do
67+
[[ -f "$exe_folder_path/$dll" && ! -f "$exe_folder_path/$dll.b" ]] && mv -f "$exe_folder_path/$dll" "$exe_folder_path/$dll.b"
9068
done
9169

9270
# === Core Install ===
9371
if [[ -f "$optipath/renames/$dll_name" ]]; then
9472
echo "✅ Using pre-renamed $dll_name"
95-
safe_copy "$optipath/renames/$dll_name" "$exe_folder_path/$dll_name" || error_exit "Failed to copy $dll_name"
73+
cp "$optipath/renames/$dll_name" "$exe_folder_path/$dll_name" || error_exit "Failed to copy $dll_name"
9674
else
9775
echo "⚠️ Pre-renamed $dll_name not found, falling back to OptiScaler.dll"
98-
safe_copy "$optipath/OptiScaler.dll" "$exe_folder_path/$dll_name" || error_exit "Failed to copy OptiScaler.dll as $dll_name"
76+
cp "$optipath/OptiScaler.dll" "$exe_folder_path/$dll_name" || error_exit "Failed to copy OptiScaler.dll as $dll_name"
9977
fi
10078

101-
safe_copy "$optipath/OptiScaler.ini" "$exe_folder_path/OptiScaler.ini" || error_exit "Failed to copy OptiScaler.ini"
79+
cp "$optipath/OptiScaler.ini" "$exe_folder_path/OptiScaler.ini" || error_exit "Failed to copy OptiScaler.ini"
10280

10381
# === Supporting Libraries ===
104-
safe_copy "$optipath/libxess.dll" "$exe_folder_path/" || true
105-
safe_copy "$optipath/amd_fidelityfx_dx12.dll" "$exe_folder_path/" || true
106-
safe_copy "$optipath/amd_fidelityfx_vk.dll" "$exe_folder_path/" || true
107-
safe_copy "$optipath/renames/nvngx.dll" "$exe_folder_path/" || true
82+
cp -f "$optipath/libxess.dll" "$exe_folder_path/" || true
83+
cp -f "$optipath/amd_fidelityfx_dx12.dll" "$exe_folder_path/" || true
84+
cp -f "$optipath/amd_fidelityfx_vk.dll" "$exe_folder_path/" || true
85+
cp -f "$optipath/renames/nvngx.dll" "$exe_folder_path/" || true
10886

10987
# === Nukem FG Mod Files ===
110-
safe_copy "$fgmodpath/dlssg_to_fsr3_amd_is_better.dll" "$exe_folder_path/" || true
111-
safe_copy "$fgmodpath/dlssg_to_fsr3.ini" "$exe_folder_path/" || true
112-
safe_copy "$fgmodpath/nvapi64.dll" "$exe_folder_path/" || true
113-
safe_copy "$fgmodpath/fakenvapi.ini" "$exe_folder_path/" || true
88+
cp -f "$fgmodpath/dlssg_to_fsr3_amd_is_better.dll" "$exe_folder_path/" || true
89+
cp -f "$fgmodpath/dlssg_to_fsr3.ini" "$exe_folder_path/" || true
90+
cp -f "$fgmodpath/nvapi64.dll" "$exe_folder_path/" || true
91+
cp -f "$fgmodpath/fakenvapi.ini" "$exe_folder_path/" || true
11492

115-
# === Optional Helpers ===
116-
safe_copy "$fgmodpath/dxvk.conf" "$exe_folder_path/" "-n" || true
93+
# === Optional Config Files ===
94+
cp -n "$fgmodpath/dxvk.conf" "$exe_folder_path/" || true
95+
# cp -n "$fgmodpath/nvngx.ini" "$exe_folder_path/" || true
11796

11897
logger -t optiscaler "✅ OptiScaler installed in: $exe_folder_path with DLL: $dll_name"
11998
echo "✅ OptiScaler installed in: $exe_folder_path with DLL: $dll_name"
@@ -122,6 +101,18 @@ echo "✅ OptiScaler installed in: $exe_folder_path with DLL: $dll_name"
122101
if [[ $# -gt 1 ]]; then
123102
echo "🚀 Launching game with args: $@"
124103
logger -t optiscaler "🚀 Launching: $@"
125-
export WINEDLLOVERRIDES="$WINEDLLOVERRIDES,$dll_name=n,b"
104+
105+
dll_override="${dll_name%.dll}"
106+
if [[ "$WINEDLLOVERRIDES" != *"$dll_override=n,b"* ]]; then
107+
export WINEDLLOVERRIDES="${WINEDLLOVERRIDES:+$WINEDLLOVERRIDES,}$dll_override=n,b"
108+
fi
109+
logger -t optiscaler "🔧 DLL override: $dll_override=n,b"
110+
111+
export SteamDeck=0
112+
126113
"$@"
114+
else
115+
echo "📝 Standalone installation complete."
116+
echo "📁 Final game path: $exe_folder_path"
117+
logger -t optiscaler "📁 Final game path: $exe_folder_path"
127118
fi

main.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -421,3 +421,60 @@ async def check_optiscaler_path(self) -> dict:
421421
except Exception as e:
422422
decky.logger.error(f"Error checking OptiScaler path: {e}")
423423
return {"exists": False, "version": ""}
424+
425+
async def get_optiscaler_fgtype(self) -> dict:
426+
"""Get the current FGType value from OptiScaler.ini."""
427+
try:
428+
import re
429+
opti_path = Path(decky.HOME) / "opti"
430+
ini_file = opti_path / "OptiScaler.ini"
431+
432+
if not ini_file.exists():
433+
return {"status": "error", "message": "OptiScaler.ini not found", "fgtype": "unknown"}
434+
435+
# Read the file content
436+
with open(ini_file, 'r') as f:
437+
content = f.read()
438+
439+
# Find the FGType setting
440+
match = re.search(r'FGType\s*=\s*(\w+)', content)
441+
if match:
442+
fgtype = match.group(1)
443+
return {"status": "success", "fgtype": fgtype}
444+
else:
445+
return {"status": "error", "message": "FGType setting not found", "fgtype": "unknown"}
446+
except Exception as e:
447+
decky.logger.error(f"Error getting FGType: {e}")
448+
return {"status": "error", "message": str(e), "fgtype": "unknown"}
449+
450+
async def set_optiscaler_fgtype(self, fgtype: str) -> dict:
451+
"""Set the FGType value in OptiScaler.ini."""
452+
try:
453+
import re
454+
opti_path = Path(decky.HOME) / "opti"
455+
ini_file = opti_path / "OptiScaler.ini"
456+
457+
if not ini_file.exists():
458+
return {"status": "error", "message": "OptiScaler.ini not found"}
459+
460+
# Validate fgtype
461+
valid_types = ["auto", "nofg", "optifg", "nukems"]
462+
if fgtype not in valid_types:
463+
return {"status": "error", "message": f"Invalid FGType: {fgtype}"}
464+
465+
# Read the file content
466+
with open(ini_file, 'r') as f:
467+
content = f.read()
468+
469+
# Replace FGType setting
470+
updated_content = re.sub(r'(FGType\s*=\s*)(\w+)', f'\\1{fgtype}', content)
471+
472+
# Write the updated content back to the file
473+
with open(ini_file, 'w') as f:
474+
f.write(updated_content)
475+
476+
decky.logger.info(f"Updated OptiScaler.ini FGType to {fgtype}")
477+
return {"status": "success", "message": f"FGType set to {fgtype}"}
478+
except Exception as e:
479+
decky.logger.error(f"Error setting FGType: {e}")
480+
return {"status": "error", "message": str(e)}

src/index.tsx

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ const downloadLatestOptiScaler = callable<
4848
}
4949
>("download_optiscaler_nightly");
5050

51+
const getOptiScalerFGType = callable<[], { status: string; fgtype: string; message?: string }>("get_optiscaler_fgtype");
52+
const setOptiScalerFGType = callable<[string], { status: string; message: string }>("set_optiscaler_fgtype");
53+
5154
function FGModInstallerSection() {
5255
const [installing, setInstalling] = useState(false);
5356
const [uninstalling, setUninstalling] = useState(false);
@@ -311,6 +314,155 @@ function FGModInstallerSection() {
311314
);
312315
}
313316

317+
function OptiScalerFGTypeSection() {
318+
const [fgType, setFgType] = useState<string>("unknown");
319+
const [isUpdating, setIsUpdating] = useState(false);
320+
const [updateMessage, setUpdateMessage] = useState<string | null>(null);
321+
322+
const fetchFGType = async () => {
323+
try {
324+
const result = await getOptiScalerFGType();
325+
if (result.status === "success") {
326+
setFgType(result.fgtype);
327+
} else {
328+
setFgType("unknown");
329+
console.error("Failed to get FGType:", result.message);
330+
}
331+
} catch (error) {
332+
logError(`Error fetching FGType: ${String(error)}`);
333+
console.error("Error fetching FGType:", error);
334+
setFgType("unknown");
335+
}
336+
};
337+
338+
useEffect(() => {
339+
// Initially fetch FGType when component mounts
340+
fetchFGType();
341+
342+
// Set up interval to refresh every 3 seconds
343+
const intervalId = setInterval(fetchFGType, 3000);
344+
345+
// Clean up interval on unmount
346+
return () => clearInterval(intervalId);
347+
}, []);
348+
349+
useEffect(() => {
350+
if (updateMessage) {
351+
const timer = setTimeout(() => setUpdateMessage(null), 3000);
352+
return () => clearTimeout(timer);
353+
}
354+
return () => {};
355+
}, [updateMessage]);
356+
357+
const handleSetFGType = async (type: string) => {
358+
setIsUpdating(true);
359+
try {
360+
const result = await setOptiScalerFGType(type);
361+
if (result.status === "success") {
362+
setUpdateMessage(`Successfully set FGType to ${type}`);
363+
fetchFGType(); // Refresh immediately
364+
} else {
365+
setUpdateMessage(`Failed to set FGType: ${result.message}`);
366+
}
367+
} catch (error) {
368+
logError(`Error setting FGType: ${String(error)}`);
369+
console.error("Error setting FGType:", error);
370+
setUpdateMessage(`Error: ${String(error)}`);
371+
} finally {
372+
setIsUpdating(false);
373+
}
374+
};
375+
376+
const getFGTypeDescription = () => {
377+
switch (fgType) {
378+
case "auto":
379+
return "Default setting (usually falls back to nofg)";
380+
case "nofg":
381+
return "No frame generation";
382+
case "optifg":
383+
return "AMD FidelityFX frame generation";
384+
case "nukems":
385+
return "Nukem9's DLSS-to-FSR3 implementation";
386+
default:
387+
return "Unknown setting";
388+
}
389+
};
390+
391+
return (
392+
<PanelSection title="OptiScaler Frame Generation Settings">
393+
<PanelSectionRow>
394+
<div style={{
395+
padding: '10px',
396+
backgroundColor: 'rgba(0, 0, 0, 0.2)',
397+
borderRadius: '4px',
398+
marginBottom: '10px'
399+
}}>
400+
<div style={{ fontWeight: 'bold', marginBottom: '5px' }}>
401+
Current FGType: <span style={{ color: fgType === "unknown" ? "red" : "green" }}>{fgType}</span>
402+
</div>
403+
<div style={{ fontSize: '0.8em', opacity: 0.8 }}>
404+
{getFGTypeDescription()}
405+
</div>
406+
</div>
407+
</PanelSectionRow>
408+
409+
<PanelSectionRow>
410+
<ButtonItem
411+
layout="below"
412+
onClick={() => handleSetFGType("auto")}
413+
disabled={isUpdating || fgType === "auto"}
414+
>
415+
Set to Auto
416+
</ButtonItem>
417+
<div style={{ fontSize: '0.8em', marginTop: '4px', opacity: 0.8 }}>
418+
Default setting, lets OptiScaler decide
419+
</div>
420+
</PanelSectionRow>
421+
422+
<PanelSectionRow>
423+
<ButtonItem
424+
layout="below"
425+
onClick={() => handleSetFGType("optifg")}
426+
disabled={isUpdating || fgType === "optifg"}
427+
>
428+
Set to OptiFG
429+
</ButtonItem>
430+
<div style={{ fontSize: '0.8em', marginTop: '4px', opacity: 0.8 }}>
431+
AMD FidelityFX frame generation (requires amd_fidelityfx_dx12.dll)
432+
</div>
433+
</PanelSectionRow>
434+
435+
<PanelSectionRow>
436+
<ButtonItem
437+
layout="below"
438+
onClick={() => handleSetFGType("nukems")}
439+
disabled={isUpdating || fgType === "nukems"}
440+
>
441+
Set to Nukems
442+
</ButtonItem>
443+
<div style={{ fontSize: '0.8em', marginTop: '4px', opacity: 0.8 }}>
444+
Nukem9's DLSS-to-FSR3 implementation (recommended)
445+
</div>
446+
</PanelSectionRow>
447+
448+
{updateMessage && (
449+
<PanelSectionRow>
450+
<div style={{
451+
padding: '10px',
452+
backgroundColor: updateMessage.includes("Failed") || updateMessage.includes("Error")
453+
? 'rgba(255, 0, 0, 0.2)'
454+
: 'rgba(0, 128, 0, 0.2)',
455+
borderRadius: '4px',
456+
marginTop: '10px'
457+
}}>
458+
{updateMessage}
459+
</div>
460+
</PanelSectionRow>
461+
)}
462+
</PanelSection>
463+
);
464+
}
465+
314466
function InstalledGamesSection() {
315467
const [games, setGames] = useState<{ appid: number; name: string }[]>([]);
316468
const [selectedGame, setSelectedGame] = useState<{ appid: number; name: string } | null>(null);
@@ -567,6 +719,7 @@ export default definePlugin(() => ({
567719
content: (
568720
<>
569721
<FGModInstallerSection />
722+
<OptiScalerFGTypeSection />
570723
<InstalledGamesSection />
571724
</>
572725
),

0 commit comments

Comments
 (0)