Skip to content

Commit

Permalink
[FIX] Update Game status after finishing playing and not logged in (#…
Browse files Browse the repository at this point in the history
…1162)

* [FIX] Update Game status after finishing playing and not logged in

* chore: version and pr comments

* await syncPlaySession only on syncPlaySession handle (#1165)

* add comment explaining gameStatusUpdate done

---------

Co-authored-by: Flavio F Lima <[email protected]>
Co-authored-by: Brett <[email protected]>
  • Loading branch information
3 people authored Nov 25, 2024
1 parent 2c723a7 commit 361be53
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 42 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "hyperplay",
"version": "0.22.0",
"version": "0.22.1",
"private": true,
"main": "build/main/main.js",
"homepage": "./",
Expand Down
47 changes: 34 additions & 13 deletions src/backend/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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)
}
)

Expand Down Expand Up @@ -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)
Expand All @@ -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,
Expand All @@ -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(
Expand All @@ -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: {
Expand Down
61 changes: 33 additions & 28 deletions src/backend/utils/quests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down

0 comments on commit 361be53

Please sign in to comment.