Replaced concurrent dictionary with manual locks inside PMCLootGenerator

This commit is contained in:
Chomp
2025-05-28 11:06:16 +01:00
parent cf15dc372b
commit 8a382f5d63
3 changed files with 45 additions and 25 deletions
@@ -1,4 +1,3 @@
using System.Collections.Concurrent;
using SPTarkov.DI.Annotations; using SPTarkov.DI.Annotations;
using SPTarkov.Server.Core.Helpers; using SPTarkov.Server.Core.Helpers;
using SPTarkov.Server.Core.Models.Eft.Common.Tables; using SPTarkov.Server.Core.Models.Eft.Common.Tables;
@@ -23,9 +22,13 @@ public class PMCLootGenerator
private readonly SeasonalEventService _seasonalEventService; private readonly SeasonalEventService _seasonalEventService;
private readonly WeightedRandomHelper _weightedRandomHelper; private readonly WeightedRandomHelper _weightedRandomHelper;
private ConcurrentDictionary<string, double>? _backpackLootPool; private Dictionary<string, double>? _backpackLootPool;
private ConcurrentDictionary<string, double>? _pocketLootPool; private Dictionary<string, double>? _pocketLootPool;
private ConcurrentDictionary<string, double>? _vestLootPool; private Dictionary<string, double>? _vestLootPool;
protected object BackpackLock = new();
protected object PocketLock = new();
protected object VestLock = new();
public PMCLootGenerator( public PMCLootGenerator(
ISptLogger<PMCLootGenerator> logger, ISptLogger<PMCLootGenerator> logger,
@@ -55,12 +58,17 @@ public class PMCLootGenerator
/// </summary> /// </summary>
/// <param name="botRole"></param> /// <param name="botRole"></param>
/// <returns>Dictionary of string and number</returns> /// <returns>Dictionary of string and number</returns>
public ConcurrentDictionary<string, double> GeneratePMCPocketLootPool(string botRole) public Dictionary<string, double> GeneratePMCPocketLootPool(string botRole)
{ {
// Hydrate loot dictionary if empty lock (PocketLock)
if (_pocketLootPool is null)
{ {
_pocketLootPool = new ConcurrentDictionary<string, double>(); // Hydrate loot dictionary if empty
if (_pocketLootPool is not null)
{
return _pocketLootPool;
}
_pocketLootPool = new Dictionary<string, double>();
var items = _databaseService.GetItems(); var items = _databaseService.GetItems();
var pmcPriceOverrides = var pmcPriceOverrides =
_databaseService.GetBots().Types[string.Equals(botRole, "pmcbear", StringComparison.OrdinalIgnoreCase) ? "bear" : "usec"].BotInventory.Items _databaseService.GetBots().Types[string.Equals(botRole, "pmcbear", StringComparison.OrdinalIgnoreCase) ? "bear" : "usec"].BotInventory.Items
@@ -102,9 +110,10 @@ public class PMCLootGenerator
} }
_weightedRandomHelper.ReduceWeightValues(_pocketLootPool); _weightedRandomHelper.ReduceWeightValues(_pocketLootPool);
}
return _pocketLootPool; return _pocketLootPool;
}
} }
protected HashSet<string> GetLootBlacklist() protected HashSet<string> GetLootBlacklist()
@@ -124,12 +133,17 @@ public class PMCLootGenerator
/// </summary> /// </summary>
/// <param name="botRole"></param> /// <param name="botRole"></param>
/// <returns>Dictionary of string and number</returns> /// <returns>Dictionary of string and number</returns>
public ConcurrentDictionary<string, double> GeneratePMCVestLootPool(string botRole) public Dictionary<string, double> GeneratePMCVestLootPool(string botRole)
{ {
// Hydrate loot dictionary if empty lock (VestLock)
if (_vestLootPool is null)
{ {
_vestLootPool = new ConcurrentDictionary<string, double>(); // Hydrate loot dictionary if empty
if (_vestLootPool is not null)
{
return _vestLootPool;
}
_vestLootPool = new Dictionary<string, double>();
var items = _databaseService.GetItems(); var items = _databaseService.GetItems();
var pmcPriceOverrides = var pmcPriceOverrides =
_databaseService.GetBots().Types[string.Equals(botRole, "pmcbear", StringComparison.OrdinalIgnoreCase) ? "bear" : "usec"].BotInventory.Items _databaseService.GetBots().Types[string.Equals(botRole, "pmcbear", StringComparison.OrdinalIgnoreCase) ? "bear" : "usec"].BotInventory.Items
@@ -171,9 +185,9 @@ public class PMCLootGenerator
} }
_weightedRandomHelper.ReduceWeightValues(_vestLootPool); _weightedRandomHelper.ReduceWeightValues(_vestLootPool);
}
return _vestLootPool; return _vestLootPool;
}
} }
/// <summary> /// <summary>
@@ -207,12 +221,17 @@ public class PMCLootGenerator
/// </summary> /// </summary>
/// <param name="botRole"></param> /// <param name="botRole"></param>
/// <returns>Dictionary of string and number</returns> /// <returns>Dictionary of string and number</returns>
public ConcurrentDictionary<string, double> GeneratePMCBackpackLootPool(string botRole) public Dictionary<string, double> GeneratePMCBackpackLootPool(string botRole)
{ {
// Hydrate loot dictionary if empty lock (BackpackLock)
if (_backpackLootPool is null)
{ {
_backpackLootPool = new ConcurrentDictionary<string, double>(); // Hydrate loot dictionary if empty
if (_backpackLootPool is not null)
{
return _backpackLootPool;
}
_backpackLootPool = new Dictionary<string, double>();
var items = _databaseService.GetItems(); var items = _databaseService.GetItems();
var pmcPriceOverrides = var pmcPriceOverrides =
_databaseService.GetBots().Types[string.Equals(botRole, "pmcbear", StringComparison.OrdinalIgnoreCase) ? "bear" : "usec"].BotInventory.Items _databaseService.GetBots().Types[string.Equals(botRole, "pmcbear", StringComparison.OrdinalIgnoreCase) ? "bear" : "usec"].BotInventory.Items
@@ -253,8 +272,8 @@ public class PMCLootGenerator
} }
_weightedRandomHelper.ReduceWeightValues(_backpackLootPool); _weightedRandomHelper.ReduceWeightValues(_backpackLootPool);
}
return _backpackLootPool; return _backpackLootPool;
}
} }
} }
@@ -165,9 +165,9 @@ public class BotLootCacheService(
if (isPmc) if (isPmc)
{ {
// Replace lootPool from bot json with our own generated list for PMCs // Replace lootPool from bot json with our own generated list for PMCs
lootPool.Backpack = _cloner.Clone(_pmcLootGenerator.GeneratePMCBackpackLootPool(botRole)).ToDictionary(); lootPool.Backpack = _cloner.Clone(_pmcLootGenerator.GeneratePMCBackpackLootPool(botRole));
lootPool.Pockets = _cloner.Clone(_pmcLootGenerator.GeneratePMCPocketLootPool(botRole)).ToDictionary(); lootPool.Pockets = _cloner.Clone(_pmcLootGenerator.GeneratePMCPocketLootPool(botRole));
lootPool.TacticalVest = _cloner.Clone(_pmcLootGenerator.GeneratePMCVestLootPool(botRole)).ToDictionary(); lootPool.TacticalVest = _cloner.Clone(_pmcLootGenerator.GeneratePMCVestLootPool(botRole));
} }
// Backpack/Pockets etc // Backpack/Pockets etc
+1
View File
@@ -1,4 +1,5 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation"> <wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=PMC/@EntryIndexedValue">PMC</s:String>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Gifter/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=Gifter/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=ragfair/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=ragfair/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Randomisable/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=Randomisable/@EntryIndexedValue">True</s:Boolean>