diff --git a/Core/Models/Spt/Config/BotConfig.cs b/Core/Models/Spt/Config/BotConfig.cs index 9b127583..6e66a316 100644 --- a/Core/Models/Spt/Config/BotConfig.cs +++ b/Core/Models/Spt/Config/BotConfig.cs @@ -427,19 +427,19 @@ public record RandomisationDetails /// Equipment chances /// [JsonPropertyName("equipment")] - public Dictionary? Equipment { get; set; } + public Dictionary? Equipment { get; set; } /// /// Weapon mod chances /// [JsonPropertyName("weaponMods")] - public Dictionary? WeaponMods { get; set; } + public Dictionary? WeaponMods { get; set; } /// /// Equipment mod chances /// [JsonPropertyName("equipmentMods")] - public Dictionary? EquipmentMods { get; set; } + public Dictionary? EquipmentMods { get; set; } [JsonPropertyName("nighttimeChanges")] public NighttimeChanges? NighttimeChanges { get; set; } diff --git a/Core/Services/BotEquipmentFilterService.cs b/Core/Services/BotEquipmentFilterService.cs index ab8f08b2..a3a1e70e 100644 --- a/Core/Services/BotEquipmentFilterService.cs +++ b/Core/Services/BotEquipmentFilterService.cs @@ -1,17 +1,38 @@ using Core.Annotations; +using Core.Helpers; using Core.Models.Eft.Common.Tables; +using Core.Models.Enums; using Core.Models.Spt.Bots; using Core.Models.Spt.Config; +using Core.Models.Utils; using Core.Servers; +using Core.Utils.Extensions; namespace Core.Services; [Injectable(InjectionType.Singleton)] -public class BotEquipmentFilterService( - ConfigServer _configServer -) +public class BotEquipmentFilterService { - protected BotConfig _botConfig = _configServer.GetConfig(); + protected ISptLogger _logger; + protected ProfileHelper _profileHelper; + protected BotHelper _botHelper; + + protected BotConfig _botConfig; + protected Dictionary _botEquipmentConfig; + + public BotEquipmentFilterService( + ISptLogger logger, + BotHelper botHelper, + ProfileHelper profileHelper, + ConfigServer configServer) + { + _logger = logger; + _profileHelper = profileHelper; + _botHelper = botHelper; + + _botConfig = configServer.GetConfig(); + _botEquipmentConfig = _botConfig.Equipment!; + } /// /// Filter a bots data to exclude equipment and cartridges defines in the botConfig @@ -20,13 +41,49 @@ public class BotEquipmentFilterService( /// bots json data to filter /// Level of the bot /// details on how to generate a bot - public void FilterBotEquipment( - string sessionId, - BotType baseBotNode, - int botLevel, - BotGenerationDetails botGenerationDetails) + public void FilterBotEquipment(string sessionId, BotType baseBotNode, int botLevel, BotGenerationDetails botGenerationDetails) { - throw new NotImplementedException(); + var pmcProfile = _profileHelper.GetPmcProfile(sessionId); + + var botRole = botGenerationDetails.IsPmc ?? false ? "pmc" : botGenerationDetails.Role; + var botEquipmentBlacklist = GetBotEquipmentBlacklist(botRole, botLevel); + var botEquipmentWhitelist = GetBotEquipmentWhitelist(botRole, botLevel); + var botWeightingAdjustments = GetBotWeightingAdjustments(botRole, botLevel); + var botWeightingAdjustmentsByPlayerLevel = GetBotWeightingAdjustmentsByPlayerLevel( + botRole, + pmcProfile.Info.Level ?? 0 + ); + + var botEquipConfig = _botEquipmentConfig[botRole]; + var randomisationDetails = _botHelper.GetBotRandomizationDetails(botLevel, botEquipConfig); + + if (botEquipmentBlacklist is not null || botEquipmentWhitelist is not null) + { + FilterEquipment(baseBotNode, botEquipmentBlacklist, botEquipmentWhitelist); + FilterCartridges(baseBotNode, botEquipmentBlacklist, botEquipmentWhitelist); + } + + if (botWeightingAdjustments is not null) + { + AdjustWeighting(botWeightingAdjustments.Equipment, baseBotNode.BotInventory.Equipment); + AdjustWeighting(botWeightingAdjustments.Ammo, baseBotNode.BotInventory.Ammo); + // Dont warn when edited item not found, we're editing usec/bear clothing and they dont have each others clothing + AdjustWeighting(botWeightingAdjustments?.Clothing, baseBotNode.BotAppearance, false); + } + + if (botWeightingAdjustmentsByPlayerLevel is not null) + { + AdjustWeighting(botWeightingAdjustmentsByPlayerLevel.Equipment, baseBotNode.BotInventory.Equipment); + AdjustWeighting(botWeightingAdjustmentsByPlayerLevel.Ammo, baseBotNode.BotInventory.Ammo); + } + + if (randomisationDetails is not null) + { + AdjustChances(randomisationDetails.Equipment, baseBotNode.BotChances.EquipmentChances); + AdjustChances(randomisationDetails.WeaponMods, baseBotNode.BotChances.WeaponModsChances); + AdjustChances(randomisationDetails.EquipmentMods, baseBotNode.BotChances.EquipmentModsChances); + AdjustGenerationChances(randomisationDetails.Generation, baseBotNode.BotGeneration); + } } /// @@ -35,10 +92,18 @@ public class BotEquipmentFilterService( /// Changes to apply /// data to update protected void AdjustChances( - Dictionary equipmentChanges, - object baseValues) + Dictionary equipmentChanges, + Dictionary baseValues) { - throw new NotImplementedException(); + if (equipmentChanges is null) + { + return; + } + + foreach (var itemKey in equipmentChanges) + { + baseValues[itemKey.Key] = equipmentChanges[itemKey.Key]; + } } /// @@ -50,7 +115,16 @@ public class BotEquipmentFilterService( Dictionary generationChanges, Generation baseBotGeneration) { - throw new NotImplementedException(); + if (generationChanges is null) + { + return; + } + + foreach (var itemKey in generationChanges) + { + baseBotGeneration.Items.Get(itemKey.Key).Weights = generationChanges.Get(itemKey.Key).Weights; + baseBotGeneration.Items.Get(itemKey.Key).Whitelist = generationChanges.Get(itemKey.Key).Whitelist; + } } /// @@ -60,7 +134,7 @@ public class BotEquipmentFilterService( /// EquipmentFilters object public EquipmentFilters GetBotEquipmentSettings(string botEquipmentRole) { - throw new NotImplementedException(); + return _botEquipmentConfig[botEquipmentRole]; } /// @@ -88,10 +162,10 @@ public class BotEquipmentFilterService( /// EquipmentBlacklistDetails object public EquipmentFilterDetails? GetBotEquipmentBlacklist(string botRole, double playerLevel) { - var blacklistDetailsForBot = _botConfig.Equipment.GetValueOrDefault(botRole, null); + var blacklistDetailsForBot = _botEquipmentConfig.GetValueOrDefault(botRole, null); - return blacklistDetailsForBot?.Blacklist?.FirstOrDefault( - (equipmentFilter) => playerLevel >= equipmentFilter.LevelRange.Min && playerLevel <= equipmentFilter.LevelRange.Max + return blacklistDetailsForBot?.Blacklist.FirstOrDefault( + equipmentFilter => playerLevel >= equipmentFilter.LevelRange.Min && playerLevel <= equipmentFilter.LevelRange.Max ); } @@ -101,9 +175,13 @@ public class BotEquipmentFilterService( /// Bot type /// Players level /// EquipmentFilterDetails object - protected EquipmentFilterDetails GetBotEquipmentWhitelist(string botRole, int playerLevel) + protected EquipmentFilterDetails? GetBotEquipmentWhitelist(string botRole, int playerLevel) { - throw new NotImplementedException(); + var whitelistDetailsForBot = _botEquipmentConfig.GetValueOrDefault(botRole, null); + + return whitelistDetailsForBot?.Whitelist.FirstOrDefault( + equipmentFilter => playerLevel >= equipmentFilter.LevelRange.Min && playerLevel <= equipmentFilter.LevelRange.Max + ); } /// @@ -112,9 +190,13 @@ public class BotEquipmentFilterService( /// Bot type to get adjustments for /// Level of bot /// Weighting adjustments for bot items - protected WeightingAdjustmentDetails GetBotWeightingAdjustments(string botRole, int botLevel) + protected WeightingAdjustmentDetails? GetBotWeightingAdjustments(string botRole, int botLevel) { - throw new NotImplementedException(); + var weightingDetailsForBot = _botEquipmentConfig.GetValueOrDefault(botRole, null); + + return weightingDetailsForBot?.WeightingAdjustmentsByBotLevel.FirstOrDefault( + x => botLevel >= x.LevelRange.Min && botLevel <= x.LevelRange.Max + ); } /// @@ -123,9 +205,13 @@ public class BotEquipmentFilterService( /// Bot type to get adjustments for /// Level of bot /// Weighting adjustments for bot items - protected WeightingAdjustmentDetails GetBotWeightingAdjustmentsByPlayerLevel(string botRole, int playerlevel) + protected WeightingAdjustmentDetails? GetBotWeightingAdjustmentsByPlayerLevel(string botRole, int playerlevel) { - throw new NotImplementedException(); + var weightingDetailsForBot = _botEquipmentConfig.GetValueOrDefault(botRole, null); + + return weightingDetailsForBot?.WeightingAdjustmentsByBotLevel.FirstOrDefault( + x => playerlevel >= x.LevelRange.Min && playerlevel <= x.LevelRange.Max + ); } /// @@ -135,12 +221,59 @@ public class BotEquipmentFilterService( /// bot .json file to update /// equipment blacklist /// Filtered bot file - protected void FilterEquipment( - BotType baseBotNode, - EquipmentFilterDetails blacklist, - EquipmentFilterDetails whitelist) + protected void FilterEquipment(BotType baseBotNode, EquipmentFilterDetails? blacklist, EquipmentFilterDetails? whitelist) { - throw new NotImplementedException(); + if (whitelist is not null) + { + foreach (var equipmentSlotKey in baseBotNode.BotInventory.Equipment) + { + var botEquipment = baseBotNode.BotInventory.Equipment[equipmentSlotKey.Key]; + + // Skip equipment slot if whitelist doesn't exist / is empty + var whitelistEquipmentForSlot = whitelist.Equipment[equipmentSlotKey.Key.ToString()]; + if (whitelistEquipmentForSlot is null || whitelistEquipmentForSlot.Count == 0) + { + continue; + } + + // Filter equipment slot items to just items in whitelist + baseBotNode.BotInventory.Equipment[equipmentSlotKey.Key] = new Dictionary(); + foreach (var dict in botEquipment) + { + if (whitelistEquipmentForSlot.Contains(dict.Key)) + { + baseBotNode.BotInventory.Equipment[equipmentSlotKey.Key][dict.Key] = botEquipment[dict.Key]; + } + } + } + + return; + } + + if (blacklist is not null) + { + foreach (var equipmentSlotKey in baseBotNode.BotInventory.Equipment) + { + var botEquipment = baseBotNode.BotInventory.Equipment[equipmentSlotKey.Key]; + + // Skip equipment slot if blacklist doesn't exist / is empty + var equipmentSlotBlacklist = blacklist.Equipment[equipmentSlotKey.Key.ToString()]; + if (equipmentSlotBlacklist is null || equipmentSlotBlacklist.Count == 0) + { + continue; + } + + // Filter equipment slot items to just items not in blacklist + baseBotNode.BotInventory.Equipment[equipmentSlotKey.Key] = new Dictionary(); + foreach (var dict in botEquipment) + { + if (!equipmentSlotBlacklist.Contains(dict.Key)) + { + baseBotNode.BotInventory.Equipment[equipmentSlotKey.Key][dict.Key] = botEquipment[dict.Key]; + } + } + } + } } /// @@ -153,8 +286,67 @@ public class BotEquipmentFilterService( /// Filtered bot file protected void FilterCartridges( BotType baseBotNode, - EquipmentFilterDetails blacklist, - EquipmentFilterDetails whitelist) + EquipmentFilterDetails? blacklist, + EquipmentFilterDetails? whitelist) + { + if (whitelist is not null) + { + foreach ( var ammoCaliber in baseBotNode.BotInventory.Ammo) { + var botAmmo = baseBotNode.BotInventory.Ammo[ammoCaliber.Key]; + + // Skip cartridge slot if whitelist doesn't exist / is empty + var whiteListedCartridgesForCaliber = whitelist.Cartridge[ammoCaliber.Key]; + if (whiteListedCartridgesForCaliber is null || whiteListedCartridgesForCaliber.Count == 0) + { + continue; + } + + // Filter calibre slot items to just items in whitelist + baseBotNode.BotInventory.Ammo[ammoCaliber.Key] = new Dictionary(); + foreach ( var dict in botAmmo) { + if (whitelist.Cartridge[ammoCaliber.Key].Contains(dict.Key)) + { + baseBotNode.BotInventory.Ammo[ammoCaliber.Key][dict.Key] = botAmmo[dict.Key]; + } + } + } + + return; + } + + if (blacklist is not null) + { + foreach ( var ammoCaliberKey in baseBotNode.BotInventory.Ammo) { + var botAmmo = baseBotNode.BotInventory.Ammo[ammoCaliberKey.Key]; + + // Skip cartridge slot if blacklist doesn't exist / is empty + var cartridgeCaliberBlacklist = blacklist.Cartridge[ammoCaliberKey.Key]; + if (cartridgeCaliberBlacklist is null || cartridgeCaliberBlacklist.Count == 0) + { + continue; + } + + // Filter cartridge slot items to just items not in blacklist + baseBotNode.BotInventory.Ammo[ammoCaliberKey.Key] = new Dictionary(); + foreach ( var dict in botAmmo) { + if (!cartridgeCaliberBlacklist.Contains(dict.Key)) + { + baseBotNode.BotInventory.Ammo[ammoCaliberKey.Key][dict.Key] = botAmmo[dict.Key]; + } + } + } + } + } + + /// + /// Add/Edit weighting changes to bot items using values from config/bot.json/equipment + /// + /// Weighting change to apply to bot + /// Bot item dictionary to adjust + protected void AdjustWeighting( + AdjustmentDetails weightingAdjustments, + Dictionary> botItemPool, + bool showEditWarnings = true) { throw new NotImplementedException(); } @@ -166,7 +358,20 @@ public class BotEquipmentFilterService( /// Bot item dictionary to adjust protected void AdjustWeighting( AdjustmentDetails weightingAdjustments, - Dictionary botItemPool, + Dictionary> botItemPool, + bool showEditWarnings = true) + { + throw new NotImplementedException(); + } + + /// + /// Add/Edit weighting changes to bot items using values from config/bot.json/equipment + /// + /// Weighting change to apply to bot + /// Bot item dictionary to adjust + protected void AdjustWeighting( + AdjustmentDetails weightingAdjustments, + Appearance botItemPool, bool showEditWarnings = true) { throw new NotImplementedException();