Fixed Weapon cache generation running 15+ times on first load due to threading issues
Expanded weapon and equipment cache to include mods - Fixes randomisation slots causing warnings during bot generation Optimised `FilterModsByBlacklist` handling of blacklists
This commit is contained in:
@@ -183,7 +183,7 @@ public class BotEquipmentModGenerator(
|
||||
var plateSlotFilteringOutcome = FilterPlateModsForSlotByLevel(
|
||||
settings,
|
||||
modSlotName.ToLower(),
|
||||
compatibleModsPool[modSlotName],
|
||||
compatibleModsPool.GetValueOrDefault(modSlotName),
|
||||
parentTemplate
|
||||
);
|
||||
switch (plateSlotFilteringOutcome.Result)
|
||||
@@ -210,7 +210,7 @@ public class BotEquipmentModGenerator(
|
||||
}
|
||||
|
||||
// Choose random mod from pool and check its compatibility
|
||||
string modTpl = null;
|
||||
string? modTpl = null;
|
||||
var found = false;
|
||||
var exhaustableModPool = CreateExhaustableArray(modPoolToChooseFrom);
|
||||
while (exhaustableModPool.HasValues())
|
||||
@@ -1837,9 +1837,11 @@ public class BotEquipmentModGenerator(
|
||||
return;
|
||||
}
|
||||
|
||||
var supportedSubModsSet = supportedSubMods.ToHashSet();
|
||||
|
||||
// Filter mods
|
||||
var filteredMods = FilterModsByBlacklist(
|
||||
supportedSubMods.ToHashSet(),
|
||||
supportedSubModsSet,
|
||||
botEquipBlacklist,
|
||||
desiredSlotName
|
||||
);
|
||||
@@ -1855,7 +1857,7 @@ public class BotEquipmentModGenerator(
|
||||
|
||||
modPool.TryAdd(modTemplate.Id, new Dictionary<string, HashSet<string>>());
|
||||
|
||||
modPool[modTemplate.Id][desiredSlotObject.Name] = supportedSubMods.ToHashSet();
|
||||
modPool[modTemplate.Id][desiredSlotObject.Name] = supportedSubModsSet;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1875,51 +1877,62 @@ public class BotEquipmentModGenerator(
|
||||
_botEquipmentModPoolService.GetCompatibleModsForWeaponSlot(parentItemId, modSlot)
|
||||
);
|
||||
|
||||
var filteredMods = FilterModsByBlacklist(modsFromDynamicPool, botEquipBlacklist, modSlot);
|
||||
if (!filteredMods.Any())
|
||||
if (modsFromDynamicPool.Count == 0)
|
||||
{
|
||||
_logger.Warning(
|
||||
_localisationService.GetText(
|
||||
"bot-unable_to_filter_mod_slot_all_blacklisted",
|
||||
modSlot
|
||||
)
|
||||
);
|
||||
|
||||
// Mod pool has no items, don't bother doing any filtering below
|
||||
return modsFromDynamicPool;
|
||||
}
|
||||
|
||||
return filteredMods;
|
||||
var filteredMods = FilterModsByBlacklist(modsFromDynamicPool, botEquipBlacklist, modSlot);
|
||||
if (filteredMods.Any())
|
||||
{
|
||||
// Filtering left at least 1 item, return it
|
||||
return filteredMods;
|
||||
}
|
||||
|
||||
_logger.Warning(
|
||||
_localisationService.GetText(
|
||||
"bot-unable_to_filter_mod_slot_all_blacklisted",
|
||||
modSlot
|
||||
)
|
||||
);
|
||||
|
||||
return modsFromDynamicPool;
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Take a list of tpls and filter out blacklisted values using itemFilterService + botEquipmentBlacklist
|
||||
/// </summary>
|
||||
/// <param name="allowedMods">Base mods to filter</param>
|
||||
/// <param name="botEquipBlacklist">Equipment blacklist</param>
|
||||
/// <param name="modSlot">Slot mods belong to</param>
|
||||
/// <returns>Filtered array of mod tpls</returns>
|
||||
/// <param name="modTplPool">Base mod tpls to filter</param>
|
||||
/// <param name="botEquipBlacklist">Equipment blacklist details for bot level range</param>
|
||||
/// <param name="modSlot">Mod slot mods belong to</param>
|
||||
/// <returns>New set of tpls not in blacklist(s)</returns>
|
||||
public HashSet<string> FilterModsByBlacklist(
|
||||
HashSet<string> allowedMods,
|
||||
HashSet<string> modTplPool,
|
||||
EquipmentFilterDetails? botEquipBlacklist,
|
||||
string modSlot
|
||||
)
|
||||
{
|
||||
// No blacklist, nothing to filter out
|
||||
if (botEquipBlacklist is null)
|
||||
if (!modTplPool.Any())
|
||||
{
|
||||
return allowedMods;
|
||||
// Mod pool has no items, don't bother doing any filtering below
|
||||
return modTplPool;
|
||||
}
|
||||
|
||||
var result = new HashSet<string>();
|
||||
// Get item blacklist and mod equipment blacklist as one Set
|
||||
var blacklist = _itemFilterService.GetBlacklistedItems();
|
||||
if (botEquipBlacklist?.Equipment is not null && botEquipBlacklist.Equipment.TryGetValue(modSlot, out var equipmentBlacklistValues))
|
||||
{
|
||||
blacklist.UnionWith(equipmentBlacklistValues);
|
||||
}
|
||||
|
||||
// Get item blacklist and mod equipment blacklist as one array
|
||||
botEquipBlacklist.Equipment.TryGetValue(modSlot, out var equipmentBlacklistValues);
|
||||
var blacklist = _itemFilterService
|
||||
.GetBlacklistedItems()
|
||||
.Concat(equipmentBlacklistValues ?? []);
|
||||
result = allowedMods.Where(tpl => !blacklist.Contains(tpl)).ToHashSet();
|
||||
var result = _cloner.Clone(modTplPool);
|
||||
|
||||
return result;
|
||||
// Filter out blacklisted tpls
|
||||
result.ExceptWith(blacklist);
|
||||
|
||||
return modTplPool;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1963,7 +1976,7 @@ public class BotEquipmentModGenerator(
|
||||
itemModPool = modPool[cylinderMagTemplate.Id];
|
||||
}
|
||||
|
||||
ExhaustableArray<string> exhaustableModPool = null;
|
||||
ExhaustableArray<string>? exhaustableModPool = null;
|
||||
var modSlot = "cartridges";
|
||||
const string camoraFirstSlot = "camora_000";
|
||||
if (itemModPool.TryGetValue(modSlot, out var value))
|
||||
|
||||
@@ -410,7 +410,7 @@ public class BotInventoryGenerator(
|
||||
/// <param name="templateInventory"></param>
|
||||
/// <param name="isPmc">is bot a PMC</param>
|
||||
/// <returns></returns>
|
||||
protected Dictionary<string, double> GetPocketPoolByGameEdition(
|
||||
protected Dictionary<string, double>? GetPocketPoolByGameEdition(
|
||||
string chosenGameVersion,
|
||||
BotTypeInventory templateInventory,
|
||||
bool isPmc
|
||||
@@ -510,7 +510,7 @@ public class BotInventoryGenerator(
|
||||
var shouldSpawn = _randomUtil.GetChance100(spawnChance ?? 0);
|
||||
if (shouldSpawn && settings.RootEquipmentPool.Any())
|
||||
{
|
||||
TemplateItem pickedItemDb = null;
|
||||
TemplateItem? pickedItemDb = null;
|
||||
var found = false;
|
||||
|
||||
// Limit attempts to find a compatible item as it's expensive to check them all
|
||||
@@ -590,7 +590,7 @@ public class BotInventoryGenerator(
|
||||
|
||||
var botEquipBlacklist = _botEquipmentFilterService.GetBotEquipmentBlacklist(
|
||||
settings.BotData.EquipmentRole,
|
||||
settings.GeneratingPlayerLevel.Value
|
||||
settings.GeneratingPlayerLevel.GetValueOrDefault(1)
|
||||
);
|
||||
|
||||
// Edge case: Filter the armor items mod pool if bot exists in config dict + config has armor slot
|
||||
|
||||
@@ -26,7 +26,13 @@ public class BotEquipmentModPoolService(
|
||||
ConcurrentDictionary<string, HashSet<string>>
|
||||
> GearModPool
|
||||
{
|
||||
get { return _gearModPool ??= GenerateGearPool(); }
|
||||
get
|
||||
{
|
||||
lock (_lockObject)
|
||||
{
|
||||
return _gearModPool ??= GenerateGearPool();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ConcurrentDictionary<
|
||||
@@ -38,7 +44,13 @@ public class BotEquipmentModPoolService(
|
||||
ConcurrentDictionary<string, HashSet<string>>
|
||||
> WeaponModPool
|
||||
{
|
||||
get { return _weaponModPool ??= GenerateWeaponPool(); }
|
||||
get
|
||||
{
|
||||
lock (_lockObject)
|
||||
{
|
||||
return _weaponModPool ??= GenerateWeaponPool();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -85,7 +97,7 @@ public class BotEquipmentModPoolService(
|
||||
// Add base item (weapon/armor) to pool
|
||||
pool.TryAdd(item.Id, new ConcurrentDictionary<string, HashSet<string>>());
|
||||
|
||||
// iterate over each items mod slots e.g. mod_muzzle
|
||||
// Iterate over each items mod slots e.g. mod_muzzle
|
||||
foreach (var slot in item.Properties.Slots)
|
||||
{
|
||||
// Get mods that fit into the current mod slot
|
||||
@@ -108,6 +120,8 @@ public class BotEquipmentModPoolService(
|
||||
|
||||
var subItemDetails = itemHelper.GetItem(itemToAddTpl).Value;
|
||||
var hasSubItemsToAdd = (subItemDetails?.Properties?.Slots?.Count ?? 0) > 0;
|
||||
|
||||
// Item has Slots + pool doesn't have value
|
||||
if (hasSubItemsToAdd && !pool.ContainsKey(subItemDetails.Id))
|
||||
// Recursive call
|
||||
{
|
||||
@@ -237,14 +251,14 @@ public class BotEquipmentModPoolService(
|
||||
ConcurrentDictionary<string, HashSet<string>>
|
||||
> GenerateWeaponPool()
|
||||
{
|
||||
var weapons = databaseService
|
||||
var weaponsAndMods = databaseService
|
||||
.GetItems()
|
||||
.Values.Where(item =>
|
||||
string.Equals(item.Type, "Item", StringComparison.OrdinalIgnoreCase)
|
||||
&& itemHelper.IsOfBaseclass(item.Id, BaseClasses.WEAPON)
|
||||
);
|
||||
&& itemHelper.IsOfBaseclasses(item.Id, [BaseClasses.WEAPON, BaseClasses.MOD]));
|
||||
logger.Warning("generating weapon pool");
|
||||
|
||||
return GeneratePool(weapons, "weapon");
|
||||
return GeneratePool(weaponsAndMods, "weapon");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -255,7 +269,7 @@ public class BotEquipmentModPoolService(
|
||||
ConcurrentDictionary<string, HashSet<string>>
|
||||
> GenerateGearPool()
|
||||
{
|
||||
var gear = databaseService
|
||||
var gearAndMods = databaseService
|
||||
.GetItems()
|
||||
.Values.Where(item =>
|
||||
string.Equals(item.Type, "Item", StringComparison.OrdinalIgnoreCase)
|
||||
@@ -266,10 +280,11 @@ public class BotEquipmentModPoolService(
|
||||
BaseClasses.VEST,
|
||||
BaseClasses.ARMOR,
|
||||
BaseClasses.HEADWEAR,
|
||||
BaseClasses.MOD
|
||||
]
|
||||
)
|
||||
);
|
||||
|
||||
return GeneratePool(gear, "gear");
|
||||
return GeneratePool(gearAndMods, "gear");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user