From 1ff8d2cbefd41fb61f36d6baf614ad5d7964f9bb Mon Sep 17 00:00:00 2001 From: Chomp Date: Mon, 17 Feb 2025 19:05:47 +0000 Subject: [PATCH] Replaced lists containing unique values with HashSets Reworked Soft Insert id checks Improved dogtag id lookup memory usage Removed wave cleanup code --- .../Core/Callbacks/ItemEventCallbacks.cs | 2 +- .../Core/Controllers/HideoutController.cs | 2 +- .../Core/Controllers/InsuranceController.cs | 3 +- .../Core/Controllers/InventoryController.cs | 2 +- .../Generators/BotEquipmentModGenerator.cs | 58 ++++----- .../Core/Generators/BotInventoryGenerator.cs | 6 +- Libraries/Core/Generators/BotLootGenerator.cs | 6 +- .../Core/Generators/BotWeaponGenerator.cs | 22 ++-- .../Generators/FenceBaseAssortGenerator.cs | 2 +- .../Core/Generators/LocationLootGenerator.cs | 2 +- Libraries/Core/Generators/LootGenerator.cs | 2 +- .../Core/Generators/PlayerScavGenerator.cs | 2 +- .../Core/Generators/RagfairAssortGenerator.cs | 2 +- .../Core/Generators/RagfairOfferGenerator.cs | 2 +- .../Generators/RepeatableQuestGenerator.cs | 4 +- Libraries/Core/Helpers/BotGeneratorHelper.cs | 4 +- Libraries/Core/Helpers/BotHelper.cs | 6 +- .../Core/Helpers/BotWeaponGeneratorHelper.cs | 6 +- .../SPTFriend/Commands/HelloMessageHandler.cs | 4 +- Libraries/Core/Helpers/HealthHelper.cs | 2 +- Libraries/Core/Helpers/HideoutHelper.cs | 4 +- Libraries/Core/Helpers/InventoryHelper.cs | 4 +- Libraries/Core/Helpers/ItemHelper.cs | 111 ++++++++++-------- Libraries/Core/Helpers/PresetHelper.cs | 2 +- Libraries/Core/Helpers/ProfileHelper.cs | 2 +- Libraries/Core/Helpers/QuestHelper.cs | 6 +- Libraries/Core/Helpers/RagfairOfferHelper.cs | 6 +- Libraries/Core/Helpers/TraderAssortHelper.cs | 2 +- .../Core/Models/Eft/Common/Tables/BotBase.cs | 2 +- .../Core/Models/Eft/Common/Tables/Reward.cs | 4 +- .../Models/Eft/Common/Tables/TemplateItem.cs | 8 +- .../Core/Models/Eft/Profile/SptProfile.cs | 2 +- Libraries/Core/Models/Enums/Money.cs | 2 +- .../Spt/Bots/GenerateEquipmentProperties.cs | 2 +- Libraries/Core/Models/Spt/Config/BotConfig.cs | 16 +-- .../Core/Models/Spt/Config/CoreConfig.cs | 2 +- .../Core/Models/Spt/Config/InventoryConfig.cs | 2 +- .../Core/Models/Spt/Config/LocationConfig.cs | 8 +- Libraries/Core/Models/Spt/Config/PmcConfig.cs | 4 +- .../Core/Models/Spt/Config/QuestConfig.cs | 12 +- .../Core/Models/Spt/Config/RagfairConfig.cs | 14 +-- .../Core/Models/Spt/Config/ScavCaseConfig.cs | 4 +- .../Core/Models/Spt/Config/TraderConfig.cs | 2 +- .../Core/Models/Spt/Services/LootRequest.cs | 2 +- Libraries/Core/Services/AirdropService.cs | 4 +- .../Services/BotEquipmentFilterService.cs | 2 +- .../Core/Services/BotLootCacheService.cs | 17 --- Libraries/Core/Services/BotNameService.cs | 2 +- Libraries/Core/Services/FenceService.cs | 6 +- Libraries/Core/Services/ItemFilterService.cs | 25 ++-- .../Core/Services/LocationLifecycleService.cs | 8 +- Libraries/Core/Services/MailSendService.cs | 4 +- .../Core/Services/PmcChatResponseService.cs | 2 +- Libraries/Core/Services/PostDbLoadService.cs | 2 +- .../Core/Services/RagfairLinkedItemService.cs | 2 +- Libraries/Core/Services/RepairService.cs | 4 +- .../Core/Services/SeasonalEventService.cs | 30 ++--- Tools/ItemTplGenerator/ItemTplGenerator.cs | 4 +- 58 files changed, 228 insertions(+), 246 deletions(-) diff --git a/Libraries/Core/Callbacks/ItemEventCallbacks.cs b/Libraries/Core/Callbacks/ItemEventCallbacks.cs index 0a2a8cd4..cc43520f 100644 --- a/Libraries/Core/Callbacks/ItemEventCallbacks.cs +++ b/Libraries/Core/Callbacks/ItemEventCallbacks.cs @@ -32,7 +32,7 @@ public class ItemEventCallbacks(HttpResponseUtil _httpResponseUtil, ItemEventRou } // List of non-critical error codes, we return true if any error NOT included is passed in - var nonCriticalErrorCodes = new List + var nonCriticalErrorCodes = new HashSet { BackendErrorCodes.NotEnoughSpace }; diff --git a/Libraries/Core/Controllers/HideoutController.cs b/Libraries/Core/Controllers/HideoutController.cs index b37ad7bc..8d8b6aa8 100644 --- a/Libraries/Core/Controllers/HideoutController.cs +++ b/Libraries/Core/Controllers/HideoutController.cs @@ -250,7 +250,7 @@ public class HideoutController( // Dont inform client when upgraded area is hall of fame or equipment stand, BSG doesn't inform client this specifc upgrade has occurred // will break client if sent - List check = [HideoutAreas.PLACE_OF_FAME]; + HashSet check = [HideoutAreas.PLACE_OF_FAME]; if (!check.Contains(dbHideoutArea.Type ?? HideoutAreas.NOTSET)) { AddContainerUpgradeToClientOutput(sessionID, dbHideoutArea.Type, dbHideoutArea, hideoutStage, output); diff --git a/Libraries/Core/Controllers/InsuranceController.cs b/Libraries/Core/Controllers/InsuranceController.cs index fe18e117..80fd0d0f 100644 --- a/Libraries/Core/Controllers/InsuranceController.cs +++ b/Libraries/Core/Controllers/InsuranceController.cs @@ -733,9 +733,8 @@ public class InsuranceController( */ public void InsureSoftInserts(Item itemWithSoftInserts, PmcData pmcData, InsureRequestData body) { - var softInsertIds = _itemHelper.GetSoftInsertSlotIds(); var softInsertSlots = pmcData.Inventory.Items.Where( - item => item.ParentId == itemWithSoftInserts.Id && softInsertIds.Contains(item.SlotId.ToLower()) + item => item.ParentId == itemWithSoftInserts.Id && _itemHelper.IsSoftInsertId(item.SlotId.ToLower()) ); foreach (var softInsertSlot in softInsertSlots) diff --git a/Libraries/Core/Controllers/InventoryController.cs b/Libraries/Core/Controllers/InventoryController.cs index 0e356215..bbb0328f 100644 --- a/Libraries/Core/Controllers/InventoryController.cs +++ b/Libraries/Core/Controllers/InventoryController.cs @@ -261,7 +261,7 @@ public class InventoryController( var foundInRaid = openedItem.Upd?.SpawnedInSession; var rewards = new List>(); - var unlockedWeaponCrates = new List + var unlockedWeaponCrates = new HashSet { ItemTpl.RANDOMLOOTCONTAINER_ARENA_WEAPONCRATE_VIOLET_OPEN, ItemTpl.RANDOMLOOTCONTAINER_ARENA_WEAPONCRATE_BLUE_OPEN, diff --git a/Libraries/Core/Generators/BotEquipmentModGenerator.cs b/Libraries/Core/Generators/BotEquipmentModGenerator.cs index 06f74df4..c78b7092 100644 --- a/Libraries/Core/Generators/BotEquipmentModGenerator.cs +++ b/Libraries/Core/Generators/BotEquipmentModGenerator.cs @@ -41,6 +41,18 @@ public class BotEquipmentModGenerator( { protected BotConfig _botConfig = _configServer.GetConfig(); + protected HashSet _modSightIds = ["mod_sight_front", "mod_sight_rear"]; + protected HashSet _scopeIds = + [ + "mod_scope", + "mod_mount", + "mod_mount_000", + "mod_scope_000", + "mod_scope_001", + "mod_scope_002", + "mod_scope_003" + ]; + /// /// Check mods are compatible and add to array /// @@ -152,7 +164,7 @@ public class BotEquipmentModGenerator( // Choose random mod from pool and check its compatibility string modTpl = null; var found = false; - var exhaustableModPool = CreateExhaustableArray(modPoolToChooseFrom.ToList()); + var exhaustableModPool = CreateExhaustableArray(modPoolToChooseFrom); while (exhaustableModPool.HasValues()) { modTpl = exhaustableModPool.GetRandomValue(); @@ -454,7 +466,7 @@ public class BotEquipmentModGenerator( var randomisationSettings = _botHelper.GetBotRandomizationDetails(request.BotData.Level ?? 0, botEquipConfig); // Iterate over mod pool and choose mods to attach - var sortedModKeys = SortModKeys(compatibleModsPool.Keys.ToList(), request.ParentTemplate.Id); + var sortedModKeys = SortModKeys(compatibleModsPool.Keys.ToHashSet(), request.ParentTemplate.Id); foreach (var modSlot in sortedModKeys) { // Check weapon has slot for mod to fit in @@ -707,7 +719,7 @@ public class BotEquipmentModGenerator( public bool ShouldForceSubStockSlots(string modSlot, EquipmentFilters botEquipConfig, TemplateItem modToAddTemplate) { // Slots a weapon can store its stock in - string[] stockSlots = ["mod_stock", "mod_stock_000", "mod_stock_001", "mod_stock_akms"]; + HashSet stockSlots = ["mod_stock", "mod_stock_000", "mod_stock_001", "mod_stock_akms"]; // Can the stock hold child items var hasSubSlots = modToAddTemplate.Properties.Slots?.Count > 0; @@ -730,7 +742,7 @@ public class BotEquipmentModGenerator( return true; } - return ((string[]) ["mod_sight_front", "mod_sight_rear"]).Contains(modSlot); + return _modSightIds.Contains(modSlot); } /// @@ -741,17 +753,7 @@ public class BotEquipmentModGenerator( /// true if it can hold a scope public bool ModSlotCanHoldScope(string modSlot, string modsParentId) { - return ((string[]) - [ - "mod_scope", - "mod_mount", - "mod_mount_000", - "mod_scope_000", - "mod_scope_001", - "mod_scope_002", - "mod_scope_003" - ]).Contains(modSlot.ToLower()) && - modsParentId == BaseClasses.MOUNT; + return _scopeIds.Contains(modSlot.ToLower()) && modsParentId == BaseClasses.MOUNT; } /// @@ -799,7 +801,7 @@ public class BotEquipmentModGenerator( /// Array of mod slot strings to sort /// The Tpl of the item with mod keys being sorted /// Sorted array - public List SortModKeys(List unsortedSlotKeys, string itemTplWithKeysToSort) + public HashSet SortModKeys(HashSet unsortedSlotKeys, string itemTplWithKeysToSort) { // No need to sort with only 1 item in array if (unsortedSlotKeys.Count <= 1) @@ -809,7 +811,7 @@ public class BotEquipmentModGenerator( var isMount = _itemHelper.IsOfBaseclass(itemTplWithKeysToSort, BaseClasses.MOUNT); - List sortedKeys = []; + HashSet sortedKeys = []; var modRecieverKey = "mod_reciever"; var modMount001Key = "mod_mount_001"; var modGasBlockKey = "mod_gas_block"; @@ -899,7 +901,7 @@ public class BotEquipmentModGenerator( } } - sortedKeys.AddRange(unsortedSlotKeys); + sortedKeys.UnionWith(unsortedSlotKeys); return sortedKeys; } @@ -1138,7 +1140,7 @@ public class BotEquipmentModGenerator( } // Filter mod pool to only items that appear in parents allowed list - preFilteredModPool = preFilteredModPool.Where(tpl => parentSlot.Props.Filters[0].Filter.Contains(tpl)).ToList(); + preFilteredModPool = preFilteredModPool.Where(tpl => parentSlot.Props.Filters[0].Filter.Contains(tpl)).ToHashSet(); if (preFilteredModPool.Count == 0) { return new ChooseRandomCompatibleModResult @@ -1158,10 +1160,10 @@ public class BotEquipmentModGenerator( /// How should the slot choice be handled - forced/normal etc /// Weapon mods at current time /// IChooseRandomCompatibleModResult - public ChooseRandomCompatibleModResult GetCompatibleModFromPool(List modPool, ModSpawn? modSpawnType, List weapon) + public ChooseRandomCompatibleModResult GetCompatibleModFromPool(HashSet modPool, ModSpawn? modSpawnType, List weapon) { // Create exhaustable pool to pick mod item from - var exhaustableModPool = CreateExhaustableArray(modPool.ToList()); + var exhaustableModPool = CreateExhaustableArray(modPool); // Create default response if no compatible item is found below ChooseRandomCompatibleModResult chosenModResult = new() @@ -1244,9 +1246,9 @@ public class BotEquipmentModGenerator( return chosenModResult; } - public ExhaustableArray CreateExhaustableArray(List itemsToAddToArray) + public ExhaustableArray CreateExhaustableArray(ICollection itemsToAddToArray) { - return new ExhaustableArray(itemsToAddToArray.ToList(), _randomUtil, _cloner); + return new ExhaustableArray(itemsToAddToArray, _randomUtil, _cloner); } /// @@ -1255,9 +1257,9 @@ public class BotEquipmentModGenerator( /// /// Tpls that are incompatible and should not be used /// string array of compatible mod tpls with weapon - public List GetFilteredModPool(HashSet modPool, HashSet tplBlacklist) + public HashSet GetFilteredModPool(HashSet modPool, HashSet tplBlacklist) { - return modPool.Where(tpl => !tplBlacklist.Contains(tpl)).ToList(); + return modPool.Where(tpl => !tplBlacklist.Contains(tpl)).ToHashSet(); } /// @@ -1442,7 +1444,7 @@ public class BotEquipmentModGenerator( /// e.g. mod_magazine / patron_in_weapon_000 /// /// string array - public List GetAmmoContainers() + public HashSet GetAmmoContainers() { return ["mod_magazine", "patron_in_weapon", "patron_in_weapon_000", "patron_in_weapon_001", "cartridges"]; } @@ -1781,7 +1783,7 @@ public class BotEquipmentModGenerator( { // Check to see if mount has a scope slot (only include primary slot, ignore the rest like the backup sight slots) // Should only find 1 as there's currently no items with a mod_scope AND a mod_scope_000 - List filter = ["mod_scope", "mod_scope_000"]; + HashSet filter = ["mod_scope", "mod_scope_000"]; var scopeSlot = itemDetails.Properties.Slots.Where( slot => filter.Contains(slot.Name) @@ -1806,7 +1808,7 @@ public class BotEquipmentModGenerator( } // No mods added to return list after filtering has occurred, send back the original mod list - if (filteredScopesAndMods is null || filteredScopesAndMods.Count() == 0) + if (filteredScopesAndMods.Count == 0) { if (_logger.IsLogEnabled(LogLevel.Debug)) { diff --git a/Libraries/Core/Generators/BotInventoryGenerator.cs b/Libraries/Core/Generators/BotInventoryGenerator.cs index 1d3bfe20..a6e441f3 100644 --- a/Libraries/Core/Generators/BotInventoryGenerator.cs +++ b/Libraries/Core/Generators/BotInventoryGenerator.cs @@ -40,7 +40,7 @@ public class BotInventoryGenerator( private readonly BotConfig _botConfig = _configServer.GetConfig(); // Slots handled individually inside `GenerateAndAddEquipmentToBot` - private readonly List _excludedEquipmentSlots = + private readonly HashSet _excludedEquipmentSlots = [ EquipmentSlots.Pockets, EquipmentSlots.FirstPrimaryWeapon, @@ -449,7 +449,7 @@ public class BotInventoryGenerator( /// true when item added public bool GenerateEquipment(GenerateEquipmentProperties settings) { - List slotsToCheck = [EquipmentSlots.Pockets.ToString(), EquipmentSlots.SecuredContainer.ToString()]; + HashSet slotsToCheck = [EquipmentSlots.Pockets.ToString(), EquipmentSlots.SecuredContainer.ToString()]; double? spawnChance = slotsToCheck.Contains(settings.RootEquipmentSlot.ToString()) ? 100 : settings.SpawnChances.EquipmentChances.GetValueOrDefault(settings.RootEquipmentSlot.ToString()); @@ -589,7 +589,7 @@ public class BotInventoryGenerator( /// Item mod pool is being retrieved and filtered /// Blacklist to filter mod pool with /// Filtered pool of mods - public Dictionary> GetFilteredDynamicModsForItem(string itemTpl, Dictionary> equipmentBlacklist) + public Dictionary> GetFilteredDynamicModsForItem(string itemTpl, Dictionary> equipmentBlacklist) { var modPool = _botEquipmentModPoolService.GetModsForGearSlot(itemTpl); foreach (var modSlot in modPool) diff --git a/Libraries/Core/Generators/BotLootGenerator.cs b/Libraries/Core/Generators/BotLootGenerator.cs index 91abbc21..5d7df60a 100644 --- a/Libraries/Core/Generators/BotLootGenerator.cs +++ b/Libraries/Core/Generators/BotLootGenerator.cs @@ -368,9 +368,9 @@ public class BotLootGenerator( /// /// /// - private List GetAvailableContainersBotCanStoreItemsIn(BotBaseInventory botInventory) + private HashSet GetAvailableContainersBotCanStoreItemsIn(BotBaseInventory botInventory) { - List result = [EquipmentSlots.Pockets]; + HashSet result = [EquipmentSlots.Pockets]; if ((botInventory.Items ?? []).Any(item => item.SlotId == EquipmentSlots.TacticalVest.ToString())) { @@ -438,7 +438,7 @@ public class BotLootGenerator( private void AddLootFromPool ( Dictionary pool, - List equipmentSlots, + HashSet equipmentSlots, double totalItemCount, BotBaseInventory inventoryToAddItemsTo, string botRole, diff --git a/Libraries/Core/Generators/BotWeaponGenerator.cs b/Libraries/Core/Generators/BotWeaponGenerator.cs index 09fa85ad..a5b7e7fb 100644 --- a/Libraries/Core/Generators/BotWeaponGenerator.cs +++ b/Libraries/Core/Generators/BotWeaponGenerator.cs @@ -200,9 +200,8 @@ public class BotWeaponGenerator( } // Add cartridge(s) to gun chamber(s) - if (weaponItemTemplate.Properties.Chambers?.Any() ?? - (false && - weaponItemTemplate.Properties.Chambers[0].Props.Filters[0].Filter.Contains(ammoTpl))) + if (weaponItemTemplate.Properties?.Chambers?.Count > 0 && + weaponItemTemplate.Properties.Chambers[0].Props.Filters[0].Filter.Contains(ammoTpl)) { // Guns have variety of possible Chamber ids, patron_in_weapon/patron_in_weapon_000/patron_in_weapon_001 var chamberSlotNames = weaponItemTemplate.Properties.Chambers.Select(chamberSlot => chamberSlot.Name); @@ -500,7 +499,7 @@ public class BotWeaponGenerator( { var id = _hashUtil.Generate(); _botGeneratorHelper.AddItemWithChildrenToEquipmentSlot( - new List + new HashSet { EquipmentSlots.SecuredContainer }, @@ -634,7 +633,7 @@ public class BotWeaponGenerator( /// /// Weapon db template to get cartridges for /// List of cartridge tpls - protected List? GetCompatibleCartridgesFromWeaponTemplate(TemplateItem weaponTemplate) + protected HashSet? GetCompatibleCartridgesFromWeaponTemplate(TemplateItem weaponTemplate) { var cartridges = weaponTemplate.Properties?.Chambers.FirstOrDefault()?.Props?.Filters?[0].Filter; if (cartridges is not null) @@ -645,7 +644,7 @@ public class BotWeaponGenerator( // Fallback to the magazine if possible, e.g. for revolvers // Grab the magazines template var firstMagazine = weaponTemplate.Properties.Slots.FirstOrDefault(slot => slot.Name == "mod_magazine"); - var magazineTemplate = _itemHelper.GetItem(firstMagazine.Props.Filters?[0].Filter[0]); + var magazineTemplate = _itemHelper.GetItem(firstMagazine.Props.Filters?[0].Filter.FirstOrDefault()); var magProperties = magazineTemplate.Value.Properties; // Get the first slots array of cartridges @@ -683,14 +682,11 @@ public class BotWeaponGenerator( if (weaponTemplate.Properties.LinkedWeapon is not null) { var ammoInChamber = _itemHelper.GetItem( - weaponTemplate.Properties.Chambers[0].Props.Filters[0].Filter[0] + weaponTemplate.Properties.Chambers[0].Props.Filters[0].Filter.FirstOrDefault() ); - if (!ammoInChamber.Key) - { - return null; - } - - return ammoInChamber.Value.Properties.Caliber; + return !ammoInChamber.Key + ? null + : ammoInChamber.Value.Properties.Caliber; } return null; diff --git a/Libraries/Core/Generators/FenceBaseAssortGenerator.cs b/Libraries/Core/Generators/FenceBaseAssortGenerator.cs index e8e1acdc..1d84c89f 100644 --- a/Libraries/Core/Generators/FenceBaseAssortGenerator.cs +++ b/Libraries/Core/Generators/FenceBaseAssortGenerator.cs @@ -227,7 +227,7 @@ public class FenceBaseAssortGenerator( if (itemHelper.IsOfBaseclass(rootItemDb.Id, BaseClasses.AMMO_BOX)) { // Get the cartridge tpl found inside ammo box - var cartridgeTplInBox = rootItemDb.Properties.StackSlots[0].Props.Filters[0].Filter[0]; + var cartridgeTplInBox = rootItemDb.Properties.StackSlots[0].Props.Filters[0].Filter.FirstOrDefault(); // Look up cartridge tpl in db var ammoItemDb = itemHelper.GetItem(cartridgeTplInBox); diff --git a/Libraries/Core/Generators/LocationLootGenerator.cs b/Libraries/Core/Generators/LocationLootGenerator.cs index a93fdc68..0dc3fba7 100644 --- a/Libraries/Core/Generators/LocationLootGenerator.cs +++ b/Libraries/Core/Generators/LocationLootGenerator.cs @@ -823,7 +823,7 @@ public class LocationLootGenerator( } // Get an array of allowed IDs after above filtering has occured - var validItemIds = spawnPoint.Template.Items.Select(item => item.Id).ToList(); + var validItemIds = spawnPoint.Template.Items.Select(item => item.Id).ToHashSet(); // Construct container to hold above filtered items, letting us pick an item for the spot var itemArray = new ProbabilityObjectArray(_mathUtil, _cloner); diff --git a/Libraries/Core/Generators/LootGenerator.cs b/Libraries/Core/Generators/LootGenerator.cs index 8d53fa79..85b85c7e 100644 --- a/Libraries/Core/Generators/LootGenerator.cs +++ b/Libraries/Core/Generators/LootGenerator.cs @@ -219,7 +219,7 @@ public class LootGenerator( /// Prevent seasonal items appearing outside their defined season /// results of filtering + blacklist used protected ItemRewardPoolResults GetItemRewardPool( - List itemTplBlacklist, + HashSet itemTplBlacklist, List itemTypeWhitelist, bool useRewardItemBlacklist, bool allowBossItems, diff --git a/Libraries/Core/Generators/PlayerScavGenerator.cs b/Libraries/Core/Generators/PlayerScavGenerator.cs index 2ccd3feb..b64aef3b 100644 --- a/Libraries/Core/Generators/PlayerScavGenerator.cs +++ b/Libraries/Core/Generators/PlayerScavGenerator.cs @@ -139,7 +139,7 @@ public class PlayerScavGenerator( /// /// Possible slotIds to add loot to protected void AddAdditionalLootToPlayerScavContainers(Dictionary possibleItemsToAdd, BotBase scavData, - List containersToAddTo) + HashSet containersToAddTo) { foreach (var tpl in possibleItemsToAdd) { diff --git a/Libraries/Core/Generators/RagfairAssortGenerator.cs b/Libraries/Core/Generators/RagfairAssortGenerator.cs index 14da9a3c..861bac4b 100644 --- a/Libraries/Core/Generators/RagfairAssortGenerator.cs +++ b/Libraries/Core/Generators/RagfairAssortGenerator.cs @@ -71,7 +71,7 @@ public class RagfairAssortGenerator( var dbItemsClone = itemHelper.GetItems().Where(item => item.Type != "Node"); /** Store processed preset tpls so we dont add them when procesing non-preset items */ - List processedArmorItems = []; + HashSet processedArmorItems = []; var seasonalEventActive = seasonalEventService.SeasonalEventEnabled(); var seasonalItemTplBlacklist = seasonalEventService.GetInactiveSeasonalEventItems(); diff --git a/Libraries/Core/Generators/RagfairOfferGenerator.cs b/Libraries/Core/Generators/RagfairOfferGenerator.cs index 4ede30ff..2299b5ff 100644 --- a/Libraries/Core/Generators/RagfairOfferGenerator.cs +++ b/Libraries/Core/Generators/RagfairOfferGenerator.cs @@ -529,7 +529,7 @@ public class RagfairOfferGenerator( // Latest first, to ensure we don't move later items off by 1 each time we remove an item below it var indexesToRemove = offerItemPlatesToRemove.Select(plateItem => itemWithChildren.IndexOf(plateItem)) - .ToList(); + .ToHashSet(); foreach (var index in indexesToRemove.OrderByDescending(x => x)) { itemWithChildren.RemoveAt(index); diff --git a/Libraries/Core/Generators/RepeatableQuestGenerator.cs b/Libraries/Core/Generators/RepeatableQuestGenerator.cs index fc3728d0..abd5c867 100644 --- a/Libraries/Core/Generators/RepeatableQuestGenerator.cs +++ b/Libraries/Core/Generators/RepeatableQuestGenerator.cs @@ -556,7 +556,7 @@ public class RepeatableQuestGenerator( var itemIdsWhitelisted = itemWhitelist .Where(p => p.MinPlayerLevel <= pmcLevel) .SelectMany(x => x.ItemIds) - .ToList(); //.Aggregate((a, p) => a.Concat(p.ItemIds), []); + .ToHashSet(); //.Aggregate((a, p) => a.Concat(p.ItemIds), []); itemSelection = itemSelection.Where( x => { @@ -579,7 +579,7 @@ public class RepeatableQuestGenerator( var itemIdsBlacklisted = itemBlacklist .Where(p => p.MinPlayerLevel <= pmcLevel) .SelectMany(x => x.ItemIds) - .ToList(); //.Aggregate(List , (a, p) => a.Concat(p.ItemIds) ); + .ToHashSet(); //.Aggregate(List , (a, p) => a.Concat(p.ItemIds) ); itemSelection = itemSelection.Where( x => diff --git a/Libraries/Core/Helpers/BotGeneratorHelper.cs b/Libraries/Core/Helpers/BotGeneratorHelper.cs index acb953c2..7b566b9e 100644 --- a/Libraries/Core/Helpers/BotGeneratorHelper.cs +++ b/Libraries/Core/Helpers/BotGeneratorHelper.cs @@ -331,7 +331,7 @@ public class BotGeneratorHelper( public ChooseRandomCompatibleModResult IsItemIncompatibleWithCurrentItems(List itemsEquipped, string tplToCheck, string equipmentSlot) { // Skip slots that have no incompatibilities - List slotsToCheck = ["Scabbard", "Backpack", "SecureContainer", "Holster", "ArmBand"]; + HashSet slotsToCheck = ["Scabbard", "Backpack", "SecureContainer", "Holster", "ArmBand"]; if (slotsToCheck.Contains(equipmentSlot)) { return new ChooseRandomCompatibleModResult @@ -530,7 +530,7 @@ public class BotGeneratorHelper( /// /// ItemAddedResult result object public ItemAddedResult AddItemWithChildrenToEquipmentSlot( - List equipmentSlots, + HashSet equipmentSlots, string rootItemId, string? rootItemTplId, List itemWithChildren, diff --git a/Libraries/Core/Helpers/BotHelper.cs b/Libraries/Core/Helpers/BotHelper.cs index ea2c4708..9056538a 100644 --- a/Libraries/Core/Helpers/BotHelper.cs +++ b/Libraries/Core/Helpers/BotHelper.cs @@ -19,7 +19,7 @@ public class BotHelper( { protected BotConfig _botConfig = _configServer.GetConfig(); protected PmcConfig _pmcConfig = _configServer.GetConfig(); - protected List _pmcNames = ["usec", "bear", "pmc", "pmcbear", "pmcusec"]; + protected HashSet _pmcNames = ["usec", "bear", "pmc", "pmcbear", "pmcusec"]; /// /// Get a template object for the specified botRole from bots.types db @@ -119,8 +119,8 @@ public class BotHelper( /// True if role is PMC public bool BotRoleIsPmc(string botRole) { - List ListToCheck = [_pmcConfig.UsecType.ToLower(), _pmcConfig.BearType.ToLower()]; - return ListToCheck.Contains( + HashSet listToCheck = [_pmcConfig.UsecType.ToLower(), _pmcConfig.BearType.ToLower()]; + return listToCheck.Contains( botRole.ToLower() ); } diff --git a/Libraries/Core/Helpers/BotWeaponGeneratorHelper.cs b/Libraries/Core/Helpers/BotWeaponGeneratorHelper.cs index d5e5a37e..c9605d48 100644 --- a/Libraries/Core/Helpers/BotWeaponGeneratorHelper.cs +++ b/Libraries/Core/Helpers/BotWeaponGeneratorHelper.cs @@ -20,7 +20,7 @@ public class BotWeaponGeneratorHelper( LocalisationService _localisationService ) { - private readonly List _magCheck = ["CylinderMagazine", "SpringDrivenCylinder"]; + private readonly HashSet _magCheck = ["CylinderMagazine", "SpringDrivenCylinder"]; /// /// Get a randomized number of bullets for a specific magazine @@ -35,7 +35,7 @@ public class BotWeaponGeneratorHelper( double? chamberBulletCount = 0; if (MagazineIsCylinderRelated(parentItem.Name)) { - var firstSlotAmmoTpl = magTemplate.Properties.Cartridges.FirstOrDefault()?.Props.Filters[0].Filter[0]; + var firstSlotAmmoTpl = magTemplate.Properties.Cartridges.FirstOrDefault()?.Props.Filters[0].Filter.FirstOrDefault(); var ammoMaxStackSize = _itemHelper.GetItem(firstSlotAmmoTpl).Value?.Properties?.StackMaxSize ?? 1; chamberBulletCount = ammoMaxStackSize == 1 ? 1 // Rotating grenade launcher @@ -110,7 +110,7 @@ public class BotWeaponGeneratorHelper( string ammoTpl, int cartridgeCount, BotBaseInventory inventory, - List equipmentSlotsToAddTo + HashSet equipmentSlotsToAddTo ) { if (equipmentSlotsToAddTo is null) diff --git a/Libraries/Core/Helpers/Dialogue/SPTFriend/Commands/HelloMessageHandler.cs b/Libraries/Core/Helpers/Dialogue/SPTFriend/Commands/HelloMessageHandler.cs index c1c874c1..1f24bb0f 100644 --- a/Libraries/Core/Helpers/Dialogue/SPTFriend/Commands/HelloMessageHandler.cs +++ b/Libraries/Core/Helpers/Dialogue/SPTFriend/Commands/HelloMessageHandler.cs @@ -12,7 +12,7 @@ public class HelloMessageHandler( MailSendService _mailSendService, RandomUtil _randomUtil) : IChatMessageHandler { - protected List _listOfMessages = ["hello", "hi", "sup", "yo", "hey", "bonjour"]; + protected HashSet _listOfGreetings = ["hello", "hi", "sup", "yo", "hey", "bonjour"]; public int GetPriority() @@ -22,7 +22,7 @@ public class HelloMessageHandler( public bool CanHandle(string message) { - return _listOfMessages.Contains(message, StringComparer.OrdinalIgnoreCase); + return _listOfGreetings.Contains(message, StringComparer.OrdinalIgnoreCase); } public void Process(string sessionId, UserDialogInfo sptFriendUser, PmcData sender) diff --git a/Libraries/Core/Helpers/HealthHelper.cs b/Libraries/Core/Helpers/HealthHelper.cs index f2da8628..64e3150a 100644 --- a/Libraries/Core/Helpers/HealthHelper.cs +++ b/Libraries/Core/Helpers/HealthHelper.cs @@ -210,7 +210,7 @@ public class HealthHelper( protected void TransferPostRaidLimbEffectsToProfile(Dictionary postRaidBodyParts, PmcData profileData) { // Iterate over each body part - List effectsToIgnore = ["Dehydration", "Exhaustion"]; + HashSet effectsToIgnore = ["Dehydration", "Exhaustion"]; foreach (var bodyPartId in postRaidBodyParts) { // Get effects on body part from profile diff --git a/Libraries/Core/Helpers/HideoutHelper.cs b/Libraries/Core/Helpers/HideoutHelper.cs index a48e91b1..1d311b64 100644 --- a/Libraries/Core/Helpers/HideoutHelper.cs +++ b/Libraries/Core/Helpers/HideoutHelper.cs @@ -38,7 +38,7 @@ public class HideoutHelper( public const string BitcoinProductionId = "5d5c205bd582a50d042a3c0e"; public const string WaterCollector = "5d5589c1f934db045e6c5492"; public const int MaxSkillPoint = 5000; - protected List _idCheck = [BitcoinFarm, CultistCircleCraftId]; + protected HashSet _idCheck = [BitcoinFarm, CultistCircleCraftId]; protected HideoutConfig hideoutConfig = _configServer.GetConfig(); /// @@ -1499,7 +1499,7 @@ public class HideoutHelper( var wallBonuses = wallAreaDb.Stages.SelectMany(stage => stage.Value.Bonuses); // Get all bonus Ids that the wall adds - List bonusIdsToRemove = []; + HashSet bonusIdsToRemove = []; foreach (var bonus in wallBonuses) { bonusIdsToRemove.Add(bonus.Id); diff --git a/Libraries/Core/Helpers/InventoryHelper.cs b/Libraries/Core/Helpers/InventoryHelper.cs index bd5f67d4..782e3600 100644 --- a/Libraries/Core/Helpers/InventoryHelper.cs +++ b/Libraries/Core/Helpers/InventoryHelper.cs @@ -39,7 +39,7 @@ public class InventoryHelper( ) { // Item types to ignore inside `GetSizeByInventoryItemHash` - private readonly List _itemBaseTypesToIgnore = [BaseClasses.BACKPACK, BaseClasses.SEARCHABLE_ITEM, BaseClasses.SIMPLE_CONTAINER]; + private readonly HashSet _itemBaseTypesToIgnore = [BaseClasses.BACKPACK, BaseClasses.SEARCHABLE_ITEM, BaseClasses.SIMPLE_CONTAINER]; protected InventoryConfig _inventoryConfig = _configServer.GetConfig(); /// @@ -1235,7 +1235,7 @@ public class InventoryHelper( } // Reset fast panel value if item was moved to a container other than pocket/rig (cant be used from fastpanel) - List slots = ["pockets", "tacticalvest"]; + HashSet slots = ["pockets", "tacticalvest"]; var wasMovedToFastPanelAccessibleContainer = slots.Contains( itemParent?.SlotId?.ToLower() ?? "" ); diff --git a/Libraries/Core/Helpers/ItemHelper.cs b/Libraries/Core/Helpers/ItemHelper.cs index cc2cd4ec..5069c12a 100644 --- a/Libraries/Core/Helpers/ItemHelper.cs +++ b/Libraries/Core/Helpers/ItemHelper.cs @@ -16,7 +16,6 @@ namespace Core.Helpers; public class ItemHelper( ISptLogger _logger, HashUtil _hashUtil, - JsonUtil _jsonUtil, RandomUtil _randomUtil, MathUtil _mathUtil, DatabaseService _databaseService, @@ -28,7 +27,7 @@ public class ItemHelper( ICloner _cloner ) { - protected List _defaultInvalidBaseTypes = + protected HashSet _defaultInvalidBaseTypes = [ BaseClasses.LOOT_CONTAINER, BaseClasses.MOB_CONTAINER, @@ -39,7 +38,7 @@ public class ItemHelper( BaseClasses.POCKETS ]; - protected List _slotsAsStrings = + protected HashSet _slotsAsStrings = [ EquipmentSlots.Headwear.ToString(), EquipmentSlots.Earpiece.ToString(), @@ -57,6 +56,38 @@ public class ItemHelper( EquipmentSlots.Scabbard.ToString() ]; + protected HashSet _dogTagTpls = + [ + ItemTpl.BARTER_DOGTAG_BEAR, + ItemTpl.BARTER_DOGTAG_BEAR_EOD, + ItemTpl.BARTER_DOGTAG_BEAR_TUE, + ItemTpl.BARTER_DOGTAG_USEC, + ItemTpl.BARTER_DOGTAG_USEC_EOD, + ItemTpl.BARTER_DOGTAG_USEC_TUE, + ItemTpl.BARTER_DOGTAG_BEAR_PRESTIGE_1, + ItemTpl.BARTER_DOGTAG_BEAR_PRESTIGE_2, + ItemTpl.BARTER_DOGTAG_USEC_PRESTIGE_1, + ItemTpl.BARTER_DOGTAG_USEC_PRESTIGE_2 + ]; + + protected HashSet _softInsertIds = + [ + "groin", + "groin_back", + "soft_armor_back", + "soft_armor_front", + "soft_armor_left", + "soft_armor_right", + "shoulder_l", + "shoulder_r", + "collar", + "helmet_top", + "helmet_back", + "helmet_eyes", + "helmet_jaw", + "helmet_ears" + ]; + /** * Does the provided pool of items contain the desired item * @param itemPool Item collection to check @@ -308,7 +339,7 @@ public class ItemHelper( * @param tpl the template id / tpl * @returns boolean; true for items that may be in player possession and not quest items */ - public bool IsValidItem(string tpl, List invalidBaseTypes = null) + public bool IsValidItem(string tpl, ICollection? invalidBaseTypes = null) { var baseTypes = invalidBaseTypes ?? _defaultInvalidBaseTypes; var itemDetails = GetItem(tpl); @@ -403,8 +434,7 @@ public class ItemHelper( } // Check if item has slots that match soft insert name ids - var softInsertIds = GetSoftInsertSlotIds(); - if (itemDbDetails.Value.Properties.Slots.Any(slot => softInsertIds.Contains(slot.Name.ToLower()))) + if (itemDbDetails.Value.Properties.Slots.Any(slot => IsSoftInsertId(slot.Name.ToLower()))) { return true; } @@ -414,32 +444,26 @@ public class ItemHelper( // Get all soft insert slot ids // @returns A List of soft insert ids (e.g. soft_armor_back, helmet_top) - public List GetSoftInsertSlotIds() + public HashSet GetSoftInsertSlotIds() { - return - [ - "groin", - "groin_back", - "soft_armor_back", - "soft_armor_front", - "soft_armor_left", - "soft_armor_right", - "shoulder_l", - "shoulder_r", - "collar", - "helmet_top", - "helmet_back", - "helmet_eyes", - "helmet_jaw", - "helmet_ears" - ]; + return _softInsertIds; + } + + /// + /// Does the passed in slot id match a soft insert id + /// + /// Id to check + /// + public bool IsSoftInsertId(string slotId) + { + return _softInsertIds.Contains(slotId); } // Returns the items total price based on the handbook or as a fallback from the prices.json if the item is not // found in the handbook. If the price can't be found at all return 0 // @param List tpls item tpls to look up the price of // @returns Total price in roubles - public double GetItemAndChildrenPrice(List tpls) + public double GetItemAndChildrenPrice(IEnumerable tpls) { // Run getItemPrice for each tpl in tpls array, return sum return tpls.Aggregate(0, (total, tpl) => total + (int) GetItemPrice(tpl).GetValueOrDefault(0)); @@ -817,21 +841,7 @@ public class ItemHelper( /// True if it is a dogtag. public bool IsDogtag(string tpl) { - List dogTagTpls = - [ - ItemTpl.BARTER_DOGTAG_BEAR, - ItemTpl.BARTER_DOGTAG_BEAR_EOD, - ItemTpl.BARTER_DOGTAG_BEAR_TUE, - ItemTpl.BARTER_DOGTAG_USEC, - ItemTpl.BARTER_DOGTAG_USEC_EOD, - ItemTpl.BARTER_DOGTAG_USEC_TUE, - ItemTpl.BARTER_DOGTAG_BEAR_PRESTIGE_1, - ItemTpl.BARTER_DOGTAG_BEAR_PRESTIGE_2, - ItemTpl.BARTER_DOGTAG_USEC_PRESTIGE_1, - ItemTpl.BARTER_DOGTAG_USEC_PRESTIGE_2 - ]; - - return dogTagTpls.Contains(tpl); + return _dogTagTpls.Contains(tpl); } /// @@ -1332,7 +1342,7 @@ public class ItemHelper( */ public bool IsAttachmentAttached(Item item) { - List check = ["hideout", "main"]; + HashSet check = ["hideout", "main"]; return !(check.Contains(item.SlotId) || _slotsAsStrings.Contains(item.SlotId) || !int.TryParse(item.SlotId, out _)); } @@ -1445,7 +1455,7 @@ public class ItemHelper( public void AddCartridgesToAmmoBox(List ammoBox, TemplateItem ammoBoxDetails) { var ammoBoxMaxCartridgeCount = ammoBoxDetails.Properties.StackSlots[0].MaxCount; - var cartridgeTpl = ammoBoxDetails.Properties.StackSlots[0].Props.Filters[0].Filter[0]; + var cartridgeTpl = ammoBoxDetails.Properties.StackSlots[0].Props.Filters[0].Filter.FirstOrDefault(); var cartridgeDetails = GetItem(cartridgeTpl); var cartridgeMaxStackSize = cartridgeDetails.Value.Properties.StackMaxSize; @@ -1496,7 +1506,7 @@ public class ItemHelper( public void AddSingleStackCartridgesToAmmoBox(List ammoBox, TemplateItem ammoBoxDetails) { var ammoBoxMaxCartridgeCount = ammoBoxDetails.Properties?.StackSlots?[0].MaxCount ?? 0; - var cartridgeTpl = ammoBoxDetails.Properties?.StackSlots?[0].Props?.Filters?[0].Filter?[0]; + var cartridgeTpl = ammoBoxDetails.Properties?.StackSlots?[0].Props?.Filters?[0].Filter?.FirstOrDefault(); ammoBox.Add( CreateCartridges( ammoBox[0].Id, @@ -1684,7 +1694,7 @@ public class ItemHelper( protected string? GetRandomValidCaliber(TemplateItem magTemplate) { var ammoTpls = magTemplate.Properties.Cartridges[0].Props.Filters[0].Filter; - List calibers = ammoTpls + var calibers = ammoTpls .Where(x => GetItem(x).Key) .Select(x => GetItem(x).Value.Properties.Caliber) .ToList(); @@ -1704,7 +1714,7 @@ public class ItemHelper( string caliber, Dictionary> staticAmmoDist, string? fallbackCartridgeTpl = null, - List? cartridgeWhitelist = null + ICollection? cartridgeWhitelist = null ) { var ammos = staticAmmoDist.GetValueOrDefault(caliber, []); @@ -1832,7 +1842,7 @@ public class ItemHelper( ) { var result = itemToAdd; - HashSet incompatibleModTpls = new(); + HashSet incompatibleModTpls = []; foreach (var slot in itemToAddTemplate.Properties.Slots) { // If only required mods is requested, skip non-essential @@ -1856,7 +1866,7 @@ public class ItemHelper( } var itemPool = slot.Props.Filters[0].Filter ?? []; - if (itemPool.Count() == 0) + if (itemPool.Count == 0) { if (_logger.IsLogEnabled(LogLevel.Debug)) { @@ -1896,7 +1906,8 @@ public class ItemHelper( var modItemDbDetails = GetItem(modItemToAdd.Template).Value; // Include conflicting items of newly added mod in pool to be used for next mod choice - modItemDbDetails.Properties.ConflictingItems.ForEach(item => incompatibleModTpls.Add(item)); + incompatibleModTpls.UnionWith(modItemDbDetails.Properties.ConflictingItems); + } return result; @@ -1908,7 +1919,7 @@ public class ItemHelper( /// Tpls to randomly choose from /// Incompatible tpls to not allow /// Chosen tpl or undefined - public string GetCompatibleTplFromArray(List possibleTpls, HashSet incompatibleModTpls) + public string? GetCompatibleTplFromArray(HashSet possibleTpls, HashSet incompatibleModTpls) { if (!possibleTpls.Any()) { @@ -1951,7 +1962,7 @@ public class ItemHelper( // Get a list of slot names that hold removable plates // Returns Array of slot ids (e.g. front_plate) - public List GetRemovablePlateSlotIds() + public HashSet GetRemovablePlateSlotIds() { return ["front_plate", "back_plate", "left_side_plate", "right_side_plate"]; } diff --git a/Libraries/Core/Helpers/PresetHelper.cs b/Libraries/Core/Helpers/PresetHelper.cs index cb1ec249..3cd30eea 100644 --- a/Libraries/Core/Helpers/PresetHelper.cs +++ b/Libraries/Core/Helpers/PresetHelper.cs @@ -189,6 +189,6 @@ public class PresetHelper( var tpls = defaultPreset is not null ? defaultPreset.Items.Select(item => item.Template) : [tpl]; // Get price of tpls - return _itemHelper.GetItemAndChildrenPrice(tpls.ToList()); + return _itemHelper.GetItemAndChildrenPrice(tpls); } } diff --git a/Libraries/Core/Helpers/ProfileHelper.cs b/Libraries/Core/Helpers/ProfileHelper.cs index 9e40dc39..e73975ac 100644 --- a/Libraries/Core/Helpers/ProfileHelper.cs +++ b/Libraries/Core/Helpers/ProfileHelper.cs @@ -199,7 +199,7 @@ public class ProfileHelper( Version = _watermark.GetVersionTag(true), Mods = new List(), ReceivedGifts = new List(), - BlacklistedItemTemplates = new List(), + BlacklistedItemTemplates = new HashSet(), FreeRepeatableRefreshUsedCount = new Dictionary(), Migrations = new Dictionary(), CultistRewards = new Dictionary(), diff --git a/Libraries/Core/Helpers/QuestHelper.cs b/Libraries/Core/Helpers/QuestHelper.cs index 5a8ddf65..96eec54e 100644 --- a/Libraries/Core/Helpers/QuestHelper.cs +++ b/Libraries/Core/Helpers/QuestHelper.cs @@ -38,7 +38,7 @@ public class QuestHelper( ICloner _cloner ) { - protected List _newlyQuestCheck = [QuestStatusEnum.Started, QuestStatusEnum.AvailableForFinish]; + protected HashSet _newlyQuestCheck = [QuestStatusEnum.Started, QuestStatusEnum.AvailableForFinish]; protected QuestConfig _questConfig = _configServer.GetConfig(); /// @@ -413,7 +413,7 @@ public class QuestHelper( } ); - return GetQuestsWithOnlyLevelRequirementStartCondition(eligibleQuests.ToList()); + return GetQuestsWithOnlyLevelRequirementStartCondition(eligibleQuests); } /** @@ -674,7 +674,7 @@ public class QuestHelper( * @param quests quests to process * @returns quest list without conditions */ - protected List GetQuestsWithOnlyLevelRequirementStartCondition(List quests) + protected List GetQuestsWithOnlyLevelRequirementStartCondition(IEnumerable quests) { return quests.Select(GetQuestWithOnlyLevelRequirementStartCondition).ToList(); } diff --git a/Libraries/Core/Helpers/RagfairOfferHelper.cs b/Libraries/Core/Helpers/RagfairOfferHelper.cs index b65b1aec..7795f9b9 100644 --- a/Libraries/Core/Helpers/RagfairOfferHelper.cs +++ b/Libraries/Core/Helpers/RagfairOfferHelper.cs @@ -477,7 +477,7 @@ public class RagfairOfferHelper( /// true if quest locked public bool TraderOfferItemQuestLocked(RagfairOffer offer, Dictionary traderAssorts) { - var itemIds = offer.Items.Select(x => x.Id).ToList(); + var itemIds = offer.Items.Select(x => x.Id).ToHashSet(); //foreach (var item in offer.Items) //{ // traderAssorts.TryGetValue(offer.User.Id, out var assorts); @@ -574,9 +574,9 @@ public class RagfairOfferHelper( return false; } - protected List GetLoyaltyLockedOffers(List offers, PmcData pmcProfile) + protected HashSet GetLoyaltyLockedOffers(List offers, PmcData pmcProfile) { - var loyaltyLockedOffers = new List(); + var loyaltyLockedOffers = new HashSet(); foreach (var offer in offers.Where(offer => OfferIsFromTrader(offer))) { if (pmcProfile.TradersInfo.TryGetValue(offer.User.Id, out var traderDetails) && diff --git a/Libraries/Core/Helpers/TraderAssortHelper.cs b/Libraries/Core/Helpers/TraderAssortHelper.cs index d711fa72..0d6dec22 100644 --- a/Libraries/Core/Helpers/TraderAssortHelper.cs +++ b/Libraries/Core/Helpers/TraderAssortHelper.cs @@ -131,7 +131,7 @@ public class TraderAssortHelper( /// /// Trader assort to modify /// Item TPLs the assort should not have - protected void RemoveItemsFromAssort(TraderAssort assortToFilter, List itemsTplsToRemove) + protected void RemoveItemsFromAssort(TraderAssort assortToFilter, HashSet itemsTplsToRemove) { assortToFilter.Items = assortToFilter.Items.Where( item => diff --git a/Libraries/Core/Models/Eft/Common/Tables/BotBase.cs b/Libraries/Core/Models/Eft/Common/Tables/BotBase.cs index 92d53df7..e4cd5648 100644 --- a/Libraries/Core/Models/Eft/Common/Tables/BotBase.cs +++ b/Libraries/Core/Models/Eft/Common/Tables/BotBase.cs @@ -301,7 +301,7 @@ public record TaskConditionCounter public record UnlockedInfo { [JsonPropertyName("unlockedProductionRecipe")] - public List? UnlockedProductionRecipe + public HashSet? UnlockedProductionRecipe { get; set; diff --git a/Libraries/Core/Models/Eft/Common/Tables/Reward.cs b/Libraries/Core/Models/Eft/Common/Tables/Reward.cs index 1c10ada9..5150d64e 100644 --- a/Libraries/Core/Models/Eft/Common/Tables/Reward.cs +++ b/Libraries/Core/Models/Eft/Common/Tables/Reward.cs @@ -97,7 +97,7 @@ public record Reward * Game editions whitelisted to get reward */ [JsonPropertyName("availableInGameEditions")] - public List? AvailableInGameEditions + public HashSet? AvailableInGameEditions { get; set; @@ -107,7 +107,7 @@ public record Reward * Game editions blacklisted from getting reward */ [JsonPropertyName("notAvailableInGameEditions")] - public List? NotAvailableInGameEditions + public HashSet? NotAvailableInGameEditions { get; set; diff --git a/Libraries/Core/Models/Eft/Common/Tables/TemplateItem.cs b/Libraries/Core/Models/Eft/Common/Tables/TemplateItem.cs index 06b137e7..bb55facd 100644 --- a/Libraries/Core/Models/Eft/Common/Tables/TemplateItem.cs +++ b/Libraries/Core/Models/Eft/Common/Tables/TemplateItem.cs @@ -482,7 +482,7 @@ public record Props } [JsonPropertyName("ConflictingItems")] - public List? ConflictingItems + public HashSet? ConflictingItems { get; set; @@ -1509,7 +1509,7 @@ public record Props } [JsonPropertyName("weapFireType")] - public List? WeapFireType + public HashSet? WeapFireType { get; set; @@ -3604,7 +3604,7 @@ public record GridProps public record GridFilter { [JsonPropertyName("Filter")] - public List? Filter + public HashSet? Filter { get; set; @@ -3755,7 +3755,7 @@ public record SlotFilter } [JsonPropertyName("Filter")] - public List? Filter + public HashSet? Filter { get; set; diff --git a/Libraries/Core/Models/Eft/Profile/SptProfile.cs b/Libraries/Core/Models/Eft/Profile/SptProfile.cs index 90fb27f0..916ba4b2 100644 --- a/Libraries/Core/Models/Eft/Profile/SptProfile.cs +++ b/Libraries/Core/Models/Eft/Profile/SptProfile.cs @@ -733,7 +733,7 @@ public record Spt * item TPLs blacklisted from being sold on flea for this profile */ [JsonPropertyName("blacklistedItemTpls")] - public List? BlacklistedItemTemplates + public HashSet? BlacklistedItemTemplates { get; set; diff --git a/Libraries/Core/Models/Enums/Money.cs b/Libraries/Core/Models/Enums/Money.cs index c108be23..6e293d53 100644 --- a/Libraries/Core/Models/Enums/Money.cs +++ b/Libraries/Core/Models/Enums/Money.cs @@ -7,7 +7,7 @@ public record Money public const string DOLLARS = "5696686a4bdc2da3298b456a"; public const string GP = "5d235b4d86f7742e017bc88a"; - public static List GetMoneyTpls() + public static HashSet GetMoneyTpls() { return [ROUBLES, EUROS, DOLLARS, GP]; } diff --git a/Libraries/Core/Models/Spt/Bots/GenerateEquipmentProperties.cs b/Libraries/Core/Models/Spt/Bots/GenerateEquipmentProperties.cs index f8e58362..787d9601 100644 --- a/Libraries/Core/Models/Spt/Bots/GenerateEquipmentProperties.cs +++ b/Libraries/Core/Models/Spt/Bots/GenerateEquipmentProperties.cs @@ -82,7 +82,7 @@ public record GenerateEquipmentProperties /// OPTIONAL - Do not generate mods for tpls in this array /// [JsonPropertyName("generateModsBlacklist")] - public List? GenerateModsBlacklist + public HashSet? GenerateModsBlacklist { get; set; diff --git a/Libraries/Core/Models/Spt/Config/BotConfig.cs b/Libraries/Core/Models/Spt/Config/BotConfig.cs index 20777c9f..513ce477 100644 --- a/Libraries/Core/Models/Spt/Config/BotConfig.cs +++ b/Libraries/Core/Models/Spt/Config/BotConfig.cs @@ -160,7 +160,7 @@ public record BotConfig : BaseConfig * Bot roles in this array will be given a dog tag on generation */ [JsonPropertyName("botRolesWithDogTags")] - public List BotRolesWithDogTags + public HashSet BotRolesWithDogTags { get; set; @@ -190,7 +190,7 @@ public record BotConfig : BaseConfig * Tpls for low profile gas blocks */ [JsonPropertyName("lowProfileGasBlockTpls")] - public List LowProfileGasBlockTpls + public HashSet LowProfileGasBlockTpls { get; set; @@ -200,7 +200,7 @@ public record BotConfig : BaseConfig * What bottypes should be excluded from having loot generated on them (backpack/pocket/vest) does not disable food/drink/special/ */ [JsonPropertyName("disableLootOnBotTypes")] - public List DisableLootOnBotTypes + public HashSet DisableLootOnBotTypes { get; set; @@ -220,7 +220,7 @@ public record BotConfig : BaseConfig * Bot roles that must have a unique name when generated vs other bots in raid */ [JsonPropertyName("botRolesThatMustHaveUniqueName")] - public List BotRolesThatMustHaveUniqueName + public HashSet BotRolesThatMustHaveUniqueName { get; set; @@ -702,7 +702,7 @@ public record EquipmentFilters /// What additional slot ids should be seen as required when choosing a mod to add to a weapon /// [JsonPropertyName("weaponSlotIdsToMakeRequired")] - public List? WeaponSlotIdsToMakeRequired + public HashSet? WeaponSlotIdsToMakeRequired { get; set; @@ -929,7 +929,7 @@ public record EquipmentFilterDetails /// Key: mod slot name e.g. mod_magazine, value: item tpls /// [JsonPropertyName("equipment")] - public Dictionary>? Equipment + public Dictionary>? Equipment { get; set; @@ -939,7 +939,7 @@ public record EquipmentFilterDetails /// Key: equipment slot name e.g. FirstPrimaryWeapon, value: item tpls /// [JsonPropertyName("gear")] - public Dictionary>? Gear + public Dictionary>? Gear { get; set; @@ -949,7 +949,7 @@ public record EquipmentFilterDetails /// Key: cartridge type e.g. Caliber23x75, value: item tpls /// [JsonPropertyName("cartridge")] - public Dictionary>? Cartridge + public Dictionary>? Cartridge { get; set; diff --git a/Libraries/Core/Models/Spt/Config/CoreConfig.cs b/Libraries/Core/Models/Spt/Config/CoreConfig.cs index c9bdd78d..108bf90c 100644 --- a/Libraries/Core/Models/Spt/Config/CoreConfig.cs +++ b/Libraries/Core/Models/Spt/Config/CoreConfig.cs @@ -335,7 +335,7 @@ public record ServerFeatures * Keyed to profile type e.g. "Standard" or "SPT Developer" */ [JsonPropertyName("createNewProfileTypesBlacklist")] - public List CreateNewProfileTypesBlacklist + public HashSet CreateNewProfileTypesBlacklist { get; set; diff --git a/Libraries/Core/Models/Spt/Config/InventoryConfig.cs b/Libraries/Core/Models/Spt/Config/InventoryConfig.cs index 5610a43a..beff16e2 100644 --- a/Libraries/Core/Models/Spt/Config/InventoryConfig.cs +++ b/Libraries/Core/Models/Spt/Config/InventoryConfig.cs @@ -60,7 +60,7 @@ public record InventoryConfig : BaseConfig * Container Tpls that should be deprioritised when choosing where to take money from for payments */ [JsonPropertyName("deprioritisedMoneyContainers")] - public List DeprioritisedMoneyContainers + public HashSet DeprioritisedMoneyContainers { get; set; diff --git a/Libraries/Core/Models/Spt/Config/LocationConfig.cs b/Libraries/Core/Models/Spt/Config/LocationConfig.cs index 536c3e0a..f732ade5 100644 --- a/Libraries/Core/Models/Spt/Config/LocationConfig.cs +++ b/Libraries/Core/Models/Spt/Config/LocationConfig.cs @@ -51,7 +51,7 @@ public record LocationConfig : BaseConfig /// Open zones to add to map /// [JsonPropertyName("openZones")] - public Dictionary> OpenZones + public Dictionary> OpenZones { get; set; @@ -61,7 +61,7 @@ public record LocationConfig : BaseConfig /// Key = map id, value = item tpls that should only have one forced loot spawn position /// [JsonPropertyName("forcedLootSingleSpawnById")] - public Dictionary> ForcedLootSingleSpawnById + public Dictionary> ForcedLootSingleSpawnById { get; set; @@ -218,7 +218,7 @@ public record LocationConfig : BaseConfig /// Containers to remove all children from when generating static/loose loot /// [JsonPropertyName("tplsToStripChildItemsFrom")] - public List TplsToStripChildItemsFrom + public HashSet TplsToStripChildItemsFrom { get; set; @@ -228,7 +228,7 @@ public record LocationConfig : BaseConfig /// Map ids players cannot visit /// [JsonPropertyName("nonMaps")] - public List NonMaps + public HashSet NonMaps { get; set; diff --git a/Libraries/Core/Models/Spt/Config/PmcConfig.cs b/Libraries/Core/Models/Spt/Config/PmcConfig.cs index 7a931593..b4bf6369 100644 --- a/Libraries/Core/Models/Spt/Config/PmcConfig.cs +++ b/Libraries/Core/Models/Spt/Config/PmcConfig.cs @@ -370,7 +370,7 @@ public record SlotLootSettings * Item Type whitelist */ [JsonPropertyName("whitelist")] - public List Whitelist + public HashSet Whitelist { get; set; @@ -380,7 +380,7 @@ public record SlotLootSettings * Item tpl blacklist */ [JsonPropertyName("blacklist")] - public List Blacklist + public HashSet Blacklist { get; set; diff --git a/Libraries/Core/Models/Spt/Config/QuestConfig.cs b/Libraries/Core/Models/Spt/Config/QuestConfig.cs index 0bc28ad9..70e6bf8e 100644 --- a/Libraries/Core/Models/Spt/Config/QuestConfig.cs +++ b/Libraries/Core/Models/Spt/Config/QuestConfig.cs @@ -62,14 +62,14 @@ public record QuestConfig : BaseConfig } [JsonPropertyName("bearOnlyQuests")] - public List? BearOnlyQuests + public HashSet? BearOnlyQuests { get; set; } [JsonPropertyName("usecOnlyQuests")] - public List? UsecOnlyQuests + public HashSet? UsecOnlyQuests { get; set; @@ -79,7 +79,7 @@ public record QuestConfig : BaseConfig * Quests that the keyed game version do not see/access */ [JsonPropertyName("profileBlacklist")] - public Dictionary>? ProfileBlacklist + public Dictionary>? ProfileBlacklist { get; set; @@ -89,7 +89,7 @@ public record QuestConfig : BaseConfig * key=questid, gameversions that can see/access quest */ [JsonPropertyName("profileWhitelist")] - public Dictionary>? ProfileWhitelist + public Dictionary>? ProfileWhitelist { get; set; @@ -266,7 +266,7 @@ public record RepeatableQuestConfig * Item base types to block when generating rewards */ [JsonPropertyName("rewardBaseTypeBlacklist")] - public List? RewardBaseTypeBlacklist + public HashSet? RewardBaseTypeBlacklist { get; set; @@ -276,7 +276,7 @@ public record RepeatableQuestConfig * Item tplIds to ignore when generating rewards */ [JsonPropertyName("rewardBlacklist")] - public List? RewardBlacklist + public HashSet? RewardBlacklist { get; set; diff --git a/Libraries/Core/Models/Spt/Config/RagfairConfig.cs b/Libraries/Core/Models/Spt/Config/RagfairConfig.cs index 6db0f17c..ee3568fa 100644 --- a/Libraries/Core/Models/Spt/Config/RagfairConfig.cs +++ b/Libraries/Core/Models/Spt/Config/RagfairConfig.cs @@ -228,7 +228,7 @@ public record Dynamic [JsonPropertyName("ignoreQualityPriceVarianceBlacklist")] /** Tpls that should not use the variable price system when their quality is < 100% (lower dura/uses = lower price) */ - public List IgnoreQualityPriceVarianceBlacklist + public HashSet IgnoreQualityPriceVarianceBlacklist { get; set; @@ -306,7 +306,7 @@ public record Dynamic [JsonPropertyName("showAsSingleStack")] /** Item tpls that should be forced to sell as a single item */ - public List ShowAsSingleStack + public HashSet ShowAsSingleStack { get; set; @@ -435,7 +435,7 @@ public record BarterDetails * Item Tpls to never be turned into a barter */ [JsonPropertyName("itemTypeBlacklist")] - public List ItemTypeBlacklist + public HashSet ItemTypeBlacklist { get; set; @@ -578,7 +578,7 @@ public record RagfairBlacklist /// Custom blacklist for item Tpls /// [JsonPropertyName("custom")] - public List Custom + public HashSet Custom { get; set; @@ -638,7 +638,7 @@ public record RagfairBlacklist /// Custom category blacklist for parent Ids /// [JsonPropertyName("customItemCategoryList")] - public List CustomItemCategoryList + public HashSet CustomItemCategoryList { get; set; @@ -661,7 +661,7 @@ public record ArmorPlateBlacklistSettings /// Item slots to NOT remove from items on flea /// [JsonPropertyName("ignoreSlots")] - public List IgnoreSlots + public HashSet IgnoreSlots { get; set; @@ -724,7 +724,7 @@ public record ArmorSettings /// What slots are to be removed when removeRemovablePlateChance is true /// [JsonPropertyName("plateSlotIdToRemovePool")] - public List PlateSlotIdToRemovePool + public HashSet? PlateSlotIdToRemovePool { get; set; diff --git a/Libraries/Core/Models/Spt/Config/ScavCaseConfig.cs b/Libraries/Core/Models/Spt/Config/ScavCaseConfig.cs index 000957ae..c2d30ac1 100644 --- a/Libraries/Core/Models/Spt/Config/ScavCaseConfig.cs +++ b/Libraries/Core/Models/Spt/Config/ScavCaseConfig.cs @@ -34,14 +34,14 @@ public record ScavCaseConfig : BaseConfig } [JsonPropertyName("rewardItemParentBlacklist")] - public List RewardItemParentBlacklist + public HashSet RewardItemParentBlacklist { get; set; } [JsonPropertyName("rewardItemBlacklist")] - public List RewardItemBlacklist + public HashSet RewardItemBlacklist { get; set; diff --git a/Libraries/Core/Models/Spt/Config/TraderConfig.cs b/Libraries/Core/Models/Spt/Config/TraderConfig.cs index 95589aaf..562a49d2 100644 --- a/Libraries/Core/Models/Spt/Config/TraderConfig.cs +++ b/Libraries/Core/Models/Spt/Config/TraderConfig.cs @@ -250,7 +250,7 @@ public record FenceConfig } [JsonPropertyName("blacklist")] - public List Blacklist + public HashSet Blacklist { get; set; diff --git a/Libraries/Core/Models/Spt/Services/LootRequest.cs b/Libraries/Core/Models/Spt/Services/LootRequest.cs index 9550b0e7..e29359b2 100644 --- a/Libraries/Core/Models/Spt/Services/LootRequest.cs +++ b/Libraries/Core/Models/Spt/Services/LootRequest.cs @@ -50,7 +50,7 @@ public record LootRequest /// Item tpl blacklist to exclude /// [JsonPropertyName("itemBlacklist")] - public List? ItemBlacklist + public HashSet? ItemBlacklist { get; set; diff --git a/Libraries/Core/Services/AirdropService.cs b/Libraries/Core/Services/AirdropService.cs index d9c76e8a..660784ce 100644 --- a/Libraries/Core/Services/AirdropService.cs +++ b/Libraries/Core/Services/AirdropService.cs @@ -171,7 +171,7 @@ public class AirdropService( var itemsMatchingTypeBlacklist = _itemHelper.GetItems() .Where(templateItem => !string.IsNullOrEmpty(templateItem.Parent)) .Where(templateItem => _itemHelper.IsOfBaseclasses(templateItem.Parent, itemTypeBlacklist)) - .Select(templateItem => templateItem.Id); + .Select(templateItem => templateItem.Id).ToHashSet(); var itemBlacklist = new HashSet(); itemBlacklist.UnionWith(lootSettingsByType.ItemBlacklist); itemBlacklist.UnionWith(_itemFilterService.GetItemRewardBlacklist()); @@ -185,7 +185,7 @@ public class AirdropService( ArmorPresetCount = lootSettingsByType.ArmorPresetCount, ItemCount = lootSettingsByType.ItemCount, WeaponCrateCount = lootSettingsByType.WeaponCrateCount, - ItemBlacklist = itemBlacklist.ToList(), + ItemBlacklist = itemBlacklist, ItemTypeWhitelist = lootSettingsByType.ItemTypeWhitelist, ItemLimits = lootSettingsByType.ItemLimits, ItemStackLimits = lootSettingsByType.ItemStackLimits, diff --git a/Libraries/Core/Services/BotEquipmentFilterService.cs b/Libraries/Core/Services/BotEquipmentFilterService.cs index 89754d19..5f8abccc 100644 --- a/Libraries/Core/Services/BotEquipmentFilterService.cs +++ b/Libraries/Core/Services/BotEquipmentFilterService.cs @@ -322,7 +322,7 @@ public class BotEquipmentFilterService var botAmmo = baseBotNode.BotInventory.Ammo[ammoCaliberKvP.Key]; // Skip cartridge slot if blacklist doesn't exist / is empty - blacklist.Cartridge.TryGetValue(ammoCaliberKvP.Key, out List cartridgeCaliberBlacklist); + blacklist.Cartridge.TryGetValue(ammoCaliberKvP.Key, out var cartridgeCaliberBlacklist); if (cartridgeCaliberBlacklist is null || cartridgeCaliberBlacklist.Count == 0) { continue; diff --git a/Libraries/Core/Services/BotLootCacheService.cs b/Libraries/Core/Services/BotLootCacheService.cs index 03699ab2..3469f029 100644 --- a/Libraries/Core/Services/BotLootCacheService.cs +++ b/Libraries/Core/Services/BotLootCacheService.cs @@ -468,23 +468,6 @@ public class BotLootCacheService( } } - /// - /// Add unique items into combined pool - /// - /// Pool of items to add to - /// items to add to combined pool if unique - protected void AddUniqueItemsToPool(List poolToAddTo, List itemsToAdd) - { - if (poolToAddTo.Count() == 0) - { - poolToAddTo.AddRange(itemsToAdd); - return; - } - - poolToAddTo.Concat(itemsToAdd); - poolToAddTo = poolToAddTo.Distinct().ToList(); - } - protected void AddItemsToPool(Dictionary poolToAddTo, Dictionary poolOfItemsToAdd) { foreach (var tpl in poolOfItemsToAdd) diff --git a/Libraries/Core/Services/BotNameService.cs b/Libraries/Core/Services/BotNameService.cs index 61e08206..22b9eb25 100644 --- a/Libraries/Core/Services/BotNameService.cs +++ b/Libraries/Core/Services/BotNameService.cs @@ -44,7 +44,7 @@ public class BotNameService( BotType botJsonTemplate, BotGenerationDetails botGenerationDetails, string botRole, - List? uniqueRoles = null) + HashSet? uniqueRoles = null) { var isPmc = botGenerationDetails.IsPmc; diff --git a/Libraries/Core/Services/FenceService.cs b/Libraries/Core/Services/FenceService.cs index f8c2b6cb..0c05cc17 100644 --- a/Libraries/Core/Services/FenceService.cs +++ b/Libraries/Core/Services/FenceService.cs @@ -1376,7 +1376,7 @@ public class FenceService( protected void RemoveRandomModsOfItem(List itemAndMods) { // Items to be removed from inventory - var toDelete = new List(); + var toDelete = new HashSet(); // Find mods to remove from item that could've been scavenged by other players in-raid foreach (var itemMod in itemAndMods) @@ -1391,7 +1391,7 @@ public class FenceService( } // Remove item and its sub-items to prevent orphans - toDelete.AddRange(itemHelper.FindAndReturnChildrenByItems(itemAndMods, itemMod.Id)); + toDelete.UnionWith(itemHelper.FindAndReturnChildrenByItems(itemAndMods, itemMod.Id)); } } @@ -1411,7 +1411,7 @@ public class FenceService( * @param itemsBeingDeleted Current list of items on weapon being deleted * @returns True if item will be removed */ - protected bool PresetModItemWillBeRemoved(Item weaponMod, List itemsBeingDeleted) + protected bool PresetModItemWillBeRemoved(Item weaponMod, HashSet itemsBeingDeleted) { var slotIdsThatCanFail = traderConfig.Fence.PresetSlotsToRemoveChancePercent; if (!slotIdsThatCanFail.TryGetValue(weaponMod.SlotId, out var removalChance) || removalChance == 0.0) diff --git a/Libraries/Core/Services/ItemFilterService.cs b/Libraries/Core/Services/ItemFilterService.cs index 2921415d..3a3067be 100644 --- a/Libraries/Core/Services/ItemFilterService.cs +++ b/Libraries/Core/Services/ItemFilterService.cs @@ -27,10 +27,7 @@ public class ItemFilterService( { if (_itemBlacklistCache.Count == 0) { - foreach (var item in _itemConfig.Blacklist) - { - _itemBlacklistCache.Add(item); - } + _itemBlacklistCache.UnionWith(_itemConfig.Blacklist); } return _itemBlacklistCache.Contains(tpl); @@ -50,36 +47,36 @@ public class ItemFilterService( * Get an array of items that should never be given as a reward to player * @returns string array of item tpls */ - public List GetItemRewardBlacklist() + public HashSet GetItemRewardBlacklist() { - return _cloner.Clone(_itemConfig.RewardItemBlacklist).ToList(); + return _cloner.Clone(_itemConfig.RewardItemBlacklist); } /** * Get an array of item types that should never be given as a reward to player * @returns string array of item base ids */ - public List GetItemRewardBaseTypeBlacklist() + public HashSet GetItemRewardBaseTypeBlacklist() { - return _cloner.Clone(_itemConfig.RewardItemTypeBlacklist).ToList(); + return _cloner.Clone(_itemConfig.RewardItemTypeBlacklist); } /** * Return every template id blacklisted in config/item.json * @returns string array of blacklisted template ids */ - public List GetBlacklistedItems() + public HashSet GetBlacklistedItems() { - return _cloner.Clone(_itemConfig.Blacklist).ToList(); + return _cloner.Clone(_itemConfig.Blacklist); } /** * Return every template id blacklisted in config/item.json/lootableItemBlacklist * @returns string array of blacklisted template ids */ - public List GetBlacklistedLootableItems() + public HashSet GetBlacklistedLootableItems() { - return _cloner.Clone(_itemConfig.LootableItemBlacklist).ToList(); + return _cloner.Clone(_itemConfig.LootableItemBlacklist); } /** @@ -96,9 +93,9 @@ public class ItemFilterService( * Return boss items in config/item.json * @returns string array of boss item template ids */ - public List GetBossItems() + public HashSet GetBossItems() { - return _cloner.Clone(_itemConfig.BossItems).ToList(); + return _cloner.Clone(_itemConfig.BossItems).ToHashSet(); } /** diff --git a/Libraries/Core/Services/LocationLifecycleService.cs b/Libraries/Core/Services/LocationLifecycleService.cs index b38523f8..fb7f1ad0 100644 --- a/Libraries/Core/Services/LocationLifecycleService.cs +++ b/Libraries/Core/Services/LocationLifecycleService.cs @@ -221,7 +221,7 @@ public class LocationLifecycleService // Find only scav extracts and overwrite existing exits with them var scavExtracts = mapExtracts.Where(extract => extract.Side.ToLower() == "scav").ToList(); - if (scavExtracts.Count() > 0) + if (scavExtracts.Count > 0) // Scav extracts found, use them { locationData.Exits.AddRange(scavExtracts); @@ -342,12 +342,6 @@ public class LocationLifecycleService return locationBaseClone; } - // If new spawn system is enabled, clear the spawn waves to prevent x2 spawns - if (locationBaseClone.NewSpawn is true) - { - locationBaseClone.Waves = []; - } - // Only requested base data, not loot if (!generateLoot) { diff --git a/Libraries/Core/Services/MailSendService.cs b/Libraries/Core/Services/MailSendService.cs index e9d9118a..b87640da 100644 --- a/Libraries/Core/Services/MailSendService.cs +++ b/Libraries/Core/Services/MailSendService.cs @@ -28,8 +28,8 @@ public class MailSendService( ) { private const string _systemSenderId = "59e7125688a45068a6249071"; - protected List _messageTypes = [MessageType.NPC_TRADER, MessageType.FLEAMARKET_MESSAGE]; - protected List _slotNames = ["hideout", "main"]; + protected HashSet _messageTypes = [MessageType.NPC_TRADER, MessageType.FLEAMARKET_MESSAGE]; + protected HashSet _slotNames = ["hideout", "main"]; /** * Send a message from an NPC (e.g. prapor) to the player with or without items using direct message text, do not look up any locale diff --git a/Libraries/Core/Services/PmcChatResponseService.cs b/Libraries/Core/Services/PmcChatResponseService.cs index fa3b01c0..f12396f3 100644 --- a/Libraries/Core/Services/PmcChatResponseService.cs +++ b/Libraries/Core/Services/PmcChatResponseService.cs @@ -91,7 +91,7 @@ public class PmcChatResponseService( } // If killer wasn't a PMC, skip - var pmcTypes = new List + var pmcTypes = new HashSet { "pmcUSEC", "pmcBEAR" diff --git a/Libraries/Core/Services/PostDbLoadService.cs b/Libraries/Core/Services/PostDbLoadService.cs index dbd5fd2c..06a22277 100644 --- a/Libraries/Core/Services/PostDbLoadService.cs +++ b/Libraries/Core/Services/PostDbLoadService.cs @@ -126,7 +126,7 @@ public class PostDbLoadService( private void RemoveNewBeginningRequirementFromPrestige() { var prestigeDb = _databaseService.GetTemplates().Prestige; - var newBeginningQuestId = new List + var newBeginningQuestId = new HashSet { "6761f28a022f60bb320f3e95", "6761ff17cdc36bd66102e9d0" diff --git a/Libraries/Core/Services/RagfairLinkedItemService.cs b/Libraries/Core/Services/RagfairLinkedItemService.cs index 13877dd6..d51e30f3 100644 --- a/Libraries/Core/Services/RagfairLinkedItemService.cs +++ b/Libraries/Core/Services/RagfairLinkedItemService.cs @@ -103,7 +103,7 @@ public class RagfairLinkedItemService( if (cylinderMod != null) { // Get the first cylinder filter tpl - var cylinderTpl = cylinderMod.Props?.Filters?[0].Filter?[0]; + var cylinderTpl = cylinderMod.Props?.Filters?[0].Filter?.FirstOrDefault(); if (!string.IsNullOrEmpty(cylinderTpl)) { // Get db data for cylinder tpl, add found slots info (camora_xxx) to linked items on revolver weapon diff --git a/Libraries/Core/Services/RepairService.cs b/Libraries/Core/Services/RepairService.cs index 1bc5a7b5..f9191348 100644 --- a/Libraries/Core/Services/RepairService.cs +++ b/Libraries/Core/Services/RepairService.cs @@ -594,7 +594,7 @@ public class RepairService( // Skill < level 10 + repairing armor if ( - new List + new HashSet { SkillTypes.LightVests, SkillTypes.HeavyVests @@ -606,7 +606,7 @@ public class RepairService( } var skillSettings = globals.Configuration.SkillsSettings.GetAllPropsAsDict(); - BuffSettings buffSettings = null; + BuffSettings? buffSettings = null; switch (itemSkillType) { case SkillTypes.LightVests: diff --git a/Libraries/Core/Services/SeasonalEventService.cs b/Libraries/Core/Services/SeasonalEventService.cs index 14828e08..94738480 100644 --- a/Libraries/Core/Services/SeasonalEventService.cs +++ b/Libraries/Core/Services/SeasonalEventService.cs @@ -26,7 +26,7 @@ public class SeasonalEventService( { private bool _christmasEventActive; - protected IReadOnlyList _christmasEventItems = + protected HashSet _christmasEventItems = [ ItemTpl.ARMOR_6B13_M_ASSAULT_ARMOR_CHRISTMAS_EDITION, ItemTpl.BACKPACK_SANTAS_BAG, @@ -57,7 +57,7 @@ public class SeasonalEventService( private List _currentlyActiveEvents = []; private bool _halloweenEventActive; - protected IReadOnlyList _halloweenEventItems = + protected HashSet _halloweenEventItems = [ ItemTpl.HEADWEAR_JACKOLANTERN_TACTICAL_PUMPKIN_HELMET, ItemTpl.FACECOVER_FACELESS_MASK, @@ -82,7 +82,7 @@ public class SeasonalEventService( /// Get an array of christmas items found in bots inventories as loot /// /// array - public IEnumerable GetChristmasEventItems() + public HashSet GetChristmasEventItems() { return _christmasEventItems; } @@ -91,7 +91,7 @@ public class SeasonalEventService( /// Get an array of halloween items found in bots inventories as loot /// /// array - public IEnumerable GetHalloweenEventItems() + public HashSet GetHalloweenEventItems() { return _halloweenEventItems; } @@ -131,17 +131,17 @@ public class SeasonalEventService( /// or, if halloween and christmas are inactive, return both sets of items /// /// array of tpl strings - public List GetInactiveSeasonalEventItems() + public HashSet GetInactiveSeasonalEventItems() { - var items = new List(); + var items = new HashSet(); if (!ChristmasEventEnabled()) { - items.AddRange(_christmasEventItems); + items.UnionWith(_christmasEventItems); } if (!HalloweenEventEnabled()) { - items.AddRange(_halloweenEventItems); + items.UnionWith(_halloweenEventItems); } return items; @@ -350,8 +350,8 @@ public class SeasonalEventService( public void RemoveChristmasItemsFromBotInventory(BotTypeInventory botInventory, string botRole) { var christmasItems = GetChristmasEventItems(); - List equipmentSlotsToFilter = [EquipmentSlots.FaceCover, EquipmentSlots.Headwear, EquipmentSlots.Backpack, EquipmentSlots.TacticalVest]; - List lootContainersToFilter = ["Backpack", "Pockets", "TacticalVest"]; + HashSet equipmentSlotsToFilter = [EquipmentSlots.FaceCover, EquipmentSlots.Headwear, EquipmentSlots.Backpack, EquipmentSlots.TacticalVest]; + HashSet lootContainersToFilter = ["Backpack", "Pockets", "TacticalVest"]; // Remove christmas related equipment foreach (var equipmentSlotKey in equipmentSlotsToFilter) @@ -731,9 +731,9 @@ public class SeasonalEventService( /// /// Dict of locations with their infection percentage /// List of location ids - protected List GetLocationsWithZombies(Dictionary locationInfections) + protected HashSet GetLocationsWithZombies(Dictionary locationInfections) { - var result = new List(); + var result = new HashSet(); // Get only the locations with an infection above 0 var infectionKeys = locationInfections.Where( @@ -743,7 +743,7 @@ public class SeasonalEventService( // Convert the infected location id into its generic location id foreach (var location in infectionKeys) { - result.AddRange(GetLocationFromInfectedLocation(location.Key)); + result.UnionWith(GetLocationFromInfectedLocation(location.Key)); } return result; @@ -794,7 +794,7 @@ public class SeasonalEventService( /// /// Seasonal event, e.g. HALLOWEEN/CHRISTMAS /// OPTIONAL - Maps to add bosses to - protected void AddEventBossesToMaps(string eventType, List mapIdWhitelist = null) + protected void AddEventBossesToMaps(string eventType, HashSet? mapIdWhitelist = null) { if (!_seasonalEventConfig.EventBossSpawns.TryGetValue(eventType.ToLower(), out var botsToAddPerMap)) { @@ -992,7 +992,7 @@ public class SeasonalEventService( protected void EnableDancingTree() { var maps = _databaseService.GetLocations(); - List mapsToCheck = ["hideout", "base", "privatearea"]; + HashSet mapsToCheck = ["hideout", "base", "privatearea"]; foreach (var mapKvP in maps.GetDictionary()) { // Skip maps that have no tree diff --git a/Tools/ItemTplGenerator/ItemTplGenerator.cs b/Tools/ItemTplGenerator/ItemTplGenerator.cs index 20c3fec5..8d8dccdd 100644 --- a/Tools/ItemTplGenerator/ItemTplGenerator.cs +++ b/Tools/ItemTplGenerator/ItemTplGenerator.cs @@ -410,14 +410,14 @@ public class ItemTplGenerator( private string GetAmmoBoxPrefix(TemplateItem item) { - var ammoItem = item.Properties?.StackSlots?[0]?.Props?.Filters?[0]?.Filter?[0]; + var ammoItem = item.Properties?.StackSlots?[0]?.Props?.Filters?[0]?.Filter?.FirstOrDefault(); return GetAmmoPrefix(items[ammoItem]); } private string GetMagazinePrefix(TemplateItem item) { - var ammoItem = item.Properties?.Cartridges?[0]?.Props?.Filters?[0]?.Filter?[0]; + var ammoItem = item.Properties?.Cartridges?[0]?.Props?.Filters?[0]?.Filter?.FirstOrDefault(); return GetAmmoPrefix(items[ammoItem]); }