summaryrefslogtreecommitdiff
path: root/src/hooks/useGameConfiguration.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/hooks/useGameConfiguration.ts')
-rw-r--r--src/hooks/useGameConfiguration.ts99
1 files changed, 99 insertions, 0 deletions
diff --git a/src/hooks/useGameConfiguration.ts b/src/hooks/useGameConfiguration.ts
new file mode 100644
index 0000000..d279a8c
--- /dev/null
+++ b/src/hooks/useGameConfiguration.ts
@@ -0,0 +1,99 @@
+import { useCallback, useEffect, useMemo, useRef, useState } from "react";
+import { Router } from "@decky/ui";
+import { getGameConfigs, getInstalledGames, updateGameConfig, resetGameConfig, resetAllGameConfigs, type GameConfigEntry, type GlobalConfig, type InstalledGame } from "../api/lsfgApi";
+import { ConfigurationData, getDefaults } from "../config/configSchema";
+
+export interface GameTarget extends InstalledGame { configured: boolean; }
+
+export function useGameConfiguration() {
+ const [games, setGames] = useState<GameConfigEntry[]>([]);
+ const [globalConfig, setGlobalConfig] = useState<GlobalConfig>({ dll: "", no_fp16: false });
+ const [installedGames, setInstalledGames] = useState<InstalledGame[]>([]);
+ const [configsLoaded, setConfigsLoaded] = useState(false);
+ const [selectedAppId, setSelectedAppId] = useState("");
+ const [runningGame, setRunningGame] = useState<GameTarget | null>(null);
+ const previousRunningAppId = useRef<string | null>(null);
+
+ const load = useCallback(async () => {
+ const [result, installed] = await Promise.all([getGameConfigs(), getInstalledGames()]);
+ if (result.success) {
+ setGlobalConfig(result.global_config || { dll: "", no_fp16: false });
+ setGames(result.games || []);
+ }
+ if (installed.success) setInstalledGames(installed.games || []);
+ setConfigsLoaded(true);
+ }, []);
+
+ useEffect(() => { load(); }, [load]);
+ useEffect(() => {
+ const poll = () => {
+ if (!configsLoaded) return;
+ const app = Router.MainRunningApp as any;
+ if (!app?.appid) return setRunningGame(null);
+ const appid = String(app.appid);
+ 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 }),
+ name,
+ configured: games.some((game) => game.appid === appid),
+ });
+ };
+ poll();
+ const interval = window.setInterval(poll, 2000);
+ return () => window.clearInterval(interval);
+ }, [configsLoaded, games, installedGames]);
+ useEffect(() => {
+ const appid = runningGame?.appid || null;
+ if (appid !== previousRunningAppId.current) {
+ previousRunningAppId.current = appid;
+ setSelectedAppId(appid || "");
+ }
+ }, [runningGame?.appid]);
+
+ 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, 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 save = useCallback(async (next: ConfigurationData) => {
+ const selectedTarget = targets.find((target) => target.appid === selectedAppId);
+ if (!selectedTarget?.name) return;
+ const result = await updateGameConfig(selectedAppId, selectedTarget.name, next);
+ if (result.success) await load();
+ }, [load, selectedAppId, targets]);
+
+ const enable = useCallback(async (appid: string) => {
+ const target = targets.find((item) => item.appid === appid);
+ if (!target?.name) return false;
+ const result = await updateGameConfig(appid, target.name, template);
+ if (result.success) await load();
+ return result.success;
+ }, [load, targets, template]);
+
+ const resetSelected = useCallback(async () => {
+ if (selectedAppId) {
+ const result = await resetGameConfig(selectedAppId);
+ if (result.success) {
+ setRunningGame((current) => current?.appid === selectedAppId ? { ...current, configured: false } : current);
+ setSelectedAppId("");
+ await load();
+ }
+ }
+ }, [load, selectedAppId]);
+ const resetAll = useCallback(async () => {
+ const result = await resetAllGameConfigs();
+ if (result.success) {
+ setRunningGame((current) => current ? { ...current, configured: false } : current);
+ setSelectedAppId("");
+ await load();
+ }
+ }, [load]);
+
+ return { config, games, targets, runningGame, selectedAppId, setSelectedAppId, save, enable, resetSelected, resetAll, reload: load };
+}