From fcabd68dfc3f704c4c9331f959b5bcac6aeac032 Mon Sep 17 00:00:00 2001 From: DrakiaXYZ Date: Mon, 20 May 2024 07:58:13 +0000 Subject: [PATCH] Fix issues around ragfair and handbook caching (!334) - Make `PenetrationDamageMod` optional in ITemplateItem - Cache handbook values if they're found after initial cache generation - Refactor how caching in RagfairPriceService is handled -- Rename `generate` methods to `refresh` to better indicate their purpose -- If item price isn't found in cache, try to find it and add it -- Refresh caches prior to returning all flea prices (This is only triggered via a route call, so shouldn't happen often) -- Remove storage of whether we've generated cache, it should always be done on load, and we dynamically add to it, so it's not necessary to keep track of Co-authored-by: DrakiaXYZ <565558+TheDgtl@users.noreply.github.com> Reviewed-on: https://dev.sp-tarkov.com/SPT-AKI/Server/pulls/334 Co-authored-by: DrakiaXYZ Co-committed-by: DrakiaXYZ --- project/src/helpers/HandbookHelper.ts | 3 +- .../models/eft/common/tables/ITemplateItem.ts | 2 +- project/src/services/RagfairPriceService.ts | 52 ++++++++++--------- 3 files changed, 30 insertions(+), 27 deletions(-) diff --git a/project/src/helpers/HandbookHelper.ts b/project/src/helpers/HandbookHelper.ts index f8486ad8..a7ee3f76 100644 --- a/project/src/helpers/HandbookHelper.ts +++ b/project/src/helpers/HandbookHelper.ts @@ -101,7 +101,7 @@ export class HandbookHelper /** * Get price from internal cache, if cache empty look up price directly in handbook (expensive) - * If no values found, return 1 + * If no values found, return 0 * @param tpl item tpl to look up price for * @returns price in roubles */ @@ -127,6 +127,7 @@ export class HandbookHelper return newValue; } + this.handbookPriceCache.items.byId.set(tpl, handbookItem.Price); return handbookItem.Price; } diff --git a/project/src/models/eft/common/tables/ITemplateItem.ts b/project/src/models/eft/common/tables/ITemplateItem.ts index 7b79d6d0..30eda3b8 100644 --- a/project/src/models/eft/common/tables/ITemplateItem.ts +++ b/project/src/models/eft/common/tables/ITemplateItem.ts @@ -358,7 +358,7 @@ export interface Props casingSounds?: string ProjectileCount?: number PenetrationChanceObstacle?: number - PenetrationDamageMod: number + PenetrationDamageMod?: number RicochetChance?: number FragmentationChance?: number Deterioration?: number diff --git a/project/src/services/RagfairPriceService.ts b/project/src/services/RagfairPriceService.ts index 99dc746b..f8f7ed5e 100644 --- a/project/src/services/RagfairPriceService.ts +++ b/project/src/services/RagfairPriceService.ts @@ -27,8 +27,6 @@ import { RandomUtil } from "@spt-aki/utils/RandomUtil"; export class RagfairPriceService implements OnLoad { protected ragfairConfig: IRagfairConfig; - protected generatedDynamicPrices: boolean; - protected generatedStaticPrices: boolean; protected prices: IRagfairServerPrices = { static: {}, dynamic: {} }; @@ -52,15 +50,8 @@ export class RagfairPriceService implements OnLoad */ public async onLoad(): Promise { - if (!this.generatedStaticPrices) - { - this.generateStaticPrices(); - } - - if (!this.generatedDynamicPrices) - { - this.generateDynamicPrices(); - } + this.refreshStaticPrices(); + this.refreshDynamicPrices(); } public getRoute(): string @@ -71,7 +62,7 @@ export class RagfairPriceService implements OnLoad /** * Iterate over all items of type "Item" in db and get template price, store in cache */ - public generateStaticPrices(): void + public refreshStaticPrices(): void { for (const item of Object.values(this.databaseServer.getTables().templates.items).filter( (x) => x._type === "Item", @@ -79,18 +70,15 @@ export class RagfairPriceService implements OnLoad { this.prices.static[item._id] = Math.round(this.handbookHelper.getTemplatePrice(item._id)); } - - this.generatedStaticPrices = true; } /** - * Create a dictionary and store prices from prices.json in it + * Copy the prices.json data into our dynamic price dictionary */ - public generateDynamicPrices(): void + public refreshDynamicPrices(): void { - Object.assign(this.prices.dynamic, this.databaseServer.getTables().templates.prices); - - this.generatedDynamicPrices = true; + const pricesTable = this.databaseServer.getTables().templates.prices; + this.prices.dynamic = { ...this.prices.dynamic, ...pricesTable }; } /** @@ -140,15 +128,15 @@ export class RagfairPriceService implements OnLoad /** * get the dynamic (flea) price for an item - * Grabs prices from prices.json and stores in class if none currently exist * @param itemTpl item template id to look up * @returns price in roubles */ public getDynamicPriceForItem(itemTpl: string): number { - if (!this.generatedDynamicPrices) + // If the price doesn't exist in the cache yet, try to find it + if (!this.prices.dynamic[itemTpl]) { - this.generateDynamicPrices(); + this.prices.dynamic[itemTpl] = this.databaseServer.getTables().templates.prices[itemTpl]; } return this.prices.dynamic[itemTpl]; @@ -161,9 +149,15 @@ export class RagfairPriceService implements OnLoad */ public getStaticPriceForItem(itemTpl: string): number { - if (!this.generatedStaticPrices) + // If the price doesn't exist in the cache yet, try to find it + if (!this.prices.static[itemTpl]) { - this.generateStaticPrices(); + // Store the price in the cache only if it exists + const itemPrice = Math.round(this.handbookHelper.getTemplatePrice(itemTpl)); + if (itemPrice !== 0) + { + this.prices.static[itemTpl] = itemPrice; + } } return this.prices.static[itemTpl]; @@ -171,10 +165,15 @@ export class RagfairPriceService implements OnLoad /** * Get prices for all items on flea, prioritize handbook prices first, use prices from prices.json if missing + * This will refresh the caches prior to building the output * @returns Dictionary of item tpls and rouble cost */ public getAllFleaPrices(): Record { + // Refresh the caches so we include any newly added custom items + this.refreshDynamicPrices(); + this.refreshStaticPrices(); + // assign dynamic (prices.json) values first, then overwrite them with static (handbook.json) // any values not stored in static data will be covered by dynamic data return { ...this.prices.dynamic, ...this.prices.static }; @@ -182,6 +181,9 @@ export class RagfairPriceService implements OnLoad public getAllStaticPrices(): Record { + // Refresh the cache so we include any newly added custom items + this.refreshStaticPrices(); + return { ...this.prices.static }; } @@ -207,7 +209,7 @@ export class RagfairPriceService implements OnLoad for (const item of barterScheme) { - price += this.prices.static[item._tpl] * item.count; + price += this.getStaticPriceForItem(item._tpl) * item.count; } return Math.round(price);