From 63db5ed6ffc30dd98f02710c817b1801553fdf6c Mon Sep 17 00:00:00 2001 From: Chomp Date: Wed, 11 Jun 2025 12:30:20 +0100 Subject: [PATCH] Fixed PMC loot pool generation not utilising the pmc pool blacklists #390 Comment improvements Renamed helped method for readability --- .../Generators/PMCLootGenerator.cs | 56 +++++++++++-------- 1 file changed, 34 insertions(+), 22 deletions(-) diff --git a/Libraries/SPTarkov.Server.Core/Generators/PMCLootGenerator.cs b/Libraries/SPTarkov.Server.Core/Generators/PMCLootGenerator.cs index 1d6a05a9..d77057ff 100644 --- a/Libraries/SPTarkov.Server.Core/Generators/PMCLootGenerator.cs +++ b/Libraries/SPTarkov.Server.Core/Generators/PMCLootGenerator.cs @@ -56,9 +56,9 @@ public class PMCLootGenerator /// /// Create a List of loot items a PMC can have in their pockets /// - /// + /// Role of PMC having loot generated (bear or usec) /// Dictionary of string and number - public Dictionary GeneratePMCPocketLootPool(string botRole) + public Dictionary GeneratePMCPocketLootPool(string pmcRole) { lock (PocketLock) { @@ -71,12 +71,12 @@ public class PMCLootGenerator _pocketLootPool = new Dictionary(); var items = _databaseService.GetItems(); var pmcPriceOverrides = - _databaseService.GetBots().Types[string.Equals(botRole, "pmcbear", StringComparison.OrdinalIgnoreCase) ? "bear" : "usec"].BotInventory.Items + _databaseService.GetBots().Types[string.Equals(pmcRole, "pmcbear", StringComparison.OrdinalIgnoreCase) ? "bear" : "usec"].BotInventory.Items .Pockets; var allowedItemTypeWhitelist = _pmcConfig.PocketLoot.Whitelist; - var blacklist = GetLootBlacklist(); + var blacklist = GetContainerLootBlacklist(); var itemsToAdd = items.Where(item => allowedItemTypeWhitelist.Contains(item.Value.Parent) && @@ -116,7 +116,11 @@ public class PMCLootGenerator } } - protected HashSet GetLootBlacklist() + /// + /// Get a generic all-container blacklist + /// + /// Hashset of blacklisted items + protected HashSet GetContainerLootBlacklist() { var blacklist = new HashSet(); blacklist.UnionWith(_pmcConfig.PocketLoot.Blacklist); @@ -129,11 +133,11 @@ public class PMCLootGenerator } /// - /// Create a List of loot items a PMC can have in their vests + /// Create a dictionary of loot items a PMC can have in their vests with a corresponding weight of being picked to spawn /// - /// - /// Dictionary of string and number - public Dictionary GeneratePMCVestLootPool(string botRole) + /// Role of PMC having loot generated (bear or usec) + /// Dictionary item template ids and a weighted chance of being picked + public Dictionary GeneratePMCVestLootPool(string pmcRole) { lock (VestLock) { @@ -143,47 +147,54 @@ public class PMCLootGenerator return _vestLootPool; } + // Create dictionary to hold vest loot _vestLootPool = new Dictionary(); + + // Get all items from database var items = _databaseService.GetItems(); + + // Grab price overrides if they exist for the pmcRole passed in var pmcPriceOverrides = - _databaseService.GetBots().Types[string.Equals(botRole, "pmcbear", StringComparison.OrdinalIgnoreCase) ? "bear" : "usec"].BotInventory.Items + _databaseService.GetBots().Types[string.Equals(pmcRole, "pmcbear", StringComparison.OrdinalIgnoreCase) ? "bear" : "usec"].BotInventory.Items .TacticalVest; - var allowedItemTypeWhitelist = _pmcConfig.VestLoot.Whitelist; + var blacklist = GetContainerLootBlacklist(); + blacklist.UnionWith(_pmcConfig.VestLoot.Blacklist); // Add vest-specific blacklist - var blacklist = GetLootBlacklist(); - - var itemsToAdd = items.Where(item => - allowedItemTypeWhitelist.Contains(item.Value.Parent) && - _itemHelper.IsValidItem(item.Value.Id) && + var itemTplsToAdd = items.Where(item => + _pmcConfig.VestLoot.Whitelist.Contains(item.Value.Parent) && // A whitelist of item types the PMC is allowed to have !blacklist.Contains(item.Value.Id) && !blacklist.Contains(item.Value.Parent) && + _itemHelper.IsValidItem(item.Value.Id) && ItemFitsInto2By2Slot(item.Value) ).Select(x => x.Key); - foreach (var tpl in itemsToAdd) - // If pmc has price override, use that. Otherwise, use flea price + foreach (var tpl in itemTplsToAdd) + // If PMC has price override, use that. Otherwise, use flea price { if (pmcPriceOverrides.TryGetValue(tpl, out var overridePrice)) { + // There's a price override for this item, use override instead of default price _vestLootPool.TryAdd(tpl, overridePrice); } else { - // Set price of item as its weight + // Store items price so we can turn it into a weighting later var price = _ragfairPriceService.GetDynamicItemPrice(tpl, Money.ROUBLES); _vestLootPool[tpl] = price ?? 0; } } + // Find the highest priced item added to vest pool var highestPrice = _vestLootPool.Max(price => price.Value); foreach (var (key, _) in _vestLootPool) - // Invert price so cheapest has a larger weight + // Invert price so cheapest has a larger weight, giving us a weighting of low-priced items being more common // Times by highest price so most expensive item has weight of 1 { _vestLootPool[key] = Math.Round(1 / _vestLootPool[key] * highestPrice); } + // Find the greatest common divisor between all the prices and apply it to reduce the values for better readability of weights _weightedRandomHelper.ReduceWeightValues(_vestLootPool); return _vestLootPool; @@ -219,7 +230,7 @@ public class PMCLootGenerator /// /// Create a List of loot items a PMC can have in their backpack /// - /// + /// Role of PMC having loot generated (bear or usec) /// Dictionary of string and number public Dictionary GeneratePMCBackpackLootPool(string botRole) { @@ -239,7 +250,8 @@ public class PMCLootGenerator var allowedItemTypeWhitelist = _pmcConfig.BackpackLoot.Whitelist; - var blacklist = GetLootBlacklist(); + var blacklist = GetContainerLootBlacklist(); + blacklist.UnionWith(_pmcConfig.BackpackLoot.Blacklist); // Add backpack-specific blacklist var itemsToAdd = items.Where(item => allowedItemTypeWhitelist.Contains(item.Value.Parent) &&