Move trader purchases over to new system

Fix callback errors not being propigated into client error message
FIx incorrect offer id being passed into `buyItem`
Update callbacks to accept a `buyCount` parameter - solves trader purchase limits being exeeded prematurely
Exit addItemToStash early if warning/error found in output
This commit is contained in:
Dev 2024-01-15 14:25:17 +00:00
parent bdc505bed6
commit 825db77b1f
5 changed files with 87 additions and 75 deletions

View File

@ -115,7 +115,7 @@ export class TradeController
type: "buy_from_trader", type: "buy_from_trader",
tid: (sellerIsTrader) ? fleaOffer.user.id : "ragfair", tid: (sellerIsTrader) ? fleaOffer.user.id : "ragfair",
// eslint-disable-next-line @typescript-eslint/naming-convention // eslint-disable-next-line @typescript-eslint/naming-convention
item_id: fleaOffer._id, // Store ragfair offerId in buyRequestData.item_id item_id: (sellerIsTrader) ? fleaOffer.root : fleaOffer._id, // Store ragfair offerId in buyRequestData.item_id
count: offer.count, count: offer.count,
// eslint-disable-next-line @typescript-eslint/naming-convention // eslint-disable-next-line @typescript-eslint/naming-convention
scheme_id: 0, scheme_id: 0,

View File

@ -109,14 +109,14 @@ export class InventoryHelper
{ {
if (typeof request.callback === "function") if (typeof request.callback === "function")
{ {
request.callback(); request.callback(itemWithModsToAddClone[0].upd.StackObjectsCount);
} }
} }
catch (err) catch (err)
{ {
// Callback failed // Callback failed
const message = typeof err === "string" const message = typeof err?.message === "string"
? err ? err.message
: this.localisationService.getText("http-unknown_error"); : this.localisationService.getText("http-unknown_error");
return this.httpResponse.appendErrorToOutput(output, message); return this.httpResponse.appendErrorToOutput(output, message);

View File

@ -2,6 +2,7 @@ import { inject, injectable } from "tsyringe";
import { InventoryHelper } from "@spt-aki/helpers/InventoryHelper"; import { InventoryHelper } from "@spt-aki/helpers/InventoryHelper";
import { ItemHelper } from "@spt-aki/helpers/ItemHelper"; import { ItemHelper } from "@spt-aki/helpers/ItemHelper";
import { TraderAssortHelper } from "@spt-aki/helpers/TraderAssortHelper";
import { TraderHelper } from "@spt-aki/helpers/TraderHelper"; import { TraderHelper } from "@spt-aki/helpers/TraderHelper";
import { IPmcData } from "@spt-aki/models/eft/common/IPmcData"; import { IPmcData } from "@spt-aki/models/eft/common/IPmcData";
import { Item, Upd } from "@spt-aki/models/eft/common/tables/IItem"; import { Item, Upd } from "@spt-aki/models/eft/common/tables/IItem";
@ -41,6 +42,7 @@ export class TradeHelper
@inject("HttpResponseUtil") protected httpResponse: HttpResponseUtil, @inject("HttpResponseUtil") protected httpResponse: HttpResponseUtil,
@inject("InventoryHelper") protected inventoryHelper: InventoryHelper, @inject("InventoryHelper") protected inventoryHelper: InventoryHelper,
@inject("RagfairServer") protected ragfairServer: RagfairServer, @inject("RagfairServer") protected ragfairServer: RagfairServer,
@inject("TraderAssortHelper") protected traderAssortHelper: TraderAssortHelper,
@inject("ConfigServer") protected configServer: ConfigServer, @inject("ConfigServer") protected configServer: ConfigServer,
) )
{ {
@ -67,62 +69,11 @@ export class TradeHelper
{ {
let output = this.eventOutputHolder.getOutput(sessionID); let output = this.eventOutputHolder.getOutput(sessionID);
const newReq = {
items: [{
// eslint-disable-next-line @typescript-eslint/naming-convention
item_id: buyRequestData.item_id,
count: buyRequestData.count,
}],
tid: buyRequestData.tid,
};
const callback = () =>
{
// Update assort/flea item values
const traderAssorts = this.traderHelper.getTraderAssortsByTraderId(buyRequestData.tid).items;
const itemPurchased = traderAssorts.find((x) => x._id === buyRequestData.item_id);
// Ensure purchase does not exceed trader item limit
const hasBuyRestrictions = this.itemHelper.hasBuyRestrictions(itemPurchased);
if (hasBuyRestrictions)
{
this.checkPurchaseIsWithinTraderItemLimit(itemPurchased, buyRequestData.item_id, buyRequestData.count);
}
// Decrement trader item count
itemPurchased.upd.StackObjectsCount -= buyRequestData.count;
if (this.traderConfig.persistPurchaseDataInProfile && hasBuyRestrictions)
{
this.traderHelper.addTraderPurchasesToPlayerProfile(sessionID, newReq);
}
/// Pay for item
output = this.paymentService.payMoney(pmcData, buyRequestData, sessionID, output);
if (output.warnings.length > 0)
{
throw new Error(`Transaction failed: ${output.warnings[0].errmsg}`);
}
if (hasBuyRestrictions)
{
// Increment non-fence trader item buy count
this.incrementAssortBuyCount(itemPurchased, buyRequestData.count);
}
};
// Handle normal traders old way...for now
if (buyRequestData.tid.toLocaleLowerCase() !== "ragfair" && buyRequestData.tid.toLocaleLowerCase() !== Traders.FENCE)
{
return this.inventoryHelper.addItem(pmcData, newReq, output, sessionID, callback, foundInRaid, upd);
}
let offerItems: Item[] = []; let offerItems: Item[] = [];
let buyCallback; let buyCallback: { (buyCount: number) };
if (buyRequestData.tid.toLocaleLowerCase() === "ragfair") if (buyRequestData.tid.toLocaleLowerCase() === "ragfair")
{ {
buyCallback = () => buyCallback = (buyCount: number) =>
{ {
const allOffers = this.ragfairServer.getOffers(); const allOffers = this.ragfairServer.getOffers();
@ -131,17 +82,23 @@ export class TradeHelper
const itemPurchased = offerWithItem.items[0]; const itemPurchased = offerWithItem.items[0];
// Ensure purchase does not exceed trader item limit // Ensure purchase does not exceed trader item limit
const hasBuyRestrictions = this.itemHelper.hasBuyRestrictions(itemPurchased); const assortHasBuyRestrictions = this.itemHelper.hasBuyRestrictions(itemPurchased);
if (hasBuyRestrictions) if (assortHasBuyRestrictions)
{ {
this.checkPurchaseIsWithinTraderItemLimit(itemPurchased, buyRequestData.item_id, buyRequestData.count); this.checkPurchaseIsWithinTraderItemLimit(itemPurchased, buyRequestData.item_id, buyCount);
} }
// Decrement trader item count // Decrement trader item count
if (this.traderConfig.persistPurchaseDataInProfile && assortHasBuyRestrictions)
if (this.traderConfig.persistPurchaseDataInProfile && hasBuyRestrictions)
{ {
this.traderHelper.addTraderPurchasesToPlayerProfile(sessionID, newReq); const itemPurchaseDat = {
items: [{
itemId: buyRequestData.item_id,
count: buyCount
}],
traderId: buyRequestData.tid
};
this.traderHelper.addTraderPurchasesToPlayerProfile(sessionID, itemPurchaseDat);
} }
/// Pay for item /// Pay for item
@ -151,10 +108,10 @@ export class TradeHelper
throw new Error(`Transaction failed: ${output.warnings[0].errmsg}`); throw new Error(`Transaction failed: ${output.warnings[0].errmsg}`);
} }
if (hasBuyRestrictions) if (assortHasBuyRestrictions)
{ {
// Increment non-fence trader item buy count // Increment non-fence trader item buy count
this.incrementAssortBuyCount(itemPurchased, buyRequestData.count); this.incrementAssortBuyCount(itemPurchased, buyCount);
} }
}; };
@ -165,7 +122,7 @@ export class TradeHelper
} }
else if (buyRequestData.tid === Traders.FENCE) else if (buyRequestData.tid === Traders.FENCE)
{ {
buyCallback = () => buyCallback = (buyCount: number) =>
{ {
// Update assort/flea item values // Update assort/flea item values
const traderAssorts = this.traderHelper.getTraderAssortsByTraderId(buyRequestData.tid).items; const traderAssorts = this.traderHelper.getTraderAssortsByTraderId(buyRequestData.tid).items;
@ -195,6 +152,59 @@ export class TradeHelper
offerItems = this.itemHelper.findAndReturnChildrenAsItems(fenceItems, buyRequestData.item_id); offerItems = this.itemHelper.findAndReturnChildrenAsItems(fenceItems, buyRequestData.item_id);
} }
else
{
// Non-fence trader
buyCallback = (buyCount: number) =>
{
// Update assort/flea item values
const traderAssorts = this.traderHelper.getTraderAssortsByTraderId(buyRequestData.tid).items;
const itemPurchased = traderAssorts.find((x) => x._id === buyRequestData.item_id);
// Ensure purchase does not exceed trader item limit
const assortHasBuyRestrictions = this.itemHelper.hasBuyRestrictions(itemPurchased);
if (assortHasBuyRestrictions)
{
this.checkPurchaseIsWithinTraderItemLimit(itemPurchased, buyRequestData.item_id, buyCount);
}
// Decrement trader item count
itemPurchased.upd.StackObjectsCount -= buyCount;
if (this.traderConfig.persistPurchaseDataInProfile && assortHasBuyRestrictions)
{
const itemPurchaseDat = {
items: [{
itemId: buyRequestData.item_id,
count: buyCount
}],
traderId: buyRequestData.tid
};
this.traderHelper.addTraderPurchasesToPlayerProfile(sessionID, itemPurchaseDat);
}
/// Pay for item
output = this.paymentService.payMoney(pmcData, buyRequestData, sessionID, output);
if (output.warnings.length > 0)
{
throw new Error(`Transaction failed: ${output.warnings[0].errmsg}`);
}
if (assortHasBuyRestrictions)
{
// Increment non-fence trader item buy count
this.incrementAssortBuyCount(itemPurchased, buyCount);
}
};
// Get all trader assort items
const traderItems = this.traderAssortHelper.getAssort(sessionID, buyRequestData.tid).items;
// Get item + children for purchase
const relevantItems = this.itemHelper.findAndReturnChildrenAsItems(traderItems, buyRequestData.item_id);
offerItems.push(...relevantItems);
}
// Get item details from db // Get item details from db
const itemDbDetails = this.itemHelper.getItem(offerItems[0]._tpl)[1]; const itemDbDetails = this.itemHelper.getItem(offerItems[0]._tpl)[1];
@ -220,7 +230,10 @@ export class TradeHelper
// Add item + children to stash // Add item + children to stash
this.inventoryHelper.addItemToStash(sessionID, request, pmcData, output); this.inventoryHelper.addItemToStash(sessionID, request, pmcData, output);
if (output.warnings.length > 0)
{
return output;
}
// Remove amount of items added to player stash // Remove amount of items added to player stash
itemsToSendRemaining -= itemCountToSend; itemsToSendRemaining -= itemCountToSend;
} }

View File

@ -308,12 +308,11 @@ export class TraderHelper
*/ */
public addTraderPurchasesToPlayerProfile( public addTraderPurchasesToPlayerProfile(
sessionID: string, sessionID: string,
// eslint-disable-next-line @typescript-eslint/naming-convention newPurchaseDetails: { items: { itemId: string; count: number; }[]; traderId: string; },
newPurchaseDetails: { items: { item_id: string; count: number; }[]; tid: string; },
): void ): void
{ {
const profile = this.profileHelper.getFullProfile(sessionID); const profile = this.profileHelper.getFullProfile(sessionID);
const traderId = newPurchaseDetails.tid; const traderId = newPurchaseDetails.traderId;
// Iterate over assorts bought and add to profile // Iterate over assorts bought and add to profile
for (const purchasedItem of newPurchaseDetails.items) for (const purchasedItem of newPurchaseDetails.items)
@ -330,9 +329,9 @@ export class TraderHelper
// Null guard when dict doesnt exist // Null guard when dict doesnt exist
const currentTime = this.timeUtil.getTimestamp(); const currentTime = this.timeUtil.getTimestamp();
if (!profile.traderPurchases[traderId][purchasedItem.item_id]) if (!profile.traderPurchases[traderId][purchasedItem.itemId])
{ {
profile.traderPurchases[traderId][purchasedItem.item_id] = { profile.traderPurchases[traderId][purchasedItem.itemId] = {
count: purchasedItem.count, count: purchasedItem.count,
purchaseTimestamp: currentTime, purchaseTimestamp: currentTime,
}; };
@ -340,8 +339,8 @@ export class TraderHelper
continue; continue;
} }
profile.traderPurchases[traderId][purchasedItem.item_id].count += purchasedItem.count; profile.traderPurchases[traderId][purchasedItem.itemId].count += purchasedItem.count;
profile.traderPurchases[traderId][purchasedItem.item_id].purchaseTimestamp = currentTime; profile.traderPurchases[traderId][purchasedItem.itemId].purchaseTimestamp = currentTime;
} }
} }

View File

@ -5,6 +5,6 @@ export interface IAddItemDirectRequest
/** Item and child mods to add to player inventory */ /** Item and child mods to add to player inventory */
itemWithModsToAdd: Item[]; itemWithModsToAdd: Item[];
foundInRaid: boolean; foundInRaid: boolean;
callback: () => void; callback: (buyCount: number) => void;
useSortingTable: boolean; useSortingTable: boolean;
} }