Fix ragfair offers not saving upd properties
Create replacement for `addItem()`, only used for ragfair purchases currently - goal is to fully remove `addItem()` Dont show warning when generating armor without a default plate on fence
This commit is contained in:
parent
743f222141
commit
8b03faca89
@ -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.root,
|
||||
item_id: fleaOffer._id, // Store ragfair offerId in buyRequestData.item_id
|
||||
count: offer.count,
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
scheme_id: 0,
|
||||
|
@ -10,6 +10,7 @@ import { TraderAssortHelper } from "@spt-aki/helpers/TraderAssortHelper";
|
||||
import { IPmcData } from "@spt-aki/models/eft/common/IPmcData";
|
||||
import { Inventory } from "@spt-aki/models/eft/common/tables/IBotBase";
|
||||
import { Item, Location, Upd } from "@spt-aki/models/eft/common/tables/IItem";
|
||||
import { IAddItemDirectRequest } from "@spt-aki/models/eft/inventory/IAddItemDirectRequest";
|
||||
import { AddItem, IAddItemRequestData } from "@spt-aki/models/eft/inventory/IAddItemRequestData";
|
||||
import { IAddItemTempObject } from "@spt-aki/models/eft/inventory/IAddItemTempObject";
|
||||
import { IInventoryMergeRequestData } from "@spt-aki/models/eft/inventory/IInventoryMergeRequestData";
|
||||
@ -67,6 +68,90 @@ export class InventoryHelper
|
||||
}
|
||||
|
||||
/**
|
||||
* Add whatever is passed in `request.itemWithModsToAdd` into player inventory (if it fits)
|
||||
* @param sessionId Session id
|
||||
* @param request addItemDirect request
|
||||
* @param pmcData Player profile
|
||||
* @param output Client response object
|
||||
* @returns IItemEventRouterResponse
|
||||
*/
|
||||
public addItemToInventory(sessionId: string, request: IAddItemDirectRequest, pmcData: IPmcData, output: IItemEventRouterResponse): IItemEventRouterResponse
|
||||
{
|
||||
const itemWithModsToAddClone = this.jsonUtil.clone(request.itemWithModsToAdd);
|
||||
|
||||
// get stash layouts ready for use
|
||||
const stashFS2D = this.getStashSlotMap(pmcData, sessionId);
|
||||
const sortingTableFS2D = this.getSortingTableSlotMap(pmcData);
|
||||
|
||||
// Find an empty slot in stash for item being added - adds 'location' property to root item
|
||||
const errorOutput = this.placeItemInInventory(
|
||||
stashFS2D,
|
||||
sortingTableFS2D,
|
||||
itemWithModsToAddClone,
|
||||
pmcData.Inventory,
|
||||
request.useSortingTable,
|
||||
output,
|
||||
);
|
||||
if (errorOutput)
|
||||
{
|
||||
// Failed to place, error out
|
||||
return errorOutput;
|
||||
}
|
||||
|
||||
// Apply/remove FiR to item + mods
|
||||
for (const item of itemWithModsToAddClone)
|
||||
{
|
||||
if (!item.upd)
|
||||
{
|
||||
item.upd = {};
|
||||
}
|
||||
|
||||
if (request.foundInRaid)
|
||||
{
|
||||
item.upd.SpawnedInSession = request.foundInRaid;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (delete item.upd.SpawnedInSession)
|
||||
{
|
||||
delete item.upd.SpawnedInSession;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove trader properties from root item
|
||||
this.removeTraderRagfairRelatedUpdProperties(itemWithModsToAddClone[0].upd);
|
||||
|
||||
// Run callback
|
||||
try
|
||||
{
|
||||
if (typeof request.callback === "function")
|
||||
{
|
||||
request.callback();
|
||||
}
|
||||
}
|
||||
catch (err)
|
||||
{
|
||||
// Callback failed
|
||||
const message = typeof err === "string"
|
||||
? err
|
||||
: this.localisationService.getText("http-unknown_error");
|
||||
|
||||
return this.httpResponse.appendErrorToOutput(output, message);
|
||||
}
|
||||
|
||||
// Add item + mods to output + profile inventory
|
||||
output.profileChanges[sessionId].items.new.push(...itemWithModsToAddClone);
|
||||
pmcData.Inventory.items.push(...itemWithModsToAddClone);
|
||||
|
||||
this.logger.debug(`Added item ${itemWithModsToAddClone[0]._tpl} with ${itemWithModsToAddClone.length - 1} mods to inventory`);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated - use addItemDirect()
|
||||
*
|
||||
* BUG: Passing the same item multiple times with a count of 1 will cause multiples of that item to be added (e.g. x3 separate objects of tar cola with count of 1 = 9 tarcolas being added to inventory)
|
||||
* @param pmcData Profile to add items to
|
||||
* @param request request data to add items
|
||||
@ -175,7 +260,7 @@ export class InventoryHelper
|
||||
{
|
||||
// Update Items `location` properties
|
||||
const itemWithChildren = this.itemHelper.findAndReturnChildrenAsItems(itemsToAddPool, itemToAdd.itemRef._id);
|
||||
const errorOutput = this.placeItemInInventory(
|
||||
const errorOutput = this.placeItemInInventoryLegacy(
|
||||
itemToAdd,
|
||||
stashFS2D,
|
||||
sortingTableFS2D,
|
||||
@ -252,7 +337,7 @@ export class InventoryHelper
|
||||
}
|
||||
|
||||
// Remove invalid properties prior to adding to inventory
|
||||
this.removeTraderRelatedUpdProperties(rootItemUpd);
|
||||
this.removeTraderRagfairRelatedUpdProperties(rootItemUpd);
|
||||
|
||||
// Add root item to client return object
|
||||
output.profileChanges[sessionID].items.new.push({
|
||||
@ -381,10 +466,10 @@ export class InventoryHelper
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove properties from a Upd object used by a trader
|
||||
* Remove properties from a Upd object used by a trader/ragfair
|
||||
* @param upd Object to update
|
||||
*/
|
||||
protected removeTraderRelatedUpdProperties(upd: Upd): void
|
||||
protected removeTraderRagfairRelatedUpdProperties(upd: Upd): void
|
||||
{
|
||||
if (upd.UnlimitedCount !== undefined)
|
||||
{
|
||||
@ -402,6 +487,108 @@ export class InventoryHelper
|
||||
}
|
||||
}
|
||||
|
||||
protected placeItemInInventory(
|
||||
stashFS2D: number[][],
|
||||
sortingTableFS2D: number[][],
|
||||
itemWithChildren: Item[],
|
||||
playerInventory: Inventory,
|
||||
useSortingTable: boolean,
|
||||
output: IItemEventRouterResponse): IItemEventRouterResponse
|
||||
{
|
||||
const itemSize = this.getItemSize(itemWithChildren[0]._tpl, itemWithChildren[0]._id, itemWithChildren);
|
||||
const findSlotResult = this.containerHelper.findSlotForItem(stashFS2D, itemSize[0], itemSize[1]);
|
||||
|
||||
if (findSlotResult.success)
|
||||
{
|
||||
/* Fill in the StashFS_2D with an imaginary item, to simulate it already being added
|
||||
* so the next item to search for a free slot won't find the same one */
|
||||
const itemSizeX = findSlotResult.rotation ? itemSize[1] : itemSize[0];
|
||||
const itemSizeY = findSlotResult.rotation ? itemSize[0] : itemSize[1];
|
||||
|
||||
try
|
||||
{
|
||||
stashFS2D = this.containerHelper.fillContainerMapWithItem(
|
||||
stashFS2D,
|
||||
findSlotResult.x,
|
||||
findSlotResult.y,
|
||||
itemSizeX,
|
||||
itemSizeY,
|
||||
false,
|
||||
); // TODO: rotation not passed in, bad?
|
||||
}
|
||||
catch (err)
|
||||
{
|
||||
const errorText = typeof err === "string" ? ` -> ${err}` : "";
|
||||
this.logger.error(this.localisationService.getText("inventory-fill_container_failed", errorText));
|
||||
|
||||
return this.httpResponse.appendErrorToOutput(
|
||||
output,
|
||||
this.localisationService.getText("inventory-no_stash_space"),
|
||||
);
|
||||
}
|
||||
// Store details for object, incuding container item will be placed in
|
||||
itemWithChildren[0].parentId = playerInventory.stash;
|
||||
itemWithChildren[0].location = {
|
||||
x: findSlotResult.x,
|
||||
y: findSlotResult.y,
|
||||
r: findSlotResult.rotation ? 1 : 0,
|
||||
rotation: findSlotResult.rotation,
|
||||
};
|
||||
|
||||
// Success! exit
|
||||
return;
|
||||
}
|
||||
|
||||
// Space not found in main stash, use sorting table
|
||||
if (useSortingTable)
|
||||
{
|
||||
const findSortingSlotResult = this.containerHelper.findSlotForItem(
|
||||
sortingTableFS2D,
|
||||
itemSize[0],
|
||||
itemSize[1],
|
||||
);
|
||||
const itemSizeX = findSortingSlotResult.rotation ? itemSize[1] : itemSize[0];
|
||||
const itemSizeY = findSortingSlotResult.rotation ? itemSize[0] : itemSize[1];
|
||||
try
|
||||
{
|
||||
sortingTableFS2D = this.containerHelper.fillContainerMapWithItem(
|
||||
sortingTableFS2D,
|
||||
findSortingSlotResult.x,
|
||||
findSortingSlotResult.y,
|
||||
itemSizeX,
|
||||
itemSizeY,
|
||||
false,
|
||||
); // TODO: rotation not passed in, bad?
|
||||
}
|
||||
catch (err)
|
||||
{
|
||||
const errorText = typeof err === "string" ? ` -> ${err}` : "";
|
||||
this.logger.error(this.localisationService.getText("inventory-fill_container_failed", errorText));
|
||||
|
||||
return this.httpResponse.appendErrorToOutput(
|
||||
output,
|
||||
this.localisationService.getText("inventory-no_stash_space"),
|
||||
);
|
||||
}
|
||||
|
||||
// Store details for object, incuding container item will be placed in
|
||||
itemWithChildren[0].parentId = playerInventory.sortingTable;
|
||||
itemWithChildren[0].location = {
|
||||
x: findSortingSlotResult.x,
|
||||
y: findSortingSlotResult.y,
|
||||
r: findSortingSlotResult.rotation ? 1 : 0,
|
||||
rotation: findSortingSlotResult.rotation,
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
return this.httpResponse.appendErrorToOutput(
|
||||
output,
|
||||
this.localisationService.getText("inventory-no_stash_space"),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Take the given item, find a free slot in passed in inventory and place it there
|
||||
* If no space in inventory, place in sorting table
|
||||
@ -414,7 +601,7 @@ export class InventoryHelper
|
||||
* @param output Client output object
|
||||
* @returns Client error output if placing item failed
|
||||
*/
|
||||
protected placeItemInInventory(
|
||||
protected placeItemInInventoryLegacy(
|
||||
itemToAdd: IAddItemTempObject,
|
||||
stashFS2D: number[][],
|
||||
sortingTableFS2D: number[][],
|
||||
@ -796,10 +983,10 @@ export class InventoryHelper
|
||||
* inputs Item template ID, Item Id, InventoryItem (item from inventory having _id and _tpl)
|
||||
* outputs [width, height]
|
||||
*/
|
||||
public getItemSize(itemTpl: string, itemID: string, inventoryItem: Item[]): number[]
|
||||
public getItemSize(itemTpl: string, itemID: string, inventoryItems: Item[]): number[]
|
||||
{
|
||||
// -> Prepares item Width and height returns [sizeX, sizeY]
|
||||
return this.getSizeByInventoryItemHash(itemTpl, itemID, this.getInventoryItemHash(inventoryItem));
|
||||
return this.getSizeByInventoryItemHash(itemTpl, itemID, this.getInventoryItemHash(inventoryItems));
|
||||
}
|
||||
|
||||
// note from 2027: there IS a thing i didn't explore and that is Merges With Children
|
||||
|
@ -5,6 +5,7 @@ import { ItemHelper } from "@spt-aki/helpers/ItemHelper";
|
||||
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";
|
||||
import { IAddItemDirectRequest } from "@spt-aki/models/eft/inventory/IAddItemDirectRequest";
|
||||
import { IItemEventRouterResponse } from "@spt-aki/models/eft/itemEvent/IItemEventRouterResponse";
|
||||
import { IProcessBuyTradeRequestData } from "@spt-aki/models/eft/trade/IProcessBuyTradeRequestData";
|
||||
import { IProcessSellTradeRequestData } from "@spt-aki/models/eft/trade/IProcessSellTradeRequestData";
|
||||
@ -18,6 +19,7 @@ import { RagfairServer } from "@spt-aki/servers/RagfairServer";
|
||||
import { FenceService } from "@spt-aki/services/FenceService";
|
||||
import { PaymentService } from "@spt-aki/services/PaymentService";
|
||||
import { HttpResponseUtil } from "@spt-aki/utils/HttpResponseUtil";
|
||||
import { JsonUtil } from "@spt-aki/utils/JsonUtil";
|
||||
|
||||
@injectable()
|
||||
export class TradeHelper
|
||||
@ -26,6 +28,7 @@ export class TradeHelper
|
||||
|
||||
constructor(
|
||||
@inject("WinstonLogger") protected logger: ILogger,
|
||||
@inject("JsonUtil") protected jsonUtil: JsonUtil,
|
||||
@inject("EventOutputHolder") protected eventOutputHolder: EventOutputHolder,
|
||||
@inject("TraderHelper") protected traderHelper: TraderHelper,
|
||||
@inject("ItemHelper") protected itemHelper: ItemHelper,
|
||||
@ -70,12 +73,14 @@ export class TradeHelper
|
||||
|
||||
const callback = () =>
|
||||
{
|
||||
// Update assort/flea item values
|
||||
let itemPurchased: Item;
|
||||
const isRagfair = buyRequestData.tid.toLocaleLowerCase() === "ragfair";
|
||||
if (isRagfair)
|
||||
{
|
||||
const allOffers = this.ragfairServer.getOffers();
|
||||
const offersWithItem = allOffers.find((x) => x.items[0]._id === buyRequestData.item_id);
|
||||
// We store ragfair offerid in buyRequestData.item_id
|
||||
const offersWithItem = allOffers.find((x) => x._id === buyRequestData.item_id);
|
||||
itemPurchased = offersWithItem.items[0];
|
||||
}
|
||||
else
|
||||
@ -119,10 +124,26 @@ export class TradeHelper
|
||||
// Increment non-fence trader item buy count
|
||||
this.incrementAssortBuyCount(itemPurchased, buyRequestData.count);
|
||||
}
|
||||
|
||||
this.logger.debug(`Bought item: ${buyRequestData.item_id} from: ${Traders[buyRequestData.tid]}`);
|
||||
};
|
||||
|
||||
if (buyRequestData.tid.toLocaleLowerCase() === "ragfair")
|
||||
{
|
||||
const allOffers = this.ragfairServer.getOffers();
|
||||
const offersWithItem = allOffers.find((x) => x._id === buyRequestData.item_id);
|
||||
|
||||
const request: IAddItemDirectRequest = {
|
||||
itemWithModsToAdd: offersWithItem.items,
|
||||
foundInRaid: true,
|
||||
callback: callback,
|
||||
useSortingTable: true
|
||||
}
|
||||
|
||||
return this.inventoryHelper.addItemToInventory(sessionID, request, pmcData, output);
|
||||
}
|
||||
|
||||
// TODO - handle traders
|
||||
// TODO - handle fence
|
||||
|
||||
return this.inventoryHelper.addItem(pmcData, newReq, output, sessionID, callback, foundInRaid, upd);
|
||||
}
|
||||
|
||||
|
10
project/src/models/eft/inventory/IAddItemDirectRequest.ts
Normal file
10
project/src/models/eft/inventory/IAddItemDirectRequest.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import { Item } from "../common/tables/IItem"
|
||||
|
||||
export interface IAddItemDirectRequest
|
||||
{
|
||||
/** Item and child mods to add to player inventory */
|
||||
itemWithModsToAdd: Item[];
|
||||
foundInRaid: boolean;
|
||||
callback: () => void;
|
||||
useSortingTable: boolean;
|
||||
}
|
@ -565,8 +565,7 @@ export class FenceService
|
||||
const plateTpl = plateSlot._props.filters[0].Plate
|
||||
if (!plateTpl)
|
||||
{
|
||||
this.logger.warning(`Fence generation: item: ${itemDbDetails._id} ${itemDbDetails._name} lacks a default plate for slot: ${plateSlot._name}, skipping`);
|
||||
|
||||
// Bsg data lacks a default plate, skip adding mod
|
||||
continue;
|
||||
}
|
||||
const modItemDbDetails = this.itemHelper.getItem(plateTpl)[1];
|
||||
|
@ -61,10 +61,10 @@ export class RagfairOfferHolder
|
||||
{
|
||||
const trader = offer.user.id;
|
||||
const offerId = offer._id;
|
||||
const template = offer.items[0]._tpl;
|
||||
const itemTpl = offer.items[0]._tpl;
|
||||
this.offersById.set(offerId, offer);
|
||||
this.addOfferByTrader(trader, offer);
|
||||
this.addOfferByTemplates(template, offer);
|
||||
this.addOfferByTemplates(itemTpl, offer);
|
||||
}
|
||||
|
||||
public removeOffer(offer: IRagfairOffer): void
|
||||
|
Loading…
x
Reference in New Issue
Block a user