diff options
Diffstat (limited to 'src/hooks/useGameConfiguration.ts')
| -rw-r--r-- | src/hooks/useGameConfiguration.ts | 91 |
1 files changed, 39 insertions, 52 deletions
diff --git a/src/hooks/useGameConfiguration.ts b/src/hooks/useGameConfiguration.ts index 3260019..2e39f5e 100644 --- a/src/hooks/useGameConfiguration.ts +++ b/src/hooks/useGameConfiguration.ts @@ -1,7 +1,7 @@ import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { useQuickAccessVisible } from "@decky/api"; import { Router } from "@decky/ui"; -import { ensureFlatpakSupport, getGameConfigs, getInstalledGames, getWorkaroundState, removeWorkaroundState, repairFlatpakSupport, resetGameConfig, resetAllGameConfigs, setWorkaroundState, updateGameConfig, type GameConfigEntry, type GlobalConfig, type InstalledGame, type WorkaroundState } from "../api/lsfgApi"; +import { getGameConfigs, getInstalledGames, getWorkaroundState, removeWorkaroundState, resetGameConfig, resetAllGameConfigs, setWorkaroundState, updateGameConfig, type GameConfigEntry, type GlobalConfig, type InstalledGame, type WorkaroundState } from "../api/lsfgApi"; import { ConfigurationData, getDefaults } from "../config/configSchema"; import { getDefaultWrapperPath, installWrapperIntegration, removeWrapperIntegration } from "../utils/steamLaunchOptions"; import { showErrorToast } from "../utils/toastUtils"; @@ -23,7 +23,6 @@ async function getSteamShortcuts(): Promise<InstalledGame[]> { appid: String(appid >>> 0), name, nonSteam: true, - transport: { kind: "host" }, }]; }); } catch { @@ -80,6 +79,7 @@ export function useGameConfiguration() { previousQuickAccessVisible.current = quickAccessVisible; if (initialLoad || becameVisible) void load(); }, [load, quickAccessVisible]); + useEffect(() => { const poll = () => { if (!configsLoaded) return; @@ -89,16 +89,25 @@ export function useGameConfiguration() { const installed = installedGames.find((game) => game.appid === appid); const name = app.display_name || installed?.name; if (!name) return setRunningGame(null); - setRunningGame((current) => current?.appid === appid ? current : { - ...(installed || { appid, name, nonSteam: false, transport: { kind: "host" } }), + const next: GameTarget = { + ...(installed || { appid, name, nonSteam: false }), name, configured: games.some((game) => game.appid === appid), - }); + }; + setRunningGame((current) => ( + current?.appid === next.appid + && current.name === next.name + && current.nonSteam === next.nonSteam + && current.configured === next.configured + ? current + : next + )); }; poll(); const interval = window.setInterval(poll, 2000); return () => window.clearInterval(interval); }, [configsLoaded, games, installedGames]); + useEffect(() => { const appid = runningGame?.appid || null; if (appid !== previousRunningAppId.current) { @@ -109,25 +118,15 @@ export function useGameConfiguration() { const targets = useMemo<GameTarget[]>(() => { const configured = installedGames.map((game) => ({ ...game, configured: games.some((item) => item.appid === game.appid) })); - for (const game of games) if (!configured.some((item) => item.appid === game.appid)) configured.push({ appid: game.appid, name: game.profile, nonSteam: false, transport: { kind: "host" }, configured: true }); + for (const game of games) if (!configured.some((item) => item.appid === game.appid)) configured.push({ appid: game.appid, name: game.profile, nonSteam: false, configured: true }); if (runningGame && !configured.some((game) => game.appid === runningGame.appid)) configured.unshift(runningGame); return configured; }, [games, installedGames, runningGame]); const template = useMemo(() => ({ ...getDefaults(), ...globalConfig }), [globalConfig]); const config = games.find((game) => game.appid === selectedAppId)?.config || template; - - const ensureTargetFlatpakSupport = useCallback(async (target: GameTarget): Promise<boolean> => { - if (target.transport.kind !== "flatpak") return true; - const result = await ensureFlatpakSupport(target.transport.flatpakAppId); - if (!result.success || result.support_status !== "ready") { - showErrorToast( - "Flatpak support unavailable", - result.error || result.message || "The required Flatpak runtime extension is not ready", - ); - return false; - } - return true; - }, []); + const runningConfig = runningGame + ? games.find((game) => game.appid === runningGame.appid)?.config || template + : template; const ensureTargetWorkarounds = useCallback(async (target: GameTarget): Promise<boolean> => { if (!installedGames.some((game) => game.appid === target.appid)) return true; @@ -148,16 +147,12 @@ export function useGameConfiguration() { target.nonSteam, wrapperPath, commandTokenAdded, - target.transport, - target.transport.kind === "flatpak" ? existing.shortcut_exe || undefined : undefined, ); stateWriteAttempted = true; const saved = await setWorkaroundState( target.appid, state, - integration.originalExecutable ?? null, integration.commandTokenAdded, - target.transport, ); if (!saved.success) throw new Error(saved.error || "Could not save workaround state"); return true; @@ -169,9 +164,7 @@ export function useGameConfiguration() { appId, target.nonSteam, wrapperPath, - integration.originalExecutable, integration.commandTokenAdded, - target.transport, ); } catch (rollbackError) { showErrorToast("Workaround rollback failed", asError(rollbackError).message); @@ -201,9 +194,7 @@ export function useGameConfiguration() { appId, target.nonSteam, wrapperPath, - target.transport.kind === "flatpak" ? existing.shortcut_exe || undefined : undefined, existing.command_token_added === true, - target.transport, ); const removed = await removeWorkaroundState(target.appid); if (!removed.success) throw new Error(removed.error || "Could not remove workaround state"); @@ -214,33 +205,37 @@ export function useGameConfiguration() { } }, [installedGames]); - const save = useCallback(async (next: ConfigurationData, cleanupLaunchOptions = false) => { - const selectedTarget = targets.find((target) => target.appid === selectedAppId); - if (!selectedTarget?.name) return; - // The profile owns its wrapper integration. Keep this check on every - // configuration save so an external edit is detected before the profile - // is changed; toggles update the sidecar only. - if (cleanupLaunchOptions && !(await ensureTargetWorkarounds(selectedTarget))) return; - const result = await updateGameConfig(selectedAppId, selectedTarget.name, next); + const saveFor = useCallback(async (appid: string, next: ConfigurationData, cleanupLaunchOptions = false) => { + const target = targets.find((item) => item.appid === appid); + if (!target?.name) return false; + if (cleanupLaunchOptions && !(await ensureTargetWorkarounds(target))) return false; + const result = await updateGameConfig(appid, target.name, next); if (result.success) await load(); - }, [ensureTargetWorkarounds, load, selectedAppId, targets]); + return result.success; + }, [ensureTargetWorkarounds, load, targets]); + + const save = useCallback( + async (next: ConfigurationData, cleanupLaunchOptions = false) => { + if (!selectedAppId) return false; + return saveFor(selectedAppId, next, cleanupLaunchOptions); + }, + [saveFor, selectedAppId], + ); const enable = useCallback(async (appid: string) => { const target = targets.find((item) => item.appid === appid); if (!target?.name) return false; - if (!(await ensureTargetFlatpakSupport(target))) return false; if (!(await ensureTargetWorkarounds(target))) return false; const result = await updateGameConfig(appid, target.name, template); if (result.success) await load(); else await removeTargetWorkarounds(target); return result.success; - }, [ensureTargetFlatpakSupport, ensureTargetWorkarounds, load, removeTargetWorkarounds, targets, template]); + }, [ensureTargetWorkarounds, load, removeTargetWorkarounds, targets, template]); + const enableAll = useCallback(async (): Promise<void> => { const available = targets.filter((target) => !target.configured && target.name); if (available.length === 0) return; - for (const target of available) { - if (!(await ensureTargetFlatpakSupport(target))) return; if (!(await ensureTargetWorkarounds(target))) return; const result = await updateGameConfig(target.appid, target.name, template); if (!result.success) { @@ -253,20 +248,11 @@ export function useGameConfiguration() { } } await load(); - }, [ensureTargetFlatpakSupport, ensureTargetWorkarounds, load, removeTargetWorkarounds, targets, template]); + }, [ensureTargetWorkarounds, load, removeTargetWorkarounds, targets, template]); + const repair = useCallback(async (appid: string): Promise<boolean> => { const target = targets.find((item) => item.appid === appid); if (!target) return false; - if (target.transport.kind === "flatpak") { - const support = await repairFlatpakSupport(target.transport.flatpakAppId); - if (!support.success || support.support_status !== "ready") { - showErrorToast( - "Flatpak support unavailable", - support.error || support.message || "The required Flatpak runtime extension is not ready", - ); - return false; - } - } const success = await ensureTargetWorkarounds(target); if (success) await load(); return success; @@ -284,6 +270,7 @@ export function useGameConfiguration() { } } }, [load, removeTargetWorkarounds, selectedAppId, targets]); + const resetAll = useCallback(async () => { for (const target of targets.filter((item) => item.configured)) { if (!(await removeTargetWorkarounds(target))) return; @@ -296,5 +283,5 @@ export function useGameConfiguration() { } }, [load, removeTargetWorkarounds, targets]); - return { config, games, targets, runningGame, selectedAppId, setSelectedAppId, save, enable, enableAll, repair, resetSelected, resetAll, reload: load }; + return { config, runningConfig, games, targets, runningGame, selectedAppId, setSelectedAppId, save, saveFor, enable, enableAll, repair, resetSelected, resetAll, reload: load }; } |
