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 <drakiaxyz@noreply.dev.sp-tarkov.com>
Co-committed-by: DrakiaXYZ <drakiaxyz@noreply.dev.sp-tarkov.com>
This commit is contained in:
DrakiaXYZ 2024-05-20 07:58:13 +00:00 committed by chomp
parent 66cac910c3
commit fcabd68dfc
3 changed files with 30 additions and 27 deletions

View File

@ -101,7 +101,7 @@ export class HandbookHelper
/** /**
* Get price from internal cache, if cache empty look up price directly in handbook (expensive) * 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 * @param tpl item tpl to look up price for
* @returns price in roubles * @returns price in roubles
*/ */
@ -127,6 +127,7 @@ export class HandbookHelper
return newValue; return newValue;
} }
this.handbookPriceCache.items.byId.set(tpl, handbookItem.Price);
return handbookItem.Price; return handbookItem.Price;
} }

View File

@ -358,7 +358,7 @@ export interface Props
casingSounds?: string casingSounds?: string
ProjectileCount?: number ProjectileCount?: number
PenetrationChanceObstacle?: number PenetrationChanceObstacle?: number
PenetrationDamageMod: number PenetrationDamageMod?: number
RicochetChance?: number RicochetChance?: number
FragmentationChance?: number FragmentationChance?: number
Deterioration?: number Deterioration?: number

View File

@ -27,8 +27,6 @@ import { RandomUtil } from "@spt-aki/utils/RandomUtil";
export class RagfairPriceService implements OnLoad export class RagfairPriceService implements OnLoad
{ {
protected ragfairConfig: IRagfairConfig; protected ragfairConfig: IRagfairConfig;
protected generatedDynamicPrices: boolean;
protected generatedStaticPrices: boolean;
protected prices: IRagfairServerPrices = { static: {}, dynamic: {} }; protected prices: IRagfairServerPrices = { static: {}, dynamic: {} };
@ -52,15 +50,8 @@ export class RagfairPriceService implements OnLoad
*/ */
public async onLoad(): Promise<void> public async onLoad(): Promise<void>
{ {
if (!this.generatedStaticPrices) this.refreshStaticPrices();
{ this.refreshDynamicPrices();
this.generateStaticPrices();
}
if (!this.generatedDynamicPrices)
{
this.generateDynamicPrices();
}
} }
public getRoute(): string 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 * 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( for (const item of Object.values(this.databaseServer.getTables().templates.items).filter(
(x) => x._type === "Item", (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.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); const pricesTable = this.databaseServer.getTables().templates.prices;
this.prices.dynamic = { ...this.prices.dynamic, ...pricesTable };
this.generatedDynamicPrices = true;
} }
/** /**
@ -140,15 +128,15 @@ export class RagfairPriceService implements OnLoad
/** /**
* get the dynamic (flea) price for an item * 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 * @param itemTpl item template id to look up
* @returns price in roubles * @returns price in roubles
*/ */
public getDynamicPriceForItem(itemTpl: string): number 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]; return this.prices.dynamic[itemTpl];
@ -161,9 +149,15 @@ export class RagfairPriceService implements OnLoad
*/ */
public getStaticPriceForItem(itemTpl: string): number 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]; 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 * 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 * @returns Dictionary of item tpls and rouble cost
*/ */
public getAllFleaPrices(): Record<string, number> public getAllFleaPrices(): Record<string, number>
{ {
// 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) // 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 // any values not stored in static data will be covered by dynamic data
return { ...this.prices.dynamic, ...this.prices.static }; return { ...this.prices.dynamic, ...this.prices.static };
@ -182,6 +181,9 @@ export class RagfairPriceService implements OnLoad
public getAllStaticPrices(): Record<string, number> public getAllStaticPrices(): Record<string, number>
{ {
// Refresh the cache so we include any newly added custom items
this.refreshStaticPrices();
return { ...this.prices.static }; return { ...this.prices.static };
} }
@ -207,7 +209,7 @@ export class RagfairPriceService implements OnLoad
for (const item of barterScheme) for (const item of barterScheme)
{ {
price += this.prices.static[item._tpl] * item.count; price += this.getStaticPriceForItem(item._tpl) * item.count;
} }
return Math.round(price); return Math.round(price);