Improved replaceIDs Method in ItemHelper

- Implemented deep cloning of input Items to prevent mutation.
- Reordered parameters: Items (required) now precede PMC data (optional).
- Updated method calls to bring them inline with these changes.
This commit is contained in:
Refringe 2024-02-05 22:22:03 -05:00
parent c29482394b
commit 42dabc057b
No known key found for this signature in database
GPG Key ID: 64E03E5F892C6F9E
13 changed files with 33 additions and 32 deletions

View File

@ -77,7 +77,7 @@ export class BuildController
// Replace duplicate Id's. The first item is the base item. // Replace duplicate Id's. The first item is the base item.
// The root ID and the base item ID need to match. // The root ID and the base item ID need to match.
body.Items = this.itemHelper.replaceIDs(pmcData, body.Items); body.Items = this.itemHelper.replaceIDs(body.Items, pmcData);
body.Root = body.Items[0]._id; body.Root = body.Items[0]._id;
// Create new object ready to save into profile userbuilds.weaponBuilds // Create new object ready to save into profile userbuilds.weaponBuilds
@ -112,7 +112,7 @@ export class BuildController
// Replace duplicate ID's. The first item is the base item. // Replace duplicate ID's. The first item is the base item.
// Root ID and the base item ID need to match. // Root ID and the base item ID need to match.
request.Items = this.itemHelper.replaceIDs(pmcData, request.Items); request.Items = this.itemHelper.replaceIDs(request.Items, pmcData);
const newBuild: IEquipmentBuild = { const newBuild: IEquipmentBuild = {
Id: request.Id, Id: request.Id,

View File

@ -799,7 +799,7 @@ export class HideoutController
const preset = this.presetHelper.getDefaultPreset(recipe.endProduct); const preset = this.presetHelper.getDefaultPreset(recipe.endProduct);
// Ensure preset has unique ids and is cloned so we don't alter the preset data stored in memory // Ensure preset has unique ids and is cloned so we don't alter the preset data stored in memory
const presetAndMods: Item[] = this.itemHelper.replaceIDs(null, this.jsonUtil.clone(preset._items)); const presetAndMods: Item[] = this.itemHelper.replaceIDs(preset._items);
this.itemHelper.remapRootItemId(presetAndMods); this.itemHelper.remapRootItemId(presetAndMods);
@ -836,11 +836,7 @@ export class HideoutController
const countOfItemsToReward = recipe.count; const countOfItemsToReward = recipe.count;
for (let index = 1; index < countOfItemsToReward; index++) for (let index = 1; index < countOfItemsToReward; index++)
{ {
const itemAndMods: Item[] = this.itemHelper.replaceIDs( const itemAndMods: Item[] = this.itemHelper.replaceIDs(itemAndChildrenToSendToPlayer[0]);
null,
this.jsonUtil.clone(itemAndChildrenToSendToPlayer[0]),
);
itemAndChildrenToSendToPlayer.push(...[itemAndMods]); itemAndChildrenToSendToPlayer.push(...[itemAndMods]);
} }
} }

View File

@ -141,8 +141,8 @@ export class InraidController
this.markOrRemoveFoundInRaidItems(postRaidRequest); this.markOrRemoveFoundInRaidItems(postRaidRequest);
postRaidRequest.profile.Inventory.items = this.itemHelper.replaceIDs( postRaidRequest.profile.Inventory.items = this.itemHelper.replaceIDs(
postRaidRequest.profile,
postRaidRequest.profile.Inventory.items, postRaidRequest.profile.Inventory.items,
postRaidRequest.profile,
serverPmcProfile.InsuredItems, serverPmcProfile.InsuredItems,
postRaidRequest.profile.Inventory.fastPanel, postRaidRequest.profile.Inventory.fastPanel,
); );
@ -317,8 +317,8 @@ export class InraidController
this.markOrRemoveFoundInRaidItems(postRaidRequest); this.markOrRemoveFoundInRaidItems(postRaidRequest);
postRaidRequest.profile.Inventory.items = this.itemHelper.replaceIDs( postRaidRequest.profile.Inventory.items = this.itemHelper.replaceIDs(
postRaidRequest.profile,
postRaidRequest.profile.Inventory.items, postRaidRequest.profile.Inventory.items,
postRaidRequest.profile,
serverPmcProfile.InsuredItems, serverPmcProfile.InsuredItems,
postRaidRequest.profile.Inventory.fastPanel, postRaidRequest.profile.Inventory.fastPanel,
); );

View File

@ -164,10 +164,10 @@ export class ProfileController
pmcData.UnlockedInfo = { unlockedProductionRecipe: [] }; pmcData.UnlockedInfo = { unlockedProductionRecipe: [] };
} }
// Change item id's to be unique // Change item IDs to be unique
pmcData.Inventory.items = this.itemHelper.replaceIDs( pmcData.Inventory.items = this.itemHelper.replaceIDs(
pmcData,
pmcData.Inventory.items, pmcData.Inventory.items,
pmcData,
null, null,
pmcData.Inventory.fastPanel, pmcData.Inventory.fastPanel,
); );

View File

@ -124,7 +124,7 @@ export class FenceBaseAssortGenerator
} }
// Construct preset + mods // Construct preset + mods
const itemAndChildren: Item[] = this.itemHelper.replaceIDs(null, this.jsonUtil.clone(defaultPreset._items)); const itemAndChildren: Item[] = this.itemHelper.replaceIDs(defaultPreset._items);
// Find root item and add some properties to it // Find root item and add some properties to it
for (let i = 0; i < itemAndChildren.length; i++) for (let i = 0; i < itemAndChildren.length; i++)

View File

@ -389,7 +389,7 @@ export class LootGenerator
chosenWeaponPreset = this.randomUtil.getArrayValue(this.presetHelper.getPresets(chosenWeaponTpl)); chosenWeaponPreset = this.randomUtil.getArrayValue(this.presetHelper.getPresets(chosenWeaponTpl));
} }
const presetAndMods: Item[] = this.itemHelper.replaceIDs(null, this.jsonUtil.clone(chosenWeaponPreset._items)); const presetAndMods: Item[] = this.itemHelper.replaceIDs(chosenWeaponPreset._items);
this.itemHelper.remapRootItemId(presetAndMods); this.itemHelper.remapRootItemId(presetAndMods);
// Add preset to return object // Add preset to return object

View File

@ -86,7 +86,7 @@ export class RagfairAssortGenerator
for (const preset of presets) for (const preset of presets)
{ {
// Update Ids and clone // Update Ids and clone
const presetAndMods: Item[] = this.itemHelper.replaceIDs(null, this.jsonUtil.clone(preset._items)); const presetAndMods: Item[] = this.itemHelper.replaceIDs(preset._items);
this.itemHelper.remapRootItemId(presetAndMods); this.itemHelper.remapRootItemId(presetAndMods);
// Add presets base item tpl to the processed list so its skipped later on when processing items // Add presets base item tpl to the processed list so its skipped later on when processing items

View File

@ -311,7 +311,7 @@ export class ScavCaseRewardGenerator
} }
// Ensure preset has unique ids and is cloned so we don't alter the preset data stored in memory // Ensure preset has unique ids and is cloned so we don't alter the preset data stored in memory
const presetAndMods: Item[] = this.itemHelper.replaceIDs(null, this.jsonUtil.clone(preset._items)); const presetAndMods: Item[] = this.itemHelper.replaceIDs(preset._items);
this.itemHelper.remapRootItemId(presetAndMods); this.itemHelper.remapRootItemId(presetAndMods);
resultItem = presetAndMods; resultItem = presetAndMods;

View File

@ -104,7 +104,7 @@ export class GiveSptCommand implements ISptCommand
for (let i = 0; i < +quantity; i++) for (let i = 0; i < +quantity; i++)
{ {
// Make sure IDs are unique before adding to array - prevent collisions // Make sure IDs are unique before adding to array - prevent collisions
const presetToSend = this.itemHelper.replaceIDs(null, this.jsonUtil.clone(preset._items)); const presetToSend = this.itemHelper.replaceIDs(preset._items);
itemsToSend.push(...presetToSend); itemsToSend.push(...presetToSend);
} }
} }

View File

@ -645,30 +645,36 @@ export class ItemHelper
} }
/** /**
* Regenerate all guids with new ids, exceptions are for items that cannot be altered (e.g. stash/sorting table) * Regenerate all GUIDs with new IDs, for the exception of special item types (e.g. quest, sorting table, etc.) This
* function will not mutate the original items array, but will return a new array with new GUIDs.
*
* @param originalItems Items to adjust the IDs of
* @param pmcData Player profile * @param pmcData Player profile
* @param items Items to adjust ID values of * @param insuredItems Insured items that should not have their IDs replaced
* @param insuredItems insured items to not replace ids for * @param fastPanel Quick slot panel
* @param fastPanel
* @returns Item[] * @returns Item[]
*/ */
public replaceIDs(pmcData: IPmcData, items: Item[], insuredItems: InsuredItem[] = null, fastPanel = null): Item[] public replaceIDs(
originalItems: Item[],
pmcData: IPmcData | null = null,
insuredItems: InsuredItem[] | null = null,
fastPanel = null,
): Item[]
{ {
// replace bsg shit long ID with proper one let items = this.jsonUtil.clone(originalItems); // Deep-clone the items to avoid mutation.
let serialisedInventory = this.jsonUtil.serialize(items); let serialisedInventory = this.jsonUtil.serialize(items);
for (const item of items) for (const item of items)
{ {
if (pmcData !== null) if (pmcData !== null)
{ {
// Insured items shouldn't be renamed // Insured items should not be renamed. Only works for PMCs.
// only works for pmcs.
if (insuredItems?.find((insuredItem) => insuredItem.itemId === item._id)) if (insuredItems?.find((insuredItem) => insuredItem.itemId === item._id))
{ {
continue; continue;
} }
// Do not replace important ID's // Do not replace the IDs of specific types of items.
if ( if (
item._id === pmcData.Inventory.equipment item._id === pmcData.Inventory.equipment
|| item._id === pmcData.Inventory.questRaidItems || item._id === pmcData.Inventory.questRaidItems
@ -681,10 +687,9 @@ export class ItemHelper
} }
} }
// replace id // Replace the ID of the item in the serialised inventory using a regular expression.
const oldId = item._id; const oldId = item._id;
const newId = this.hashUtil.generate(); const newId = this.hashUtil.generate();
serialisedInventory = serialisedInventory.replace(new RegExp(oldId, "g"), newId); serialisedInventory = serialisedInventory.replace(new RegExp(oldId, "g"), newId);
// Also replace in quick slot if the old ID exists. // Also replace in quick slot if the old ID exists.

View File

@ -351,7 +351,7 @@ export class QuestHelper
if (defaultPreset) if (defaultPreset)
{ {
// Found preset, use mods to hydrate reward item // Found preset, use mods to hydrate reward item
const presetAndMods: Item[] = this.itemHelper.replaceIDs(null, this.jsonUtil.clone(defaultPreset._items)); const presetAndMods: Item[] = this.itemHelper.replaceIDs(defaultPreset._items);
const newRootId = this.itemHelper.remapRootItemId(presetAndMods); const newRootId = this.itemHelper.remapRootItemId(presetAndMods);
questReward.items = presetAndMods; questReward.items = presetAndMods;

View File

@ -455,7 +455,7 @@ export class FenceService
continue; continue;
} }
const desiredAssortItemAndChildrenClone = this.jsonUtil.clone( let desiredAssortItemAndChildrenClone = this.jsonUtil.clone(
this.itemHelper.findAndReturnChildrenAsItems(baseFenceAssort.items, chosenBaseAssortRoot._id), this.itemHelper.findAndReturnChildrenAsItems(baseFenceAssort.items, chosenBaseAssortRoot._id),
); );
@ -492,7 +492,7 @@ export class FenceService
} }
// MUST randomise Ids as its possible to add the same base fence assort twice = duplicate IDs = dead client // MUST randomise Ids as its possible to add the same base fence assort twice = duplicate IDs = dead client
this.itemHelper.replaceIDs(null, desiredAssortItemAndChildrenClone); desiredAssortItemAndChildrenClone = this.itemHelper.replaceIDs(desiredAssortItemAndChildrenClone);
this.itemHelper.remapRootItemId(desiredAssortItemAndChildrenClone); this.itemHelper.remapRootItemId(desiredAssortItemAndChildrenClone);
const rootItemBeingAdded = desiredAssortItemAndChildrenClone[0]; const rootItemBeingAdded = desiredAssortItemAndChildrenClone[0];

View File

@ -435,7 +435,7 @@ export class MailSendService
itemsToSendToPlayer = { stash: parentItem.parentId, data: [] }; itemsToSendToPlayer = { stash: parentItem.parentId, data: [] };
// Ensure Ids are unique and cont collide with items in player inventory later // Ensure Ids are unique and cont collide with items in player inventory later
messageDetails.items = this.itemHelper.replaceIDs(null, messageDetails.items); messageDetails.items = this.itemHelper.replaceIDs(messageDetails.items);
for (const reward of messageDetails.items) for (const reward of messageDetails.items)
{ {