Persist durability changes + faceshield hit values incurred during a raid (!110)

Fixes insured items comin back full durability

Co-authored-by: CWX <CWX@noreply.dev.sp-tarkov.com>
Co-authored-by: Dev <dev@dev.sp-tarkov.com>
Reviewed-on: https://dev.sp-tarkov.com/SPT-AKI/Server/pulls/110
This commit is contained in:
chomp 2023-08-05 17:26:16 +00:00
parent 9dd2d3cd04
commit a962823192
4 changed files with 161 additions and 65 deletions

View File

@ -341,6 +341,7 @@ export interface BackendCounter
export interface InsuredItem export interface InsuredItem
{ {
/** Trader Id item was insured by */
tid: string tid: string
itemId: string itemId: string
} }

View File

@ -0,0 +1,7 @@
export interface IInsuredItemsData
{
id: string
durability?: number
maxDurability?: number
hits?: number
}

View File

@ -1,6 +1,7 @@
import { PlayerRaidEndState } from "../../../models/enums/PlayerRaidEndState"; import { PlayerRaidEndState } from "../../../models/enums/PlayerRaidEndState";
import { IPmcData } from "../common/IPmcData"; import { IPmcData } from "../common/IPmcData";
import { ISyncHealthRequestData } from "../health/ISyncHealthRequestData"; import { ISyncHealthRequestData } from "../health/ISyncHealthRequestData";
import { IInsuredItemsData } from "./IInsuredItemsData";
export interface ISaveProgressRequestData export interface ISaveProgressRequestData
{ {
@ -8,4 +9,5 @@ export interface ISaveProgressRequestData
profile: IPmcData profile: IPmcData
isPlayerScav: boolean isPlayerScav: boolean
health: ISyncHealthRequestData health: ISyncHealthRequestData
insurance: IInsuredItemsData[]
} }

View File

@ -8,8 +8,8 @@ import { NotificationSendHelper } from "../helpers/NotificationSendHelper";
import { SecureContainerHelper } from "../helpers/SecureContainerHelper"; import { SecureContainerHelper } from "../helpers/SecureContainerHelper";
import { TraderHelper } from "../helpers/TraderHelper"; import { TraderHelper } from "../helpers/TraderHelper";
import { IPmcData } from "../models/eft/common/IPmcData"; import { IPmcData } from "../models/eft/common/IPmcData";
import { InsuredItem } from "../models/eft/common/tables/IBotBase";
import { Item } from "../models/eft/common/tables/IItem"; import { Item } from "../models/eft/common/tables/IItem";
import { IInsuredItemsData } from "../models/eft/inRaid/IInsuredItemsData";
import { ISaveProgressRequestData } from "../models/eft/inRaid/ISaveProgressRequestData"; import { ISaveProgressRequestData } from "../models/eft/inRaid/ISaveProgressRequestData";
import { IUserDialogInfo } from "../models/eft/profile/IAkiProfile"; import { IUserDialogInfo } from "../models/eft/profile/IAkiProfile";
import { ConfigTypes } from "../models/enums/ConfigTypes"; import { ConfigTypes } from "../models/enums/ConfigTypes";
@ -21,6 +21,7 @@ import { ILogger } from "../models/spt/utils/ILogger";
import { ConfigServer } from "../servers/ConfigServer"; import { ConfigServer } from "../servers/ConfigServer";
import { DatabaseServer } from "../servers/DatabaseServer"; import { DatabaseServer } from "../servers/DatabaseServer";
import { SaveServer } from "../servers/SaveServer"; import { SaveServer } from "../servers/SaveServer";
import { JsonUtil } from "../utils/JsonUtil";
import { RandomUtil } from "../utils/RandomUtil"; import { RandomUtil } from "../utils/RandomUtil";
import { TimeUtil } from "../utils/TimeUtil"; import { TimeUtil } from "../utils/TimeUtil";
import { LocaleService } from "./LocaleService"; import { LocaleService } from "./LocaleService";
@ -38,6 +39,7 @@ export class InsuranceService
@inject("SecureContainerHelper") protected secureContainerHelper: SecureContainerHelper, @inject("SecureContainerHelper") protected secureContainerHelper: SecureContainerHelper,
@inject("RandomUtil") protected randomUtil: RandomUtil, @inject("RandomUtil") protected randomUtil: RandomUtil,
@inject("ItemHelper") protected itemHelper: ItemHelper, @inject("ItemHelper") protected itemHelper: ItemHelper,
@inject("JsonUtil") protected jsonUtil: JsonUtil,
@inject("TimeUtil") protected timeUtil: TimeUtil, @inject("TimeUtil") protected timeUtil: TimeUtil,
@inject("SaveServer") protected saveServer: SaveServer, @inject("SaveServer") protected saveServer: SaveServer,
@inject("TraderHelper") protected traderHelper: TraderHelper, @inject("TraderHelper") protected traderHelper: TraderHelper,
@ -52,6 +54,11 @@ export class InsuranceService
this.insuranceConfig = this.configServer.getConfig(ConfigTypes.INSURANCE); this.insuranceConfig = this.configServer.getConfig(ConfigTypes.INSURANCE);
} }
/**
* Does player have insurance array
* @param sessionId Player id
* @returns True if exists
*/
public insuranceExists(sessionId: string): boolean public insuranceExists(sessionId: string): boolean
{ {
return this.insured[sessionId] !== undefined; return this.insured[sessionId] !== undefined;
@ -203,7 +210,7 @@ export class InsuranceService
} }
/** /**
* Store lost gear post-raid inside profile * Store lost gear post-raid inside profile, ready for later code to pick it up and mail it
* @param pmcData player profile to store gear in * @param pmcData player profile to store gear in
* @param offraidData post-raid request object * @param offraidData post-raid request object
* @param preRaidGear gear player wore prior to raid * @param preRaidGear gear player wore prior to raid
@ -218,27 +225,136 @@ export class InsuranceService
const equipmentToSendToPlayer = []; const equipmentToSendToPlayer = [];
for (const insuredItem of pmcData.InsuredItems) for (const insuredItem of pmcData.InsuredItems)
{ {
// Check insured item was on player during raid // Skip insured items not on player when they started raid
if (preRaidGearHash[insuredItem.itemId]) const preRaidItem = preRaidGearHash[insuredItem.itemId];
if (!preRaidItem)
{ {
// This item exists in preRaidGear, meaning we brought it into the raid continue;
// Check if item missing OR player died with item on }
if (!offRaidGearHash[insuredItem.itemId] || playerDied)
{ // Skip items we should never return
equipmentToSendToPlayer.push({ if (this.insuranceConfig.blacklistedEquipment.includes(preRaidItem.slotId))
"pmcData": pmcData, {
"insuredItem": insuredItem, continue;
"item": preRaidGearHash[insuredItem.itemId], }
"sessionID": sessionID
}); // Check if item missing in post-raid gear OR player died
} // Catches both events: player died with item on + player survied but dropped item in raid
if (!offRaidGearHash[insuredItem.itemId] || playerDied)
{
equipmentToSendToPlayer.push({
pmcData: pmcData,
itemToReturnToPlayer: this.getInsuredItemDetails(pmcData, preRaidItem, offraidData.insurance.find(x => x.id === insuredItem.itemId)),
traderId: insuredItem.tid,
sessionID: sessionID
});
} }
} }
// Process all insured items lost in-raid // Process all insured items lost in-raid
for (const gear of equipmentToSendToPlayer) for (const gear of equipmentToSendToPlayer)
{ {
this.addGearToSend(gear.pmcData, gear.insuredItem, gear.item, gear.sessionID); this.addGearToSend(gear);
}
}
/**
* Take preraid item and update properties to ensure its ready to be given to player in insurance return mail
* @param pmcData Player profile
* @param insuredItem Insured items properties
* @param preRaidItem Insured item as it was pre-raid
* @param insuredItemFromClient Item data when player left raid (durability values)
* @returns Item object
*/
protected getInsuredItemDetails(pmcData: IPmcData, preRaidItem: Item, insuredItemFromClient: IInsuredItemsData): Item
{
// Get baseline item to return, clone pre raid item
const itemToReturn: Item = this.jsonUtil.clone(preRaidItem);
// Add upd if it doesnt exist
if (!itemToReturn.upd)
{
itemToReturn.upd = {};
}
// Check for slotid values that need to be updated and adjust
this.updateSlotIdValue(pmcData.Inventory.equipment, itemToReturn);
// Remove location property
if (itemToReturn.slotId === "hideout" && "location" in itemToReturn)
{
delete itemToReturn.location;
}
// Remove found in raid status when upd exists + SpawnedInSession value exists
if ("upd" in itemToReturn && "SpawnedInSession" in itemToReturn.upd)
{
itemToReturn.upd.SpawnedInSession = false;
}
// Client item has durability values, Ensure values persist into server data
if (insuredItemFromClient.durability)
{
// Item didnt have Repairable object pre-raid, add it
if (!itemToReturn.upd.Repairable)
{
itemToReturn.upd.Repairable = {
Durability: insuredItemFromClient.durability,
MaxDurability: insuredItemFromClient.maxDurability
};
}
else
{
itemToReturn.upd.Repairable.Durability = insuredItemFromClient.durability;
itemToReturn.upd.Repairable.MaxDurability = insuredItemFromClient.maxDurability;
}
}
// Client item has FaceShield values, Ensure values persist into server data
if (insuredItemFromClient?.hits)
{
// Item didnt have faceshield object pre-raid, add it
if (!itemToReturn.upd.FaceShield)
{
itemToReturn.upd.FaceShield = {
Hits: insuredItemFromClient.hits
};
}
else
{
itemToReturn.upd.FaceShield.Hits = insuredItemFromClient.hits;
}
}
return itemToReturn;
}
/**
* Reset slotId property to "hideout" when necessary (used to be in )
* @param pmcData Players pmcData.Inventory.equipment value
* @param itemToReturn item we will send to player as insurance return
*/
protected updateSlotIdValue(playerBaseInventoryEquipmentId: string, itemToReturn: Item): void
{
const pocketSlots = [
"pocket1",
"pocket2",
"pocket3",
"pocket4"
];
// Some pockets can lose items with player death, some don't
if (!("slotId" in itemToReturn) || pocketSlots.includes(itemToReturn.slotId))
{
itemToReturn.slotId = "hideout";
}
// Mark root-level items for later processing
if (itemToReturn.parentId === playerBaseInventoryEquipmentId)
{
itemToReturn.slotId = "hideout";
} }
} }
@ -260,67 +376,36 @@ export class InsuranceService
/** /**
* Add gear item to InsuredItems array in player profile * Add gear item to InsuredItems array in player profile
* @param pmcData profile to store item in
* @param insuredItem Item to store in profile
* @param actualItem item to store
* @param sessionID Session id * @param sessionID Session id
* @param pmcData Player profile
* @param itemToReturnToPlayer item to store
* @param traderId Id of trader item was insured with
*/ */
protected addGearToSend(pmcData: IPmcData, insuredItem: InsuredItem, actualItem: Item, sessionID: string): void protected addGearToSend(gear: { sessionID: string; pmcData: IPmcData; itemToReturnToPlayer: Item; traderId: string}): void
{ {
// Skip items defined in config const sessionId = gear.sessionID;
if (this.insuranceConfig.blacklistedEquipment.includes(actualItem.slotId)) const pmcData = gear.pmcData;
const itemToReturnToPlayer = gear.itemToReturnToPlayer;
const traderId = gear.traderId;
// Ensure insurance array is init
if (!this.insuranceExists(sessionId))
{ {
return; this.resetInsurance(sessionId);
} }
const pocketSlots = [ // init trader insurance array
"pocket1", if (!this.insuranceTraderArrayExists(sessionId, traderId))
"pocket2",
"pocket3",
"pocket4"
];
// Check and correct the validity of the slotId
if (!("slotId" in actualItem) || pocketSlots.includes(actualItem.slotId))
{ {
actualItem.slotId = "hideout"; this.resetInsuranceTraderArray(sessionId, traderId);
} }
// Mark root-level items for later this.addInsuranceItemToArray(sessionId, traderId, itemToReturnToPlayer);
if (actualItem.parentId === pmcData.Inventory.equipment)
{
actualItem.slotId = "hideout";
}
// Clear the location attribute of the item in the container. // Remove item from insured items array as its been processed
if (actualItem.slotId === "hideout" && "location" in actualItem)
{
delete actualItem.location;
}
// Remove found in raid status
if ("upd" in actualItem && "SpawnedInSession" in actualItem.upd)
{
actualItem.upd.SpawnedInSession = false;
}
// Mark to add to insurance
if (!this.insuranceExists(sessionID))
{
this.resetInsurance(sessionID);
}
if (!this.insuranceTraderArrayExists(sessionID, insuredItem.tid))
{
this.resetInsuranceTraderArray(sessionID, insuredItem.tid);
}
this.addInsuranceItemToArray(sessionID, insuredItem.tid, actualItem);
// Remove processed item from array
pmcData.InsuredItems = pmcData.InsuredItems.filter((item) => pmcData.InsuredItems = pmcData.InsuredItems.filter((item) =>
{ {
return item.itemId !== insuredItem.itemId; return item.itemId !== itemToReturnToPlayer._id;
}); });
} }
@ -353,6 +438,7 @@ export class InsuranceService
*/ */
public addInsuranceItemToArray(sessionId: string, traderId: string, itemToAdd: Item): void public addInsuranceItemToArray(sessionId: string, traderId: string, itemToAdd: Item): void
{ {
this.insured[sessionId][traderId].push(itemToAdd); this.insured[sessionId][traderId].push(itemToAdd);
} }