diff --git a/package.json b/package.json index 090c624201..3c7eb4f795 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "hyperplay", - "version": "0.22.0", + "version": "0.22.1", "private": true, "main": "build/main/main.js", "homepage": "./", diff --git a/src/backend/main.ts b/src/backend/main.ts index c477af39bb..a35a0c44f2 100644 --- a/src/backend/main.ts +++ b/src/backend/main.ts @@ -1111,9 +1111,23 @@ function startNewPlaySession(appName: string) { return prevStartTime } -async function syncPlaySession(appName: string, runner: Runner) { +async function postPlaySession( + appName: string, + runner: Runner, + sessionPlaytimeInMs: bigint +) { + const game = gameManagerMap[runner].getGameInfo(appName) + const { hyperPlayListing } = await gameIsEpicForwarderOnHyperPlay(game) + await postPlaySessionTime( + hyperPlayListing?.project_id || appName, + // round up to prevent session time loss + parseInt(((sessionPlaytimeInMs + BigInt(1000)) / BigInt(1000)).toString()) + ) +} + +function syncPlaySession(appName: string) { if (!Object.hasOwn(gamePlaySessionStartTimes, appName)) { - return + return BigInt(0) } // reset the time counter and start new session slightly before ending current session to prevent time loss @@ -1130,21 +1144,14 @@ async function syncPlaySession(appName: string, runner: Runner) { sessionPlaytimeInMinutes + BigInt(tsStore.get(`${appName}.totalPlayed`, 0)) tsStore.set(`${appName}.totalPlayed`, Number(totalPlaytime)) - const game = gameManagerMap[runner].getGameInfo(appName) - const { hyperPlayListing } = await gameIsEpicForwarderOnHyperPlay(game) - await postPlaySessionTime( - hyperPlayListing?.project_id || appName, - // round up to prevent session time loss - parseInt(((sessionPlaytimeInMs + BigInt(1000)) / BigInt(1000)).toString()) - ) - return sessionPlaytimeInMs } ipcMain.handle( 'syncPlaySession', async (e, appName: string, runner: Runner) => { - await syncPlaySession(appName, runner) + const sessionPlaytimeInMs = syncPlaySession(appName) + await postPlaySession(appName, runner, sessionPlaytimeInMs) } ) @@ -1317,8 +1324,6 @@ ipcMain.handle( // Update playtime and last played date const finishedPlayingDate = new Date() tsStore.set(`${appName}.lastPlayed`, finishedPlayingDate.toISOString()) - // Playtime of this session in minutes. Uses hrtime for monotonic timer not subject to clock drift or sync errors - const sessionPlaytimeInMs = await syncPlaySession(appName, runner) if (runner === 'gog') { await updateGOGPlaytime(appName, startPlayingDate, finishedPlayingDate) @@ -1327,6 +1332,12 @@ ipcMain.handle( await addRecentGame(game) if (autoSyncSaves && isOnline()) { + /** + * @dev It sets to done, so the GlobalState knows that the game session stopped. + * Then it changes the status to syncing-saves. Then It sets to done again. + * Otherwise it would count the Syncing Saves time (which can be long depending on the game) as playing time as well. + * done is not only the state for stopping playing but for finishing any other process that came before. + */ sendFrontendMessage('gameStatusUpdate', { appName, runner, @@ -1339,6 +1350,12 @@ ipcMain.handle( status: 'syncing-saves' }) + sendFrontendMessage('gameStatusUpdate', { + appName, + runner, + status: 'done' + }) + logInfo(`Uploading saves for ${title}`, LogPrefix.Backend) try { await gameManagerMap[runner].syncSaves( @@ -1362,6 +1379,10 @@ ipcMain.handle( status: 'done' }) + // Playtime of this session in milliseconds. Uses hrtime for monotonic timer not subject to clock drift or sync errors + const sessionPlaytimeInMs = syncPlaySession(appName) + postPlaySession(appName, runner, sessionPlaytimeInMs) + trackEvent({ event: 'Game Closed', properties: { diff --git a/src/backend/utils/quests.ts b/src/backend/utils/quests.ts index 1225ef065c..85cd8b8f21 100644 --- a/src/backend/utils/quests.ts +++ b/src/backend/utils/quests.ts @@ -7,36 +7,41 @@ export async function postPlaySessionTime( appName: string, playSessionInSeconds: number ) { - logInfo( - `Posting play session for project id ${appName}. Time played in seconds was ${playSessionInSeconds}`, - LogPrefix.HyperPlay - ) - const cookieString = await getPartitionCookies({ - partition: 'persist:auth', - url: DEV_PORTAL_URL - }) - const response = await fetch(`${DEV_PORTAL_URL}api/v1/quests/playStreak`, { - method: 'POST', - headers: { - Cookie: cookieString - }, - body: JSON.stringify({ - project_id: appName, - play_session_in_seconds: playSessionInSeconds + try { + logInfo( + `Posting play session for project id ${appName}. Time played in seconds was ${playSessionInSeconds}`, + LogPrefix.HyperPlay + ) + const cookieString = await getPartitionCookies({ + partition: 'persist:auth', + url: DEV_PORTAL_URL }) - }) - if (!response.ok) { - throw await response.text() + const response = await fetch(`${DEV_PORTAL_URL}api/v1/quests/playStreak`, { + method: 'POST', + headers: { + Cookie: cookieString + }, + body: JSON.stringify({ + project_id: appName, + play_session_in_seconds: playSessionInSeconds + }) + }) + if (!response.ok) { + throw await response.text() + } + const resultJson = await response.json() + logInfo( + `Posted playstreak playsession. response: ${JSON.stringify( + resultJson, + null, + 4 + )}`, + LogPrefix.HyperPlay + ) + } catch (error) { + logInfo(`Error in postPlaySessionTime: ${error}`, LogPrefix.HyperPlay) + throw error } - const resultJson = await response.json() - logInfo( - `Posted playstreak playsession. response: ${JSON.stringify( - resultJson, - null, - 4 - )}`, - LogPrefix.HyperPlay - ) } export async function checkG7ConnectionStatus() {