diff --git a/project/assets/configs/hideout.json b/project/assets/configs/hideout.json index 47bdfb7c..b28f446e 100644 --- a/project/assets/configs/hideout.json +++ b/project/assets/configs/hideout.json @@ -7,5 +7,6 @@ }, "expCraftAmount": 10, "overrideCraftTimeSeconds": -1, - "overrideBuildTimeSeconds": -1 + "overrideBuildTimeSeconds": -1, + "updateProfileHideoutWhenActiveWithinMinutes": 90 } \ No newline at end of file diff --git a/project/src/controllers/GameController.ts b/project/src/controllers/GameController.ts index f32fed06..f8be4796 100644 --- a/project/src/controllers/GameController.ts +++ b/project/src/controllers/GameController.ts @@ -39,6 +39,7 @@ import { GiftService } from "@spt-aki/services/GiftService"; import { ItemBaseClassService } from "@spt-aki/services/ItemBaseClassService"; import { LocalisationService } from "@spt-aki/services/LocalisationService"; import { OpenZoneService } from "@spt-aki/services/OpenZoneService"; +import { ProfileActivityService } from "@spt-aki/services/ProfileActivityService"; import { ProfileFixerService } from "@spt-aki/services/ProfileFixerService"; import { RaidTimeAdjustmentService } from "@spt-aki/services/RaidTimeAdjustmentService"; import { SeasonalEventService } from "@spt-aki/services/SeasonalEventService"; @@ -78,6 +79,7 @@ export class GameController @inject("ItemBaseClassService") protected itemBaseClassService: ItemBaseClassService, @inject("GiftService") protected giftService: GiftService, @inject("RaidTimeAdjustmentService") protected raidTimeAdjustmentService: RaidTimeAdjustmentService, + @inject("ProfileActivityService") protected profileActivityService: ProfileActivityService, @inject("ApplicationContext") protected applicationContext: ApplicationContext, @inject("ConfigServer") protected configServer: ConfigServer, ) @@ -109,6 +111,8 @@ export class GameController // Store client start time in app context this.applicationContext.addValue(ContextVariableType.CLIENT_START_TIMESTAMP, startTimeStampMS); + this.profileActivityService.setActivityTimestamp(sessionID); + if (this.coreConfig.fixes.fixShotgunDispersion) { this.fixShotgunDispersions(); @@ -504,6 +508,7 @@ export class GameController */ public getKeepAlive(sessionId: string): IGameKeepAliveResponse { + this.profileActivityService.setActivityTimestamp(sessionId); return { msg: "OK", utc_time: new Date().getTime() / 1000 }; } diff --git a/project/src/controllers/HideoutController.ts b/project/src/controllers/HideoutController.ts index 64a42525..d6d27841 100644 --- a/project/src/controllers/HideoutController.ts +++ b/project/src/controllers/HideoutController.ts @@ -48,6 +48,7 @@ import { SaveServer } from "@spt-aki/servers/SaveServer"; import { FenceService } from "@spt-aki/services/FenceService"; import { LocalisationService } from "@spt-aki/services/LocalisationService"; import { PlayerService } from "@spt-aki/services/PlayerService"; +import { ProfileActivityService } from "@spt-aki/services/ProfileActivityService"; import { HashUtil } from "@spt-aki/utils/HashUtil"; import { HttpResponseUtil } from "@spt-aki/utils/HttpResponseUtil"; import { JsonUtil } from "@spt-aki/utils/JsonUtil"; @@ -79,6 +80,7 @@ export class HideoutController @inject("HideoutHelper") protected hideoutHelper: HideoutHelper, @inject("ScavCaseRewardGenerator") protected scavCaseRewardGenerator: ScavCaseRewardGenerator, @inject("LocalisationService") protected localisationService: LocalisationService, + @inject("ProfileActivityService") protected profileActivityService: ProfileActivityService, @inject("ConfigServer") protected configServer: ConfigServer, @inject("JsonUtil") protected jsonUtil: JsonUtil, @inject("FenceService") protected fenceService: FenceService, @@ -1323,7 +1325,13 @@ export class HideoutController { for (const sessionID in this.saveServer.getProfiles()) { - if ("Hideout" in this.saveServer.getProfile(sessionID).characters.pmc) + if ( + "Hideout" in this.saveServer.getProfile(sessionID).characters.pmc + && this.profileActivityService.activeWithinLastMinutes( + sessionID, + this.hideoutConfig.updateProfileHideoutWhenActiveWithinMinutes, + ) + ) { this.hideoutHelper.updatePlayerHideout(sessionID); } diff --git a/project/src/di/Container.ts b/project/src/di/Container.ts index f9012381..2fdfde9d 100644 --- a/project/src/di/Container.ts +++ b/project/src/di/Container.ts @@ -213,6 +213,7 @@ import { OpenZoneService } from "@spt-aki/services/OpenZoneService"; import { PaymentService } from "@spt-aki/services/PaymentService"; import { PlayerService } from "@spt-aki/services/PlayerService"; import { PmcChatResponseService } from "@spt-aki/services/PmcChatResponseService"; +import { ProfileActivityService } from "@spt-aki/services/ProfileActivityService"; import { ProfileFixerService } from "@spt-aki/services/ProfileFixerService"; import { ProfileSnapshotService } from "@spt-aki/services/ProfileSnapshotService"; import { RagfairCategoriesService } from "@spt-aki/services/RagfairCategoriesService"; @@ -747,6 +748,10 @@ export class Container depContainer.register("GiftService", GiftService); depContainer.register("MailSendService", MailSendService); depContainer.register("RaidTimeAdjustmentService", RaidTimeAdjustmentService); + + depContainer.register("ProfileActivityService", ProfileActivityService, { + lifecycle: Lifecycle.Singleton, + }); } private static registerServers(depContainer: DependencyContainer): void diff --git a/project/src/models/spt/config/IHideoutConfig.ts b/project/src/models/spt/config/IHideoutConfig.ts index e2f419b2..0fc1caca 100644 --- a/project/src/models/spt/config/IHideoutConfig.ts +++ b/project/src/models/spt/config/IHideoutConfig.ts @@ -11,4 +11,6 @@ export interface IHideoutConfig extends IBaseConfig expCraftAmount: number; overrideCraftTimeSeconds: number; overrideBuildTimeSeconds: number; + /** Only process a profiles hideout crafts when it has been active in the last x minutes */ + updateProfileHideoutWhenActiveWithinMinutes: number; } diff --git a/project/src/services/ProfileActivityService.ts b/project/src/services/ProfileActivityService.ts new file mode 100644 index 00000000..025a3885 --- /dev/null +++ b/project/src/services/ProfileActivityService.ts @@ -0,0 +1,36 @@ +import { injectable } from "tsyringe"; + +@injectable() +export class ProfileActivityService +{ + protected profileActivityTimestamps: Record = {}; + + /** + * Was the requested profile active in the last requested minutes + * @param sessionId Profile to check + * @param minutes Minutes to check for activity in + * @returns True when profile was active within past x minutes + */ + public activeWithinLastMinutes(sessionId: string, minutes: number): boolean + { + const currentTimestamp = new Date().getTime() / 1000; + const storedActivityTimestamp = this.profileActivityTimestamps[sessionId]; + if (!storedActivityTimestamp) + { + // No value, no assumed activity (server offline?) + return false; + } + + // True if difference since last timestamp to now is below desired amount + return (currentTimestamp - storedActivityTimestamp) < (minutes * 60); // convert minutes to seconds to compare + } + + /** + * Update the timestamp a profile was last observed active + * @param sessionId Profile to update + */ + public setActivityTimestamp(sessionId: string): void + { + this.profileActivityTimestamps[sessionId] = new Date().getTime() / 1000; + } +}