BotGen fixes

This commit is contained in:
Chomp
2025-01-20 21:26:03 +00:00
parent 59cbaa6b02
commit e56b0a37ef
14 changed files with 193 additions and 130 deletions
@@ -147,7 +147,7 @@ public class BotEquipmentModGenerator(
// Choose random mod from pool and check its compatibility
string modTpl = null;
var found = false;
var exhaustableModPool = CreateExhaustableArray(modPoolToChooseFrom);
var exhaustableModPool = CreateExhaustableArray(modPoolToChooseFrom.ToList());
while (exhaustableModPool.HasValues())
{
modTpl = exhaustableModPool.GetRandomValue();
@@ -220,7 +220,7 @@ public class BotEquipmentModGenerator(
/// <param name="armorItem">The armor items db template</param>
/// <returns>Array of plate tpls to choose from</returns>
public FilterPlateModsForSlotByLevelResult FilterPlateModsForSlotByLevel(GenerateEquipmentProperties settings, string modSlot,
List<string> existingPlateTplPool, TemplateItem armorItem)
HashSet<string> existingPlateTplPool, TemplateItem armorItem)
{
throw new NotImplementedException();
}
@@ -359,8 +359,7 @@ public class BotEquipmentModGenerator(
continue;
}
if (
IsModValidForSlot(modToAdd, modsParentSlot, modSlot, request.ParentTemplate, request.BotData.Role)
if (!IsModValidForSlot(modToAdd, modsParentSlot, modSlot, request.ParentTemplate, request.BotData.Role)
)
{
continue;
@@ -837,7 +836,7 @@ public class BotEquipmentModGenerator(
);
if (onlyLowProfileGasBlocks.Count() > 0)
{
modPool = onlyLowProfileGasBlocks.ToList();
modPool = onlyLowProfileGasBlocks.ToHashSet();
}
}
else if (request.WeaponStats.HasRearIronSight ?? false && modPool.Count() > 1)
@@ -848,7 +847,7 @@ public class BotEquipmentModGenerator(
);
if (onlyHighProfileGasBlocks.Count() > 0)
{
modPool = onlyHighProfileGasBlocks.ToList();
modPool = onlyHighProfileGasBlocks.ToHashSet();
}
}
}
@@ -860,7 +859,7 @@ public class BotEquipmentModGenerator(
request.RandomisationSettings.MinimumMagazineSize is not null
)
{
modPool = GetFilterdMagazinePoolByCapacity(request, modPool).ToList();
modPool = GetFilterdMagazinePoolByCapacity(request, modPool).ToHashSet();
}
// Pick random mod that's compatible
@@ -919,7 +918,7 @@ public class BotEquipmentModGenerator(
/// <param name="modPool">Pool of magazine tpls to filter</param>
/// <returns>Filtered pool of magazine tpls</returns>
/// <exception cref="NotImplementedException"></exception>
public IEnumerable<string> GetFilterdMagazinePoolByCapacity(ModToSpawnRequest modSpawnRequest, List<string> modPool)
public IEnumerable<string> GetFilterdMagazinePoolByCapacity(ModToSpawnRequest modSpawnRequest, HashSet<string> modPool)
{
var weaponTpl = modSpawnRequest.Weapon[0].Template;
modSpawnRequest.RandomisationSettings.MinimumMagazineSize.TryGetValue(weaponTpl, out var minMagSizeFromSettings);
@@ -950,7 +949,7 @@ public class BotEquipmentModGenerator(
/// <param name="weapon">Array of weapon items chosen item will be added to</param>
/// <param name="modSlotName">Name of slot picked mod will be placed into</param>
/// <returns>Chosen weapon details</returns>
public ChooseRandomCompatibleModResult GetCompatibleWeaponModTplForSlotFromPool(ModToSpawnRequest request, List<string> modPool, Slot parentSlot,
public ChooseRandomCompatibleModResult GetCompatibleWeaponModTplForSlotFromPool(ModToSpawnRequest request, HashSet<string> modPool, Slot parentSlot,
ModSpawn? choiceTypeEnum, List<Item> weapon, string modSlotName)
{
// Filter out incompatible mods from pool
@@ -985,7 +984,7 @@ public class BotEquipmentModGenerator(
public ChooseRandomCompatibleModResult GetCompatibleModFromPool(List<string> modPool, ModSpawn? modSpawnType, List<Item> weapon)
{
// Create exhaustable pool to pick mod item from
var exhaustableModPool = CreateExhaustableArray(modPool);
var exhaustableModPool = CreateExhaustableArray(modPool.ToList());
// Create default response if no compatible item is found below
ChooseRandomCompatibleModResult chosenModResult = new()
@@ -1063,9 +1062,9 @@ public class BotEquipmentModGenerator(
return chosenModResult;
}
public ExhaustableArray<T> CreateExhaustableArray<T>(List<T> itemsToAddToArray) // TODO: this wont likely be needed, reimplement for C#
public ExhaustableArray<T> CreateExhaustableArray<T>(List<T> itemsToAddToArray)
{
return new ExhaustableArray<T>(itemsToAddToArray, _randomUtil, _cloner);
return new ExhaustableArray<T>(itemsToAddToArray.ToList(), _randomUtil, _cloner);
}
/// <summary>
@@ -1074,7 +1073,7 @@ public class BotEquipmentModGenerator(
/// <param name="modPool"></param>
/// <param name="tplBlacklist">Tpls that are incompatible and should not be used</param>
/// <returns>string array of compatible mod tpls with weapon</returns>
public List<string> GetFilteredModPool(List<string> modPool, List<string> tplBlacklist)
public List<string> GetFilteredModPool(HashSet<string> modPool, List<string> tplBlacklist)
{
return modPool.Where((tpl) => !tplBlacklist.Contains(tpl)).ToList();
}
@@ -1088,7 +1087,7 @@ public class BotEquipmentModGenerator(
/// <param name="request"></param>
/// <param name="weaponTemplate">Mods root parent (weapon/equipment)</param>
/// <returns>Array of mod tpls</returns>
public List<string> GetModPoolForSlot(ModToSpawnRequest request, TemplateItem weaponTemplate)
public HashSet<string> GetModPoolForSlot(ModToSpawnRequest request, TemplateItem weaponTemplate)
{
// Mod is flagged as being default only, try and find it in globals
if (request.ModSpawnResult == ModSpawn.DEFAULT_MOD)
@@ -1105,7 +1104,7 @@ public class BotEquipmentModGenerator(
return request.ItemModPool[request.ModSlot];
}
public List<string> GetModPoolForDefaultSlot(ModToSpawnRequest request, TemplateItem weaponTemplate)
public HashSet<string> GetModPoolForDefaultSlot(ModToSpawnRequest request, TemplateItem weaponTemplate)
{
var matchingModFromPreset = GetMatchingModFromPreset(request, weaponTemplate);
if (matchingModFromPreset is null)
@@ -1166,7 +1165,7 @@ public class BotEquipmentModGenerator(
var newListOfModsForSlot = parentSlotCompatibleItems.Where((tpl) => !request.ConflictingItemTpls.Contains(tpl));
if (newListOfModsForSlot.Count() > 0)
{
return newListOfModsForSlot.ToList();
return newListOfModsForSlot.ToHashSet();
}
}
@@ -1353,7 +1352,7 @@ public class BotEquipmentModGenerator(
/// <param name="modTemplate">db object for modItem we get compatible mods from</param>
/// <param name="modPool">Pool of mods we are adding to</param>
/// <param name="botEquipBlacklist">A blacklist of items that cannot be picked</param>
public void AddCompatibleModsForProvidedMod(string desiredSlotName, TemplateItem modTemplate, Dictionary<string, Dictionary<string, List<string>>> modPool,
public void AddCompatibleModsForProvidedMod(string desiredSlotName, TemplateItem modTemplate, Dictionary<string, Dictionary<string, HashSet<string>>> modPool,
EquipmentFilterDetails botEquipBlacklist)
{
var desiredSlotObject = modTemplate.Properties.Slots?.FirstOrDefault((slot) => slot.Name.Contains(desiredSlotName));
@@ -1369,7 +1368,7 @@ public class BotEquipmentModGenerator(
}
// Filter mods
var filteredMods = FilterModsByBlacklist(supportedSubMods, botEquipBlacklist, desiredSlotName);
var filteredMods = FilterModsByBlacklist(supportedSubMods.ToHashSet(), botEquipBlacklist, desiredSlotName);
if (!filteredMods.Any())
{
_logger.Warning(
@@ -1390,7 +1389,7 @@ public class BotEquipmentModGenerator(
modPool[modTemplate.Id] = new();
}
modPool[modTemplate.Id][desiredSlotObject.Name] = supportedSubMods;
modPool[modTemplate.Id][desiredSlotObject.Name] = supportedSubMods.ToHashSet();
}
/// <summary>
@@ -1400,7 +1399,7 @@ public class BotEquipmentModGenerator(
/// <param name="modSlot">Slot item should fit in</param>
/// <param name="botEquipBlacklist">Equipment that should not be picked</param>
/// <returns>Array of compatible items for that slot</returns>
public List<string> GetDynamicModPool(string parentItemId, string modSlot, EquipmentFilterDetails botEquipBlacklist)
public HashSet<string> GetDynamicModPool(string parentItemId, string modSlot, EquipmentFilterDetails botEquipBlacklist)
{
var modsFromDynamicPool = _cloner.Clone(
_botEquipmentModPoolService.GetCompatibleModsForWeaponSlot(parentItemId, modSlot)
@@ -1424,7 +1423,7 @@ public class BotEquipmentModGenerator(
/// <param name="botEquipBlacklist">Equipment blacklist</param>
/// <param name="modSlot">Slot mods belong to</param>
/// <returns>Filtered array of mod tpls</returns>
public List<string> FilterModsByBlacklist(List<string> allowedMods, EquipmentFilterDetails? botEquipBlacklist, string modSlot)
public HashSet<string> FilterModsByBlacklist(HashSet<string> allowedMods, EquipmentFilterDetails? botEquipBlacklist, string modSlot)
{
// No blacklist, nothing to filter out
if (botEquipBlacklist is null)
@@ -1432,12 +1431,12 @@ public class BotEquipmentModGenerator(
return allowedMods;
}
var result = new List<string>();
var result = new HashSet<string>();
// Get item blacklist and mod equipment blacklist as one array
botEquipBlacklist.Equipment.TryGetValue(modSlot, out var equipmentBlacklistValues);
var blacklist = _itemFilterService.GetBlacklistedItems().Concat(equipmentBlacklistValues ?? []);
result = allowedMods.Where((tpl) => !blacklist.Contains(tpl)).ToList();
result = allowedMods.Where((tpl) => !blacklist.Contains(tpl)).ToHashSet();
return result;
}
@@ -1452,7 +1451,7 @@ public class BotEquipmentModGenerator(
/// <param name="modPool">ModPool which should include available cartridges</param>
/// <param name="cylinderMagParentId">The CylinderMagazine's UID</param>
/// <param name="cylinderMagTemplate">The CylinderMagazine's template</param>
public void FillCamora(List<Item> items, Dictionary<string, Dictionary<string, List<string>>> modPool, string cylinderMagParentId,
public void FillCamora(List<Item> items, Dictionary<string, Dictionary<string, HashSet<string>>> modPool, string cylinderMagParentId,
TemplateItem cylinderMagTemplate)
{
var itemModPool = modPool[cylinderMagTemplate.Id];
@@ -1474,7 +1473,7 @@ public class BotEquipmentModGenerator(
modPool[cylinderMagTemplate.Id] = new();
foreach (var camora in camoraSlots)
{
modPool[cylinderMagTemplate.Id][camora.Name] = camora.Props.Filters?[0].Filter;
modPool[cylinderMagTemplate.Id][camora.Name] = camora.Props.Filters?[0].Filter.ToHashSet();
}
itemModPool = modPool[cylinderMagTemplate.Id];
@@ -1485,12 +1484,12 @@ public class BotEquipmentModGenerator(
var camoraFirstSlot = "camora_000";
if (itemModPool.TryGetValue(modSlot, out var value))
{
exhaustableModPool = CreateExhaustableArray(value);
exhaustableModPool = CreateExhaustableArray(value.ToList());
}
else if (itemModPool.ContainsKey(camoraFirstSlot))
{
modSlot = camoraFirstSlot;
exhaustableModPool = CreateExhaustableArray(MergeCamoraPools(itemModPool));
exhaustableModPool = CreateExhaustableArray(MergeCamoraPools(itemModPool).ToList());
}
else
{
@@ -1531,12 +1530,12 @@ public class BotEquipmentModGenerator(
/// </summary>
/// <param name="camorasWithShells">Dictionary of camoras we want to merge into one array</param>
/// <returns>String array of shells for multiple camora sources</returns>
public List<string> MergeCamoraPools(Dictionary<string, List<string>> camorasWithShells)
public HashSet<string> MergeCamoraPools(Dictionary<string, HashSet<string>> camorasWithShells)
{
return camorasWithShells
.SelectMany(shellKvP => shellKvP.Value)
.Distinct()
.ToList();
.ToHashSet();
}
/// <summary>
@@ -1548,7 +1547,7 @@ public class BotEquipmentModGenerator(
/// <param name="scopes">Full scope pool</param>
/// <param name="botWeaponSightWhitelist">Whitelist of scope types by weapon base type</param>
/// <returns>Array of scope tpls that have been filtered to just ones allowed for that weapon type</returns>
public List<string> FilterSightsByWeaponType(Item weapon, List<string> scopes, Dictionary<string, List<string>> botWeaponSightWhitelist)
public HashSet<string> FilterSightsByWeaponType(Item weapon, HashSet<string> scopes, Dictionary<string, List<string>> botWeaponSightWhitelist)
{
var weaponDetails = _itemHelper.GetItem(weapon.Template);
@@ -1562,7 +1561,7 @@ public class BotEquipmentModGenerator(
}
// Filter items that are not directly scopes OR mounts that do not hold the type of scope we allow for this weapon type
List<string> filteredScopesAndMods = [];
HashSet<string> filteredScopesAndMods = [];
foreach (var item in scopes)
{
// Mods is a scope, check base class is allowed
@@ -201,7 +201,7 @@ public class BotInventoryGenerator(
Inventory = botInventory,
BotEquipmentConfig = botEquipConfig,
RandomisationDetails = randomistionDetails,
GeneratingPlayerLevel = pmcProfile.Info.Level,
GeneratingPlayerLevel = pmcProfile.Info.Level
}
);
}
@@ -222,7 +222,7 @@ public class BotInventoryGenerator(
Inventory = botInventory,
BotEquipmentConfig = botEquipConfig,
RandomisationDetails = randomistionDetails,
GenerateModsBlacklist = [ItemTpl.POCKETS_1X4_TUE],
GenerateModsBlacklist = [ItemTpl.POCKETS_1X4_TUE, ItemTpl.POCKETS_LARGE],
GeneratingPlayerLevel = pmcProfile.Info.Level,
}
);
@@ -483,7 +483,7 @@ public class BotInventoryGenerator(
// Does item have slots for sub-mods to be inserted into
if (pickedItemDb.Properties?.Slots?.Count > 0
&& settings?.GenerateModsBlacklist is not null
&& settings.GenerateModsBlacklist.Contains(pickedItemDb.Id))
&& !settings.GenerateModsBlacklist.Contains(pickedItemDb.Id))
{
var childItemsToAdd = _botEquipmentModGenerator.GenerateModsForEquipment(
[item],
@@ -512,17 +512,20 @@ public class BotInventoryGenerator(
/// <param name="itemTpl">Item mod pool is being retrieved and filtered</param>
/// <param name="equipmentBlacklist">Blacklist to filter mod pool with</param>
/// <returns>Filtered pool of mods</returns>
public Dictionary<string, List<string>> GetFilteredDynamicModsForItem(string itemTpl, Dictionary<string, List<string>> equipmentBlacklist)
public Dictionary<string, HashSet<string>> GetFilteredDynamicModsForItem(string itemTpl, Dictionary<string, List<string>> equipmentBlacklist)
{
var modPool = _botEquipmentModPoolService.GetModsForGearSlot(itemTpl);
foreach (var modSlot in modPool.Keys ?? Enumerable.Empty<string>())
foreach (var modSlot in modPool)
{
var blacklistedMods = equipmentBlacklist[modSlot] ?? [];
var filteredMods = modPool[modSlot].Where((slotName) => !blacklistedMods.Contains(slotName));
// Get blacklist
equipmentBlacklist.TryGetValue(modSlot.Key, out var blacklistedMods);
// Get mods not on blacklist
var filteredMods = modPool[modSlot.Key].Where((slotName) => !(blacklistedMods ?? []).Contains(slotName));
if (filteredMods.Any())
{
modPool[modSlot] = filteredMods.ToList();
modPool[modSlot.Key] = filteredMods.ToHashSet();
}
}
+8 -11
View File
@@ -446,7 +446,7 @@ public class BotLootGenerator(
return;
}
var weightedItemTpl = _weightedRandomHelper.GetWeightedValue<string>(pool);
var weightedItemTpl = _weightedRandomHelper.GetWeightedValue(pool);
var (key, itemToAddTemplate) = _itemHelper.GetItem(weightedItemTpl);
if (!key)
@@ -456,16 +456,13 @@ public class BotLootGenerator(
continue;
}
if (itemSpawnLimits is not null)
if (itemSpawnLimits is not null && ItemHasReachedSpawnLimit(itemToAddTemplate, botRole, itemSpawnLimits))
{
if (ItemHasReachedSpawnLimit(itemToAddTemplate, botRole, itemSpawnLimits))
{
// Remove item from pool to prevent it being picked again
pool.Remove(weightedItemTpl);
// Remove item from pool to prevent it being picked again
pool.Remove(weightedItemTpl);
i--;
continue;
}
i--;
continue;
}
var newRootItemId = _hashUtil.Generate();
@@ -541,9 +538,9 @@ public class BotLootGenerator(
if (fitItemIntoContainerAttempts >= 4)
{
_logger.Debug(
$"Failed placing item: {i} of: {totalItemCount} items into: {botRole} " +
$"Failed placing item: {itemToAddTemplate.Name}: {i} of: {totalItemCount} items into: {botRole} " +
$"containers: {string.Join(",", equipmentSlots)}. Tried: {fitItemIntoContainerAttempts} " +
$"times, reason: {itemAddedResult.ToString()}, skipping"
$"times, reason: {itemAddedResult}, skipping"
);
break;
@@ -348,7 +348,7 @@ public class BotWeaponGenerator(
}
// Iterate over required slots in db item, check mod exists for that slot
foreach (var modSlotTemplate in modTemplate.Properties.Slots.Where((slot) => slot.Required ?? false))
foreach (var modSlotTemplate in modTemplate.Properties.Slots?.Where((slot) => slot.Required.GetValueOrDefault(false)) ?? [])
{
var slotName = modSlotTemplate.Name;
var hasWeaponSlotItem = weaponItemList.Any(
@@ -553,9 +553,7 @@ public class BotWeaponGenerator(
protected string GetWeightedCompatibleAmmo(Dictionary<string, Dictionary<string, double>> cartridgePool, TemplateItem weaponTemplate)
{
var desiredCaliber = GetWeaponCaliber(weaponTemplate);
var cartridgePoolForWeapon = cartridgePool[desiredCaliber];
if (cartridgePoolForWeapon is null || cartridgePoolForWeapon?.Count == 0)
if (!cartridgePool.TryGetValue(desiredCaliber, out var cartridgePoolForWeapon) && cartridgePoolForWeapon.Keys.Count > 0)
{
_logger.Debug(
_localisationService.GetText(
@@ -1,4 +1,4 @@
using SptCommon.Annotations;
using SptCommon.Annotations;
using Core.Helpers;
using Core.Models.Eft.Common.Tables;
using Core.Models.Enums;
@@ -31,7 +31,7 @@ public class ExternalInventoryMagGen(
public void Process(InventoryMagGen inventoryMagGen)
{
// Cout of attempts to fit a magazine into bot inventory
// Count of attempts to fit a magazine into bot inventory
var fitAttempts = 0;
// Magazine Db template
@@ -41,6 +41,7 @@ public class ExternalInventoryMagGen(
List<string> attemptedMagBlacklist = [];
var defaultMagazineTpl = _botWeaponGeneratorHelper.GetWeaponsDefaultMagazineTpl(weapon);
var randomizedMagazineCount = _botWeaponGeneratorHelper.GetRandomizedMagazineCount(inventoryMagGen.GetMagCount());
var isShotgun = _itemHelper.IsOfBaseclass(weapon.Id, BaseClasses.SHOTGUN);
for (var i = 0; i < randomizedMagazineCount; i++)
{
var magazineWithAmmo = _botWeaponGeneratorHelper.CreateMagazineWithAmmo(
@@ -99,16 +100,23 @@ public class ExternalInventoryMagGen(
break;
}
// Edge case - some weapons (SKS) have an internal magazine as default, choose random non-internal magazine to add to bot instead
// Edge case - some weapons (SKS + shotguns) have an internal magazine as default, choose random non-internal magazine to add to bot instead
if (magTemplate.Properties.ReloadMagType == "InternalMagazine")
{
var result = GetRandomExternalMagazineForInternalMagazineGun(
inventoryMagGen.GetWeaponTemplate().Id,
attemptedMagBlacklist
);
if (result?.Id is null)
{
_logger.Debug($"Unable to add additional magazine into bot inventory for weapon: {weapon.Name}, attempted: {fitAttempts} times");
// Highly likely shotgun has no external mags
if (isShotgun)
{
break;
}
_logger.Debug($"Unable to add additional magazine into bot inventory: vest/pockets for weapon: {weapon.Name}, attempted: {fitAttempts} times. Reason: {fitsIntoInventory}");
break;
}
+1 -1
View File
@@ -582,7 +582,7 @@ public class BotGeneratorHelper(
{
parentItem.ParentId = container.Id;
parentItem.SlotId = slotGrid.Name;
parentItem.Location = new ItemLocation()
parentItem.Location = new ItemLocation
{
X = findSlotResult.X,
Y = findSlotResult.Y,
+16 -12
View File
@@ -28,39 +28,38 @@ public class ContainerHelper
return new FindSlotResult(false);
}
// Down
// Down = y
for (var y = 0; y < limitY; y++)
{
// Across
if (container2D[y].All((x) => x == 1))
{
// Every item in row is full, skip row
continue;
}
// Try each slot on the row (across = x)
for (var x = 0; x < limitX; x++)
{
var foundSlot = LocateSlot(container2D, containerX, containerY, x, y, itemWidth, itemHeight);
if (foundSlot)
{
return new FindSlotResult(true, x, y, rotation);
}
// Failed to find slot, rotate item and try again
if (!foundSlot && itemWidth * itemHeight > 1)
if (!foundSlot && ItemBiggerThan1X1(itemWidth, itemHeight))
{
// Bigger than 1x1
// Bigger than 1x1, try rotating
foundSlot = LocateSlot(container2D, containerX, containerY, x, y, itemHeight, itemWidth); // Height/Width swapped
if (foundSlot)
{
// Found a slot for it when rotated
rotation = true;
return new FindSlotResult(true, x, y, rotation);
}
}
if (!foundSlot)
{
// Didn't fit this hole, try again
continue;
}
return new FindSlotResult(true, x, y, rotation);
}
}
@@ -68,6 +67,11 @@ public class ContainerHelper
return new FindSlotResult(false);
}
private bool ItemBiggerThan1X1(int itemWidth, int itemHeight)
{
return itemWidth * itemHeight > 1;
}
/// <summary>
/// Find a slot inside a container an item can be placed in
/// </summary>
@@ -163,6 +163,11 @@ public class DurabilityLimitsHelper(
return _botConfig.Durability.Default.Weapon.LowestMax;
}
if (botRole == "pmc")
{
return _botConfig.Durability.Pmc.Weapon.LowestMax;
}
_botConfig.Durability.BotDurabilities.TryGetValue(botRole, out var durability);
return durability.Weapon.LowestMax;
}
@@ -174,6 +179,11 @@ public class DurabilityLimitsHelper(
return _botConfig.Durability.Default.Weapon.HighestMax;
}
if (botRole == "pmc")
{
return _botConfig.Durability.Pmc.Weapon.HighestMax;
}
_botConfig.Durability.BotDurabilities.TryGetValue(botRole, out var durability);
return durability.Weapon.HighestMax;
}
@@ -211,6 +221,11 @@ public class DurabilityLimitsHelper(
return _botConfig.Durability.Default.Weapon.MinDelta;
}
if (botRole == "pmc")
{
return _botConfig.Durability.Pmc.Weapon.MinDelta;
}
_botConfig.Durability.BotDurabilities.TryGetValue(botRole, out var value);
return value.Weapon.MinDelta;
@@ -223,6 +238,11 @@ public class DurabilityLimitsHelper(
return _botConfig.Durability.Default.Weapon.HighestMax;
}
if (botRole == "pmc")
{
return _botConfig.Durability.Pmc.Weapon.HighestMax;
}
_botConfig.Durability.BotDurabilities.TryGetValue(botRole, out var value);
return value.Weapon.HighestMax;
@@ -235,6 +255,11 @@ public class DurabilityLimitsHelper(
return _botConfig.Durability.Default.Armor.MinDelta;
}
if (botRole == "pmc")
{
return _botConfig.Durability.Pmc.Armor.MinDelta;
}
_botConfig.Durability.BotDurabilities.TryGetValue(botRole, out var value);
return value.Armor.MinDelta;
@@ -247,6 +272,11 @@ public class DurabilityLimitsHelper(
return _botConfig.Durability.Default.Armor.MaxDelta;
}
if (botRole == "pmc")
{
return _botConfig.Durability.Pmc.Armor.MaxDelta;
}
_botConfig.Durability.BotDurabilities.TryGetValue(botRole, out var value);
return value.Armor.MaxDelta;
@@ -259,6 +289,11 @@ public class DurabilityLimitsHelper(
return _botConfig.Durability.Default.Armor.MinLimitPercent;
}
if (botRole == "pmc")
{
return _botConfig.Durability.Pmc.Armor.MinLimitPercent;
}
_botConfig.Durability.BotDurabilities.TryGetValue(botRole, out var value);
return value.Armor.MinLimitPercent;
@@ -271,6 +306,11 @@ public class DurabilityLimitsHelper(
return _botConfig.Durability.Default.Weapon.MinLimitPercent;
}
if (botRole == "pmc")
{
return _botConfig.Durability.Pmc.Weapon.MinLimitPercent;
}
_botConfig.Durability.BotDurabilities.TryGetValue(botRole, out var value);
return value.Weapon.MinLimitPercent;
+13 -3
View File
@@ -336,7 +336,17 @@ public class InventoryHelper(
/// <returns>Two-dimensional representation of container</returns>
protected int[][] GetBlankContainerMap(int containerH, int containerY)
{
return Enumerable.Repeat(Enumerable.Repeat(0, containerH).ToArray(), containerY).ToArray();
//var x = new int[containerY][];
//for (int i = 0; i < containerY; i++)
//{
// x[i] = new int[containerH];
//}
//return x;
return Enumerable.Range(0, containerY)
.Select(i => new int[containerH])
.ToArray();
}
/// <summary>
@@ -395,12 +405,12 @@ public class InventoryHelper(
}
// Fill the corresponding cells in the container map to show the slot is taken
Array.Fill(containerRow, 1, itemLocation.X.Value, fillTo.Value);
Array.Fill(containerRow, 1, itemLocation.X.Value, fW);
} catch (Exception ex) {
_logger.Error(
_localisationService.GetText("inventory-unable_to_fill_container", new {
id = item.Id,
error = ex.Message
error = $"{ex.Message} {ex.StackTrace}"
})
);
}
@@ -1,2 +1,2 @@
global using GlobalAmmo = System.Collections.Generic.Dictionary<string, System.Collections.Generic.Dictionary<string, double>>;
global using GlobalMods = System.Collections.Generic.Dictionary<string, System.Collections.Generic.Dictionary<string, System.Collections.Generic.List<string>>>;
global using GlobalAmmo = System.Collections.Generic.Dictionary<string, System.Collections.Generic.Dictionary<string, double>>;
global using GlobalMods = System.Collections.Generic.Dictionary<string, System.Collections.Generic.Dictionary<string, System.Collections.Generic.HashSet<string>>>;
@@ -8,7 +8,7 @@ public record FilterPlateModsForSlotByLevelResult
public Result? Result { get; set; }
[JsonPropertyName("plateModTpls")]
public List<string>? PlateModTemplates { get; set; }
public HashSet<string>? PlateModTemplates { get; set; }
}
public enum Result
@@ -38,7 +38,7 @@ public record ModToSpawnRequest
/// Pool of items to pick from
/// </summary>
[JsonPropertyName("itemModPool")]
public Dictionary<string, List<string>>? ItemModPool { get; set; }
public Dictionary<string, HashSet<string>>? ItemModPool { get; set; }
/// <summary>
/// List with only weapon tpl in it, ready for mods to be added
@@ -5,7 +5,6 @@ using Core.Helpers;
using Core.Servers;
using Core.Models.Enums;
using Core.Models.Spt.Config;
using System.Collections.Generic;
namespace Core.Services;
@@ -18,7 +17,8 @@ public class BotEquipmentModPoolService
protected LocalisationService _localisationService;
protected ConfigServer _configServer;
protected bool _weaponPoolGenerated = false;
protected bool _weaponPoolGenerated;
protected bool _armorPoolGenerated;
protected Dictionary<string, Dictionary<string, HashSet<string>>> _weaponModPool;
protected Dictionary<string, Dictionary<string, HashSet<string>>> _gearModPool;
protected BotConfig _botConfig;
@@ -110,34 +110,6 @@ public class BotEquipmentModPoolService
}
}
}
//foreach (var slot in item.Properties.Slots)
//{
// var itemsThatFit = slot.Props.Filters[0].Filter;
// foreach (var itemToAddTpl in itemsThatFit)
// {
// // Ensure key/value exists
// pool.TryAdd(slot.Name, new Dictionary<string, List<string>>());
// pool.TryGetValue(item.Id, out var poolToAddTo);
// poolToAddTo ??= new Dictionary<string, List<string>>();
// // only add item to pool if it doesn't already exist
// poolToAddTo.TryAdd(slot.Name, []);
// if (!poolToAddTo[slot.Name].Any(x => x == itemToAddTpl))
// {
// poolToAddTo[slot.Name].Add(itemToAddTpl);
// // Check item added into array for slots, need to iterate over those
// var subItemDetails = _itemHelper.GetItem(itemToAddTpl).Value;
// var hasSubItemsToAdd = (subItemDetails?.Properties?.Slots?.Count ?? 0) > 0;
// if (hasSubItemsToAdd && !pool.ContainsKey(subItemDetails.Id))
// {
// // Recursive call
// GeneratePool([subItemDetails], poolType);
// }
// }
// }
//}
}
}
@@ -150,12 +122,12 @@ public class BotEquipmentModPoolService
}
/**
* Get array of compatible mods for an items mod slot (generate pool if it doesnt exist already)
* Get array of compatible mods for an items mod slot (generate pool if it doesn't exist already)
* @param itemTpl item to look up
* @param slotName slot to get compatible mods for
* @returns tpls that fit the slot
*/
public List<string> GetCompatibleModsForWeaponSlot(string itemTpl, string slotName)
public HashSet<string> GetCompatibleModsForWeaponSlot(string itemTpl, string slotName)
{
if (!_weaponPoolGenerated)
{
@@ -163,18 +135,7 @@ public class BotEquipmentModPoolService
GenerateWeaponPool();
}
return _weaponModPool[itemTpl][slotName].ToList();
}
/**
* Get array of compatible mods for an items mod slot (generate pool if it doesnt exist already)
* @param itemTpl item to look up
* @param slotName slot to get compatible mods for
* @returns tpls that fit the slot
*/
public List<string> GetCompatibleModsForGearSlot(string itemTpl, string slotName)
{
throw new NotImplementedException();
return _weaponModPool[itemTpl][slotName];
}
/**
@@ -182,9 +143,16 @@ public class BotEquipmentModPoolService
* @param itemTpl items tpl to look up mods for
* @returns Dictionary of mods (keys are mod slot names) with array of compatible mod tpls as value
*/
public Dictionary<string, List<string>> GetModsForGearSlot(string itemTpl)
public Dictionary<string, HashSet<string>>? GetModsForGearSlot(string itemTpl)
{
throw new NotImplementedException();
if (!_armorPoolGenerated)
{
GenerateGearPool();
}
return _gearModPool.TryGetValue(itemTpl, out var value)
? value
: null;
}
/**
@@ -192,9 +160,14 @@ public class BotEquipmentModPoolService
* @param itemTpl Weapons tpl to look up mods for
* @returns Dictionary of mods (keys are mod slot names) with array of compatible mod tpls as value
*/
public Dictionary<string, List<string>> GetModsForWeaponSlot(string itemTpl)
public Dictionary<string, HashSet<string>> GetModsForWeaponSlot(string itemTpl)
{
throw new NotImplementedException();
if (!_weaponPoolGenerated)
{
GenerateWeaponPool();
}
return _weaponModPool[itemTpl];
}
/**
@@ -215,6 +188,17 @@ public class BotEquipmentModPoolService
*/
protected void GenerateGearPool()
{
throw new NotImplementedException();
var gear = _databaseService.GetItems().Values.Where(
(item) => item.Type == "Item"
&& _itemHelper.IsOfBaseclasses(item.Id, [
BaseClasses.ARMORED_EQUIPMENT,
BaseClasses.VEST,
BaseClasses.ARMOR,
BaseClasses.HEADWEAR,
]));
GeneratePool(gear, "gear");
// Flag pool as being complete
_armorPoolGenerated = true;
}
}
+23 -3
View File
@@ -6,6 +6,7 @@ using Core.Models.Eft.Common.Tables;
using Core.Models.Eft.ItemEvent;
using Core.Models.Eft.Repair;
using Core.Models.Enums;
using Core.Models.Utils;
using Core.Utils;
namespace Core.Services;
@@ -13,13 +14,16 @@ namespace Core.Services;
[Injectable(InjectionType.Singleton)]
public class RepairService
{
private readonly ISptLogger<RepairService> _logger;
private readonly RandomUtil _randomUtil;
private readonly WeightedRandomHelper _weightedRandomHelper;
public RepairService(
ISptLogger<RepairService> _logger,
RandomUtil randomUtil,
WeightedRandomHelper weightedRandomHelper)
{
this._logger = _logger;
_randomUtil = randomUtil;
_weightedRandomHelper = weightedRandomHelper;
}
@@ -165,10 +169,26 @@ public class RepairService
/// Add random buff to item
/// </summary>
/// <param name="itemConfig">weapon/armor config</param>
/// <param name="repairDetails">Details for item to repair</param>
public void AddBuff(Core.Models.Spt.Config.BonusSettings itemConfig, Item item)
/// <param name="item">Item to repair</param>
public void AddBuff(Models.Spt.Config.BonusSettings itemConfig, Item item)
{
throw new NotImplementedException();
_logger.Error("NOT IMPLEMENTED - AddBuff");
//var bonusRarity = _weightedRandomHelper.GetWeightedValue<string>(itemConfig.RarityWeight);
//var bonusType = _weightedRandomHelper.GetWeightedValue<string>(itemConfig.BonusTypeWeight);
//var bonusValues = itemConfig[bonusRarity][bonusType].valuesMinMax;
//var bonusValue = _randomUtil.GetFloat(bonusValues.min, bonusValues.max);
//var bonusThresholdPercents = itemConfig[bonusRarity][bonusType].activeDurabilityPercentMinMax;
//var bonusThresholdPercent = _randomUtil.GetInt(bonusThresholdPercents.min, bonusThresholdPercents.max);
//item.Upd.Buff = new UpdBuff {
// Rarity = bonusRarity,
// BuffType = bonusType,
// Value = bonusValue,
// ThresholdDurability = _randomUtil.GetPercentOfValue(bonusThresholdPercent, item.Upd.Repairable.Durability, 2).toFixed(2),
// )
//};
}
/// <summary>