From bbef4b0e91e7afc3ce2be9998367530ee22ae776 Mon Sep 17 00:00:00 2001 From: ProbablyRaging Date: Tue, 20 Aug 2024 21:50:26 +1000 Subject: [PATCH] Replaced the `add all games with drops remaining` button with two new options in the `settings` screen Fixed an issue where SGI would become temporarily unresponsive when stopping the `card farming` feature if there were a lot of games in the `card farming list` --- components/automation/CardFarming.jsx | 61 +++++++++----- components/automation/StopButton.jsx | 21 ++--- components/gameslist/Achievements.jsx | 2 +- components/gameslist/Automate.jsx | 7 +- components/gameslist/GameAchievementList.jsx | 2 +- components/gameslist/GameIdleList.jsx | 3 +- components/gameslist/GamesList.jsx | 2 - components/gameslist/GamesWithDrops.jsx | 65 -------------- components/gameslist/PageHeader.jsx | 7 +- components/settings/AchievementSettings.jsx | 3 +- components/settings/CardSettings.jsx | 89 +++++++++++++++++--- components/settings/Settings.jsx | 54 +++++++++--- latest.json | 6 +- src-tauri/src/main.rs | 2 +- src-tauri/tauri.conf.json | 2 +- utils/utils.js | 15 +++- 16 files changed, 201 insertions(+), 140 deletions(-) delete mode 100644 components/gameslist/GamesWithDrops.jsx diff --git a/components/automation/CardFarming.jsx b/components/automation/CardFarming.jsx index c580dce..4d1c970 100644 --- a/components/automation/CardFarming.jsx +++ b/components/automation/CardFarming.jsx @@ -1,5 +1,5 @@ import React, { useEffect, useState, useRef } from 'react'; -import { checkDrops, logEvent, startIdler, stopIdler } from '@/utils/utils'; +import { checkDrops, getAllGamesWithDrops, logEvent, startIdler, stopIdler } from '@/utils/utils'; import StopButton from './StopButton'; import { Button, Skeleton, Spinner } from '@nextui-org/react'; import { IoCheckmark } from 'react-icons/io5'; @@ -50,31 +50,44 @@ export default function CardFarming({ setActivePage }) { const cardFarming = JSON.parse(localStorage.getItem('cardFarming')) || []; const steamCookies = JSON.parse(localStorage.getItem('steamCookies')) || {}; const userSummary = JSON.parse(localStorage.getItem('userSummary')) || {}; + const settings = JSON.parse(localStorage.getItem('settings')) || {}; const gameDataArr = cardFarming.map(game => JSON.parse(game)); const gamesSet = new Set(); let totalDrops = 0; - const dropCheckPromises = gameDataArr.map(async (gameData) => { - try { - const dropsRemaining = await checkDrops(userSummary.steamId, gameData.game.id, steamCookies.sid, steamCookies.sls); - if (dropsRemaining > 0) { - logEvent(`[Card Farming] ${dropsRemaining} drops remaining for ${gameData.game.name} - starting`); + try { + if (settings.cardFarming.allGames) { + const gamesWithDrops = await getAllGamesWithDrops(userSummary.steamId, steamCookies.sid, steamCookies.sls); + for (const gameData of gamesWithDrops) { if (gamesSet.size < 30) { - console.log(gameData); gamesSet.add({ appId: gameData.game.id, appName: gameData.game.name }); - totalDrops += dropsRemaining; + totalDrops += gameData.game.remaining; + logEvent(`[Card Farming] ${gameData.game.remaining} drops remaining for ${gameData.game.name} - starting`); + } else { + break; } - } else { - logEvent(`[Card Farming] ${dropsRemaining} drops remaining for ${gameData.game.name} - removed from list`); - removeGameFromFarmingList(gameData.game.id); } - } catch (error) { - logEvent(`[Error] [Card Farming] ${error}`); + } else { + const dropCheckPromises = gameDataArr.map(async (gameData) => { + if (gamesSet.size >= 30) return Promise.resolve(); + const dropsRemaining = await checkDrops(userSummary.steamId, gameData.game.id, steamCookies.sid, steamCookies.sls); + if (dropsRemaining > 0) { + if (gamesSet.size < 30) { + gamesSet.add({ appId: gameData.game.id, appName: gameData.game.name }); + totalDrops += dropsRemaining; + logEvent(`[Card Farming] ${dropsRemaining} drops remaining for ${gameData.game.name} - starting`); + } + } else { + logEvent(`[Card Farming] ${dropsRemaining} drops remaining for ${gameData.game.name} - removed from list`); + removeGameFromFarmingList(gameData.game.id); + } + }); + await Promise.all(dropCheckPromises); } - }); - - await Promise.all(dropCheckPromises); + } catch (error) { + logEvent(`[Error] [Card Farming] ${error}`); + } return { totalDrops, gamesSet }; }; @@ -133,13 +146,17 @@ export default function CardFarming({ setActivePage }) { localStorage.setItem('cardFarming', JSON.stringify(updatedCardFarming)); }; - const handleCancel = () => { - for (const game of gamesWithDrops) { - stopIdler(game.appId); - } - isMountedRef.current = false; - abortControllerRef.current.abort(); + const handleCancel = async () => { setActivePage('games'); + try { + const stopPromises = Array.from(gamesWithDrops).map(game => stopIdler(game.appId)); + await Promise.all(stopPromises); + } catch (error) { + console.error('Error stopping games:', error); + } finally { + isMountedRef.current = false; + abortControllerRef.current.abort(); + } }; return ( diff --git a/components/automation/StopButton.jsx b/components/automation/StopButton.jsx index aad5e1d..ac36550 100644 --- a/components/automation/StopButton.jsx +++ b/components/automation/StopButton.jsx @@ -9,19 +9,20 @@ export default function StopButton({ setActivePage, isMountedRef, abortControlle ...Array.from({ length: 500 }, (_, i) => 6 - i * 0.01), ]; - const handleStop = () => { - if (screen === 'card-farming') { - for (const game of gamesWithDrops) { - stopIdler(game.appId); + const handleStop = async () => { + setActivePage('games'); + try { + if (screen === 'card-farming') { + const stopPromises = Array.from(gamesWithDrops).map(game => stopIdler(game.appId)); + await Promise.all(stopPromises); + } else { + await stopIdler(currentGame.appId); } + } catch (error) { + console.error('Error stopping games:', error); + } finally { isMountedRef.current = false; abortControllerRef.current.abort(); - setActivePage('games'); - } else { - isMountedRef.current = false; - abortControllerRef.current.abort(); - setActivePage('games'); - stopIdler(currentGame.appId); } }; diff --git a/components/gameslist/Achievements.jsx b/components/gameslist/Achievements.jsx index eb3fe17..c4dba21 100644 --- a/components/gameslist/Achievements.jsx +++ b/components/gameslist/Achievements.jsx @@ -328,7 +328,7 @@ export default function Achievements({ steamId, appId, setShowAchievements }) { - + ); } \ No newline at end of file diff --git a/components/gameslist/Automate.jsx b/components/gameslist/Automate.jsx index 309d747..92f5adf 100644 --- a/components/gameslist/Automate.jsx +++ b/components/gameslist/Automate.jsx @@ -11,6 +11,7 @@ export default function Automate({ setActivePage }) { const startCardFarming = async () => { const steamRunning = await invoke('check_status'); const steamCookies = JSON.parse(localStorage.getItem('steamCookies')) || {}; + const settings = JSON.parse(localStorage.getItem('settings')) || {}; if (!steamRunning) { return toast.error('Steam is not running'); } @@ -27,8 +28,8 @@ export default function Automate({ setActivePage }) { return toast.error('Steam credentials need to be updated'); } const cardFarming = JSON.parse(localStorage.getItem('cardFarming')) || []; - if (cardFarming.length < 1) { - return toast.error('No games in card farming list'); + if (!settings.cardFarming.allGames && cardFarming.length < 1) { + return toast.error('Enable the "All games" setting or add some games to your card farming list'); } setActivePage('card-farming'); }; @@ -89,7 +90,7 @@ export default function Automate({ setActivePage }) { - + ); } \ No newline at end of file diff --git a/components/gameslist/GameAchievementList.jsx b/components/gameslist/GameAchievementList.jsx index d4a2faa..091cf31 100644 --- a/components/gameslist/GameAchievementList.jsx +++ b/components/gameslist/GameAchievementList.jsx @@ -157,7 +157,7 @@ export default function GameAchievementList({ gameList, favorites, cardFarming, ); })} - + ); diff --git a/components/gameslist/GameIdleList.jsx b/components/gameslist/GameIdleList.jsx index 2f86b88..30abcef 100644 --- a/components/gameslist/GameIdleList.jsx +++ b/components/gameslist/GameIdleList.jsx @@ -53,7 +53,6 @@ export default function GameIdleList({ gameList, favorites, cardFarming, achieve setTimeout(() => { let cardFarming = JSON.parse(localStorage.getItem('cardFarming')) || []; cardFarming.push(JSON.stringify(item)); - console.log(cardFarming.map(JSON.parse)); localStorage.setItem('cardFarming', JSON.stringify(cardFarming)); const newCardFarming = (localStorage.getItem('cardFarming') && JSON.parse(localStorage.getItem('cardFarming'))) || []; setCardFarming(newCardFarming.map(JSON.parse)); @@ -158,7 +157,7 @@ export default function GameIdleList({ gameList, favorites, cardFarming, achieve ); })} - + ); diff --git a/components/gameslist/GamesList.jsx b/components/gameslist/GamesList.jsx index fcb6b58..d4b5f50 100644 --- a/components/gameslist/GamesList.jsx +++ b/components/gameslist/GamesList.jsx @@ -161,9 +161,7 @@ export default function GamesList({ steamId, inputValue, isQuery, activePage, se showStats={showStats} handleShowStats={handleShowStats} filteredGames={filteredGames} - setFilteredGames={setFilteredGames} visibleGames={visibleGames} - setVisibleGames={setVisibleGames} /> )} diff --git a/components/gameslist/GamesWithDrops.jsx b/components/gameslist/GamesWithDrops.jsx deleted file mode 100644 index a7bbe31..0000000 --- a/components/gameslist/GamesWithDrops.jsx +++ /dev/null @@ -1,65 +0,0 @@ -import React, { useState } from 'react'; -import { Button } from '@nextui-org/react'; -import { Slide, ToastContainer, toast } from 'react-toastify'; -import 'react-toastify/dist/ReactToastify.css'; - -export default function GamesWithDrops({ setFilteredGames, setVisibleGames }) { - const [isLoading, setIsLoading] = useState(false); - - const handleClick = async () => { - setIsLoading(true); - const userSummary = JSON.parse(localStorage.getItem('userSummary')) || {}; - const steamCookies = JSON.parse(localStorage.getItem('steamCookies')) || {}; - if (!steamCookies.sid || !steamCookies.sls) { - setIsLoading(false); - return toast.error('Missing credentials in Settings'); - } - const validate = await fetch('https://apibase.vercel.app/api/route', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ route: 'validate-session', sid: steamCookies?.sid, sls: steamCookies?.sls }), - }); - if (validate.status === 500) { - localStorage.removeItem('steamCookies'); - setIsLoading(false); - return toast.error('Steam credentials need to be updated'); - } - const response = await fetch('https://apibase.vercel.app/api/route', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ route: 'games-with-drops', sid: steamCookies?.sid, sls: steamCookies?.sls, steamId: userSummary.steamId }), - }); - if (response.status === 500) { - localStorage.removeItem('steamCookies'); - setIsLoading(false); - return toast.error('Steam credentials need to be updated'); - } - const data = await response.json(); - const gameDataArr = []; - if (data.games && data.games.length > 0) { - for (const game of data.games) { - gameDataArr.push(JSON.stringify(game)); - } - localStorage.setItem('cardFarming', JSON.stringify(gameDataArr)); - setFilteredGames(gameDataArr.map(JSON.parse)); - setVisibleGames(gameDataArr.map(JSON.parse).slice(0, 50)); - setIsLoading(false); - } else { - setIsLoading(false); - return toast.error('No games founds. Try manually adding them'); - } - }; - - return ( - - - - - ); -} \ No newline at end of file diff --git a/components/gameslist/PageHeader.jsx b/components/gameslist/PageHeader.jsx index eb1b72f..d0706fc 100644 --- a/components/gameslist/PageHeader.jsx +++ b/components/gameslist/PageHeader.jsx @@ -3,9 +3,8 @@ import { Button, Select, SelectItem, Tooltip } from '@nextui-org/react'; import { IoIosStats } from 'react-icons/io'; import { MdSort } from 'react-icons/md'; import Automate from './Automate'; -import GamesWithDrops from './GamesWithDrops'; -export default function PageHeader({ activePage, setActivePage, sortStyle, setSortStyle, showStats, handleShowStats, filteredGames, setFilteredGames, visibleGames, setVisibleGames }) { +export default function PageHeader({ activePage, setActivePage, sortStyle, setSortStyle, showStats, handleShowStats, filteredGames, visibleGames }) { const sortOptions = [ { key: 'a-z', label: 'Title Ascending' }, { key: 'z-a', label: 'Title Descending' }, @@ -48,10 +47,6 @@ export default function PageHeader({ activePage, setActivePage, sortStyle, setSo
- {sortStyle === 'cardFarming' && ( - - )} -
diff --git a/components/settings/AchievementSettings.jsx b/components/settings/AchievementSettings.jsx index 542cf5e..f8a3f76 100644 --- a/components/settings/AchievementSettings.jsx +++ b/components/settings/AchievementSettings.jsx @@ -83,7 +83,7 @@ export default function AchievementSettings({ settings, setSettings }) { +

Unlock interval

@@ -92,7 +92,6 @@ export default function AchievementSettings({ settings, setSettings }) {

} - isDisabled={localSettings.achievementUnlocker.random} size='sm' step={5} minValue={5} diff --git a/components/settings/CardSettings.jsx b/components/settings/CardSettings.jsx index 67a795f..6130f01 100644 --- a/components/settings/CardSettings.jsx +++ b/components/settings/CardSettings.jsx @@ -1,9 +1,9 @@ import React, { useEffect, useState } from 'react'; import ExtLink from '../ExtLink'; -import { Button, Input, Skeleton } from '@nextui-org/react'; +import { Button, Checkbox, Input, Skeleton } from '@nextui-org/react'; import { logEvent } from '@/utils/utils'; -export default function CardSettings() { +export default function CardSettings({ settings, setSettings }) { let [isLoading, setIsLoading] = useState(false); const [sidValue, setSidValue] = useState(''); const [slsValue, setSlsValue] = useState(''); @@ -11,6 +11,13 @@ export default function CardSettings() { const [loginState, setLoginState] = useState(false); const [steamUser, setSteamUser] = useState(null); const [validationError, setValidationError] = useState(false); + const [localSettings, setLocalSettings] = useState(null); + + useEffect(() => { + if (settings) { + setLocalSettings(settings); + } + }, [settings]); useEffect(() => { setIsLoading(true); @@ -86,20 +93,82 @@ export default function CardSettings() { logEvent('[Settings - Card Farming] Logged out'); }; + const handleCheckboxChange = (e) => { + const { name, checked } = e.target; + const updatedSettings = { + ...localSettings, + achievementUnlocker: { + ...localSettings.achievementUnlocker + }, + cardFarming: { + ...localSettings.cardFarming, + [name]: checked + } + }; + const checkboxNames = Object.keys(updatedSettings.cardFarming); + if (checked) { + const otherCheckboxName = checkboxNames.find(checkbox => checkbox !== name); + updatedSettings.cardFarming[otherCheckboxName] = false; + } else { + const otherCheckboxName = checkboxNames.find(checkbox => checkbox !== name); + if (!updatedSettings.cardFarming[otherCheckboxName]) { + updatedSettings.cardFarming[name] = true; + } + } + localStorage.setItem('settings', JSON.stringify(updatedSettings)); + updateSettings(updatedSettings); + logEvent(`[Settings - Card Farming] Changed '${name}' to '${updatedSettings.cardFarming[name]}'`); + }; + + const updateSettings = (newSettings) => { + setLocalSettings(newSettings); + setSettings(newSettings); + try { + localStorage.setItem('settings', JSON.stringify(newSettings)); + } catch (error) { + console.error('Failed to save settings to localStorage:', error); + } + }; + return (
-

- Card Farming -

+
+

+ Card Farming +

+

+ Steam credentials are required in order to use the Card Farming feature. Learn more +

+
-
-
-
-

- Steam credentials are required in order to use the Card Farming feature. Learn more +

+ +
+

+ Card farming list

+
+
+ +
+

+ All games with drops +

+
+
+ +
+
{ + const getAppVersion = async () => { + const appVersion = await getVersion(); + setVersion(appVersion); + }; + getAppVersion(); + }, []); useEffect(() => { const defaultSettings = { + cardFarming: { + listGames: true, + allGames: false + }, achievementUnlocker: { - interval: [30, 130] + interval: [30, 130], + idle: false } }; - let currentSettings = JSON.parse(localStorage.getItem('settings')); - if (!currentSettings) { - localStorage.setItem('settings', JSON.stringify(defaultSettings)); - currentSettings = JSON.parse(localStorage.getItem('settings')); + let currentSettings = JSON.parse(localStorage.getItem('settings')) || {}; + let updatedSettings = { + cardFarming: { + ...defaultSettings.cardFarming, + ...currentSettings.cardFarming + }, + achievementUnlocker: { + ...defaultSettings.achievementUnlocker, + ...currentSettings.achievementUnlocker + } + }; + if (JSON.stringify(currentSettings) !== JSON.stringify(updatedSettings)) { + localStorage.setItem('settings', JSON.stringify(updatedSettings)); } - setSettings(currentSettings); + setSettings(updatedSettings); }, []); return ( @@ -27,9 +51,14 @@ export default function Settings() {
-

- Settings -

+
+

+ Settings +

+

+ v{version} +

+
@@ -37,6 +66,11 @@ export default function Settings() { Help

+ +

+ Changelog +

+

Report an issue diff --git a/latest.json b/latest.json index e32c73a..6c5d4fb 100644 --- a/latest.json +++ b/latest.json @@ -1,9 +1,9 @@ { - "version": "1.3.4", + "version": "1.3.5", "platforms": { "windows-x86_64": { - "signature": "dW50cnVzdGVkIGNvbW1lbnQ6IHNpZ25hdHVyZSBmcm9tIHRhdXJpIHNlY3JldCBrZXkKUlVUSDh2NGF3cDBSMHF1TjhnbkVPV05sbXNrRkJlNnFHSnB1MFVVVW5JVWs5SjFRNHl6aUVKRVZXN3RLYkExdm0vTGU4Q0RZRXRtbUF3czNzUWJnZVRjU3MrK01LRUk1cWd3PQp0cnVzdGVkIGNvbW1lbnQ6IHRpbWVzdGFtcDoxNzI0MTQwOTk5CWZpbGU6U3RlYW0gR2FtZSBJZGxlcl8xLjMuNF94NjRfZW4tVVMubXNpLnppcApFWHp2aHRCdTVoV3dqQVlQLzFJT0lPQWJ3WCs0V0h3anNqQjJHVlQ5Q0RCekVOWEZQTXYvTHVKQmdHeFFSQzd2MGx1RTdXbzNXNk5WS0hYODBUOEtDQT09Cg==", - "url": "https://github.com/ProbablyRaging/steam-game-idler/releases/download/1.3.4/Steam.Game.Idler_1.3.4_x64_en-US.msi.zip" + "signature": "dW50cnVzdGVkIGNvbW1lbnQ6IHNpZ25hdHVyZSBmcm9tIHRhdXJpIHNlY3JldCBrZXkKUlVUSDh2NGF3cDBSMHBPNSsyWmFPRjhLWkxibkFuNzViMHFJY2V1Y2NnbFBDdmNZMWg4SllFMHNBOEMyZTB5RUxoMXo0bTNPMWVpam5UT2pZRm9yY3F4NVRFOVhub0VBNXdVPQp0cnVzdGVkIGNvbW1lbnQ6IHRpbWVzdGFtcDoxNzI0MTU0NTAyCWZpbGU6U3RlYW0gR2FtZSBJZGxlcl8xLjMuNV94NjRfZW4tVVMubXNpLnppcApsTk5ZUCtrREVaZjY3U2hqYmpYSklHVG93MDFKV0N3OC84d1VXK2NIL1RCdHd2WFpUVjVCOXhiZTkvanZhLzV0V2R0T0pYRjJNOHRXM3k3Slhld0tEdz09Cg==", + "url": "https://github.com/ProbablyRaging/steam-game-idler/releases/download/1.3.5/Steam.Game.Idler_1.3.5_x64_en-US.msi.zip" } } } \ No newline at end of file diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index f008fef..b3b614d 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -55,7 +55,7 @@ fn start_idle(file_path: String, app_id: String, quiet: String) -> Result<(), St } #[tauri::command] -fn stop_idle(app_id: String) -> Result<(), String> { +async fn stop_idle(app_id: String) -> Result<(), String> { let wmic_output = std::process::Command::new("wmic") .args(&["process", "get", "processid,commandline"]) .creation_flags(0x08000000) diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 6d3fd84..0300edb 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -9,7 +9,7 @@ }, "package": { "productName": "Steam Game Idler", - "version": "1.3.4" + "version": "1.3.5" }, "tauri": { "allowlist": { diff --git a/utils/utils.js b/utils/utils.js index 4dd1728..67ff596 100644 --- a/utils/utils.js +++ b/utils/utils.js @@ -49,7 +49,6 @@ export async function unlockAchievement(appId, achievementId, unlockAll) { statistics('achievement'); logEvent(`Unlocked achievement ${achievementId} (${appId})`); } else { - toast.error('Steam is not running'); logEvent(`[Error] Achievement failed - Steam is not running`); } } @@ -72,6 +71,20 @@ export async function checkDrops(steamId, appId, sid, sls) { } } +export async function getAllGamesWithDrops(steamId, sid, sls) { + const response = await fetch('https://apibase.vercel.app/api/route', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ route: 'games-with-drops', steamId: steamId, sid: sid, sls: sls }), + }) + if (response.status !== 500) { + const data = await response.json(); + return data.games; + } else { + return 0; + } +} + export async function logEvent(message) { try { await invoke('log_event', { message });