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",
tid: (sellerIsTrader) ? fleaOffer.user.id : "ragfair",
// 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,
// eslint-disable-next-line @typescript-eslint/naming-convention
scheme_id: 0,

View File

@ -109,14 +109,14 @@ export class InventoryHelper
{
if (typeof request.callback === "function")
{
request.callback();
request.callback(itemWithModsToAddClone[0].upd.StackObjectsCount);
}
}
catch (err)
{
// Callback failed
const message = typeof err === "string"
? err
const message = typeof err?.message === "string"
? err.message
: this.localisationService.getText("http-unknown_error");
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 { ItemHelper } from "@spt-aki/helpers/ItemHelper";
import { TraderAssortHelper } from "@spt-aki/helpers/TraderAssortHelper";
import { TraderHelper } from "@spt-aki/helpers/TraderHelper";
import { IPmcData } from "@spt-aki/models/eft/common/IPmcData";
import { Item, Upd } from "@spt-aki/models/eft/common/tables/IItem";
@ -41,6 +42,7 @@ export class TradeHelper
@inject("HttpResponseUtil") protected httpResponse: HttpResponseUtil,
@inject("InventoryHelper") protected inventoryHelper: InventoryHelper,
@inject("RagfairServer") protected ragfairServer: RagfairServer,
@inject("TraderAssortHelper") protected traderAssortHelper: TraderAssortHelper,
@inject("ConfigServer") protected configServer: ConfigServer,
)
{
@ -67,62 +69,11 @@ export class TradeHelper
{
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 buyCallback;
let buyCallback: { (buyCount: number) };
if (buyRequestData.tid.toLocaleLowerCase() === "ragfair")
{
buyCallback = () =>
buyCallback = (buyCount: number) =>
{
const allOffers = this.ragfairServer.getOffers();
@ -131,17 +82,23 @@ export class TradeHelper
const itemPurchased = offerWithItem.items[0];
// Ensure purchase does not exceed trader item limit
const hasBuyRestrictions = this.itemHelper.hasBuyRestrictions(itemPurchased);
if (hasBuyRestrictions)
const assortHasBuyRestrictions = this.itemHelper.hasBuyRestrictions(itemPurchased);
if (assortHasBuyRestrictions)
{
this.checkPurchaseIsWithinTraderItemLimit(itemPurchased, buyRequestData.item_id, buyRequestData.count);
this.checkPurchaseIsWithinTraderItemLimit(itemPurchased, buyRequestData.item_id, buyCount);
}
// Decrement trader item count
if (this.traderConfig.persistPurchaseDataInProfile && hasBuyRestrictions)
if (this.traderConfig.persistPurchaseDataInProfile && assortHasBuyRestrictions)
{
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
@ -151,10 +108,10 @@ export class TradeHelper
throw new Error(`Transaction failed: ${output.warnings[0].errmsg}`);
}
if (hasBuyRestrictions)
if (assortHasBuyRestrictions)
{
// 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)
{
buyCallback = () =>
buyCallback = (buyCount: number) =>
{
// Update assort/flea item values
const traderAssorts = this.traderHelper.getTraderAssortsByTraderId(buyRequestData.tid).items;
@ -195,6 +152,59 @@ export class TradeHelper
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
const itemDbDetails = this.itemHelper.getItem(offerItems[0]._tpl)[1];
@ -220,7 +230,10 @@ export class TradeHelper
// Add item + children to stash
this.inventoryHelper.addItemToStash(sessionID, request, pmcData, output);
if (output.warnings.length > 0)
{
return output;
}
// Remove amount of items added to player stash
itemsToSendRemaining -= itemCountToSend;
}

View File

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