change vars to MongoId, remove underscore from injections, fix bug introduced from last PR

This commit is contained in:
Cj
2025-07-06 16:40:08 -04:00
parent 3817d6cca4
commit 090d7b6494
23 changed files with 499 additions and 496 deletions
@@ -237,7 +237,7 @@
},
"Pickup": {
"_id": "67d03016c971a7faef94af07",
"traderId": "{traderId}",
"traderId": "54cb57776803fa99248b456e",
"location": "any",
"image": "/files/quest/icon/62bd61b1b818ff064405b827.jpg",
"type": "PickUp",
@@ -44,7 +44,7 @@ namespace SPTarkov.Server.Core.Extensions
/// </summary>
/// <param name="weaponTemplate">Weapon to get default magazine for</param>
/// <returns>Tpl of magazine</returns>
public static string? GetWeaponsDefaultMagazineTpl(this TemplateItem weaponTemplate)
public static MongoId? GetWeaponsDefaultMagazineTpl(this TemplateItem weaponTemplate)
{
return weaponTemplate.Properties.DefMagType;
}
@@ -21,22 +21,22 @@ namespace SPTarkov.Server.Core.Generators;
[Injectable]
public class BotEquipmentModGenerator(
ISptLogger<BotEquipmentModGenerator> _logger,
RandomUtil _randomUtil,
ItemHelper _itemHelper,
BotEquipmentFilterService _botEquipmentFilterService,
ItemFilterService _itemFilterService,
ProfileHelper _profileHelper,
BotWeaponModLimitService _botWeaponModLimitService,
BotHelper _botHelper,
BotGeneratorHelper _botGeneratorHelper,
BotWeaponGeneratorHelper _botWeaponGeneratorHelper,
WeightedRandomHelper _weightedRandomHelper,
PresetHelper _presetHelper,
ServerLocalisationService _serverLocalisationService,
BotEquipmentModPoolService _botEquipmentModPoolService,
ConfigServer _configServer,
ICloner _cloner
ISptLogger<BotEquipmentModGenerator> logger,
RandomUtil randomUtil,
ItemHelper itemHelper,
BotEquipmentFilterService botEquipmentFilterService,
ItemFilterService itemFilterService,
ProfileHelper profileHelper,
BotWeaponModLimitService botWeaponModLimitService,
BotHelper botHelper,
BotGeneratorHelper botGeneratorHelper,
BotWeaponGeneratorHelper botWeaponGeneratorHelper,
WeightedRandomHelper weightedRandomHelper,
PresetHelper presetHelper,
ServerLocalisationService serverLocalisationService,
BotEquipmentModPoolService botEquipmentModPoolService,
ConfigServer configServer,
ICloner cloner
)
{
protected static readonly FrozenSet<string> _modSightIds =
@@ -95,7 +95,7 @@ public class BotEquipmentModGenerator(
const string modScopeKey = "mod_scope";
const string modScope000Key = "mod_scope_000";
protected readonly BotConfig _botConfig = _configServer.GetConfig<BotConfig>();
protected readonly BotConfig _botConfig = configServer.GetConfig<BotConfig>();
/// <summary>
/// Check mods are compatible and add to array
@@ -121,7 +121,7 @@ public class BotEquipmentModGenerator(
// Get mod pool for the desired item
if (!settings.ModPool.TryGetValue(parentTemplate.Id, out var compatibleModsPool))
{
_logger.Warning(
logger.Warning(
$"bot: {settings.BotData.Role} lacks a mod slot pool for item: {parentTemplate.Id} {parentTemplate.Name}"
);
}
@@ -133,8 +133,8 @@ public class BotEquipmentModGenerator(
var itemSlotTemplate = GetModItemSlotFromDbTemplate(modSlotName, parentTemplate);
if (itemSlotTemplate is null)
{
_logger.Error(
_serverLocalisationService.GetText(
logger.Error(
serverLocalisationService.GetText(
"bot-mod_slot_missing_from_item",
new
{
@@ -186,7 +186,7 @@ public class BotEquipmentModGenerator(
// Slot can hold armor plates + we are filtering possible items by bot level, handle
if (
settings.BotEquipmentConfig.FilterPlatesByLevel.GetValueOrDefault(false)
&& _itemHelper.IsRemovablePlateSlot(modSlotName.ToLowerInvariant())
&& itemHelper.IsRemovablePlateSlot(modSlotName.ToLowerInvariant())
)
{
var plateSlotFilteringOutcome = FilterPlateModsForSlotByLevel(
@@ -197,17 +197,18 @@ public class BotEquipmentModGenerator(
);
switch (plateSlotFilteringOutcome.Result)
{
case Result.UNKNOWN_FAILURE or Result.NO_DEFAULT_FILTER:
if (_logger.IsLogEnabled(LogLevel.Debug))
case Result.UNKNOWN_FAILURE
or Result.NO_DEFAULT_FILTER:
if (logger.IsLogEnabled(LogLevel.Debug))
{
_logger.Debug(
logger.Debug(
$"Plate slot: {modSlotName} selection for armor: {parentTemplate.Id} failed: {plateSlotFilteringOutcome.Result}, skipping"
);
}
continue;
case Result.LACKS_PLATE_WEIGHTS:
_logger.Warning(
logger.Warning(
$"Plate slot: {modSlotName} lacks weights for armor: {parentTemplate.Id}, unable to adjust plate choice, using existing data"
);
break;
@@ -226,7 +227,7 @@ public class BotEquipmentModGenerator(
modTpl = exhaustableModPool.GetRandomValue();
if (
modTpl is not null
&& !_botGeneratorHelper
&& !botGeneratorHelper
.IsItemIncompatibleWithCurrentItems(equipment, modTpl.Value, modSlotName)
.Incompatible.GetValueOrDefault(false)
)
@@ -240,7 +241,7 @@ public class BotEquipmentModGenerator(
if (!found && itemSlotTemplate.Required.GetValueOrDefault(false))
{
modTpl = GetRandomModTplFromItemDb(
modTpl,
modTpl.Value,
itemSlotTemplate,
modSlotName,
equipment
@@ -255,7 +256,7 @@ public class BotEquipmentModGenerator(
}
// Get chosen mods db template and check it fits into slot
var modTemplate = _itemHelper.GetItem(modTpl.Value);
var modTemplate = itemHelper.GetItem(modTpl.Value);
if (
!IsModValidForSlot(
modTemplate,
@@ -274,7 +275,7 @@ public class BotEquipmentModGenerator(
equipment.Add(
CreateModItem(
modId,
modTpl,
modTpl.Value,
parentId,
modSlotName,
modTemplate.Value,
@@ -283,7 +284,7 @@ public class BotEquipmentModGenerator(
);
// Does item being added exist in mod pool - has its own mod pool
if (settings.ModPool.ContainsKey(modTpl))
if (settings.ModPool.ContainsKey(modTpl.Value))
// Call self again with mod being added as item to add child mods to
{
GenerateModsForEquipment(
@@ -322,7 +323,7 @@ public class BotEquipmentModGenerator(
};
// Not pmc or not a plate slot, return original mod pool array
if (!_itemHelper.IsRemovablePlateSlot(modSlot))
if (!itemHelper.IsRemovablePlateSlot(modSlot))
{
result.Result = Result.NOT_PLATE_HOLDING_SLOT;
result.PlateModTemplates = existingPlateTplPool;
@@ -357,11 +358,11 @@ public class BotEquipmentModGenerator(
}
// Choose a plate level based on weighting
var chosenArmorPlateLevelString = _weightedRandomHelper.GetWeightedValue(plateWeights);
var chosenArmorPlateLevelString = weightedRandomHelper.GetWeightedValue(plateWeights);
// Convert the array of ids into database items
var platesFromDb = existingPlateTplPool.Select(plateTpl =>
_itemHelper.GetItem(plateTpl).Value
itemHelper.GetItem(plateTpl).Value
);
// Filter plates to the chosen level based on its armorClass property
@@ -411,9 +412,9 @@ public class BotEquipmentModGenerator(
// No valid plate class found in 3 tries, attempt default plates
if (findCompatiblePlateAttempts >= maxAttempts)
{
if (_logger.IsLogEnabled(LogLevel.Debug))
if (logger.IsLogEnabled(LogLevel.Debug))
{
_logger.Debug(
logger.Debug(
$"Plate filter too restrictive for armor: {armorItem.Name} {armorItem.Id}, unable to find plates of level: {chosenArmorPlateLevelString}, using items default plate"
);
}
@@ -435,7 +436,7 @@ public class BotEquipmentModGenerator(
if (defaultPresetPlateSlot is not null)
{
// Found a plate, exit
var plateItem = _itemHelper.GetItem(defaultPresetPlateSlot.Template);
var plateItem = itemHelper.GetItem(defaultPresetPlateSlot.Template);
platesOfDesiredLevel = [plateItem.Value];
break;
@@ -492,9 +493,9 @@ public class BotEquipmentModGenerator(
/// <param name="armorItemTpl"></param>
/// <param name="modSlot"></param>
/// <returns>Armor IItem</returns>
protected Item? GetDefaultPresetArmorSlot(string armorItemTpl, string modSlot)
protected Item? GetDefaultPresetArmorSlot(MongoId armorItemTpl, string modSlot)
{
var defaultPreset = _presetHelper.GetDefaultPreset(armorItemTpl);
var defaultPreset = presetHelper.GetDefaultPreset(armorItemTpl);
return defaultPreset?.Items?.FirstOrDefault(item =>
string.Equals(item.SlotId, modSlot, StringComparison.OrdinalIgnoreCase)
@@ -507,12 +508,12 @@ public class BotEquipmentModGenerator(
/// <param name="sessionId">Session id</param>
/// <param name="request">Data used to generate the weapon</param>
/// <returns>Weapon + mods array</returns>
public List<Item> GenerateModsForWeapon(string sessionId, GenerateWeaponRequest request)
public List<Item> GenerateModsForWeapon(MongoId sessionId, GenerateWeaponRequest request)
{
if (ItemLacksSlotsCartridgesAndChambers(request.ParentTemplate))
{
_logger.Error(
_serverLocalisationService.GetText(
logger.Error(
serverLocalisationService.GetText(
"bot-unable_to_add_mods_to_weapon_missing_ammo_slot",
new
{
@@ -526,20 +527,20 @@ public class BotEquipmentModGenerator(
return request.Weapon;
}
var pmcProfile = _profileHelper.GetPmcProfile(sessionId);
var pmcProfile = profileHelper.GetPmcProfile(sessionId);
// Get pool of mods that fit weapon
request.ModPool.TryGetValue(request.ParentTemplate.Id, out var compatibleModsPool);
_botConfig.Equipment.TryGetValue(request.BotData.EquipmentRole, out var botEquipConfig);
var botEquipBlacklist = _botEquipmentFilterService.GetBotEquipmentBlacklist(
var botEquipBlacklist = botEquipmentFilterService.GetBotEquipmentBlacklist(
request.BotData.EquipmentRole,
pmcProfile?.Info?.Level ?? 0
);
var botWeaponSightWhitelist = _botEquipmentFilterService.GetBotWeaponSightWhitelist(
var botWeaponSightWhitelist = botEquipmentFilterService.GetBotWeaponSightWhitelist(
request.BotData.EquipmentRole
);
var randomisationSettings = _botHelper.GetBotRandomizationDetails(
var randomisationSettings = botHelper.GetBotRandomizationDetails(
request.BotData.Level ?? 0,
botEquipConfig
);
@@ -555,8 +556,8 @@ public class BotEquipmentModGenerator(
var modsParentSlot = GetModItemSlotFromDbTemplate(modSlot, request.ParentTemplate);
if (modsParentSlot is null)
{
_logger.Error(
_serverLocalisationService.GetText(
logger.Error(
serverLocalisationService.GetText(
"bot-weapon_missing_mod_slot",
new
{
@@ -574,7 +575,7 @@ public class BotEquipmentModGenerator(
// If the parent is a UBGL, the patron_in_weapon will be generated later - so skip it for now
if (
modSlot == "patron_in_weapon"
&& _itemHelper.IsOfBaseclass(request.ParentTemplate.Id, BaseClasses.UBGL)
&& itemHelper.IsOfBaseclass(request.ParentTemplate.Id, BaseClasses.UBGL)
)
{
continue;
@@ -634,7 +635,7 @@ public class BotEquipmentModGenerator(
var modToAddTemplate = modToAdd.Value.Value;
// Skip adding mod to weapon if type limit reached
if (
_botWeaponModLimitService.WeaponModHasReachedLimit(
botWeaponModLimitService.WeaponModHasReachedLimit(
request.BotData.EquipmentRole,
modToAddTemplate,
request.ModLimits,
@@ -716,7 +717,7 @@ public class BotEquipmentModGenerator(
}
// Gather stats on mods being added to weapon
if (_itemHelper.IsOfBaseclass(modToAddTemplate.Id, BaseClasses.IRON_SIGHT))
if (itemHelper.IsOfBaseclass(modToAddTemplate.Id, BaseClasses.IRON_SIGHT))
{
if (modSlot == "mod_sight_front")
{
@@ -729,7 +730,7 @@ public class BotEquipmentModGenerator(
}
else if (
!(request.WeaponStats.HasOptic ?? false)
&& _itemHelper.IsOfBaseclass(modToAddTemplate.Id, BaseClasses.SIGHTS)
&& itemHelper.IsOfBaseclass(modToAddTemplate.Id, BaseClasses.SIGHTS)
)
{
request.WeaponStats.HasOptic = true;
@@ -757,8 +758,8 @@ public class BotEquipmentModGenerator(
// However, the recursion doesn't go over the slots of the parent mod but over the modPool which is given by the bot config
// where we decided to keep cartridges instead of camoras. And since a CylinderMagazine only has one cartridge entry and
// this entry is not to be filled, we need a special handling for the CylinderMagazine
var modParentItem = _itemHelper.GetItem(modToAddTemplate.Parent).Value;
if (_botWeaponGeneratorHelper.MagazineIsCylinderRelated(modParentItem.Name))
var modParentItem = itemHelper.GetItem(modToAddTemplate.Parent).Value;
if (botWeaponGeneratorHelper.MagazineIsCylinderRelated(modParentItem.Name))
{
// We don't have child mods, we need to create the camoras for the magazines instead
FillCamora(request.Weapon, request.ModPool, modId, modToAddTemplate);
@@ -775,7 +776,7 @@ public class BotEquipmentModGenerator(
&& modToAddTemplate.Properties.Slots.Any()
)
{
var modFromService = _botEquipmentModPoolService.GetModsForWeaponSlot(
var modFromService = botEquipmentModPoolService.GetModsForWeaponSlot(
modToAddTemplate.Id
);
if (modFromService?.Count > 0)
@@ -789,7 +790,7 @@ public class BotEquipmentModGenerator(
if (!containsModInPool && !isRandomisableSlot)
{
// Check for required mods the item we've added needs to be classified as 'valid'
var modFromService = _botEquipmentModPoolService.GetRequiredModsForWeaponSlot(
var modFromService = botEquipmentModPoolService.GetRequiredModsForWeaponSlot(
modToAddTemplate.Id
);
if (modFromService?.Count > 0)
@@ -884,7 +885,7 @@ public class BotEquipmentModGenerator(
/// <param name="modSlot">e.g. mod_scope, mod_mount</param>
/// <param name="modsParentId">Parent id of mod item</param>
/// <returns>true if it can hold a scope</returns>
public bool ModSlotCanHoldScope(string modSlot, string modsParentId)
public bool ModSlotCanHoldScope(string modSlot, MongoId modsParentId)
{
return _scopeIds.Contains(modSlot.ToLowerInvariant()) && modsParentId == BaseClasses.MOUNT;
}
@@ -903,14 +904,14 @@ public class BotEquipmentModGenerator(
{
if (modSpawnChances is null)
{
_logger.Warning("AdjustSlotSpawnChances() modSpawnChances missing");
logger.Warning("AdjustSlotSpawnChances() modSpawnChances missing");
return;
}
if (modSlotsToAdjust is null)
{
_logger.Warning("AdjustSlotSpawnChances() modSlotsToAdjust missing");
logger.Warning("AdjustSlotSpawnChances() modSlotsToAdjust missing");
return;
}
@@ -949,7 +950,7 @@ public class BotEquipmentModGenerator(
return unsortedSlotKeys;
}
var isMount = _itemHelper.IsOfBaseclass(itemTplWithKeysToSort, BaseClasses.MOUNT);
var isMount = itemHelper.IsOfBaseclass(itemTplWithKeysToSort, BaseClasses.MOUNT);
HashSet<string> sortedKeys = [];
@@ -1086,7 +1087,7 @@ public class BotEquipmentModGenerator(
return ModSpawn.SPAWN;
}
var spawnMod = _randomUtil.RollChance(
var spawnMod = randomUtil.RollChance(
modSpawnChances.GetValueOrDefault(modSlotName.ToLowerInvariant())
);
if (
@@ -1115,12 +1116,12 @@ public class BotEquipmentModGenerator(
var parentSlot = request.ParentTemplate.Properties.Slots?.FirstOrDefault(i =>
i.Name == request.ModSlot
);
var weaponTemplate = _itemHelper.GetItem(request.Weapon[0].Template).Value;
var weaponTemplate = itemHelper.GetItem(request.Weapon[0].Template).Value;
// It's ammo, use predefined ammo parameter
if (GetAmmoContainers().Contains(request.ModSlot) && request.ModSlot != "mod_magazine")
{
return _itemHelper.GetItem(request.AmmoTpl);
return itemHelper.GetItem(request.AmmoTpl);
}
// Ensure there's a pool of mods to pick from
@@ -1128,9 +1129,9 @@ public class BotEquipmentModGenerator(
if ((modPool is null || !modPool.Any()) && !(parentSlot?.Required ?? false))
{
// Nothing in mod pool + item not required
if (_logger.IsLogEnabled(LogLevel.Debug))
if (logger.IsLogEnabled(LogLevel.Debug))
{
_logger.Debug(
logger.Debug(
$"Mod pool for optional slot: {request.ModSlot} on item: {request.ParentTemplate.Name} was empty, skipping mod"
);
}
@@ -1212,9 +1213,9 @@ public class BotEquipmentModGenerator(
&& !parentSlot.Required.GetValueOrDefault(false)
)
{
if (_logger.IsLogEnabled(LogLevel.Debug))
if (logger.IsLogEnabled(LogLevel.Debug))
{
_logger.Debug(
logger.Debug(
$"Unable to find compatible mod of type: {parentSlot.Name}, in slot: {request.ModSlot} reason: {chosenModResult.Reason}"
);
}
@@ -1250,7 +1251,7 @@ public class BotEquipmentModGenerator(
{
if (parentSlot.Required.GetValueOrDefault(false))
{
_logger.Warning(
logger.Warning(
$"Required slot unable to be filled, {request.ModSlot} on {request.ParentTemplate.Name} {request.ParentTemplate.Id} for weapon: {request.Weapon[0].Template}"
);
}
@@ -1258,7 +1259,7 @@ public class BotEquipmentModGenerator(
return null;
}
return _itemHelper.GetItem(chosenModResult.ChosenTemplate);
return itemHelper.GetItem(chosenModResult.ChosenTemplate);
}
/// <summary>
@@ -1279,7 +1280,7 @@ public class BotEquipmentModGenerator(
);
var desiredMagazineTpls = modPool.Where(magTpl =>
{
var magazineDb = _itemHelper.GetItem(magTpl).Value;
var magazineDb = itemHelper.GetItem(magTpl).Value;
return magazineDb.Properties is not null
&& magazineDb.Properties.Cartridges.FirstOrDefault().MaxCount
>= minMagSizeFromSettings;
@@ -1287,7 +1288,7 @@ public class BotEquipmentModGenerator(
if (!desiredMagazineTpls.Any())
{
_logger.Warning(
logger.Warning(
$"Magazine size filter for: {weaponTpl} was too strict, ignoring filter"
);
@@ -1377,7 +1378,7 @@ public class BotEquipmentModGenerator(
while (exhaustableModPool.HasValues())
{
chosenTpl = exhaustableModPool.GetRandomValue();
var pickedItemDetails = _itemHelper.GetItem(chosenTpl);
var pickedItemDetails = itemHelper.GetItem(chosenTpl);
if (!pickedItemDetails.Key)
// Not valid item, try again
{
@@ -1445,7 +1446,7 @@ public class BotEquipmentModGenerator(
public ExhaustableArray<T> CreateExhaustableArray<T>(ICollection<T> itemsToAddToArray)
{
return new ExhaustableArray<T>(itemsToAddToArray, _randomUtil, _cloner);
return new ExhaustableArray<T>(itemsToAddToArray, randomUtil, cloner);
}
/// <summary>
@@ -1516,9 +1517,9 @@ public class BotEquipmentModGenerator(
{
if (request.ItemModPool[request.ModSlot]?.Count > 1)
{
if (_logger.IsLogEnabled(LogLevel.Debug))
if (logger.IsLogEnabled(LogLevel.Debug))
{
_logger.Debug(
logger.Debug(
$"{request.BotData.Role} No default: {request.ModSlot} mod found for: {weaponTemplate.Name}, using existing pool"
);
}
@@ -1553,8 +1554,7 @@ public class BotEquipmentModGenerator(
// Mod isn't in existing pool, only add if it has no children and exists inside parent filter
if (
(parentSlotCompatibleItems?.Contains(matchingModFromPreset.Template) ?? false)
&& _itemHelper.GetItem(matchingModFromPreset.Template).Value.Properties.Slots?.Count
== 0
&& itemHelper.GetItem(matchingModFromPreset.Template).Value.Properties.Slots?.Count == 0
)
{
// Chosen mod has no conflicts + no children + is in parent compat list
@@ -1564,9 +1564,9 @@ public class BotEquipmentModGenerator(
}
// Above chosen mod had conflicts with existing weapon mods
if (_logger.IsLogEnabled(LogLevel.Debug))
if (logger.IsLogEnabled(LogLevel.Debug))
{
_logger.Debug(
logger.Debug(
$"{request.BotData.Role} Chosen default: {request.ModSlot} mod found for: {weaponTemplate.Name} weapon conflicts with item on weapon, cannot use default"
);
}
@@ -1575,9 +1575,9 @@ public class BotEquipmentModGenerator(
if (existingModPool.Count == 1)
{
// The only item in pool isn't compatible
if (_logger.IsLogEnabled(LogLevel.Debug))
if (logger.IsLogEnabled(LogLevel.Debug))
{
_logger.Debug(
logger.Debug(
$"{request.BotData.Role} {request.ModSlot} Mod pool for: {weaponTemplate.Name} weapon has only incompatible items, using parent list instead"
);
}
@@ -1620,23 +1620,25 @@ public class BotEquipmentModGenerator(
/// <param name="weaponTemplate">Weapons db template</param>
/// <param name="parentItemTpl">Tpl of the parent item</param>
/// <returns>Default preset found</returns>
protected Preset? GetMatchingPreset(TemplateItem weaponTemplate, string parentItemTpl)
protected Preset? GetMatchingPreset(TemplateItem weaponTemplate, MongoId parentItemTpl)
{
// Edge case - using mp5sd reciever means default mp5 handguard doesn't fit
var isMp5sd = parentItemTpl == "5926f2e086f7745aae644231";
// Edge case - using MP5SD receiver means default mp5 handguard doesn't fit
var isMp5sd = parentItemTpl == ItemTpl.RECEIVER_HK_MP5SD_9X19_UPPER;
if (isMp5sd)
{
return _presetHelper.GetPreset("59411abb86f77478f702b5d2");
return presetHelper.GetPreset(new MongoId("59411abb86f77478f702b5d2"));
}
// Edge case - dvl 500mm is the silenced barrel and has specific muzzle mods
var isDvl500mmSilencedBarrel = parentItemTpl == "5888945a2459774bf43ba385";
var isDvl500mmSilencedBarrel =
parentItemTpl == ItemTpl.BARREL_DVL10_762X51_500MM_SUPPRESSED;
if (isDvl500mmSilencedBarrel)
{
return _presetHelper.GetPreset("59e8d2b386f77445830dd299");
return presetHelper.GetPreset(new MongoId("59e8d2b386f77445830dd299"));
}
return _presetHelper.GetDefaultPreset(weaponTemplate.Id);
return presetHelper.GetDefaultPreset(weaponTemplate.Id);
}
/// <summary>
@@ -1645,12 +1647,12 @@ public class BotEquipmentModGenerator(
/// <param name="weapon">Array of items that make up a weapon</param>
/// <param name="modTpl">Mod to check compatibility with weapon</param>
/// <returns>True if incompatible</returns>
public bool WeaponModComboIsIncompatible(List<Item> weapon, string modTpl)
public bool WeaponModComboIsIncompatible(List<Item> weapon, MongoId modTpl)
{
// STM-9 + AR-15 Lone Star Ion Lite handguard
if (
weapon[0].Template == "60339954d62c9b14ed777c06"
&& modTpl == "5d4405f0a4b9361e6a4e6bd9"
weapon[0].Template == ItemTpl.SMG_SOYUZTM_STM9_GEN2_9X19_CARBINE
&& modTpl == ItemTpl.HANDGUARD_AR15_LONE_STAR_ION_LITE
)
{
return true;
@@ -1671,7 +1673,7 @@ public class BotEquipmentModGenerator(
/// <returns>Item object</returns>
public Item CreateModItem(
MongoId modId,
string modTpl,
MongoId modTpl,
string parentId,
string modSlot,
TemplateItem modTemplate,
@@ -1684,7 +1686,7 @@ public class BotEquipmentModGenerator(
Template = modTpl,
ParentId = parentId,
SlotId = modSlot,
Upd = _botGeneratorHelper.GenerateExtraPropertiesForItem(modTemplate, botRole),
Upd = botGeneratorHelper.GenerateExtraPropertiesForItem(modTemplate, botRole),
};
}
@@ -1707,7 +1709,7 @@ public class BotEquipmentModGenerator(
/// <param name="items">Items to ensure picked mod is compatible with</param>
/// <returns>Item tpl</returns>
public MongoId? GetRandomModTplFromItemDb(
string fallbackModTpl,
MongoId fallbackModTpl,
Slot parentSlot,
string modSlot,
List<Item> items
@@ -1723,7 +1725,7 @@ public class BotEquipmentModGenerator(
{
tmpModTpl = exhaustableModPool.GetRandomValue();
if (
!_botGeneratorHelper
!botGeneratorHelper
.IsItemIncompatibleWithCurrentItems(items, tmpModTpl, modSlot)
.Incompatible.GetValueOrDefault(false)
)
@@ -1758,15 +1760,15 @@ public class BotEquipmentModGenerator(
// Mod lacks db template object
if (modBeingAddedDbTemplate.Value is null)
{
_logger.Error(
_serverLocalisationService.GetText(
logger.Error(
serverLocalisationService.GetText(
"bot-no_item_template_found_when_adding_mod",
new { modId = modBeingAddedDbTemplate.Value?.Id ?? "UNKNOWN", modSlot }
)
);
if (_logger.IsLogEnabled(LogLevel.Debug))
if (logger.IsLogEnabled(LogLevel.Debug))
{
_logger.Debug($"Item -> {parentTemplate?.Id}; Slot -> {modSlot}");
logger.Debug($"Item -> {parentTemplate?.Id}; Slot -> {modSlot}");
}
return false;
@@ -1778,8 +1780,8 @@ public class BotEquipmentModGenerator(
// Parent slot must be filled but db object is invalid, show warning and return false
if (slotAddedToTemplate.Required ?? false)
{
_logger.Warning(
_serverLocalisationService.GetText(
logger.Warning(
serverLocalisationService.GetText(
"bot-unable_to_add_mod_item_invalid",
new
{
@@ -1809,7 +1811,7 @@ public class BotEquipmentModGenerator(
public void AddCompatibleModsForProvidedMod(
string desiredSlotName,
TemplateItem modTemplate,
IDictionary<string, Dictionary<string, HashSet<MongoId>>> modPool,
IDictionary<MongoId, Dictionary<string, HashSet<MongoId>>> modPool,
EquipmentFilterDetails botEquipBlacklist
)
{
@@ -1833,8 +1835,8 @@ public class BotEquipmentModGenerator(
);
if (!filteredMods.Any())
{
_logger.Warning(
_serverLocalisationService.GetText(
logger.Warning(
serverLocalisationService.GetText(
"bot-unable_to_filter_mods_all_blacklisted",
new { slotName = desiredSlotObject.Name, itemName = modTemplate.Name }
)
@@ -1859,8 +1861,8 @@ public class BotEquipmentModGenerator(
EquipmentFilterDetails botEquipBlacklist
)
{
var modsFromDynamicPool = _cloner.Clone(
_botEquipmentModPoolService.GetCompatibleModsForWeaponSlot(parentItemId, modSlot)
var modsFromDynamicPool = cloner.Clone(
botEquipmentModPoolService.GetCompatibleModsForWeaponSlot(parentItemId, modSlot)
);
if (modsFromDynamicPool.Count == 0)
@@ -1876,8 +1878,8 @@ public class BotEquipmentModGenerator(
return filteredMods;
}
_logger.Warning(
_serverLocalisationService.GetText(
logger.Warning(
serverLocalisationService.GetText(
"bot-unable_to_filter_mod_slot_all_blacklisted",
modSlot
)
@@ -1906,7 +1908,7 @@ public class BotEquipmentModGenerator(
}
// Get item blacklist and mod equipment blacklist as one Set
var blacklist = _itemFilterService.GetBlacklistedItems();
var blacklist = itemFilterService.GetBlacklistedItems();
if (
botEquipBlacklist?.Equipment is not null
&& botEquipBlacklist.Equipment.TryGetValue(modSlot, out var equipmentBlacklistValues)
@@ -1915,7 +1917,7 @@ public class BotEquipmentModGenerator(
blacklist.UnionWith(equipmentBlacklistValues);
}
var result = _cloner.Clone(modTplPool);
var result = cloner.Clone(modTplPool);
// Filter out blacklisted tpls
result.ExceptWith(blacklist);
@@ -1935,15 +1937,15 @@ public class BotEquipmentModGenerator(
/// <param name="cylinderMagTemplate">The CylinderMagazine's template</param>
public void FillCamora(
List<Item> items,
Dictionary<string, Dictionary<string, HashSet<MongoId>>> modPool,
Dictionary<MongoId, Dictionary<string, HashSet<MongoId>>> modPool,
string cylinderMagParentId,
TemplateItem cylinderMagTemplate
)
{
if (!modPool.TryGetValue(cylinderMagTemplate.Id, out var itemModPool))
{
_logger.Warning(
_serverLocalisationService.GetText(
logger.Warning(
serverLocalisationService.GetText(
"bot-unable_to_fill_camora_slot_mod_pool_empty",
new { weaponId = cylinderMagTemplate.Id, weaponName = cylinderMagTemplate.Name }
)
@@ -1978,8 +1980,8 @@ public class BotEquipmentModGenerator(
}
else
{
_logger.Error(
_serverLocalisationService.GetText(
logger.Error(
serverLocalisationService.GetText(
"bot-missing_cartridge_slot",
cylinderMagTemplate.Id
)
@@ -1988,13 +1990,13 @@ public class BotEquipmentModGenerator(
return;
}
string? modTpl = null;
var modTpl = MongoId.Empty();
var found = false;
while (exhaustableModPool.HasValues())
{
modTpl = exhaustableModPool.GetRandomValue();
if (
!_botGeneratorHelper
!botGeneratorHelper
.IsItemIncompatibleWithCurrentItems(items, modTpl, modSlot)
.Incompatible.GetValueOrDefault(false)
)
@@ -2006,8 +2008,8 @@ public class BotEquipmentModGenerator(
if (!found)
{
_logger.Error(
_serverLocalisationService.GetText("bot-no_compatible_camora_ammo_found", modSlot)
logger.Error(
serverLocalisationService.GetText("bot-no_compatible_camora_ammo_found", modSlot)
);
return;
@@ -2054,7 +2056,7 @@ public class BotEquipmentModGenerator(
Dictionary<MongoId, List<MongoId>> botWeaponSightWhitelist
)
{
var weaponDetails = _itemHelper.GetItem(weapon.Template);
var weaponDetails = itemHelper.GetItem(weapon.Template);
// Return original scopes array if whitelist not found
if (
@@ -2064,9 +2066,9 @@ public class BotEquipmentModGenerator(
)
)
{
if (_logger.IsLogEnabled(LogLevel.Debug))
if (logger.IsLogEnabled(LogLevel.Debug))
{
_logger.Debug(
logger.Debug(
$"Unable to find whitelist for weapon type: {weaponDetails.Value.Parent} {weaponDetails.Value.Name}, skipping sight filtering"
);
}
@@ -2079,7 +2081,7 @@ public class BotEquipmentModGenerator(
foreach (var item in scopes)
{
// Mods is a scope, check base class is allowed
if (_itemHelper.IsOfBaseclasses(item, whitelistedSightTypes))
if (itemHelper.IsOfBaseclasses(item, whitelistedSightTypes))
{
// Add mod to allowed list
filteredScopesAndMods.Add(item);
@@ -2088,9 +2090,9 @@ public class BotEquipmentModGenerator(
// Edge case, what if item is a mount for a scope and not directly a scope?
// Check item is mount + has child items
var itemDetails = _itemHelper.GetItem(item).Value;
var itemDetails = itemHelper.GetItem(item).Value;
if (
_itemHelper.IsOfBaseclass(item, BaseClasses.MOUNT)
itemHelper.IsOfBaseclass(item, BaseClasses.MOUNT)
&& itemDetails.Properties.Slots.Any()
)
{
@@ -2106,8 +2108,8 @@ public class BotEquipmentModGenerator(
scopeSlot?.All(slot =>
slot.Props.Filters[0]
.Filter.All(tpl =>
_itemHelper.IsOfBaseclasses(tpl, whitelistedSightTypes)
|| _itemHelper.IsOfBaseclass(tpl, BaseClasses.MOUNT)
itemHelper.IsOfBaseclasses(tpl, whitelistedSightTypes)
|| itemHelper.IsOfBaseclass(tpl, BaseClasses.MOUNT)
)
) ?? false
)
@@ -2121,9 +2123,9 @@ public class BotEquipmentModGenerator(
// No mods added to return list after filtering has occurred, send back the original mod list
if (filteredScopesAndMods.Count == 0)
{
if (_logger.IsLogEnabled(LogLevel.Debug))
if (logger.IsLogEnabled(LogLevel.Debug))
{
_logger.Debug(
logger.Debug(
$"Scope whitelist too restrictive for: {weapon.Template} {weaponDetails.Value.Name}, skipping filter"
);
}
@@ -20,25 +20,25 @@ namespace SPTarkov.Server.Core.Generators;
[Injectable]
public class BotGenerator(
ISptLogger<BotGenerator> _logger,
HashUtil _hashUtil,
RandomUtil _randomUtil,
DatabaseService _databaseService,
BotInventoryGenerator _botInventoryGenerator,
BotLevelGenerator _botLevelGenerator,
BotEquipmentFilterService _botEquipmentFilterService,
WeightedRandomHelper _weightedRandomHelper,
BotHelper _botHelper,
BotGeneratorHelper _botGeneratorHelper,
SeasonalEventService _seasonalEventService,
ItemFilterService _itemFilterService,
BotNameService _botNameService,
ConfigServer _configServer,
ICloner _cloner
ISptLogger<BotGenerator> logger,
HashUtil hashUtil,
RandomUtil randomUtil,
DatabaseService databaseService,
BotInventoryGenerator botInventoryGenerator,
BotLevelGenerator botLevelGenerator,
BotEquipmentFilterService botEquipmentFilterService,
WeightedRandomHelper weightedRandomHelper,
BotHelper botHelper,
BotGeneratorHelper botGeneratorHelper,
SeasonalEventService seasonalEventService,
ItemFilterService itemFilterService,
BotNameService botNameService,
ConfigServer configServer,
ICloner cloner
)
{
protected readonly BotConfig _botConfig = _configServer.GetConfig<BotConfig>();
protected readonly PmcConfig _pmcConfig = _configServer.GetConfig<PmcConfig>();
protected readonly BotConfig _botConfig = configServer.GetConfig<BotConfig>();
protected readonly PmcConfig _pmcConfig = configServer.GetConfig<PmcConfig>();
/// <summary>
/// Generate a player scav bot object
@@ -50,7 +50,7 @@ public class BotGenerator(
/// <param name="profile">profile of player generating pscav</param>
/// <returns>BotBase</returns>
public PmcData GeneratePlayerScav(
string sessionId,
MongoId sessionId,
string role,
string difficulty,
BotType botTemplate,
@@ -121,7 +121,7 @@ public class BotGenerator(
/// <param name="botGenerationDetails">details on how to generate bots</param>
/// <returns>constructed bot</returns>
public BotBase PrepareAndGenerateBot(
string sessionId,
MongoId sessionId,
BotGenerationDetails? botGenerationDetails
)
{
@@ -136,10 +136,10 @@ public class BotGenerator(
botGenerationDetails.IsPmc ?? false
? preparedBotBase.Info.Side // Use side to get usec.json or bear.json when bot will be PMC
: botGenerationDetails.Role;
var botJsonTemplateClone = _cloner.Clone(_botHelper.GetBotTemplate(botRole));
var botJsonTemplateClone = cloner.Clone(botHelper.GetBotTemplate(botRole));
if (botJsonTemplateClone is null)
{
_logger.Error(
logger.Error(
$"Unable to retrieve: {botRole} bot template, cannot generate bot of this type"
);
}
@@ -170,7 +170,7 @@ public class BotGenerator(
/// <returns>BotBase object</returns>
public BotBase GetCloneOfBotBase()
{
return _cloner.Clone(_databaseService.GetBots().Base);
return cloner.Clone(databaseService.GetBots().Base);
}
/// <summary>
@@ -182,14 +182,14 @@ public class BotGenerator(
/// <param name="botGenerationDetails">details on how to generate the bot</param>
/// <returns>BotBase object</returns>
public BotBase GenerateBot(
string sessionId,
MongoId sessionId,
BotBase bot,
BotType botJsonTemplate,
BotGenerationDetails botGenerationDetails
)
{
var botRoleLowercase = botGenerationDetails.Role.ToLowerInvariant();
var botLevel = _botLevelGenerator.GenerateBotLevel(
var botLevel = botLevelGenerator.GenerateBotLevel(
botJsonTemplate.BotExperience.Level,
botGenerationDetails,
bot
@@ -198,7 +198,7 @@ public class BotGenerator(
// Only filter bot equipment, never players
if (!botGenerationDetails.IsPlayerScav.GetValueOrDefault(false))
{
_botEquipmentFilterService.FilterBotEquipment(
botEquipmentFilterService.FilterBotEquipment(
sessionId,
botJsonTemplate,
botLevel.Level.Value,
@@ -206,7 +206,7 @@ public class BotGenerator(
);
}
bot.Info.Nickname = _botNameService.GenerateUniqueBotNickname(
bot.Info.Nickname = botNameService.GenerateUniqueBotNickname(
botJsonTemplate,
botGenerationDetails,
botRoleLowercase,
@@ -224,16 +224,16 @@ public class BotGenerator(
&& ShouldSimulatePlayerScav(botRoleLowercase)
)
{
_botNameService.AddRandomPmcNameToBotMainProfileNicknameProperty(bot);
botNameService.AddRandomPmcNameToBotMainProfileNicknameProperty(bot);
SetRandomisedGameVersionAndCategory(bot.Info);
}
if (!_seasonalEventService.ChristmasEventEnabled())
if (!seasonalEventService.ChristmasEventEnabled())
// Process all bots EXCEPT gifter, he needs christmas items
{
if (botGenerationDetails.Role != "gifter")
{
_seasonalEventService.RemoveChristmasItemsFromBotInventory(
seasonalEventService.RemoveChristmasItemsFromBotInventory(
botJsonTemplate.BotInventory,
botGenerationDetails.Role
);
@@ -272,9 +272,7 @@ public class BotGenerator(
);
bot.Info.Settings.UseSimpleAnimator =
botJsonTemplate.BotExperience.UseSimpleAnimator ?? false;
bot.Info.Voice = _weightedRandomHelper.GetWeightedValue(
botJsonTemplate.BotAppearance.Voice
);
bot.Info.Voice = weightedRandomHelper.GetWeightedValue(botJsonTemplate.BotAppearance.Voice);
bot.Health = GenerateHealth(
botJsonTemplate.BotHealth,
botGenerationDetails.IsPlayerScav.GetValueOrDefault(false)
@@ -298,7 +296,7 @@ public class BotGenerator(
// Filter out blacklisted gear from the base template
FilterBlacklistedGear(botJsonTemplate, botGenerationDetails);
bot.Inventory = _botInventoryGenerator.GenerateInventory(
bot.Inventory = botInventoryGenerator.GenerateInventory(
sessionId,
botJsonTemplate,
botRoleLowercase,
@@ -335,7 +333,7 @@ public class BotGenerator(
public bool ShouldSimulatePlayerScav(string botRole)
{
return botRole == Roles.Assault
&& _randomUtil.GetChance100(_botConfig.ChanceAssaultScavHasPlayerScavName);
&& randomUtil.GetChance100(_botConfig.ChanceAssaultScavHasPlayerScavName);
}
/// <summary>
@@ -353,14 +351,14 @@ public class BotGenerator(
{
if (!experiences.TryGetValue(botDifficulty.ToLowerInvariant(), out var result))
{
if (_logger.IsLogEnabled(LogLevel.Debug))
if (logger.IsLogEnabled(LogLevel.Debug))
{
_logger.Debug(
logger.Debug(
$"Unable to find experience: {botDifficulty} for {role} bot, falling back to `normal`"
);
}
return _randomUtil.GetInt(experiences["normal"].Min, experiences["normal"].Max);
return randomUtil.GetInt(experiences["normal"].Min, experiences["normal"].Max);
}
// Some bots have -1/-1, shortcut result
@@ -370,7 +368,7 @@ public class BotGenerator(
return -1;
}
return _randomUtil.GetInt(result.Min, result.Max);
return randomUtil.GetInt(result.Min, result.Max);
}
/// <summary>
@@ -388,7 +386,7 @@ public class BotGenerator(
{
if (!standingsForKill.TryGetValue(botDifficulty.ToLowerInvariant(), out var result))
{
_logger.Warning(
logger.Warning(
$"Unable to find standing for kill value for: {role} {botDifficulty}, falling back to `normal`"
);
@@ -413,7 +411,7 @@ public class BotGenerator(
{
if (!aggressorBonuses.TryGetValue(botDifficulty.ToLowerInvariant(), out var result))
{
_logger.Warning(
logger.Warning(
$"Unable to find aggressor bonus for kill value for: {role} {botDifficulty}, falling back to `normal`"
);
@@ -433,8 +431,8 @@ public class BotGenerator(
BotGenerationDetails botGenerationDetails
)
{
var blacklist = _botEquipmentFilterService.GetBotEquipmentBlacklist(
_botGeneratorHelper.GetBotEquipmentRole(botGenerationDetails.Role),
var blacklist = botEquipmentFilterService.GetBotEquipmentBlacklist(
botGeneratorHelper.GetBotEquipmentRole(botGenerationDetails.Role),
botGenerationDetails.PlayerLevel.GetValueOrDefault(1)
);
@@ -491,7 +489,7 @@ public class BotGenerator(
// Create a set of tpls to remove
var keysToRemove = container
.Where(item => _itemFilterService.IsLootableItemBlacklisted(item.Key))
.Where(item => itemFilterService.IsLootableItemBlacklisted(item.Key))
.Select(item => item.Key)
.ToHashSet();
@@ -516,12 +514,12 @@ public class BotGenerator(
)
{
// Choose random values by weight
bot.Customization.Head = _weightedRandomHelper.GetWeightedValue<string>(appearance.Head);
bot.Customization.Feet = _weightedRandomHelper.GetWeightedValue<string>(appearance.Feet);
bot.Customization.Body = _weightedRandomHelper.GetWeightedValue<string>(appearance.Body);
bot.Customization.Head = weightedRandomHelper.GetWeightedValue<string>(appearance.Head);
bot.Customization.Feet = weightedRandomHelper.GetWeightedValue<string>(appearance.Feet);
bot.Customization.Body = weightedRandomHelper.GetWeightedValue<string>(appearance.Body);
var bodyGlobalDictDb = _databaseService.GetGlobals().Configuration.Customization.Body;
var chosenBodyTemplate = _databaseService.GetCustomization()[bot.Customization.Body];
var bodyGlobalDictDb = databaseService.GetGlobals().Configuration.Customization.Body;
var chosenBodyTemplate = databaseService.GetCustomization()[bot.Customization.Body];
// Some bodies have matching hands, look up body to see if this is the case
var chosenBody = bodyGlobalDictDb.FirstOrDefault(c =>
@@ -530,7 +528,7 @@ public class BotGenerator(
bot.Customization.Hands =
chosenBody.Value?.IsNotRandom ?? false
? chosenBody.Value.Hands // Has fixed hands for chosen body, update to match
: _weightedRandomHelper.GetWeightedValue<string>(appearance.Hands); // Hands can be random, choose any from weighted dict
: weightedRandomHelper.GetWeightedValue<string>(appearance.Hands); // Hands can be random, choose any from weighted dict
}
/// <summary>
@@ -543,23 +541,23 @@ public class BotGenerator(
{
var bodyParts = playerScav
? GetLowestHpBody(healthObj.BodyParts)
: _randomUtil.GetArrayValue(healthObj.BodyParts);
: randomUtil.GetArrayValue(healthObj.BodyParts);
BotBaseHealth health = new()
{
Hydration = new CurrentMinMax
{
Current = _randomUtil.GetDouble(healthObj.Hydration.Min, healthObj.Hydration.Max),
Current = randomUtil.GetDouble(healthObj.Hydration.Min, healthObj.Hydration.Max),
Maximum = healthObj.Hydration.Max,
},
Energy = new CurrentMinMax
{
Current = _randomUtil.GetDouble(healthObj.Energy.Min, healthObj.Energy.Max),
Current = randomUtil.GetDouble(healthObj.Energy.Min, healthObj.Energy.Max),
Maximum = healthObj.Energy.Max,
},
Temperature = new CurrentMinMax
{
Current = _randomUtil.GetDouble(
Current = randomUtil.GetDouble(
healthObj.Temperature.Min,
healthObj.Temperature.Max
),
@@ -573,7 +571,7 @@ public class BotGenerator(
{
Health = new CurrentMinMax
{
Current = _randomUtil.GetDouble(bodyParts.Head.Min, bodyParts.Head.Max),
Current = randomUtil.GetDouble(bodyParts.Head.Min, bodyParts.Head.Max),
Maximum = Math.Round(bodyParts.Head.Max),
},
}
@@ -584,7 +582,7 @@ public class BotGenerator(
{
Health = new CurrentMinMax
{
Current = _randomUtil.GetDouble(
Current = randomUtil.GetDouble(
bodyParts.Chest.Min,
bodyParts.Chest.Max
),
@@ -598,7 +596,7 @@ public class BotGenerator(
{
Health = new CurrentMinMax
{
Current = _randomUtil.GetDouble(
Current = randomUtil.GetDouble(
bodyParts.Stomach.Min,
bodyParts.Stomach.Max
),
@@ -612,7 +610,7 @@ public class BotGenerator(
{
Health = new CurrentMinMax
{
Current = _randomUtil.GetDouble(
Current = randomUtil.GetDouble(
bodyParts.LeftArm.Min,
bodyParts.LeftArm.Max
),
@@ -626,7 +624,7 @@ public class BotGenerator(
{
Health = new CurrentMinMax
{
Current = _randomUtil.GetDouble(
Current = randomUtil.GetDouble(
bodyParts.RightArm.Min,
bodyParts.RightArm.Max
),
@@ -640,7 +638,7 @@ public class BotGenerator(
{
Health = new CurrentMinMax
{
Current = _randomUtil.GetDouble(
Current = randomUtil.GetDouble(
bodyParts.LeftLeg.Min,
bodyParts.LeftLeg.Max
),
@@ -654,7 +652,7 @@ public class BotGenerator(
{
Health = new CurrentMinMax
{
Current = _randomUtil.GetDouble(
Current = randomUtil.GetDouble(
bodyParts.RightLeg.Min,
bodyParts.RightLeg.Max
),
@@ -742,7 +740,7 @@ public class BotGenerator(
return new CommonSkill
{
Id = Enum.Parse<SkillTypes>(kvp.Key),
Progress = _randomUtil.GetDouble(skill.Min, skill.Max),
Progress = randomUtil.GetDouble(skill.Min, skill.Max),
PointsEarnedDuringSession = 0,
LastAccess = 0,
};
@@ -779,7 +777,7 @@ public class BotGenerator(
return new MasterySkill
{
Id = kvp.Key,
Progress = _randomUtil.GetDouble(skill.Min, skill.Max),
Progress = randomUtil.GetDouble(skill.Min, skill.Max),
};
})
.Where(baseSkill => baseSkill != null)
@@ -796,7 +794,7 @@ public class BotGenerator(
{
bot.Id = new MongoId();
bot.Aid = botGenerationDetails.IsPmc.GetValueOrDefault(false)
? _hashUtil.GenerateAccountId()
? hashUtil.GenerateAccountId()
: 0;
}
@@ -856,7 +854,7 @@ public class BotGenerator(
}
// Choose random weighted game version for bot
botInfo.GameVersion = _weightedRandomHelper.GetWeightedValue(_pmcConfig.GameVersionWeight);
botInfo.GameVersion = weightedRandomHelper.GetWeightedValue(_pmcConfig.GameVersionWeight);
// Choose appropriate member category value
switch (botInfo.GameVersion)
@@ -869,7 +867,7 @@ public class BotGenerator(
break;
default:
// Everyone else gets a weighted randomised category
botInfo.MemberCategory = _weightedRandomHelper.GetWeightedValue(
botInfo.MemberCategory = weightedRandomHelper.GetWeightedValue(
_pmcConfig.AccountTypeWeight
);
break;
@@ -17,22 +17,22 @@ namespace SPTarkov.Server.Core.Generators;
[Injectable]
public class BotInventoryGenerator(
ISptLogger<BotInventoryGenerator> _logger,
RandomUtil _randomUtil,
ProfileActivityService _profileActivityService,
BotWeaponGenerator _botWeaponGenerator,
BotLootGenerator _botLootGenerator,
BotGeneratorHelper _botGeneratorHelper,
ProfileHelper _profileHelper,
BotHelper _botHelper,
WeightedRandomHelper _weightedRandomHelper,
ItemHelper _itemHelper,
WeatherHelper _weatherHelper,
ServerLocalisationService _serverLocalisationService,
BotEquipmentFilterService _botEquipmentFilterService,
BotEquipmentModPoolService _botEquipmentModPoolService,
BotEquipmentModGenerator _botEquipmentModGenerator,
ConfigServer _configServer
ISptLogger<BotInventoryGenerator> logger,
RandomUtil randomUtil,
ProfileActivityService profileActivityService,
BotWeaponGenerator botWeaponGenerator,
BotLootGenerator botLootGenerator,
BotGeneratorHelper botGeneratorHelper,
ProfileHelper profileHelper,
BotHelper botHelper,
WeightedRandomHelper weightedRandomHelper,
ItemHelper itemHelper,
WeatherHelper weatherHelper,
ServerLocalisationService serverLocalisationService,
BotEquipmentFilterService botEquipmentFilterService,
BotEquipmentModPoolService botEquipmentModPoolService,
BotEquipmentModGenerator botEquipmentModGenerator,
ConfigServer configServer
)
{
// Slots handled individually inside `GenerateAndAddEquipmentToBot`
@@ -49,7 +49,7 @@ public class BotInventoryGenerator(
EquipmentSlots.Earpiece,
];
private readonly BotConfig _botConfig = _configServer.GetConfig<BotConfig>();
private readonly BotConfig _botConfig = configServer.GetConfig<BotConfig>();
private readonly HashSet<string> _slotsToCheck =
[
@@ -68,7 +68,7 @@ public class BotInventoryGenerator(
/// <param name="chosenGameVersion">Game version for bot, only really applies for PMCs</param>
/// <returns>PmcInventory object with equipment/weapons/loot</returns>
public BotBaseInventory GenerateInventory(
string sessionId,
MongoId sessionId,
BotType botJsonTemplate,
string botRole,
bool isPmc,
@@ -84,7 +84,7 @@ public class BotInventoryGenerator(
var botInventory = GenerateInventoryBase();
// Get generated raid details bot will be spawned in
var raidConfig = _profileActivityService
var raidConfig = profileActivityService
.GetProfileActivityRaidData(sessionId)
?.RaidConfiguration;
@@ -113,7 +113,7 @@ public class BotInventoryGenerator(
);
// Pick loot and add to bots containers (rig/backpack/pockets/secure)
_botLootGenerator.GenerateLoot(
botLootGenerator.GenerateLoot(
sessionId,
botJsonTemplate,
isPmc,
@@ -177,7 +177,7 @@ public class BotInventoryGenerator(
/// <param name="chosenGameVersion">Game version for bot, only really applies for PMCs</param>
/// <param name="raidConfig">RadiConfig</param>
public void GenerateAndAddEquipmentToBot(
string sessionId,
MongoId sessionId,
BotTypeInventory templateInventory,
Chances wornItemChances,
string botRole,
@@ -189,16 +189,16 @@ public class BotInventoryGenerator(
)
{
_botConfig.Equipment.TryGetValue(
_botGeneratorHelper.GetBotEquipmentRole(botRole),
botGeneratorHelper.GetBotEquipmentRole(botRole),
out var botEquipConfig
);
var randomistionDetails = _botHelper.GetBotRandomizationDetails(botLevel, botEquipConfig);
var randomistionDetails = botHelper.GetBotRandomizationDetails(botLevel, botEquipConfig);
// Apply nighttime changes if its nighttime + there's changes to make
if (
randomistionDetails?.NighttimeChanges is not null
&& raidConfig is not null
&& _weatherHelper.IsNightTime(raidConfig.TimeVariant, raidConfig.Location)
&& weatherHelper.IsNightTime(raidConfig.TimeVariant, raidConfig.Location)
)
{
foreach (
@@ -218,8 +218,8 @@ public class BotInventoryGenerator(
}
// Get profile of player generating bots, we use their level later on
var pmcProfile = _profileHelper.GetPmcProfile(sessionId);
var botEquipmentRole = _botGeneratorHelper.GetBotEquipmentRole(botRole);
var pmcProfile = profileHelper.GetPmcProfile(sessionId);
var botEquipmentRole = botGeneratorHelper.GetBotEquipmentRole(botRole);
// Iterate over all equipment slots of bot, do it in specifc order to reduce conflicts
// e.g. ArmorVest should be generated after TactivalVest
@@ -431,14 +431,14 @@ public class BotInventoryGenerator(
)
{
var tacVestsWithArmor = templateEquipment[EquipmentSlots.TacticalVest]
.Where(kvp => _itemHelper.ItemHasSlots(kvp.Key))
.Where(kvp => itemHelper.ItemHasSlots(kvp.Key))
.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
if (!tacVestsWithArmor.Any())
{
if (_logger.IsLogEnabled(LogLevel.Debug))
if (logger.IsLogEnabled(LogLevel.Debug))
{
_logger.Debug(
logger.Debug(
$"Unable to filter to only armored rigs as bot: {botRole} has none in pool"
);
}
@@ -462,14 +462,14 @@ public class BotInventoryGenerator(
)
{
var tacVestsWithoutArmor = templateEquipment[EquipmentSlots.TacticalVest]
.Where(kvp => !_itemHelper.ItemHasSlots(kvp.Key))
.Where(kvp => !itemHelper.ItemHasSlots(kvp.Key))
.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
if (!allowEmptyResult && !tacVestsWithoutArmor.Any())
{
if (_logger.IsLogEnabled(LogLevel.Debug))
if (logger.IsLogEnabled(LogLevel.Debug))
{
_logger.Debug(
logger.Debug(
$"Unable to filter to only unarmored rigs as bot: {botRole} has none in pool"
);
}
@@ -495,8 +495,8 @@ public class BotInventoryGenerator(
if (!spawnChance.HasValue)
{
_logger.Warning(
_serverLocalisationService.GetText(
logger.Warning(
serverLocalisationService.GetText(
"bot-no_spawn_chance_defined_for_equipment_slot",
settings.RootEquipmentSlot
)
@@ -506,7 +506,7 @@ public class BotInventoryGenerator(
}
// Roll dice on equipment item
var shouldSpawn = _randomUtil.GetChance100(spawnChance ?? 0);
var shouldSpawn = randomUtil.GetChance100(spawnChance ?? 0);
if (shouldSpawn && settings.RootEquipmentPool.Any())
{
TemplateItem? pickedItemDb = null;
@@ -522,22 +522,22 @@ public class BotInventoryGenerator(
return false;
}
var chosenItemTpl = _weightedRandomHelper.GetWeightedValue(
var chosenItemTpl = weightedRandomHelper.GetWeightedValue(
settings.RootEquipmentPool
);
var dbResult = _itemHelper.GetItem(chosenItemTpl);
var dbResult = itemHelper.GetItem(chosenItemTpl);
if (!dbResult.Key)
{
_logger.Error(
_serverLocalisationService.GetText(
logger.Error(
serverLocalisationService.GetText(
"bot-missing_item_template",
chosenItemTpl
)
);
if (_logger.IsLogEnabled(LogLevel.Debug))
if (logger.IsLogEnabled(LogLevel.Debug))
{
_logger.Debug($"EquipmentSlot-> {settings.RootEquipmentSlot}");
logger.Debug($"EquipmentSlot-> {settings.RootEquipmentSlot}");
}
// Remove picked item
@@ -549,7 +549,7 @@ public class BotInventoryGenerator(
}
// Is the chosen item compatible with other items equipped
var compatibilityResult = _botGeneratorHelper.IsItemIncompatibleWithCurrentItems(
var compatibilityResult = botGeneratorHelper.IsItemIncompatibleWithCurrentItems(
settings.Inventory.Items,
chosenItemTpl,
settings.RootEquipmentSlot.ToString()
@@ -584,13 +584,13 @@ public class BotInventoryGenerator(
Template = pickedItemDb.Id,
ParentId = settings.Inventory.Equipment,
SlotId = settings.RootEquipmentSlot.ToString(),
Upd = _botGeneratorHelper.GenerateExtraPropertiesForItem(
Upd = botGeneratorHelper.GenerateExtraPropertiesForItem(
pickedItemDb,
settings.BotData.Role
),
};
var botEquipBlacklist = _botEquipmentFilterService.GetBotEquipmentBlacklist(
var botEquipBlacklist = botEquipmentFilterService.GetBotEquipmentBlacklist(
settings.BotData.EquipmentRole,
settings.GeneratingPlayerLevel.GetValueOrDefault(1)
);
@@ -617,7 +617,7 @@ public class BotInventoryGenerator(
// Does item have slots for sub-mods to be inserted into
if (pickedItemDb.Properties?.Slots?.Count > 0 && !itemIsOnGenerateModBlacklist)
{
var childItemsToAdd = _botEquipmentModGenerator.GenerateModsForEquipment(
var childItemsToAdd = botEquipmentModGenerator.GenerateModsForEquipment(
[item],
id,
pickedItemDb,
@@ -649,7 +649,7 @@ public class BotInventoryGenerator(
Dictionary<string, HashSet<MongoId>> equipmentBlacklist
)
{
var modPool = _botEquipmentModPoolService.GetModsForGearSlot(itemTpl);
var modPool = botEquipmentModPoolService.GetModsForGearSlot(itemTpl);
return modPool.ToDictionary(
kvp => kvp.Key,
@@ -672,7 +672,7 @@ public class BotInventoryGenerator(
return filteredMods;
}
_logger.Warning(
logger.Warning(
$"Filtering: '{modSlot}' resulted in 0 mods. Reverting to original set for slot"
);
@@ -696,7 +696,7 @@ public class BotInventoryGenerator(
public void GenerateAndAddWeaponsToBot(
BotTypeInventory templateInventory,
Chances equipmentChances,
string sessionId,
MongoId sessionId,
BotBaseInventory botInventory,
string botRole,
bool isPmc,
@@ -734,7 +734,7 @@ public class BotInventoryGenerator(
/// <returns>What slots bot should have weapons generated for</returns>
public List<DesiredWeapons> GetDesiredWeaponsForBot(Chances equipmentChances)
{
var shouldSpawnPrimary = _randomUtil.GetChance100(
var shouldSpawnPrimary = randomUtil.GetChance100(
equipmentChances.EquipmentChances["FirstPrimaryWeapon"]
);
return
@@ -749,7 +749,7 @@ public class BotInventoryGenerator(
Slot = EquipmentSlots.SecondPrimaryWeapon,
ShouldSpawn =
shouldSpawnPrimary
&& _randomUtil.GetChance100(
&& randomUtil.GetChance100(
equipmentChances.EquipmentChances["SecondPrimaryWeapon"]
),
},
@@ -758,7 +758,7 @@ public class BotInventoryGenerator(
Slot = EquipmentSlots.Holster,
ShouldSpawn =
!shouldSpawnPrimary
|| _randomUtil.GetChance100(equipmentChances.EquipmentChances["Holster"]), // No primary = force pistol
|| randomUtil.GetChance100(equipmentChances.EquipmentChances["Holster"]), // No primary = force pistol
},
];
}
@@ -776,7 +776,7 @@ public class BotInventoryGenerator(
/// <param name="itemGenerationWeights"></param>
/// <param name="botLevel"></param>
public void AddWeaponAndMagazinesToInventory(
string sessionId,
MongoId sessionId,
DesiredWeapons weaponSlot,
BotTypeInventory templateInventory,
BotBaseInventory botInventory,
@@ -787,7 +787,7 @@ public class BotInventoryGenerator(
int botLevel
)
{
var generatedWeapon = _botWeaponGenerator.GenerateRandomWeapon(
var generatedWeapon = botWeaponGenerator.GenerateRandomWeapon(
sessionId,
weaponSlot.Slot.ToString(),
templateInventory,
@@ -800,7 +800,7 @@ public class BotInventoryGenerator(
botInventory.Items.AddRange(generatedWeapon.Weapon);
_botWeaponGenerator.AddExtraMagazinesToInventory(
botWeaponGenerator.AddExtraMagazinesToInventory(
generatedWeapon,
itemGenerationWeights.Items.Magazines,
botInventory,
@@ -11,9 +11,9 @@ namespace SPTarkov.Server.Core.Generators;
[Injectable]
public class BotLevelGenerator(
ISptLogger<BotLevelGenerator> _logger,
RandomUtil _randomUtil,
DatabaseService _databaseService
ISptLogger<BotLevelGenerator> logger,
RandomUtil randomUtil,
DatabaseService databaseService
)
{
/// <summary>
@@ -34,7 +34,7 @@ public class BotLevelGenerator(
return new RandomisedBotLevelResult { Exp = 0, Level = 1 };
}
var expTable = _databaseService.GetGlobals().Configuration.Exp.Level.ExperienceTable;
var expTable = databaseService.GetGlobals().Configuration.Exp.Level.ExperienceTable;
var botLevelRange = GetRelativePmcBotLevelRange(
botGenerationDetails,
levelDetails,
@@ -54,7 +54,7 @@ public class BotLevelGenerator(
// Sprinkle in some random exp within the level, unless we are at max level.
if (level < expTable.Length - 1)
{
exp += _randomUtil.GetInt(0, expTable[level].Experience.Value - 1);
exp += randomUtil.GetInt(0, expTable[level].Experience.Value - 1);
}
return new RandomisedBotLevelResult { Level = level, Exp = exp };
@@ -62,7 +62,7 @@ public class BotLevelGenerator(
public double ChooseBotLevel(double min, double max, int shift, double number)
{
return _randomUtil.GetBiasedRandomNumber(min, max, shift, number);
return randomUtil.GetBiasedRandomNumber(min, max, shift, number);
}
/// <summary>
@@ -16,23 +16,23 @@ namespace SPTarkov.Server.Core.Generators;
[Injectable]
public class BotLootGenerator(
ISptLogger<BotLootGenerator> _logger,
RandomUtil _randomUtil,
ItemHelper _itemHelper,
InventoryHelper _inventoryHelper,
HandbookHelper _handbookHelper,
BotGeneratorHelper _botGeneratorHelper,
BotWeaponGenerator _botWeaponGenerator,
WeightedRandomHelper _weightedRandomHelper,
BotHelper _botHelper,
BotLootCacheService _botLootCacheService,
ServerLocalisationService _serverLocalisationService,
ConfigServer _configServer,
ICloner _cloner
ISptLogger<BotLootGenerator> logger,
RandomUtil randomUtil,
ItemHelper itemHelper,
InventoryHelper inventoryHelper,
HandbookHelper handbookHelper,
BotGeneratorHelper botGeneratorHelper,
BotWeaponGenerator botWeaponGenerator,
WeightedRandomHelper weightedRandomHelper,
BotHelper botHelper,
BotLootCacheService botLootCacheService,
ServerLocalisationService serverLocalisationService,
ConfigServer configServer,
ICloner cloner
)
{
protected readonly BotConfig _botConfig = _configServer.GetConfig<BotConfig>();
protected readonly PmcConfig _pmcConfig = _configServer.GetConfig<PmcConfig>();
protected readonly BotConfig _botConfig = configServer.GetConfig<BotConfig>();
protected readonly PmcConfig _pmcConfig = configServer.GetConfig<PmcConfig>();
/// <summary>
/// </summary>
@@ -43,7 +43,7 @@ public class BotLootGenerator(
var limits = GetItemSpawnLimitsForBotType(botRole);
// Clone limits and set all values to 0 to use as a running total
var limitsForBotDict = _cloner.Clone(limits);
var limitsForBotDict = cloner.Clone(limits);
// Init current count of items we want to limit
foreach (var limit in limitsForBotDict)
{
@@ -67,7 +67,7 @@ public class BotLootGenerator(
/// <param name="botInventory">Inventory to add loot to</param>
/// <param name="botLevel">Level of bot</param>
public void GenerateLoot(
string sessionId,
MongoId sessionId,
BotType botJsonTemplate,
bool isPmc,
string botRole,
@@ -92,27 +92,27 @@ public class BotLootGenerator(
|| itemCounts.Grenades.Weights is null
)
{
_logger.Warning(
_serverLocalisationService.GetText("bot-unable_to_generate_bot_loot", botRole)
logger.Warning(
serverLocalisationService.GetText("bot-unable_to_generate_bot_loot", botRole)
);
return;
}
var backpackLootCount = _weightedRandomHelper.GetWeightedValue(
var backpackLootCount = weightedRandomHelper.GetWeightedValue(
itemCounts.BackpackLoot.Weights
);
var pocketLootCount = _weightedRandomHelper.GetWeightedValue(itemCounts.PocketLoot.Weights);
var vestLootCount = _weightedRandomHelper.GetWeightedValue(itemCounts.VestLoot.Weights);
var specialLootItemCount = _weightedRandomHelper.GetWeightedValue(
var pocketLootCount = weightedRandomHelper.GetWeightedValue(itemCounts.PocketLoot.Weights);
var vestLootCount = weightedRandomHelper.GetWeightedValue(itemCounts.VestLoot.Weights);
var specialLootItemCount = weightedRandomHelper.GetWeightedValue(
itemCounts.SpecialItems.Weights
);
var healingItemCount = _weightedRandomHelper.GetWeightedValue(itemCounts.Healing.Weights);
var drugItemCount = _weightedRandomHelper.GetWeightedValue(itemCounts.Drugs.Weights);
var foodItemCount = _weightedRandomHelper.GetWeightedValue(itemCounts.Food.Weights);
var drinkItemCount = _weightedRandomHelper.GetWeightedValue(itemCounts.Drink.Weights);
var currencyItemCount = _weightedRandomHelper.GetWeightedValue(itemCounts.Currency.Weights);
var stimItemCount = _weightedRandomHelper.GetWeightedValue(itemCounts.Stims.Weights);
var grenadeCount = _weightedRandomHelper.GetWeightedValue(itemCounts.Grenades.Weights);
var healingItemCount = weightedRandomHelper.GetWeightedValue(itemCounts.Healing.Weights);
var drugItemCount = weightedRandomHelper.GetWeightedValue(itemCounts.Drugs.Weights);
var foodItemCount = weightedRandomHelper.GetWeightedValue(itemCounts.Food.Weights);
var drinkItemCount = weightedRandomHelper.GetWeightedValue(itemCounts.Drink.Weights);
var currencyItemCount = weightedRandomHelper.GetWeightedValue(itemCounts.Currency.Weights);
var stimItemCount = weightedRandomHelper.GetWeightedValue(itemCounts.Stims.Weights);
var grenadeCount = weightedRandomHelper.GetWeightedValue(itemCounts.Grenades.Weights);
// If bot has been flagged as not having loot, set below counts to 0
if (_botConfig.DisableLootOnBotTypes.Contains(botRole.ToLowerInvariant()))
@@ -139,7 +139,7 @@ public class BotLootGenerator(
// Special items
AddLootFromPool(
_botLootCacheService.GetLootFromCache(
botLootCacheService.GetLootFromCache(
botRole,
isPmc,
LootCacheType.Special,
@@ -155,7 +155,7 @@ public class BotLootGenerator(
// Healing items / Meds
AddLootFromPool(
_botLootCacheService.GetLootFromCache(
botLootCacheService.GetLootFromCache(
botRole,
isPmc,
LootCacheType.HealingItems,
@@ -173,7 +173,7 @@ public class BotLootGenerator(
// Drugs
AddLootFromPool(
_botLootCacheService.GetLootFromCache(
botLootCacheService.GetLootFromCache(
botRole,
isPmc,
LootCacheType.DrugItems,
@@ -191,7 +191,7 @@ public class BotLootGenerator(
// Food
AddLootFromPool(
_botLootCacheService.GetLootFromCache(
botLootCacheService.GetLootFromCache(
botRole,
isPmc,
LootCacheType.FoodItems,
@@ -209,7 +209,7 @@ public class BotLootGenerator(
// Drink
AddLootFromPool(
_botLootCacheService.GetLootFromCache(
botLootCacheService.GetLootFromCache(
botRole,
isPmc,
LootCacheType.DrinkItems,
@@ -227,7 +227,7 @@ public class BotLootGenerator(
// Currency
AddLootFromPool(
_botLootCacheService.GetLootFromCache(
botLootCacheService.GetLootFromCache(
botRole,
isPmc,
LootCacheType.CurrencyItems,
@@ -245,7 +245,7 @@ public class BotLootGenerator(
// Stims
AddLootFromPool(
_botLootCacheService.GetLootFromCache(
botLootCacheService.GetLootFromCache(
botRole,
isPmc,
LootCacheType.StimItems,
@@ -263,7 +263,7 @@ public class BotLootGenerator(
// Grenades
AddLootFromPool(
_botLootCacheService.GetLootFromCache(
botLootCacheService.GetLootFromCache(
botRole,
isPmc,
LootCacheType.GrenadeItems,
@@ -285,7 +285,7 @@ public class BotLootGenerator(
if (containersBotHasAvailable.Contains(EquipmentSlots.Backpack))
{
// Add randomly generated weapon to PMC backpacks
if (isPmc && _randomUtil.GetChance100(_pmcConfig.LooseWeaponInBackpackChancePercent))
if (isPmc && randomUtil.GetChance100(_pmcConfig.LooseWeaponInBackpackChancePercent))
{
AddLooseWeaponsToInventorySlot(
sessionId,
@@ -302,7 +302,7 @@ public class BotLootGenerator(
var backpackLootRoubleTotal = GetBackpackRoubleTotalByLevel(botLevel, isPmc);
AddLootFromPool(
_botLootCacheService.GetLootFromCache(
botLootCacheService.GetLootFromCache(
botRole,
isPmc,
LootCacheType.Backpack,
@@ -325,7 +325,7 @@ public class BotLootGenerator(
// Vest
{
AddLootFromPool(
_botLootCacheService.GetLootFromCache(
botLootCacheService.GetLootFromCache(
botRole,
isPmc,
LootCacheType.Vest,
@@ -345,7 +345,7 @@ public class BotLootGenerator(
// Pockets
AddLootFromPool(
_botLootCacheService.GetLootFromCache(
botLootCacheService.GetLootFromCache(
botRole,
isPmc,
LootCacheType.Pocket,
@@ -368,7 +368,7 @@ public class BotLootGenerator(
if (!isPmc || (isPmc && _pmcConfig.AddSecureContainerLootFromBotConfig))
{
AddLootFromPool(
_botLootCacheService.GetLootFromCache(
botLootCacheService.GetLootFromCache(
botRole,
isPmc,
LootCacheType.Secure,
@@ -458,7 +458,7 @@ public class BotLootGenerator(
{
// surv12
AddLootFromPool(
new Dictionary<MongoId, double> { { "5d02797c86f774203f38e30a", 1 } },
new Dictionary<MongoId, double> { { ItemTpl.MEDICAL_SURV12_FIELD_SURGICAL_KIT, 1 } },
[EquipmentSlots.SecuredContainer],
1,
botInventory,
@@ -470,7 +470,10 @@ public class BotLootGenerator(
// AFAK
AddLootFromPool(
new Dictionary<MongoId, double> { { "60098ad7c2240c0fe85c570a", 1 } },
new Dictionary<MongoId, double>
{
{ ItemTpl.MEDKIT_AFAK_TACTICAL_INDIVIDUAL_FIRST_AID_KIT, 1 },
},
[EquipmentSlots.SecuredContainer],
10,
botInventory,
@@ -524,12 +527,12 @@ public class BotLootGenerator(
return;
}
var weightedItemTpl = _weightedRandomHelper.GetWeightedValue(pool);
var (key, itemToAddTemplate) = _itemHelper.GetItem(weightedItemTpl);
var weightedItemTpl = weightedRandomHelper.GetWeightedValue(pool);
var (key, itemToAddTemplate) = itemHelper.GetItem(weightedItemTpl);
if (!key)
{
_logger.Warning(
logger.Warning(
$"Unable to process item tpl: {weightedItemTpl} for slots: {equipmentSlots} on bot: {botRole}"
);
@@ -555,7 +558,7 @@ public class BotLootGenerator(
{
Id = newRootItemId,
Template = itemToAddTemplate?.Id ?? string.Empty,
Upd = _botGeneratorHelper.GenerateExtraPropertiesForItem(
Upd = botGeneratorHelper.GenerateExtraPropertiesForItem(
itemToAddTemplate,
botRole
),
@@ -565,7 +568,7 @@ public class BotLootGenerator(
// Is Simple-Wallet / WZ wallet
if (_botConfig.WalletLoot.WalletTplPool.Contains(weightedItemTpl))
{
var addCurrencyToWallet = _randomUtil.GetChance100(
var addCurrencyToWallet = randomUtil.GetChance100(
_botConfig.WalletLoot.ChancePercent
);
if (addCurrencyToWallet)
@@ -574,11 +577,11 @@ public class BotLootGenerator(
var itemsToAdd = CreateWalletLoot(newRootItemId);
// Get the container grid for the wallet
var containerGrid = _inventoryHelper.GetContainerSlotMap(weightedItemTpl);
var containerGrid = inventoryHelper.GetContainerSlotMap(weightedItemTpl);
// Check if all the chosen currency items fit into wallet
var canAddToContainer = _inventoryHelper.CanPlaceItemsInContainer(
_cloner.Clone(containerGrid), // MUST clone grid before passing in as function modifies grid
var canAddToContainer = inventoryHelper.CanPlaceItemsInContainer(
cloner.Clone(containerGrid), // MUST clone grid before passing in as function modifies grid
itemsToAdd
);
if (canAddToContainer)
@@ -586,7 +589,7 @@ public class BotLootGenerator(
// Add each currency to wallet
foreach (var itemToAdd in itemsToAdd)
{
_inventoryHelper.PlaceItemInContainer(
inventoryHelper.PlaceItemInContainer(
containerGrid,
itemToAdd,
itemWithChildrenToAdd[0].Id,
@@ -603,7 +606,7 @@ public class BotLootGenerator(
AddRequiredChildItemsToParent(itemToAddTemplate, itemWithChildrenToAdd, isPmc, botRole);
// Attempt to add item to container(s)
var itemAddedResult = _botGeneratorHelper.AddItemWithChildrenToEquipmentSlot(
var itemAddedResult = botGeneratorHelper.AddItemWithChildrenToEquipmentSlot(
equipmentSlots,
newRootItemId,
itemToAddTemplate.Id,
@@ -618,9 +621,9 @@ public class BotLootGenerator(
if (itemAddedResult == ItemAddedResult.NO_CONTAINERS)
{
// Bot has no container to put item in, exit
if (_logger.IsLogEnabled(LogLevel.Debug))
if (logger.IsLogEnabled(LogLevel.Debug))
{
_logger.Debug(
logger.Debug(
$"Unable to add: {totalItemCount} items to bot as it lacks a container to include them"
);
}
@@ -631,9 +634,9 @@ public class BotLootGenerator(
fitItemIntoContainerAttempts++;
if (fitItemIntoContainerAttempts >= 4)
{
if (_logger.IsLogEnabled(LogLevel.Debug))
if (logger.IsLogEnabled(LogLevel.Debug))
{
_logger.Debug(
logger.Debug(
$"Failed placing item: {itemToAddTemplate.Id} - {itemToAddTemplate.Name}: {i} of: {totalItemCount} items into: {botRole} "
+ $"containers: {string.Join(",", equipmentSlots)}. Tried: {fitItemIntoContainerAttempts} "
+ $"times, reason: {itemAddedResult}, skipping"
@@ -653,7 +656,7 @@ public class BotLootGenerator(
// Stop adding items to bots pool if rolling total is over total limit
if (totalValueLimitRub > 0)
{
currentTotalRub += _handbookHelper.GetTemplatePrice(itemToAddTemplate.Id);
currentTotalRub += handbookHelper.GetTemplatePrice(itemToAddTemplate.Id);
if (currentTotalRub > totalValueLimitRub)
{
break;
@@ -672,14 +675,14 @@ public class BotLootGenerator(
List<List<Item>> result = [];
// Choose how many stacks of currency will be added to wallet
var itemCount = _randomUtil.GetInt(
var itemCount = randomUtil.GetInt(
_botConfig.WalletLoot.ItemCount.Min,
_botConfig.WalletLoot.ItemCount.Max
);
for (var index = 0; index < itemCount; index++)
{
// Choose the size of the currency stack - default is 5k, 10k, 15k, 20k, 25k
var chosenStackCount = _weightedRandomHelper.GetWeightedValue(
var chosenStackCount = weightedRandomHelper.GetWeightedValue(
_botConfig.WalletLoot.StackSizeWeight
);
List<Item> items =
@@ -687,7 +690,7 @@ public class BotLootGenerator(
new()
{
Id = new MongoId(),
Template = _weightedRandomHelper.GetWeightedValue(
Template = weightedRandomHelper.GetWeightedValue(
_botConfig.WalletLoot.CurrencyWeight
),
ParentId = walletId,
@@ -715,24 +718,24 @@ public class BotLootGenerator(
)
{
// Fill ammo box
if (_itemHelper.IsOfBaseclass(itemToAddTemplate.Id, BaseClasses.AMMO_BOX))
if (itemHelper.IsOfBaseclass(itemToAddTemplate.Id, BaseClasses.AMMO_BOX))
{
_itemHelper.AddCartridgesToAmmoBox(itemToAddChildrenTo, itemToAddTemplate);
itemHelper.AddCartridgesToAmmoBox(itemToAddChildrenTo, itemToAddTemplate);
}
// Make money a stack
else if (_itemHelper.IsOfBaseclass(itemToAddTemplate.Id, BaseClasses.MONEY))
else if (itemHelper.IsOfBaseclass(itemToAddTemplate.Id, BaseClasses.MONEY))
{
RandomiseMoneyStackSize(botRole, itemToAddTemplate, itemToAddChildrenTo[0]);
}
// Make ammo a stack
else if (_itemHelper.IsOfBaseclass(itemToAddTemplate.Id, BaseClasses.AMMO))
else if (itemHelper.IsOfBaseclass(itemToAddTemplate.Id, BaseClasses.AMMO))
{
RandomiseAmmoStackSize(isPmc, itemToAddTemplate, itemToAddChildrenTo[0]);
}
// Must add soft inserts/plates
else if (_itemHelper.ItemRequiresSoftInserts(itemToAddTemplate.Id))
else if (itemHelper.ItemRequiresSoftInserts(itemToAddTemplate.Id))
{
_itemHelper.AddChildSlotItems(itemToAddChildrenTo, itemToAddTemplate);
itemHelper.AddChildSlotItems(itemToAddChildrenTo, itemToAddTemplate);
}
}
@@ -749,7 +752,7 @@ public class BotLootGenerator(
/// <param name="botLevel"></param>
/// <param name="containersIdFull"></param>
public void AddLooseWeaponsToInventorySlot(
string sessionId,
MongoId sessionId,
BotBaseInventory botInventory,
EquipmentSlots equipmentSlot,
BotTypeInventory? templateInventory,
@@ -760,7 +763,7 @@ public class BotLootGenerator(
HashSet<string>? containersIdFull
)
{
var chosenWeaponType = _randomUtil.GetArrayValue<string>(
var chosenWeaponType = randomUtil.GetArrayValue<string>(
[
EquipmentSlots.FirstPrimaryWeapon.ToString(),
EquipmentSlots.FirstPrimaryWeapon.ToString(),
@@ -768,7 +771,7 @@ public class BotLootGenerator(
EquipmentSlots.Holster.ToString(),
]
);
var randomisedWeaponCount = _randomUtil.GetInt(
var randomisedWeaponCount = randomUtil.GetInt(
_pmcConfig.LooseWeaponInBackpackLootMinMax.Min,
_pmcConfig.LooseWeaponInBackpackLootMinMax.Max
);
@@ -780,7 +783,7 @@ public class BotLootGenerator(
for (var i = 0; i < randomisedWeaponCount; i++)
{
var generatedWeapon = _botWeaponGenerator.GenerateRandomWeapon(
var generatedWeapon = botWeaponGenerator.GenerateRandomWeapon(
sessionId,
chosenWeaponType,
templateInventory,
@@ -794,13 +797,13 @@ public class BotLootGenerator(
var weaponRootItem = generatedWeapon.Weapon?.FirstOrDefault();
if (weaponRootItem is null)
{
_logger.Error(
logger.Error(
$"Generated loose weapon: {chosenWeaponType} for: {botRole} level: {botLevel} was null, skipping"
);
continue;
}
var result = _botGeneratorHelper.AddItemWithChildrenToEquipmentSlot(
var result = botGeneratorHelper.AddItemWithChildrenToEquipmentSlot(
[equipmentSlot],
weaponRootItem.Id,
weaponRootItem.Template,
@@ -811,9 +814,9 @@ public class BotLootGenerator(
if (result != ItemAddedResult.SUCCESS)
{
if (_logger.IsLogEnabled(LogLevel.Debug))
if (logger.IsLogEnabled(LogLevel.Debug))
{
_logger.Debug(
logger.Debug(
$"Failed to add additional weapon: {weaponRootItem.Id} to bot backpack, reason: {result.ToString()}"
);
}
@@ -855,26 +858,26 @@ public class BotLootGenerator(
}
// Use tryAdd to see if it exists, and automatically add 1
if (!itemSpawnLimits.CurrentLimits.TryAdd(idToCheckFor, 1))
// if it does exist, come in here and increment
// Increment item count with this bot type
if (!itemSpawnLimits.CurrentLimits.TryAdd(idToCheckFor.Value, 1))
// if it does exist, come in here and increment item count with this bot type
{
itemSpawnLimits.CurrentLimits[idToCheckFor]++;
itemSpawnLimits.CurrentLimits[idToCheckFor.Value]++;
}
// Check if over limit
var currentLimitCount = itemSpawnLimits.CurrentLimits[idToCheckFor];
var currentLimitCount = itemSpawnLimits.CurrentLimits[idToCheckFor.Value];
if (
itemSpawnLimits.CurrentLimits[idToCheckFor] > itemSpawnLimits.GlobalLimits[idToCheckFor]
itemSpawnLimits.CurrentLimits[idToCheckFor.Value]
> itemSpawnLimits.GlobalLimits[idToCheckFor.Value]
)
{
// Prevent edge-case of small loot pools + code trying to add limited item over and over infinitely
if (currentLimitCount > currentLimitCount * 10)
{
if (_logger.IsLogEnabled(LogLevel.Debug))
if (logger.IsLogEnabled(LogLevel.Debug))
{
_logger.Debug(
_serverLocalisationService.GetText(
logger.Debug(
serverLocalisationService.GetText(
"bot-item_spawn_limit_reached_skipping_item",
new
{
@@ -911,10 +914,10 @@ public class BotLootGenerator(
var currencyWeight = currencyWeights[moneyItem.Template];
_itemHelper.AddUpdObjectToItem(moneyItem);
itemHelper.AddUpdObjectToItem(moneyItem);
moneyItem.Upd.StackObjectsCount = int.Parse(
_weightedRandomHelper.GetWeightedValue(currencyWeight)
weightedRandomHelper.GetWeightedValue(currencyWeight)
);
}
@@ -926,8 +929,8 @@ public class BotLootGenerator(
/// <param name="ammoItem">Ammo item to randomise</param>
public void RandomiseAmmoStackSize(bool isPmc, TemplateItem itemTemplate, Item ammoItem)
{
var randomSize = _itemHelper.GetRandomisedAmmoStackSize(itemTemplate);
_itemHelper.AddUpdObjectToItem(ammoItem);
var randomSize = itemHelper.GetRandomisedAmmoStackSize(itemTemplate);
itemHelper.AddUpdObjectToItem(ammoItem);
ammoItem.Upd.StackObjectsCount = randomSize;
}
@@ -938,9 +941,9 @@ public class BotLootGenerator(
/// </summary>
/// <param name="botRole">what role does the bot have</param>
/// <returns>Dictionary of tplIds and limit</returns>
public Dictionary<string, double> GetItemSpawnLimitsForBotType(string botRole)
public Dictionary<MongoId, double> GetItemSpawnLimitsForBotType(string botRole)
{
if (_botHelper.IsBotPmc(botRole))
if (botHelper.IsBotPmc(botRole))
{
return _botConfig.ItemSpawnLimits["pmc"];
}
@@ -950,14 +953,14 @@ public class BotLootGenerator(
return _botConfig.ItemSpawnLimits[botRole.ToLowerInvariant()];
}
_logger.Warning(
_serverLocalisationService.GetText(
logger.Warning(
serverLocalisationService.GetText(
"bot-unable_to_find_spawn_limits_fallback_to_defaults",
botRole
)
);
return new Dictionary<string, double>();
return [];
}
/// <summary>
@@ -966,9 +969,9 @@ public class BotLootGenerator(
/// <param name="itemTemplate">item we want to look for in spawn limits</param>
/// <param name="spawnLimits">Limits to check for item</param>
/// <returns>id as string, otherwise undefined</returns>
public string? GetMatchingIdFromSpawnLimits(
public MongoId? GetMatchingIdFromSpawnLimits(
TemplateItem itemTemplate,
Dictionary<string, double> spawnLimits
Dictionary<MongoId, double> spawnLimits
)
{
if (spawnLimits.ContainsKey(itemTemplate.Id))
@@ -19,29 +19,29 @@ namespace SPTarkov.Server.Core.Generators;
[Injectable(InjectionType.Singleton)]
public class BotWeaponGenerator(
ISptLogger<BotWeaponGenerator> _logger,
DatabaseService _databaseService,
ItemHelper _itemHelper,
WeightedRandomHelper _weightedRandomHelper,
BotGeneratorHelper _botGeneratorHelper,
RandomUtil _randomUtil,
BotWeaponGeneratorHelper _botWeaponGeneratorHelper,
BotWeaponModLimitService _botWeaponModLimitService,
BotEquipmentModGenerator _botEquipmentModGenerator,
ServerLocalisationService _serverLocalisationService,
RepairService _repairService,
ICloner _cloner,
ConfigServer _configServer,
ISptLogger<BotWeaponGenerator> logger,
DatabaseService databaseService,
ItemHelper itemHelper,
WeightedRandomHelper weightedRandomHelper,
BotGeneratorHelper botGeneratorHelper,
RandomUtil randomUtil,
BotWeaponGeneratorHelper botWeaponGeneratorHelper,
BotWeaponModLimitService botWeaponModLimitService,
BotEquipmentModGenerator botEquipmentModGenerator,
ServerLocalisationService serverLocalisationService,
RepairService repairService,
ICloner cloner,
ConfigServer configServer,
IEnumerable<IInventoryMagGen> inventoryMagGenComponents
)
{
protected const string _modMagazineSlotId = "mod_magazine";
protected readonly BotConfig _botConfig = _configServer.GetConfig<BotConfig>();
protected readonly BotConfig _botConfig = configServer.GetConfig<BotConfig>();
protected readonly IEnumerable<IInventoryMagGen> _inventoryMagGenComponents = MagGenSetUp(
inventoryMagGenComponents
);
protected readonly PmcConfig _pmcConfig = _configServer.GetConfig<PmcConfig>();
protected readonly RepairConfig _repairConfig = _configServer.GetConfig<RepairConfig>();
protected readonly PmcConfig _pmcConfig = configServer.GetConfig<PmcConfig>();
protected readonly RepairConfig _repairConfig = configServer.GetConfig<RepairConfig>();
protected static List<IInventoryMagGen> MagGenSetUp(IEnumerable<IInventoryMagGen> components)
{
@@ -62,8 +62,8 @@ public class BotWeaponGenerator(
/// <param name="isPmc">Is weapon generated for a pmc</param>
/// <param name="botLevel"></param>
/// <returns>GenerateWeaponResult object</returns>
public GenerateWeaponResult GenerateRandomWeapon(
string sessionId,
public GenerateWeaponResult? GenerateRandomWeapon(
MongoId sessionId,
string equipmentSlot,
BotTypeInventory botTemplateInventory,
string weaponParentId,
@@ -100,11 +100,11 @@ public class BotWeaponGenerator(
{
if (!Enum.TryParse(equipmentSlot, out EquipmentSlots key))
{
_logger.Error($"Unable to parse equipment slot: {equipmentSlot}");
logger.Error($"Unable to parse equipment slot: {equipmentSlot}");
}
var weaponPool = botTemplateInventory.Equipment[key];
return _weightedRandomHelper.GetWeightedValue(weaponPool);
return weightedRandomHelper.GetWeightedValue(weaponPool);
}
/// <summary>
@@ -121,8 +121,8 @@ public class BotWeaponGenerator(
/// <param name="botLevel">The level of the bot.</param>
/// <returns>GenerateWeaponResult object.</returns>
public GenerateWeaponResult? GenerateWeaponByTpl(
string sessionId,
string weaponTpl,
MongoId sessionId,
MongoId weaponTpl,
string slotName,
BotTypeInventory botTemplateInventory,
string weaponParentId,
@@ -133,14 +133,12 @@ public class BotWeaponGenerator(
)
{
var modPool = botTemplateInventory.Mods;
var weaponItemTemplate = _itemHelper.GetItem(weaponTpl).Value;
var weaponItemTemplate = itemHelper.GetItem(weaponTpl).Value;
if (weaponItemTemplate is null)
{
_logger.Error(
_serverLocalisationService.GetText("bot-missing_item_template", weaponTpl)
);
_logger.Error($"WeaponSlot -> {slotName}");
logger.Error(serverLocalisationService.GetText("bot-missing_item_template", weaponTpl));
logger.Error($"WeaponSlot -> {slotName}");
return null;
}
@@ -148,10 +146,10 @@ public class BotWeaponGenerator(
// Find ammo to use when filling magazines/chamber
if (botTemplateInventory.Ammo is null)
{
_logger.Error(
_serverLocalisationService.GetText("bot-no_ammo_found_in_bot_json", botRole)
logger.Error(
serverLocalisationService.GetText("bot-no_ammo_found_in_bot_json", botRole)
);
_logger.Error(_serverLocalisationService.GetText("bot-generation_failed"));
logger.Error(serverLocalisationService.GetText("bot-generation_failed"));
}
var ammoTpl = GetWeightedCompatibleAmmo(botTemplateInventory.Ammo, weaponItemTemplate);
@@ -166,20 +164,20 @@ public class BotWeaponGenerator(
);
// Chance to add randomised weapon enhancement
if (isPmc && _randomUtil.GetChance100(_pmcConfig.WeaponHasEnhancementChancePercent))
if (isPmc && randomUtil.GetChance100(_pmcConfig.WeaponHasEnhancementChancePercent))
// Add buff to weapon root
{
_repairService.AddBuff(_repairConfig.RepairKit.Weapon, weaponWithModsArray[0]);
repairService.AddBuff(_repairConfig.RepairKit.Weapon, weaponWithModsArray[0]);
}
// Add mods to weapon base
if (modPool.ContainsKey(weaponTpl))
{
// Role to treat bot as e.g. pmc/scav/boss
var botEquipmentRole = _botGeneratorHelper.GetBotEquipmentRole(botRole);
var botEquipmentRole = botGeneratorHelper.GetBotEquipmentRole(botRole);
// Different limits if bot is boss vs scav
var modLimits = _botWeaponModLimitService.GetWeaponModLimits(botEquipmentRole);
var modLimits = botWeaponModLimitService.GetWeaponModLimits(botEquipmentRole);
GenerateWeaponRequest generateWeaponModsRequest = new()
{
@@ -199,7 +197,7 @@ public class BotWeaponGenerator(
WeaponStats = new WeaponStats(),
ConflictingItemTpls = [],
};
weaponWithModsArray = _botEquipmentModGenerator.GenerateModsForWeapon(
weaponWithModsArray = botEquipmentModGenerator.GenerateModsForWeapon(
sessionId,
generateWeaponModsRequest
);
@@ -218,7 +216,7 @@ public class BotWeaponGenerator(
);
}
var tempList = _cloner.Clone(
var tempList = cloner.Clone(
weaponWithModsArray.Where(item => item.SlotId == _modMagazineSlotId)
);
// Fill existing magazines to full and sync ammo type
@@ -248,7 +246,7 @@ public class BotWeaponGenerator(
string? ubglAmmoTpl = null;
if (ubglMod is not null)
{
var ubglTemplate = _itemHelper.GetItem(ubglMod.Template).Value;
var ubglTemplate = itemHelper.GetItem(ubglMod.Template).Value;
ubglAmmoTpl = GetWeightedCompatibleAmmo(botTemplateInventory.Ammo, ubglTemplate);
// this can be null - example - FollowerBoarClose2 can have an UBGL but doesn't have the ammo caliber defined in its json
// the default ammo passed from GetWeightCompatibleAmmo can be null
@@ -277,7 +275,7 @@ public class BotWeaponGenerator(
/// <param name="chamberSlotIds">Name of slots to create or add ammo to</param>
protected void AddCartridgeToChamber(
List<Item> weaponWithModsList,
string ammoTemplate,
MongoId ammoTemplate,
List<string> chamberSlotIds
)
{
@@ -318,7 +316,7 @@ public class BotWeaponGenerator(
/// <param name="botRole">For durability values</param>
/// <returns>Base weapon item in a list</returns>
protected List<Item> ConstructWeaponBaseList(
string weaponTemplate,
MongoId weaponTemplate,
string weaponParentId,
string equipmentSlot,
TemplateItem weaponItemTemplate,
@@ -333,7 +331,7 @@ public class BotWeaponGenerator(
Template = weaponTemplate,
ParentId = weaponParentId,
SlotId = equipmentSlot,
Upd = _botGeneratorHelper.GenerateExtraPropertiesForItem(
Upd = botGeneratorHelper.GenerateExtraPropertiesForItem(
weaponItemTemplate,
botRole
),
@@ -351,7 +349,7 @@ public class BotWeaponGenerator(
/// <param name="botRole">Bot role</param>
/// <returns>List of weapon mods</returns>
protected List<Item> GetPresetWeaponMods(
string weaponTemplate,
MongoId weaponTemplate,
string equipmentSlot,
string weaponParentId,
TemplateItem itemTemplate,
@@ -359,8 +357,8 @@ public class BotWeaponGenerator(
)
{
// Invalid weapon generated, fallback to preset
_logger.Warning(
_serverLocalisationService.GetText(
logger.Warning(
serverLocalisationService.GetText(
"bot-weapon_generated_incorrect_using_default",
$"{weaponTemplate} - {itemTemplate.Name}"
)
@@ -369,11 +367,11 @@ public class BotWeaponGenerator(
// TODO: Preset weapons trigger a lot of warnings regarding missing ammo in magazines & such
Preset? preset = null;
foreach (var (_, itemPreset) in _databaseService.GetGlobals().ItemPresets)
foreach (var (_, itemPreset) in databaseService.GetGlobals().ItemPresets)
{
if (itemPreset.Items[0].Template == weaponTemplate)
{
preset = _cloner.Clone(itemPreset);
preset = cloner.Clone(itemPreset);
break;
}
@@ -384,7 +382,7 @@ public class BotWeaponGenerator(
var parentItem = preset.Items[0];
parentItem.ParentId = weaponParentId;
parentItem.SlotId = equipmentSlot;
parentItem.Upd = _botGeneratorHelper.GenerateExtraPropertiesForItem(
parentItem.Upd = botGeneratorHelper.GenerateExtraPropertiesForItem(
itemTemplate,
botRole
);
@@ -393,8 +391,8 @@ public class BotWeaponGenerator(
}
else
{
_logger.Error(
_serverLocalisationService.GetText("bot-missing_weapon_preset", weaponTemplate)
logger.Error(
serverLocalisationService.GetText("bot-missing_weapon_preset", weaponTemplate)
);
}
@@ -411,7 +409,7 @@ public class BotWeaponGenerator(
{
foreach (var mod in weaponItemList)
{
var modTemplate = _itemHelper.GetItem(mod.Template).Value;
var modTemplate = itemHelper.GetItem(mod.Template).Value;
if (!modTemplate.Properties.Slots?.Any() ?? false)
{
continue;
@@ -430,8 +428,8 @@ public class BotWeaponGenerator(
);
if (!hasWeaponSlotItem)
{
_logger.Warning(
_serverLocalisationService.GetText(
logger.Warning(
serverLocalisationService.GetText(
"bot-weapons_required_slot_missing_item",
new
{
@@ -474,22 +472,22 @@ public class BotWeaponGenerator(
botRole
);
var magTemplate = _itemHelper.GetItem(magazineTpl).Value;
var magTemplate = itemHelper.GetItem(magazineTpl.Value).Value;
if (magTemplate is null)
{
_logger.Error(
_serverLocalisationService.GetText("bot-unable_to_find_magazine_item", magazineTpl)
logger.Error(
serverLocalisationService.GetText("bot-unable_to_find_magazine_item", magazineTpl)
);
return;
}
//var isInternalMag = magTemplate.Properties.ReloadMagType == ReloadMode.InternalMagazine;
var ammoTemplate = _itemHelper.GetItem(generatedWeaponResult.ChosenAmmoTemplate);
var ammoTemplate = itemHelper.GetItem(generatedWeaponResult.ChosenAmmoTemplate);
if (!ammoTemplate.Key)
{
_logger.Error(
_serverLocalisationService.GetText(
logger.Error(
serverLocalisationService.GetText(
"bot-unable_to_find_ammo_item",
generatedWeaponResult.ChosenAmmoTemplate
)
@@ -539,7 +537,7 @@ public class BotWeaponGenerator(
{
// Find ubgl mod item + get details of it from db
var ubglMod = weaponMods.FirstOrDefault(x => x.SlotId == "mod_launcher");
var ubglDbTemplate = _itemHelper.GetItem(ubglMod.Template).Value;
var ubglDbTemplate = itemHelper.GetItem(ubglMod.Template).Value;
// Define min/max of how many grenades bot will have
GenerationData ubglMinMax = new()
@@ -549,7 +547,7 @@ public class BotWeaponGenerator(
};
// get ammo template from db
var ubglAmmoDbTemplate = _itemHelper
var ubglAmmoDbTemplate = itemHelper
.GetItem(generatedWeaponResult.ChosenUbglAmmoTemplate)
.Value;
@@ -578,7 +576,7 @@ public class BotWeaponGenerator(
/// <param name="inventory">Player inventory.</param>
protected void AddAmmoToSecureContainer(
int stackCount,
string ammoTpl,
MongoId ammoTpl,
int stackSize,
BotBaseInventory inventory
)
@@ -586,7 +584,7 @@ public class BotWeaponGenerator(
for (var i = 0; i < stackCount; i++)
{
var id = new MongoId();
_botGeneratorHelper.AddItemWithChildrenToEquipmentSlot(
botGeneratorHelper.AddItemWithChildrenToEquipmentSlot(
new HashSet<EquipmentSlots> { EquipmentSlots.SecuredContainer },
id,
ammoTpl,
@@ -611,7 +609,7 @@ public class BotWeaponGenerator(
/// <param name="weaponTemplate">Weapon to get magazine template for.</param>
/// <param name="botRole">The bot type we are getting the magazine for.</param>
/// <returns>Magazine template string.</returns>
protected string GetMagazineTemplateFromWeaponTemplate(
protected MongoId? GetMagazineTemplateFromWeaponTemplate(
List<Item> weaponMods,
TemplateItem weaponTemplate,
string botRole
@@ -631,8 +629,8 @@ public class BotWeaponGenerator(
if (!weaponTemplate.Properties.IsChamberLoad ?? false)
// Shouldn't happen
{
_logger.Warning(
_serverLocalisationService.GetText(
logger.Warning(
serverLocalisationService.GetText(
"bot-weapon_missing_magazine_or_chamber",
new { weaponId = weaponTemplate.Id, botRole }
)
@@ -641,9 +639,9 @@ public class BotWeaponGenerator(
var defaultMagTplId = weaponTemplate.GetWeaponsDefaultMagazineTpl();
if (_logger.IsLogEnabled(LogLevel.Debug))
if (logger.IsLogEnabled(LogLevel.Debug))
{
_logger.Debug(
logger.Debug(
$"[{botRole}] Unable to find magazine for weapon: {weaponTemplate.Id} {weaponTemplate.Name}, using mag template default: {defaultMagTplId}."
);
}
@@ -671,10 +669,10 @@ public class BotWeaponGenerator(
|| cartridgePoolForWeapon?.Count == 0
)
{
if (_logger.IsLogEnabled(LogLevel.Debug))
if (logger.IsLogEnabled(LogLevel.Debug))
{
_logger.Debug(
_serverLocalisationService.GetText(
logger.Debug(
serverLocalisationService.GetText(
"bot-no_caliber_data_for_weapon_falling_back_to_default",
new
{
@@ -725,7 +723,7 @@ public class BotWeaponGenerator(
}
// Get the caliber data from the first compatible round in the magazine
var magazineCaliberData = _itemHelper
var magazineCaliberData = itemHelper
.GetItem(compatibleCartridgesInMagazine.FirstOrDefault())
.Value.Properties.Caliber;
cartridgePoolForWeapon = cartridgePool[magazineCaliberData];
@@ -745,7 +743,7 @@ public class BotWeaponGenerator(
}
}
return _weightedRandomHelper.GetWeightedValue(compatibleCartridges);
return weightedRandomHelper.GetWeightedValue(compatibleCartridges);
}
/// <summary>
@@ -792,7 +790,7 @@ public class BotWeaponGenerator(
return [];
}
var magazineTemplate = _itemHelper.GetItem(
var magazineTemplate = itemHelper.GetItem(
magazineSlot.Props?.Filters.FirstOrDefault()?.Filter?.FirstOrDefault()
?? new MongoId(null)
);
@@ -837,7 +835,7 @@ public class BotWeaponGenerator(
if (!string.IsNullOrEmpty(weaponTemplate.Properties.LinkedWeapon))
{
var ammoInChamber = _itemHelper.GetItem(
var ammoInChamber = itemHelper.GetItem(
weaponTemplate.Properties.Chambers[0].Props.Filters[0].Filter.FirstOrDefault()
);
return !ammoInChamber.Key ? null : ammoInChamber.Value.Properties.Caliber;
@@ -855,14 +853,14 @@ public class BotWeaponGenerator(
protected void FillExistingMagazines(
List<Item> weaponMods,
Item magazine,
string cartridgeTemplate
MongoId cartridgeTemplate
)
{
var magazineTemplate = _itemHelper.GetItem(magazine.Template).Value;
var magazineTemplate = itemHelper.GetItem(magazine.Template).Value;
if (magazineTemplate is null)
{
_logger.Error(
_serverLocalisationService.GetText(
logger.Error(
serverLocalisationService.GetText(
"bot-unable_to_find_magazine_item",
magazine.Template
)
@@ -872,12 +870,12 @@ public class BotWeaponGenerator(
}
// Magazine, usually
var parentItem = _itemHelper.GetItem(magazineTemplate.Parent).Value;
var parentItem = itemHelper.GetItem(magazineTemplate.Parent).Value;
// Revolver shotgun (MTs-255-12) uses a magazine with chambers, not cartridges ("camora_xxx")
// Exchange of the camora ammo is not necessary we could also just check for stackSize > 0 here
// and remove the else
if (_botWeaponGeneratorHelper.MagazineIsCylinderRelated(parentItem.Name))
if (botWeaponGeneratorHelper.MagazineIsCylinderRelated(parentItem.Name))
{
FillCamorasWithAmmo(weaponMods, magazine.Id, cartridgeTemplate);
}
@@ -898,7 +896,7 @@ public class BotWeaponGenerator(
/// <param name="weaponMods">Weapon with children.</param>
/// <param name="ubglMod">Underbarrrel grenade launcher item.</param>
/// <param name="ubglAmmoTpl">Grenade ammo template.</param>
protected void FillUbgl(List<Item> weaponMods, Item ubglMod, string ubglAmmoTpl)
protected void FillUbgl(List<Item> weaponMods, Item ubglMod, MongoId ubglAmmoTpl)
{
weaponMods.Add(
new Item
@@ -922,7 +920,7 @@ public class BotWeaponGenerator(
protected void AddOrUpdateMagazinesChildWithAmmo(
List<Item> weaponWithMods,
Item magazine,
string chosenAmmoTpl,
MongoId chosenAmmoTpl,
TemplateItem magazineTemplate
)
{
@@ -939,7 +937,7 @@ public class BotWeaponGenerator(
List<Item> magazineWithCartridges = [magazine];
// Add cartridges as children to above mag array
_itemHelper.FillMagazineWithCartridge(
itemHelper.FillMagazineWithCartridge(
magazineWithCartridges,
magazineTemplate,
chosenAmmoTpl,
@@ -950,7 +948,7 @@ public class BotWeaponGenerator(
var magazineIndex = weaponWithMods.FindIndex(i => i.Id == magazine.Id); // magazineWithCartridges
if (magazineIndex == -1)
{
_logger.Error(
logger.Error(
$"Unable to add cartridges: {chosenAmmoTpl} to magazine: {magazine.Id} as none found"
);
@@ -969,7 +967,7 @@ public class BotWeaponGenerator(
/// <param name="weaponMods">Weapon mods to find and update camora mod(s) from</param>
/// <param name="magazineId">Magazine id to find and add to</param>
/// <param name="ammoTpl">Ammo template id to hydrate with</param>
protected void FillCamorasWithAmmo(List<Item> weaponMods, string magazineId, string ammoTpl)
protected void FillCamorasWithAmmo(List<Item> weaponMods, MongoId magazineId, MongoId ammoTpl)
{
// for CylinderMagazine we exchange the ammo in the "camoras".
// This might not be necessary since we already filled the camoras with a random whitelisted and compatible ammo type,
@@ -40,7 +40,7 @@ public class CompletionQuestGenerator(
/// </param>
/// <returns>quest type format for "Completion" (see assets/database/templates/repeatableQuests.json)</returns>
public RepeatableQuest? Generate(
string sessionId,
MongoId sessionId,
int pmcLevel,
MongoId traderId,
QuestTypePool questTypePool,
@@ -289,7 +289,7 @@ public class CompletionQuestGenerator(
/// <param name="itemSelection">Filtered item selection</param>
/// <param name="roublesBudget">Budget in roubles</param>
/// <returns>Chosen item template Ids</returns>
protected List<string> GenerateAvailableForFinish(
protected List<MongoId> GenerateAvailableForFinish(
RepeatableQuest quest,
Completion completionConfig,
RepeatableQuestConfig repeatableConfig,
@@ -299,7 +299,7 @@ public class CompletionQuestGenerator(
{
// Store the indexes of items we are asking player to supply
var distinctItemsToRetrieveCount = randomUtil.GetInt(1, completionConfig.UniqueItemCount);
var chosenRequirementItemsTpls = new List<string>();
var chosenRequirementItemsTpls = new List<MongoId>();
var usedItemIndexes = new HashSet<int>();
for (var i = 0; i < distinctItemsToRetrieveCount; i++)
@@ -71,7 +71,7 @@ public class EliminationQuestGenerator(
/// </param>
/// <returns>Object of quest type format for "Elimination" (see assets/database/templates/repeatableQuests.json)</returns>
public RepeatableQuest? Generate(
string sessionId,
MongoId sessionId,
int pmcLevel,
MongoId traderId,
QuestTypePool questTypePool,
@@ -44,7 +44,7 @@ public class ExplorationQuestGenerator(
/// </param>
/// <returns>object of quest type format for "Exploration" (see assets/database/templates/repeatableQuests.json)</returns>
public RepeatableQuest? Generate(
string sessionId,
MongoId sessionId,
int pmcLevel,
MongoId traderId,
QuestTypePool questTypePool,
@@ -8,7 +8,7 @@ namespace SPTarkov.Server.Core.Generators.RepeatableQuestGeneration;
public interface IRepeatableQuestGenerator
{
public RepeatableQuest? Generate(
string sessionId,
MongoId sessionId,
int pmcLevel,
MongoId traderId,
QuestTypePool questTypePool,
@@ -24,9 +24,9 @@ public class PickupQuestGenerator(
HashUtil hashUtil
) : IRepeatableQuestGenerator
{
// TODO: This isn't really implemented well at all, what even is this.
// TODO: This isn't really implemented, not in the current pool.
public RepeatableQuest? Generate(
string sessionId,
MongoId sessionId,
int pmcLevel,
MongoId traderId,
QuestTypePool questTypePool,
@@ -64,7 +64,7 @@ public class RepeatableQuestRewardGenerator(
MongoId traderId,
RepeatableQuestConfig repeatableConfig,
BaseQuestConfig eliminationConfig,
List<string>? rewardTplBlacklist = null
List<MongoId>? rewardTplBlacklist = null
)
{
// Get vars to configure rewards with
@@ -6,9 +6,9 @@ using SPTarkov.Server.Core.Utils;
namespace SPTarkov.Server.Core.Generators.WeaponGen.Implementations;
[Injectable]
public class BarrelInvetoryMagGen(
RandomUtil _randomUtil,
BotWeaponGeneratorHelper _botWeaponGeneratorHelper
public class BarrelInventoryMagGen(
RandomUtil randomUtil,
BotWeaponGeneratorHelper botWeaponGeneratorHelper
) : InventoryMagGen, IInventoryMagGen
{
public int GetPriority()
@@ -28,17 +28,17 @@ public class BarrelInvetoryMagGen(
if (inventoryMagGen.GetAmmoTemplate().Properties.StackMaxRandom == 1)
// Doesn't stack
{
randomisedAmmoStackSize = _randomUtil.GetInt(3, 6);
randomisedAmmoStackSize = randomUtil.GetInt(3, 6);
}
else
{
randomisedAmmoStackSize = _randomUtil.GetInt(
randomisedAmmoStackSize = randomUtil.GetInt(
inventoryMagGen.GetAmmoTemplate().Properties.StackMinRandom.Value,
inventoryMagGen.GetAmmoTemplate().Properties.StackMaxRandom.Value
);
}
_botWeaponGeneratorHelper.AddAmmoIntoEquipmentSlots(
botWeaponGeneratorHelper.AddAmmoIntoEquipmentSlots(
inventoryMagGen.GetAmmoTemplate().Id,
(int)randomisedAmmoStackSize,
inventoryMagGen.GetPmcInventory(),
@@ -1,6 +1,7 @@
using SPTarkov.DI.Annotations;
using SPTarkov.Server.Core.Extensions;
using SPTarkov.Server.Core.Helpers;
using SPTarkov.Server.Core.Models.Common;
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
using SPTarkov.Server.Core.Models.Enums;
using SPTarkov.Server.Core.Models.Utils;
@@ -12,12 +13,12 @@ namespace SPTarkov.Server.Core.Generators.WeaponGen.Implementations;
[Injectable]
public class ExternalInventoryMagGen(
ISptLogger<ExternalInventoryMagGen> _logger,
ItemHelper _itemHelper,
ServerLocalisationService _serverLocalisationService,
BotWeaponGeneratorHelper _botWeaponGeneratorHelper,
BotGeneratorHelper _botGeneratorHelper,
RandomUtil _randomUtil
ISptLogger<ExternalInventoryMagGen> logger,
ItemHelper itemHelper,
ServerLocalisationService serverLocalisationService,
BotWeaponGeneratorHelper botWeaponGeneratorHelper,
BotGeneratorHelper botGeneratorHelper,
RandomUtil randomUtil
) : InventoryMagGen, IInventoryMagGen
{
public int GetPriority()
@@ -39,22 +40,22 @@ public class ExternalInventoryMagGen(
var magTemplate = inventoryMagGen.GetMagazineTemplate();
var magazineTpl = magTemplate.Id;
var weapon = inventoryMagGen.GetWeaponTemplate();
List<string> attemptedMagBlacklist = [];
List<MongoId> attemptedMagBlacklist = [];
var defaultMagazineTpl = weapon.GetWeaponsDefaultMagazineTpl();
var isShotgun = _itemHelper.IsOfBaseclass(weapon.Id, BaseClasses.SHOTGUN);
var isShotgun = itemHelper.IsOfBaseclass(weapon.Id, BaseClasses.SHOTGUN);
var randomizedMagazineCount = _botWeaponGeneratorHelper.GetRandomizedMagazineCount(
var randomizedMagazineCount = botWeaponGeneratorHelper.GetRandomizedMagazineCount(
inventoryMagGen.GetMagCount()
);
for (var i = 0; i < randomizedMagazineCount; i++)
{
var magazineWithAmmo = _botWeaponGeneratorHelper.CreateMagazineWithAmmo(
var magazineWithAmmo = botWeaponGeneratorHelper.CreateMagazineWithAmmo(
magazineTpl,
inventoryMagGen.GetAmmoTemplate().Id,
magTemplate
);
var fitsIntoInventory = _botGeneratorHelper.AddItemWithChildrenToEquipmentSlot(
var fitsIntoInventory = botGeneratorHelper.AddItemWithChildrenToEquipmentSlot(
[EquipmentSlots.TacticalVest, EquipmentSlots.Pockets],
magazineWithAmmo[0].Id,
magazineTpl,
@@ -74,9 +75,9 @@ public class ExternalInventoryMagGen(
// Prevent infinite loop by only allowing 5 attempts at fitting a magazine into inventory
if (fitAttempts > 5)
{
if (_logger.IsLogEnabled(LogLevel.Debug))
if (logger.IsLogEnabled(LogLevel.Debug))
{
_logger.Debug(
logger.Debug(
$"Failed {fitAttempts} times to add magazine {magazineTpl} to bot inventory, stopping"
);
}
@@ -110,12 +111,12 @@ public class ExternalInventoryMagGen(
}
// Set chosen magazine tpl to the weapons default magazine tpl and try to fit into inventory next loop
magazineTpl = defaultMagazineTpl;
magTemplate = _itemHelper.GetItem(magazineTpl).Value;
magazineTpl = defaultMagazineTpl.Value;
magTemplate = itemHelper.GetItem(magazineTpl).Value;
if (magTemplate is null)
{
_logger.Error(
_serverLocalisationService.GetText(
logger.Error(
serverLocalisationService.GetText(
"bot-unable_to_find_default_magazine_item",
magazineTpl
)
@@ -140,9 +141,9 @@ public class ExternalInventoryMagGen(
break;
}
if (_logger.IsLogEnabled(LogLevel.Debug))
if (logger.IsLogEnabled(LogLevel.Debug))
{
_logger.Debug(
logger.Debug(
$"Unable to add additional magazine into bot inventory: vest/pockets for weapon: {weapon.Name}, attempted: {fitAttempts} times. Reason: {fitsIntoInventory}"
);
}
@@ -174,12 +175,12 @@ public class ExternalInventoryMagGen(
/// <param name="magazineBlacklist"> Blacklisted magazines </param>
/// <returns> Item of chosen magazine </returns>
public TemplateItem? GetRandomExternalMagazineForInternalMagazineGun(
string weaponTpl,
List<string> magazineBlacklist
MongoId weaponTpl,
List<MongoId> magazineBlacklist
)
{
// The mag Slot data for the weapon
var magSlot = _itemHelper
var magSlot = itemHelper
.GetItem(weaponTpl)
.Value.Properties.Slots.FirstOrDefault(x => x.Name == "mod_magazine");
if (magSlot is null)
@@ -191,7 +192,7 @@ public class ExternalInventoryMagGen(
var magazinePool = magSlot
.Props.Filters[0]
.Filter.Where(x => !magazineBlacklist.Contains(x))
.Select(x => _itemHelper.GetItem(x).Value);
.Select(x => itemHelper.GetItem(x).Value);
if (magazinePool is null)
{
return null;
@@ -207,6 +208,6 @@ public class ExternalInventoryMagGen(
}
// Randomly chosen external magazine
return _randomUtil.GetArrayValue(externalMagazineOnlyPool);
return randomUtil.GetArrayValue(externalMagazineOnlyPool);
}
}
@@ -5,7 +5,7 @@ using SPTarkov.Server.Core.Models.Enums;
namespace SPTarkov.Server.Core.Generators.WeaponGen.Implementations;
[Injectable]
public class InternalMagazineInventoryMagGen(BotWeaponGeneratorHelper _botWeaponGeneratorHelper)
public class InternalMagazineInventoryMagGen(BotWeaponGeneratorHelper botWeaponGeneratorHelper)
: InventoryMagGen,
IInventoryMagGen
{
@@ -22,11 +22,11 @@ public class InternalMagazineInventoryMagGen(BotWeaponGeneratorHelper _botWeapon
public void Process(InventoryMagGen inventoryMagGen)
{
var bulletCount = _botWeaponGeneratorHelper.GetRandomizedBulletCount(
var bulletCount = botWeaponGeneratorHelper.GetRandomizedBulletCount(
inventoryMagGen.GetMagCount(),
inventoryMagGen.GetMagazineTemplate()
);
_botWeaponGeneratorHelper.AddAmmoIntoEquipmentSlots(
botWeaponGeneratorHelper.AddAmmoIntoEquipmentSlots(
inventoryMagGen.GetAmmoTemplate().Id,
(int)bulletCount,
inventoryMagGen.GetPmcInventory(),
@@ -5,7 +5,7 @@ using SPTarkov.Server.Core.Models.Enums;
namespace SPTarkov.Server.Core.Generators.WeaponGen.Implementations;
[Injectable]
public class UbglExternalMagGen(BotWeaponGeneratorHelper _botWeaponGeneratorHelper)
public class UbglExternalMagGen(BotWeaponGeneratorHelper botWeaponGeneratorHelper)
: InventoryMagGen,
IInventoryMagGen
{
@@ -21,11 +21,11 @@ public class UbglExternalMagGen(BotWeaponGeneratorHelper _botWeaponGeneratorHelp
public void Process(InventoryMagGen inventoryMagGen)
{
var bulletCount = _botWeaponGeneratorHelper.GetRandomizedBulletCount(
var bulletCount = botWeaponGeneratorHelper.GetRandomizedBulletCount(
inventoryMagGen.GetMagCount(),
inventoryMagGen.GetMagazineTemplate()
);
_botWeaponGeneratorHelper.AddAmmoIntoEquipmentSlots(
botWeaponGeneratorHelper.AddAmmoIntoEquipmentSlots(
inventoryMagGen.GetAmmoTemplate().Id,
(int)bulletCount,
inventoryMagGen.GetPmcInventory(),
@@ -6,11 +6,11 @@ namespace SPTarkov.Server.Core.Generators.WeaponGen;
[Injectable]
public class InventoryMagGen()
{
private readonly TemplateItem _ammoTemplate;
private readonly TemplateItem _magazineTemplate;
private readonly GenerationData _magCounts;
private readonly BotBaseInventory _pmcInventory;
private readonly TemplateItem _weaponTemplate;
private readonly TemplateItem? _ammoTemplate;
private readonly TemplateItem? _magazineTemplate;
private readonly GenerationData? _magCounts;
private readonly BotBaseInventory? _pmcInventory;
private readonly TemplateItem? _weaponTemplate;
public InventoryMagGen(
GenerationData magCounts,
@@ -30,26 +30,26 @@ public class InventoryMagGen()
public GenerationData GetMagCount()
{
return _magCounts;
return _magCounts!;
}
public TemplateItem GetMagazineTemplate()
{
return _magazineTemplate;
return _magazineTemplate!;
}
public TemplateItem GetWeaponTemplate()
{
return _weaponTemplate;
return _weaponTemplate!;
}
public TemplateItem GetAmmoTemplate()
{
return _ammoTemplate;
return _ammoTemplate!;
}
public BotBaseInventory GetPmcInventory()
{
return _pmcInventory;
return _pmcInventory!;
}
}
@@ -3,7 +3,7 @@ global using GlobalAmmo = System.Collections.Generic.Dictionary<
System.Collections.Generic.Dictionary<string, double>
>;
global using GlobalMods = System.Collections.Generic.Dictionary<
string,
SPTarkov.Server.Core.Models.Common.MongoId,
System.Collections.Generic.Dictionary<
string,
System.Collections.Generic.HashSet<SPTarkov.Server.Core.Models.Common.MongoId>
@@ -786,7 +786,7 @@ public record Props
public bool? IsBoltCatch { get; set; }
[JsonPropertyName("defMagType")]
public string? DefMagType { get; set; }
public MongoId? DefMagType { get; set; }
[JsonPropertyName("defAmmo")]
public string? DefAmmo { get; set; }
@@ -1,4 +1,5 @@
using System.Text.Json.Serialization;
using SPTarkov.Server.Core.Models.Common;
namespace SPTarkov.Server.Core.Models.Spt.Bots;
@@ -8,8 +9,8 @@ public record ItemSpawnLimitSettings
public Dictionary<string, object>? ExtensionData { get; set; }
[JsonPropertyName("currentLimits")]
public Dictionary<string, double>? CurrentLimits { get; set; }
public Dictionary<MongoId, double>? CurrentLimits { get; set; }
[JsonPropertyName("globalLimits")]
public Dictionary<string, double>? GlobalLimits { get; set; }
public Dictionary<MongoId, double>? GlobalLimits { get; set; }
}
@@ -51,7 +51,7 @@ public record BotConfig : BaseConfig
/// key: itemTpl: value: max item count>
/// </summary>
[JsonPropertyName("itemSpawnLimits")]
public required Dictionary<string, Dictionary<string, double>> ItemSpawnLimits { get; set; }
public required Dictionary<string, Dictionary<MongoId, double>> ItemSpawnLimits { get; set; }
/// <summary>
/// Blacklist/whitelist items on a bot