Reworked how the flea market categories are calculated, instead of trying to be smart and add/remove in a cache as offers are created, calculate the categories when needed
Categories: Are now much more accurate take into account when player is below flea unlock level Any with a (1) and no offers have been fixed Take into account when offers are barters + barters are filtered out Skip items with a type of `node` during flea assort generation
This commit is contained in:
parent
56366068e0
commit
7f995de5d1
@ -95,7 +95,11 @@ export class RagfairController
|
||||
const pmcProfile = this.profileHelper.getPmcProfile(sessionID);
|
||||
|
||||
result.offers = this.getOffersForSearchType(searchRequest, itemsToAdd, traderAssorts, pmcProfile);
|
||||
result.categories = this.getSpecificCategories(searchRequest, result.offers);
|
||||
|
||||
if (searchRequest.updateOfferCount)
|
||||
{
|
||||
result.categories = this.getSpecificCategories(pmcProfile, searchRequest, result.offers);
|
||||
}
|
||||
|
||||
// Client requested "required search"
|
||||
if (searchRequest.neededSearchId)
|
||||
@ -131,10 +135,8 @@ export class RagfairController
|
||||
}
|
||||
}
|
||||
|
||||
// Set categories count (needed for categories to show when choosing 'Linked search')
|
||||
this.ragfairHelper.countCategories(result);
|
||||
|
||||
result.offersCount = result.offers.length;
|
||||
|
||||
// Handle paging before returning results only if searching for general items, not preset items
|
||||
if (searchRequest.buildCount === 0)
|
||||
{
|
||||
@ -176,21 +178,28 @@ export class RagfairController
|
||||
* @param offers ragfair offers to get categories for
|
||||
* @returns record with tpls + counts
|
||||
*/
|
||||
protected getSpecificCategories(searchRequest: ISearchRequestData, offers: IRagfairOffer[]): Record<string, number>
|
||||
protected getSpecificCategories(pmcProfile: IPmcData, searchRequest: ISearchRequestData, offers: IRagfairOffer[]): Record<string, number>
|
||||
{
|
||||
// Linked/required search categories
|
||||
const playerHasFleaUnlocked = pmcProfile.Info.Level > this.databaseServer.getTables().globals.config.RagFair.minUserLevel;
|
||||
let offerPool = [];
|
||||
if (this.isLinkedSearch(searchRequest) || this.isRequiredSearch(searchRequest))
|
||||
{
|
||||
return this.ragfairServer.getBespokeCategories(offers);
|
||||
offerPool = offers;
|
||||
}
|
||||
|
||||
// Get all categories
|
||||
if ((searchRequest.linkedSearchId === "" && searchRequest.neededSearchId === ""))
|
||||
else if ((searchRequest.linkedSearchId === "" && searchRequest.neededSearchId === ""))
|
||||
{
|
||||
return this.ragfairServer.getAllCategories();
|
||||
// Get all categories
|
||||
offerPool = this.ragfairOfferService.getOffers();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.logger.error("Unable to get categories from search criteria, see log for request data");
|
||||
this.logger.debug(JSON.stringify(searchRequest));
|
||||
return {};
|
||||
}
|
||||
|
||||
return {};
|
||||
return this.ragfairServer.getAllActiveCategories(playerHasFleaUnlocked, searchRequest, offerPool);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -79,6 +79,11 @@ export class RagfairAssortGenerator
|
||||
const seasonalItemTplBlacklist = this.seasonalEventService.getAllSeasonalEventItems();
|
||||
for (const item of items)
|
||||
{
|
||||
if (item._type === "Node")
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!this.itemHelper.isValidItem(item._id, ragfairItemInvalidBaseTypes))
|
||||
{
|
||||
continue;
|
||||
|
@ -21,7 +21,6 @@ import { DatabaseServer } from "@spt-aki/servers/DatabaseServer";
|
||||
import { SaveServer } from "@spt-aki/servers/SaveServer";
|
||||
import { FenceService } from "@spt-aki/services/FenceService";
|
||||
import { LocalisationService } from "@spt-aki/services/LocalisationService";
|
||||
import { RagfairCategoriesService } from "@spt-aki/services/RagfairCategoriesService";
|
||||
import { RagfairOfferService } from "@spt-aki/services/RagfairOfferService";
|
||||
import { RagfairPriceService } from "@spt-aki/services/RagfairPriceService";
|
||||
import { HashUtil } from "@spt-aki/utils/HashUtil";
|
||||
@ -51,7 +50,6 @@ export class RagfairOfferGenerator
|
||||
@inject("RagfairPriceService") protected ragfairPriceService: RagfairPriceService,
|
||||
@inject("LocalisationService") protected localisationService: LocalisationService,
|
||||
@inject("PaymentHelper") protected paymentHelper: PaymentHelper,
|
||||
@inject("RagfairCategoriesService") protected ragfairCategoriesService: RagfairCategoriesService,
|
||||
@inject("FenceService") protected fenceService: FenceService,
|
||||
@inject("ItemHelper") protected itemHelper: ItemHelper,
|
||||
@inject("ConfigServer") protected configServer: ConfigServer,
|
||||
@ -431,8 +429,6 @@ export class RagfairOfferGenerator
|
||||
1,
|
||||
isPreset || isPackOffer,
|
||||
); // sellAsOnePiece
|
||||
|
||||
this.ragfairCategoriesService.incrementCategory(offer);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -510,8 +506,6 @@ export class RagfairOfferGenerator
|
||||
|
||||
const offer = this.createFleaOffer(traderID, time, items, barterSchemeItems, loyalLevel, false);
|
||||
|
||||
this.ragfairCategoriesService.incrementCategory(offer);
|
||||
|
||||
// Refresh complete, reset flag to false
|
||||
trader.base.refreshTraderRagfairOffers = false;
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { inject, injectable } from "tsyringe";
|
||||
|
||||
import { Category } from "@spt-aki/models/eft/common/tables/IHandbookBase";
|
||||
import { Money } from "@spt-aki/models/enums/Money";
|
||||
import { DatabaseServer } from "@spt-aki/servers/DatabaseServer";
|
||||
import { JsonUtil } from "@spt-aki/utils/JsonUtil";
|
||||
@ -164,4 +165,9 @@ export class HandbookHelper
|
||||
const price = this.getTemplatePrice(currencyTypeTo);
|
||||
return price ? Math.round(roubleCurrencyCount / price) : 0;
|
||||
}
|
||||
|
||||
public getCategoryById(handbookId: string): Category
|
||||
{
|
||||
return this.databaseServer.getTables().templates.handbook.Categories.find(x => x.Id === handbookId);
|
||||
}
|
||||
}
|
||||
|
@ -147,31 +147,6 @@ export class RagfairHelper
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Because of presets, categories are not always 1 */
|
||||
public countCategories(result: IGetOffersResult): void
|
||||
{
|
||||
const categories = {};
|
||||
|
||||
for (const offer of result.offers)
|
||||
{
|
||||
// only the first item can have presets
|
||||
const item = offer.items[0];
|
||||
categories[item._tpl] = categories[item._tpl] || 0;
|
||||
categories[item._tpl]++;
|
||||
}
|
||||
|
||||
// not in search mode, add back non-weapon items
|
||||
for (const category in result.categories)
|
||||
{
|
||||
if (!categories[category])
|
||||
{
|
||||
categories[category] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
result.categories = categories;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges Root Items
|
||||
* Ragfair allows abnormally large stacks.
|
||||
|
@ -58,6 +58,7 @@ export class TraderAssortHelper
|
||||
* Filter out assorts not unlocked due to level OR quest completion
|
||||
* @param sessionId session id
|
||||
* @param traderId traders id
|
||||
* @param flea Should assorts player hasn't unlocked be returned - default false
|
||||
* @returns a traders' assorts
|
||||
*/
|
||||
public getAssort(sessionId: string, traderId: string, flea = false): ITraderAssort
|
||||
|
@ -154,7 +154,7 @@ export interface Blacklist
|
||||
enableBsgList: boolean;
|
||||
/** Should quest items be blacklisted from flea */
|
||||
enableQuestList: boolean;
|
||||
/** Should trader items that are blacklisted by bsg */
|
||||
/** Should trader items that are blacklisted by bsg be listed on flea */
|
||||
traderItems: boolean;
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,7 @@ import { RagfairOfferGenerator } from "@spt-aki/generators/RagfairOfferGenerator
|
||||
import { TraderAssortHelper } from "@spt-aki/helpers/TraderAssortHelper";
|
||||
import { TraderHelper } from "@spt-aki/helpers/TraderHelper";
|
||||
import { IRagfairOffer } from "@spt-aki/models/eft/ragfair/IRagfairOffer";
|
||||
import { ISearchRequestData } from "@spt-aki/models/eft/ragfair/ISearchRequestData";
|
||||
import { ConfigTypes } from "@spt-aki/models/enums/ConfigTypes";
|
||||
import { Traders } from "@spt-aki/models/enums/Traders";
|
||||
import { IRagfairConfig } from "@spt-aki/models/spt/config/IRagfairConfig";
|
||||
@ -82,14 +83,9 @@ export class RagfairServer
|
||||
return Object.keys(this.ragfairConfig.traders).filter((x) => this.ragfairConfig.traders[x]);
|
||||
}
|
||||
|
||||
public getAllCategories(): Record<string, number>
|
||||
public getAllActiveCategories(fleaUnlocked: boolean, searchRequestData: ISearchRequestData, offers: IRagfairOffer[]): Record<string, number>
|
||||
{
|
||||
return this.ragfairCategoriesService.getAllCategories();
|
||||
}
|
||||
|
||||
public getBespokeCategories(offers: IRagfairOffer[]): Record<string, number>
|
||||
{
|
||||
return this.ragfairCategoriesService.getBespokeCategories(offers);
|
||||
return this.ragfairCategoriesService.getCategoriesFromOffers(offers, searchRequestData, fleaUnlocked);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,96 +1,71 @@
|
||||
import { inject, injectable } from "tsyringe";
|
||||
|
||||
import { PaymentHelper } from "@spt-aki/helpers/PaymentHelper";
|
||||
import { IRagfairOffer } from "@spt-aki/models/eft/ragfair/IRagfairOffer";
|
||||
import { ISearchRequestData, OfferOwnerType } from "@spt-aki/models/eft/ragfair/ISearchRequestData";
|
||||
import { MemberCategory } from "@spt-aki/models/enums/MemberCategory";
|
||||
import { ILogger } from "@spt-aki/models/spt/utils/ILogger";
|
||||
|
||||
@injectable()
|
||||
export class RagfairCategoriesService
|
||||
{
|
||||
protected categories: Record<string, number> = {};
|
||||
|
||||
constructor(@inject("WinstonLogger") protected logger: ILogger)
|
||||
constructor(
|
||||
@inject("WinstonLogger") protected logger: ILogger,
|
||||
@inject("PaymentHelper") protected paymentHelper: PaymentHelper,
|
||||
)
|
||||
{}
|
||||
|
||||
/**
|
||||
* Get all flea categories and their count of offers
|
||||
* @returns item categories and count
|
||||
* Get a dictionary of each item the play can see in their flea menu, filtered by what is available for them to buy
|
||||
* @param offers All offers in flea
|
||||
* @param searchRequestData Search criteria requested
|
||||
* @param fleaUnlocked Can player see full flea yet (level 15 by default)
|
||||
* @returns KVP of item tpls + count of offers
|
||||
*/
|
||||
public getAllCategories(): Record<string, number>
|
||||
public getCategoriesFromOffers(offers: IRagfairOffer[], searchRequestData: ISearchRequestData, fleaUnlocked: boolean): Record<string, number>
|
||||
{
|
||||
return this.categories;
|
||||
}
|
||||
|
||||
/**
|
||||
* With the supplied items, get custom categories
|
||||
* @returns a custom list of categories
|
||||
*/
|
||||
public getBespokeCategories(offers: IRagfairOffer[]): Record<string, number>
|
||||
{
|
||||
return this.processOffersIntoCategories(offers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Take an array of ragfair offers and create a dictionary of items with thier corrisponding offer count
|
||||
* @param offers ragfair offers
|
||||
* @returns categories and count
|
||||
*/
|
||||
protected processOffersIntoCategories(offers: IRagfairOffer[]): Record<string, number>
|
||||
{
|
||||
const result = {};
|
||||
const validOffersForPlayerToSee = {};
|
||||
for (const offer of offers)
|
||||
{
|
||||
this.addOrIncrementCategory(offer, result);
|
||||
}
|
||||
const isTraderOffer = offer.user.memberType === MemberCategory.TRADER;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increment or decrement a category array
|
||||
* @param offer Offer to process
|
||||
* @param categories Categories to update
|
||||
* @param increment (Optional) Should item be incremented or decremented
|
||||
*/
|
||||
protected addOrIncrementCategory(offer: IRagfairOffer, categories: Record<string, number>, increment = true): void
|
||||
{
|
||||
const itemId = offer.items[0]._tpl;
|
||||
if (increment)
|
||||
{
|
||||
categories[itemId] = categories[itemId] ? categories[itemId] + 1 : 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// No category, no work to do
|
||||
if (categories[itemId])
|
||||
// Not level 15 and offer is from player, skip
|
||||
if (!fleaUnlocked && !isTraderOffer)
|
||||
{
|
||||
categories[itemId]--;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Remove category entirely as its 0 or less
|
||||
if (categories[itemId] < 1)
|
||||
{
|
||||
delete categories[itemId];
|
||||
}
|
||||
// Remove items not for money when `removeBartering` is enabled
|
||||
if (searchRequestData.removeBartering && (offer.requirements.length > 1 || !this.paymentHelper.isMoneyTpl(offer.requirements[0]._tpl)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Remove when filter set to players only + offer is from trader
|
||||
if (searchRequestData.offerOwnerType === OfferOwnerType.PLAYEROWNERTYPE && isTraderOffer)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Remove when filter set to traders only + offer is not from trader
|
||||
if (searchRequestData.offerOwnerType === OfferOwnerType.TRADEROWNERTYPE && !isTraderOffer)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const itemTpl = offer.items[0]._tpl
|
||||
|
||||
if (!validOffersForPlayerToSee[itemTpl])
|
||||
{
|
||||
validOffersForPlayerToSee[itemTpl] = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
validOffersForPlayerToSee[itemTpl]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Increase category count by 1
|
||||
* @param offer
|
||||
*/
|
||||
public incrementCategory(offer: IRagfairOffer): void
|
||||
{
|
||||
this.addOrIncrementCategory(offer, this.categories);
|
||||
this.categories[offer.items[0]._tpl]++;
|
||||
}
|
||||
return validOffersForPlayerToSee;
|
||||
|
||||
/**
|
||||
* Reduce category count by 1
|
||||
* @param offer
|
||||
*/
|
||||
public decrementCategory(offer: IRagfairOffer): void
|
||||
{
|
||||
this.addOrIncrementCategory(offer, this.categories, false);
|
||||
this.categories[offer.items[0]._tpl]--;
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,6 @@ import { ConfigServer } from "@spt-aki/servers/ConfigServer";
|
||||
import { DatabaseServer } from "@spt-aki/servers/DatabaseServer";
|
||||
import { SaveServer } from "@spt-aki/servers/SaveServer";
|
||||
import { LocalisationService } from "@spt-aki/services/LocalisationService";
|
||||
import { RagfairCategoriesService } from "@spt-aki/services/RagfairCategoriesService";
|
||||
import { HttpResponseUtil } from "@spt-aki/utils/HttpResponseUtil";
|
||||
import { RagfairOfferHolder } from "@spt-aki/utils/RagfairOfferHolder";
|
||||
import { TimeUtil } from "@spt-aki/utils/TimeUtil";
|
||||
@ -33,7 +32,6 @@ export class RagfairOfferService
|
||||
@inject("DatabaseServer") protected databaseServer: DatabaseServer,
|
||||
@inject("SaveServer") protected saveServer: SaveServer,
|
||||
@inject("RagfairServerHelper") protected ragfairServerHelper: RagfairServerHelper,
|
||||
@inject("RagfairCategoriesService") protected ragfairCategoriesService: RagfairCategoriesService,
|
||||
@inject("ProfileHelper") protected profileHelper: ProfileHelper,
|
||||
@inject("EventOutputHolder") protected eventOutputHolder: EventOutputHolder,
|
||||
@inject("HttpResponseUtil") protected httpResponse: HttpResponseUtil,
|
||||
@ -222,9 +220,6 @@ export class RagfairOfferService
|
||||
this.returnPlayerOffer(staleOffer);
|
||||
}
|
||||
|
||||
// Reduce category count by 1 as offer is now stale and about to be removed
|
||||
this.ragfairCategoriesService.decrementCategory(staleOffer);
|
||||
|
||||
// Remove expired existing offer from global offers
|
||||
this.removeOfferById(staleOffer._id);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user