Add new endpoint to calcualte a reduced raid time for scavs and send the maps base.EscapeTimeLimit value to client for PMC raids

This commit is contained in:
Dev 2023-11-26 21:11:03 +00:00
parent 1350fdb78b
commit ac459335c0
9 changed files with 203 additions and 5 deletions

View File

@ -793,5 +793,106 @@
"minFillStaticMagazinePercent": 50, "minFillStaticMagazinePercent": 50,
"makeWishingTreeAlwaysGiveGift": true, "makeWishingTreeAlwaysGiveGift": true,
"allowDuplicateItemsInStaticContainers": true, "allowDuplicateItemsInStaticContainers": true,
"looseLootBlacklist": {} "looseLootBlacklist": {},
"scavRaidTimeSettings": {
"bigmap": {
"reducedChancePercent": 40,
"reductionPercentWeights": {
"20": 12,
"40": 5,
"60": 2,
"80": 1
}
},
"factory4_day": {
"reducedChancePercent": 60,
"reductionPercentWeights": {
"20": 12,
"40": 5,
"60": 2,
"80": 1
}
},
"factory4_night": {
"reducedChancePercent": 40,
"reductionPercentWeights": {
"20": 12,
"40": 5,
"60": 2,
"80": 1
}
},
"interchange": {
"reducedChancePercent": 50,
"reductionPercentWeights": {
"20": 12,
"40": 5,
"60": 2,
"80": 1
}
},
"rezervbase": {
"reducedChancePercent": 40,
"reductionPercentWeights": {
"20": 12,
"40": 5,
"60": 2,
"80": 1
}
},
"laboratory": {
"reducedChancePercent": 30,
"reductionPercentWeights": {
"20": 12,
"40": 5,
"60": 2,
"80": 1
}
},
"lighthouse": {
"reducedChancePercent": 40,
"reductionPercentWeights": {
"20": 12,
"40": 5,
"60": 2,
"80": 1
}
},
"shoreline": {
"reducedChancePercent": 40,
"reductionPercentWeights": {
"20": 25,
"40": 10,
"60": 1,
"80": 1
}
},
"tarkovstreets": {
"reducedChancePercent": 40,
"reductionPercentWeights": {
"20": 25,
"40": 10,
"60": 1,
"80": 1
}
},
"woods": {
"reducedChancePercent": 40,
"reductionPercentWeights": {
"20": 25,
"40": 10,
"60": 1,
"80": 1
}
},
"default": {
"reducedChancePercent": 25,
"reductionPercentWeights": {
"20": 12,
"40": 5,
"60": 2,
"80": 1
}
}
}
} }

View File

@ -10,6 +10,7 @@ import { IGameEmptyCrcRequestData } from "@spt-aki/models/eft/game/IGameEmptyCrc
import { IGameKeepAliveResponse } from "@spt-aki/models/eft/game/IGameKeepAliveResponse"; import { IGameKeepAliveResponse } from "@spt-aki/models/eft/game/IGameKeepAliveResponse";
import { IGameLogoutResponseData } from "@spt-aki/models/eft/game/IGameLogoutResponseData"; import { IGameLogoutResponseData } from "@spt-aki/models/eft/game/IGameLogoutResponseData";
import { IGameStartResponse } from "@spt-aki/models/eft/game/IGameStartResponse"; import { IGameStartResponse } from "@spt-aki/models/eft/game/IGameStartResponse";
import { IGetRaidTimeRequest } from "@spt-aki/models/eft/game/IGetRaidTimeRequest";
import { IReportNicknameRequestData } from "@spt-aki/models/eft/game/IReportNicknameRequestData"; import { IReportNicknameRequestData } from "@spt-aki/models/eft/game/IReportNicknameRequestData";
import { IServerDetails } from "@spt-aki/models/eft/game/IServerDetails"; import { IServerDetails } from "@spt-aki/models/eft/game/IServerDetails";
import { IVersionValidateRequestData } from "@spt-aki/models/eft/game/IVersionValidateRequestData"; import { IVersionValidateRequestData } from "@spt-aki/models/eft/game/IVersionValidateRequestData";
@ -157,6 +158,16 @@ class GameCallbacks implements OnLoad
{ {
return this.httpResponse.nullResponse(); return this.httpResponse.nullResponse();
} }
/**
* Handle singleplayer/settings/getRaidTime
* @returns string
*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars
public getRaidTime(url: string, request: IGetRaidTimeRequest, sessionID: string): any
{
return this.httpResponse.noBody(this.gameController.getRaidTime(sessionID, request));
}
} }
export {GameCallbacks}; export {GameCallbacks};

View File

@ -17,7 +17,7 @@ export class ApplicationContext
* *
* const activePlayerSessionId = this.applicationContext.getLatestValue(ContextVariableType.SESSION_ID).getValue<string>(); * const activePlayerSessionId = this.applicationContext.getLatestValue(ContextVariableType.SESSION_ID).getValue<string>();
* *
* const matchInfo = this.applicationContext.getLatestValue(ContextVariableType.MATCH_INFO).getValue<IStartOfflineRaidRequestData>(); * const matchInfo = this.applicationContext.getLatestValue(ContextVariableType.RAID_CONFIGURATION).getValue<IGetRaidConfigurationRequestData>();
* @param type * @param type
* @returns * @returns
*/ */

View File

@ -1,5 +1,4 @@
export enum ContextVariableType export enum ContextVariableType {
{
/** Logged in users session id */ /** Logged in users session id */
SESSION_ID = 0, SESSION_ID = 0,
/** Currently acive raid information */ /** Currently acive raid information */
@ -7,5 +6,5 @@ export enum ContextVariableType
/** Timestamp when client first connected */ /** Timestamp when client first connected */
CLIENT_START_TIMESTAMP = 2, CLIENT_START_TIMESTAMP = 2,
/** When player is loading into map and loot is requested */ /** When player is loading into map and loot is requested */
REGISTER_PLAYER_REQUEST = 3, REGISTER_PLAYER_REQUEST = 3
} }

View File

@ -5,6 +5,7 @@ import { ContextVariableType } from "@spt-aki/context/ContextVariableType";
import { HideoutHelper } from "@spt-aki/helpers/HideoutHelper"; import { HideoutHelper } from "@spt-aki/helpers/HideoutHelper";
import { HttpServerHelper } from "@spt-aki/helpers/HttpServerHelper"; import { HttpServerHelper } from "@spt-aki/helpers/HttpServerHelper";
import { ProfileHelper } from "@spt-aki/helpers/ProfileHelper"; import { ProfileHelper } from "@spt-aki/helpers/ProfileHelper";
import { WeightedRandomHelper } from "@spt-aki/helpers/WeightedRandomHelper";
import { PreAkiModLoader } from "@spt-aki/loaders/PreAkiModLoader"; import { PreAkiModLoader } from "@spt-aki/loaders/PreAkiModLoader";
import { IEmptyRequestData } from "@spt-aki/models/eft/common/IEmptyRequestData"; import { IEmptyRequestData } from "@spt-aki/models/eft/common/IEmptyRequestData";
import { ILooseLoot } from "@spt-aki/models/eft/common/ILooseLoot"; import { ILooseLoot } from "@spt-aki/models/eft/common/ILooseLoot";
@ -14,7 +15,10 @@ import { ICheckVersionResponse } from "@spt-aki/models/eft/game/ICheckVersionRes
import { ICurrentGroupResponse } from "@spt-aki/models/eft/game/ICurrentGroupResponse"; import { ICurrentGroupResponse } from "@spt-aki/models/eft/game/ICurrentGroupResponse";
import { IGameConfigResponse } from "@spt-aki/models/eft/game/IGameConfigResponse"; import { IGameConfigResponse } from "@spt-aki/models/eft/game/IGameConfigResponse";
import { IGameKeepAliveResponse } from "@spt-aki/models/eft/game/IGameKeepAliveResponse"; import { IGameKeepAliveResponse } from "@spt-aki/models/eft/game/IGameKeepAliveResponse";
import { IGetRaidTimeRequest } from "@spt-aki/models/eft/game/IGetRaidTimeRequest";
import { IGetRaidTimeResponse } from "@spt-aki/models/eft/game/IGetRaidTimeResponse";
import { IServerDetails } from "@spt-aki/models/eft/game/IServerDetails"; import { IServerDetails } from "@spt-aki/models/eft/game/IServerDetails";
import { IGetRaidConfigurationRequestData } from "@spt-aki/models/eft/match/IGetRaidConfigurationRequestData";
import { IAkiProfile } from "@spt-aki/models/eft/profile/IAkiProfile"; import { IAkiProfile } from "@spt-aki/models/eft/profile/IAkiProfile";
import { AccountTypes } from "@spt-aki/models/enums/AccountTypes"; import { AccountTypes } from "@spt-aki/models/enums/AccountTypes";
import { ConfigTypes } from "@spt-aki/models/enums/ConfigTypes"; import { ConfigTypes } from "@spt-aki/models/enums/ConfigTypes";
@ -68,6 +72,7 @@ export class GameController
@inject("SeasonalEventService") protected seasonalEventService: SeasonalEventService, @inject("SeasonalEventService") protected seasonalEventService: SeasonalEventService,
@inject("ItemBaseClassService") protected itemBaseClassService: ItemBaseClassService, @inject("ItemBaseClassService") protected itemBaseClassService: ItemBaseClassService,
@inject("GiftService") protected giftService: GiftService, @inject("GiftService") protected giftService: GiftService,
@inject("WeightedRandomHelper") protected weightedRandomHelper: WeightedRandomHelper,
@inject("ApplicationContext") protected applicationContext: ApplicationContext, @inject("ApplicationContext") protected applicationContext: ApplicationContext,
@inject("ConfigServer") protected configServer: ConfigServer, @inject("ConfigServer") protected configServer: ConfigServer,
) )
@ -475,6 +480,53 @@ export class GameController
}; };
} }
/**
* singleplayer/settings/getRaidTime
*/
public getRaidTime(sessionId: string, request: IGetRaidTimeRequest): IGetRaidTimeResponse
{
const baseEscapeTimeMinutes = this.databaseServer.getTables().locations[request.Location.toLowerCase()].base.EscapeTimeLimit;
const result: IGetRaidTimeResponse = {
RaidTimeMinutes: baseEscapeTimeMinutes
}
// Pmc raid, send default
if (request.Side.toLowerCase() === "pmc")
{
return result;
}
// We're scav
let mapSettings = this.locationConfig.scavRaidTimeSettings[request.Location.toLowerCase()];
if (!mapSettings)
{
this.logger.warning(`Unable to find scav raid time settings for map: ${request.Location}, using defaults`);
mapSettings = this.locationConfig.scavRaidTimeSettings.default;
}
// Chance of reducing raid time for scav, not guaranteed
if (!this.randomUtil.getChance100(mapSettings.reducedChancePercent))
{
// Send default
return result;
}
// Get the weighted percent to reduce the raid time by
const chosenRaidReductionPercent = this.weightedRandomHelper.getWeightedValue<string>(
mapSettings.reductionPercentWeights,
);
// How many minutes raid will be
const newRaidTime = Math.floor(this.randomUtil.reduceValueByPercent(baseEscapeTimeMinutes, Number.parseInt(chosenRaidReductionPercent)));
// Update result object with new time
result.RaidTimeMinutes = newRaidTime;
this.logger.debug(`Reduced: ${request.Location} raid time by: ${chosenRaidReductionPercent}% to ${newRaidTime} minutes`)
return result;
}
/** /**
* BSG have two values for shotgun dispersion, we make sure both have the same value * BSG have two values for shotgun dispersion, we make sure both have the same value
*/ */

View File

@ -38,6 +38,14 @@ export interface ILocationConfig extends IBaseConfig
allowDuplicateItemsInStaticContainers: boolean; allowDuplicateItemsInStaticContainers: boolean;
/** Key: map, value: loose loot ids to ignore */ /** Key: map, value: loose loot ids to ignore */
looseLootBlacklist: Record<string, string[]>; looseLootBlacklist: Record<string, string[]>;
/** Key: map, value: settings to control how long scav raids are*/
scavRaidTimeSettings: Record<string, IScavRaidTimeLocationSettings>;
}
export interface IScavRaidTimeLocationSettings
{
reducedChancePercent: number
reductionPercentWeights: Record<string, number>
} }
export interface IContainerRandomistionSettings export interface IContainerRandomistionSettings

View File

@ -89,6 +89,14 @@ export class GameStaticRouter extends StaticRouter
return this.gameCallbacks.reportNickname(url, info, sessionID); return this.gameCallbacks.reportNickname(url, info, sessionID);
}, },
), ),
new RouteAction(
"/singleplayer/settings/getRaidTime",
// eslint-disable-next-line @typescript-eslint/no-unused-vars
(url: string, info: any, sessionID: string, output: string): any =>
{
return this.gameCallbacks.getRaidTime(url, info, sessionID);
},
)
]); ]);
} }
} }

View File

@ -34,6 +34,13 @@ export class HttpResponseUtil
return this.clearString(this.jsonUtil.serialize(data)); return this.clearString(this.jsonUtil.serialize(data));
} }
/**
* Game client needs server responses in a particular format
* @param data
* @param err
* @param errmsg
* @returns
*/
public getBody<T>(data: T, err = 0, errmsg = null): IGetBodyResponseData<T> public getBody<T>(data: T, err = 0, errmsg = null): IGetBodyResponseData<T>
{ {
return this.clearString(this.getUnclearedBody(data, err, errmsg)); return this.clearString(this.getUnclearedBody(data, err, errmsg));

View File

@ -231,6 +231,18 @@ export class RandomUtil
return Number.parseFloat(((percent * number) / 100).toFixed(toFixed)); return Number.parseFloat(((percent * number) / 100).toFixed(toFixed));
} }
/**
* Reduce a value by a percentage
* @param number Value to reduce
* @param percentage Percentage to reduce value by
* @returns Reduced value
*/
public reduceValueByPercent(number: number, percentage: number): number
{
const reductionAmount = number * (percentage / 100);
return number - reductionAmount;
}
/** /**
* Check if number passes a check out of 100 * Check if number passes a check out of 100
* @param chancePercent value check needs to be above * @param chancePercent value check needs to be above