Converted ReplaceIDs into extension method

This commit is contained in:
Chomp
2025-07-05 17:25:59 +01:00
parent 3c9f9e18fb
commit f140e1e106
14 changed files with 83 additions and 74 deletions
@@ -1,4 +1,5 @@
using SPTarkov.DI.Annotations;
using SPTarkov.Server.Core.Extensions;
using SPTarkov.Server.Core.Generators;
using SPTarkov.Server.Core.Helpers;
using SPTarkov.Server.Core.Models.Common;
@@ -1215,10 +1216,12 @@ public class HideoutController(
var countOfItemsToReward = recipe.Count;
for (var index = 1; index < countOfItemsToReward; index++)
{
var itemAndMods = _itemHelper.ReplaceIDs(
_cloner.Clone(itemAndChildrenToSendToPlayer.FirstOrDefault())
);
itemAndChildrenToSendToPlayer.AddRange([itemAndMods]);
var firstItemWithChildrenClone = _cloner
.Clone(itemAndChildrenToSendToPlayer.FirstOrDefault())
.ReplaceIDs()
.ToList();
itemAndChildrenToSendToPlayer.AddRange([firstItemWithChildrenClone]);
}
}
@@ -1231,12 +1234,12 @@ public class HideoutController(
var defaultPreset = _presetHelper.GetDefaultPreset(recipe.EndProduct);
// Ensure preset has unique ids and is cloned so we don't alter the preset data stored in memory
var presetAndMods = _itemHelper.ReplaceIDs(_cloner.Clone(defaultPreset.Items));
var presetAndModsClone = _cloner.Clone(defaultPreset.Items).ReplaceIDs().ToList();
_itemHelper.RemapRootItemId(presetAndMods);
_itemHelper.RemapRootItemId(presetAndModsClone);
// Store preset items in array
return [presetAndMods];
return [presetAndModsClone];
}
/// <summary>
@@ -382,5 +382,36 @@ namespace SPTarkov.Server.Core.Extensions
// Return all items returned and exclude the secure container item itself
return itemsInSecureContainer.Where(x => x != secureContainer.Id).ToList();
}
/// <summary>
/// Regenerate all GUIDs with new IDs, except special item types (e.g. quest, sorting table, etc.)
/// </summary>
/// <param name="items"></param>
/// <returns></returns>
public static IEnumerable<Item> ReplaceIDs(this IEnumerable<Item> items)
{
foreach (var item in items)
{
// Generate new id
var newId = new MongoId();
// Keep copy of original id
var originalId = item.Id;
// Update items id to new one we generated
item.Id = newId;
// Find all children of item and update their parent ids to match
var childItems = items.Where(x =>
string.Equals(x.ParentId, originalId, StringComparison.OrdinalIgnoreCase)
);
foreach (var childItem in childItems)
{
childItem.ParentId = newId;
}
}
return items;
}
}
}
@@ -1,4 +1,5 @@
using SPTarkov.DI.Annotations;
using SPTarkov.Server.Core.Extensions;
using SPTarkov.Server.Core.Helpers;
using SPTarkov.Server.Core.Models.Common;
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
@@ -162,7 +163,7 @@ public class FenceBaseAssortGenerator(
}
// Construct preset + mods
var itemAndChildren = itemHelper.ReplaceIDs(_cloner.Clone(defaultPreset.Items));
var itemAndChildren = _cloner.Clone(defaultPreset.Items).ReplaceIDs().ToList();
// Find root item and add some properties to it
for (var i = 0; i < itemAndChildren.Count; i++)
@@ -1171,7 +1171,7 @@ public class LocationLootGenerator(
var itemWithChildren = lootItems.FindAndReturnChildrenAsItems(chosenItem.Id);
// Ensure all IDs are unique
itemWithChildren = _itemHelper.ReplaceIDs(_cloner.Clone(itemWithChildren));
itemWithChildren = _cloner.Clone(itemWithChildren).ReplaceIDs().ToList();
if (_locationConfig.TplsToStripChildItemsFrom.Contains(chosenItem.Template))
// Strip children from parent before adding
@@ -1280,12 +1280,12 @@ public class LocationLootGenerator(
var defaultPreset = _presetHelper.GetDefaultPreset(chosenTpl);
if (defaultPreset is not null)
{
var presetAndMods = _itemHelper.ReplaceIDs(_cloner.Clone(defaultPreset.Items));
_itemHelper.RemapRootItemId(presetAndMods);
var presetAndModsClone = _cloner.Clone(defaultPreset.Items).ReplaceIDs().ToList();
_itemHelper.RemapRootItemId(presetAndModsClone);
// Use original items parentId otherwise item doesn't get added to container correctly
presetAndMods.FirstOrDefault().ParentId = rootItem.ParentId;
items = presetAndMods;
presetAndModsClone.FirstOrDefault().ParentId = rootItem.ParentId;
items = presetAndModsClone;
}
else
{
@@ -1,5 +1,6 @@
using System.Text.Json.Serialization;
using SPTarkov.DI.Annotations;
using SPTarkov.Server.Core.Extensions;
using SPTarkov.Server.Core.Helpers;
using SPTarkov.Server.Core.Models.Common;
using SPTarkov.Server.Core.Models.Eft.Common;
@@ -200,12 +201,13 @@ public class LootGenerator(
for (var i = 0; i < randomisedItemCount; i++)
{
// Clone preset and alter Ids to be unique
var presetWithUniqueIds = _itemHelper.ReplaceIDs(
_cloner.Clone(preset.Items)
);
var presetWithUniqueIdsClone = _cloner
.Clone(preset.Items)
.ReplaceIDs()
.ToList();
// Add to results
result.Add(presetWithUniqueIds);
result.Add(presetWithUniqueIdsClone);
}
}
@@ -497,13 +499,13 @@ public class LootGenerator(
return false;
}
var presetAndMods = _itemHelper.ReplaceIDs(_cloner.Clone(chosenPreset.Items));
_itemHelper.RemapRootItemId(presetAndMods);
var presetAndModsClone = _cloner.Clone(chosenPreset.Items).ReplaceIDs().ToList();
_itemHelper.RemapRootItemId(presetAndModsClone);
_itemHelper.SetFoundInRaid(presetAndMods);
_itemHelper.SetFoundInRaid(presetAndModsClone);
// Add chosen preset tpl to result array
result.Add(presetAndMods);
result.Add(presetAndModsClone);
if (itemLimitCount is not null)
// Increment item count as item has been chosen and its inside itemLimitCount dictionary
@@ -565,13 +567,13 @@ public class LootGenerator(
}
// Clean up Ids to ensure they're all unique and prevent collisions
var presetAndMods = _itemHelper.ReplaceIDs(_cloner.Clone(chosenWeaponPreset.Items));
_itemHelper.RemapRootItemId(presetAndMods);
var presetAndModsClone = _cloner.Clone(chosenWeaponPreset.Items).ReplaceIDs().ToList();
_itemHelper.RemapRootItemId(presetAndModsClone);
// Add preset to return object
itemsToReturn.Add(presetAndMods);
itemsToReturn.Add(presetAndModsClone);
// Get a random collection of weapon mods related to chosen weawpon and add them to result array
// Get a random collection of weapon mods related to chosen weapon and add them to result array
var linkedItemsToWeapon = _ragfairLinkedItemService.GetLinkedDbItems(chosenWeaponTpl);
itemsToReturn.AddRange(
GetSealedContainerWeaponModRewards(
@@ -763,7 +765,7 @@ public class LootGenerator(
var preset = _presetHelper.GetDefaultPreset(chosenRewardItemTpl);
// Ensure preset has unique ids and is cloned so we don't alter the preset data stored in memory
var presetAndMods = _itemHelper.ReplaceIDs(preset.Items);
var presetAndMods = preset.Items.ReplaceIDs().ToList();
_itemHelper.RemapRootItemId(presetAndMods);
itemsToReturn.Add(presetAndMods);
@@ -1,4 +1,5 @@
using SPTarkov.DI.Annotations;
using SPTarkov.Server.Core.Extensions;
using SPTarkov.Server.Core.Helpers;
using SPTarkov.Server.Core.Models.Common;
using SPTarkov.Server.Core.Models.Eft.Common;
@@ -65,22 +66,22 @@ public class RagfairAssortGenerator(
foreach (var preset in presets)
{
// Update Ids and clone
var presetAndMods = itemHelper.ReplaceIDs(cloner.Clone(preset.Items));
itemHelper.RemapRootItemId(presetAndMods);
var presetAndModsClone = cloner.Clone(preset.Items).ReplaceIDs().ToList();
itemHelper.RemapRootItemId(presetAndModsClone);
// Add presets base item tpl to the processed list so its skipped later on when processing items
processedArmorItems.Add(preset.Items[0].Template);
presetAndMods[0].ParentId = "hideout";
presetAndMods[0].SlotId = "hideout";
presetAndMods[0].Upd = new Upd
presetAndModsClone[0].ParentId = "hideout";
presetAndModsClone[0].SlotId = "hideout";
presetAndModsClone[0].Upd = new Upd
{
StackObjectsCount = 99999999,
UnlimitedCount = true,
SptPresetId = preset.Id,
};
results.Add(presetAndMods);
results.Add(presetAndModsClone);
}
foreach (var item in dbItemsClone)
@@ -1,5 +1,6 @@
using SPTarkov.Common.Extensions;
using SPTarkov.DI.Annotations;
using SPTarkov.Server.Core.Extensions;
using SPTarkov.Server.Core.Helpers;
using SPTarkov.Server.Core.Models.Common;
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
@@ -403,7 +404,7 @@ public class ScavCaseRewardGenerator(
}
// Ensure preset has unique ids and is cloned so we don't alter the preset data stored in memory
var presetAndMods = _itemHelper.ReplaceIDs(_cloner.Clone(preset.Items));
var presetAndMods = _cloner.Clone(preset.Items).ReplaceIDs().ToList();
_itemHelper.RemapRootItemId(presetAndMods);
resultItem = presetAndMods;
@@ -234,7 +234,7 @@ public class GiveSptCommand(
for (var i = 0; i < quantity; i++)
{
var items = _cloner.Clone(preset.Items);
items = _itemHelper.ReplaceIDs(items);
items = items.ReplaceIDs().ToList();
itemsToSend.AddRange(items);
}
}
@@ -837,7 +837,7 @@ public class ItemHelper(
while (remainingCount.Value != 0)
{
// Clone item and make IDs unique
var itemWithChildrenClone = ReplaceIDs(_cloner.Clone(itemWithChildren));
var itemWithChildrenClone = _cloner.Clone(itemWithChildren).ReplaceIDs().ToList();
// Set stack count to new value
var amount = Math.Min(remainingCount ?? 0, maxStackSize ?? 0);
@@ -1017,37 +1017,6 @@ public class ItemHelper(
}
}
/// <summary>
/// Regenerate all GUIDs with new IDs, except special item types (e.g. quest, sorting table, etc.)
/// </summary>
/// <param name="items"></param>
/// <returns></returns>
public List<Item> ReplaceIDs(List<Item> items)
{
foreach (var item in items)
{
// Generate new id
var newId = new MongoId();
// Keep copy of original id
var originalId = item.Id;
// Update items id to new one we generated
item.Id = newId;
// Find all children of item and update their parent ids to match
var childItems = items.Where(x =>
string.Equals(x.ParentId, originalId, StringComparison.OrdinalIgnoreCase)
);
foreach (var childItem in childItems)
{
childItem.ParentId = newId;
}
}
return items;
}
/// <summary>
/// Regenerate all GUIDs with new IDs, except special item types (e.g. quest, sorting table, etc.) This
/// function will not mutate the original items list, but will return a new list with new GUIDs.
@@ -383,7 +383,7 @@ public class RewardHelper(
if (defaultPreset is not null)
{
// Found preset, use mods to hydrate reward item
var presetAndMods = _itemHelper.ReplaceIDs(_cloner.Clone(defaultPreset.Items));
var presetAndMods = _cloner.Clone(defaultPreset.Items).ReplaceIDs().ToList();
var newRootId = _itemHelper.RemapRootItemId(presetAndMods);
reward.Items = presetAndMods;
@@ -66,7 +66,7 @@ public record SealedAirdropContainerSettings
public Dictionary<string, object>? ExtensionData { get; set; }
[JsonPropertyName("weaponRewardWeight")]
public required Dictionary<string, double> WeaponRewardWeight { get; set; }
public required Dictionary<MongoId, double> WeaponRewardWeight { get; set; }
[JsonPropertyName("defaultPresetsOnly")]
public bool DefaultPresetsOnly { get; set; }
@@ -399,7 +399,7 @@ public class CircleOfCultistService(
}
// Ensure preset has unique ids and is cloned so we don't alter the preset data stored in memory
var presetAndMods = _itemHelper.ReplaceIDs(defaultPreset.Items);
var presetAndMods = defaultPreset.Items.ReplaceIDs().ToList();
_itemHelper.RemapRootItemId(presetAndMods);
// Set item as FiR
@@ -494,7 +494,7 @@ public class CircleOfCultistService(
}
// Ensure preset has unique ids and is cloned so we don't alter the preset data stored in memory
var presetAndMods = _itemHelper.ReplaceIDs(defaultPreset.Items);
var presetAndMods = defaultPreset.Items.ReplaceIDs().ToList();
_itemHelper.RemapRootItemId(presetAndMods);
// Set item as FiR
@@ -858,9 +858,10 @@ public class FenceService(
}
// MUST randomise Ids as its possible to add the same base fence assort twice = duplicate IDs = dead client
desiredAssortItemAndChildrenClone = itemHelper.ReplaceIDs(
_cloner.Clone(desiredAssortItemAndChildrenClone)
);
desiredAssortItemAndChildrenClone = _cloner
.Clone(desiredAssortItemAndChildrenClone)
.ReplaceIDs()
.ToList();
itemHelper.RemapRootItemId(desiredAssortItemAndChildrenClone);
var rootItemBeingAdded = desiredAssortItemAndChildrenClone[0];
@@ -516,7 +516,7 @@ public class MailSendService(
};
// Ensure Ids are unique and cont collide with items in player inventory later
messageDetails.Items = _itemHelper.ReplaceIDs(_cloner.Clone(messageDetails.Items));
messageDetails.Items = _cloner.Clone(messageDetails.Items).ReplaceIDs().ToList();
// Ensure item exits in items db
foreach (var reward in messageDetails.Items)