Further implementation of gear/weapon generation

This commit is contained in:
Chomp
2025-01-20 13:56:59 +00:00
parent 5c6515e37f
commit f15f7fef56
7 changed files with 271 additions and 16 deletions
@@ -860,7 +860,7 @@ public class BotEquipmentModGenerator(
request.RandomisationSettings.MinimumMagazineSize is not null
)
{
modPool = GetFilterdMagazinePoolByCapacity(request, modPool);
modPool = GetFilterdMagazinePoolByCapacity(request, modPool).ToList();
}
// Pick random mod that's compatible
@@ -919,9 +919,24 @@ 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 List<string> GetFilterdMagazinePoolByCapacity(ModToSpawnRequest modSpawnRequest, List<string> modPool)
public IEnumerable<string> GetFilterdMagazinePoolByCapacity(ModToSpawnRequest modSpawnRequest, List<string> modPool)
{
throw new NotImplementedException();
var weaponTpl = modSpawnRequest.Weapon[0].Template;
modSpawnRequest.RandomisationSettings.MinimumMagazineSize.TryGetValue(weaponTpl, out var minMagSizeFromSettings);
var minMagazineSize = minMagSizeFromSettings;
var desiredMagazineTpls = modPool.Where((magTpl) => {
var magazineDb = _itemHelper.GetItem(magTpl).Value;
return magazineDb.Properties is not null && magazineDb.Properties.Cartridges.FirstOrDefault().MaxCount >= minMagazineSize;
});
if (!desiredMagazineTpls.Any())
{
_logger.Warning("Magazine size filter for ${ weaponTpl} was too strict, ignoring filter");
return modPool;
}
return desiredMagazineTpls;
}
/// <summary>
@@ -1420,7 +1435,8 @@ public class BotEquipmentModGenerator(
var result = new List<string>();
// Get item blacklist and mod equipment blacklist as one array
var blacklist = _itemFilterService.GetBlacklistedItems().Concat(botEquipBlacklist.Equipment[modSlot]);
botEquipBlacklist.Equipment.TryGetValue(modSlot, out var equipmentBlacklistValues);
var blacklist = _itemFilterService.GetBlacklistedItems().Concat(equipmentBlacklistValues ?? []);
result = allowedMods.Where((tpl) => !blacklist.Contains(tpl)).ToList();
return result;
+2 -2
View File
@@ -668,8 +668,8 @@ public class BotGenerator(
// Common skills have additional props
if (isCommonSkills)
{
((Common)skillToAdd).PointsEarnedDuringSession = 0;
((Common)skillToAdd).LastAccess = 0;
skillToAdd.PointsEarnedDuringSession = 0;
skillToAdd.LastAccess = 0;
}
return skillToAdd;
@@ -2,6 +2,7 @@ using System.Text.Json.Serialization;
using Core.Models.Common;
using Core.Models.Enums;
using Core.Utils.Json.Converters;
using SptCommon.Extensions;
namespace Core.Models.Eft.Common.Tables;
@@ -57,6 +58,19 @@ public record Appearance
[JsonPropertyName("voice")]
[JsonConverter(typeof(ArrayToObjectFactoryConverter))]
public Dictionary<string, double>? Voice { get; set; }
public Dictionary<string, double> this[string propName]
{
get
{
var matchingProp = GetType()
.GetProperties()
.SingleOrDefault(p => p.GetJsonName() == propName)
?.GetValue(this);
return (Dictionary<string, double>)matchingProp;
}
}
}
public record Chances
@@ -348,8 +348,45 @@ public class BotEquipmentFilterService
bool showEditWarnings = true)
{
//TODO, bad typing by key with method below due to, EquipmentSlots
// MAKE CONSISTENT BEFORE IMPLEMENTING
throw new NotImplementedException();
if (weightingAdjustments is null)
{
return;
}
if (weightingAdjustments.Add?.Count > 0)
{
foreach (var poolAdjustmentKvP in weightingAdjustments.Add)
{
var locationToUpdate = botItemPool[Enum.Parse<EquipmentSlots>(poolAdjustmentKvP.Key)];
foreach (var itemToAddKvP in poolAdjustmentKvP.Value)
{
locationToUpdate[itemToAddKvP.Key] = itemToAddKvP.Value;
}
}
}
if (weightingAdjustments.Edit?.Count > 0)
{
foreach (var poolAdjustmentKvP in weightingAdjustments.Edit)
{
var locationToUpdate = botItemPool[Enum.Parse<EquipmentSlots>(poolAdjustmentKvP.Key)];
foreach (var itemToEditKvP in poolAdjustmentKvP.Value)
{
// Only make change if item exists as we're editing, not adding
if (locationToUpdate[itemToEditKvP.Key] != null || locationToUpdate[itemToEditKvP.Key] == 0)
{
locationToUpdate[itemToEditKvP.Key] = itemToEditKvP.Value;
}
else
{
if (showEditWarnings)
{
_logger.Debug($"Tried to edit a non - existent item for slot: {poolAdjustmentKvP} {itemToEditKvP}");
}
}
}
}
}
}
/// <summary>
@@ -414,6 +451,44 @@ public class BotEquipmentFilterService
Appearance botItemPool,
bool showEditWarnings = true)
{
throw new NotImplementedException();
if (weightingAdjustments is null)
{
return;
}
if (weightingAdjustments.Add?.Count > 0)
{
foreach (var poolAdjustmentKvP in weightingAdjustments.Add)
{
var locationToUpdate = botItemPool[poolAdjustmentKvP.Key];
foreach (var itemToAddKvP in poolAdjustmentKvP.Value)
{
locationToUpdate[itemToAddKvP.Key] = itemToAddKvP.Value;
}
}
}
if (weightingAdjustments.Edit?.Count > 0)
{
foreach (var poolAdjustmentKvP in weightingAdjustments.Edit)
{
var locationToUpdate = botItemPool[poolAdjustmentKvP.Key];
foreach (var itemToEditKvP in poolAdjustmentKvP.Value)
{
// Only make change if item exists as we're editing, not adding
if (locationToUpdate[itemToEditKvP.Key] != null || locationToUpdate[itemToEditKvP.Key] == 0)
{
locationToUpdate[itemToEditKvP.Key] = itemToEditKvP.Value;
}
else
{
if (showEditWarnings)
{
_logger.Debug($"Tried to edit a non - existent item for slot: {poolAdjustmentKvP} {itemToEditKvP}");
}
}
}
}
}
}
}
@@ -1,18 +1,144 @@
using SptCommon.Annotations;
using SptCommon.Annotations;
using Core.Models.Eft.Common.Tables;
using Core.Models.Utils;
using Core.Helpers;
using Core.Servers;
using Core.Models.Enums;
using Core.Models.Spt.Config;
using System.Collections.Generic;
namespace Core.Services;
[Injectable(InjectionType.Singleton)]
public class BotEquipmentModPoolService
{
protected ISptLogger<BotEquipmentModPoolService> _logger;
protected ItemHelper _itemHelper;
protected DatabaseService _databaseService;
protected LocalisationService _localisationService;
protected ConfigServer _configServer;
protected bool _weaponPoolGenerated = false;
protected Dictionary<string, Dictionary<string, HashSet<string>>> _weaponModPool;
protected Dictionary<string, Dictionary<string, HashSet<string>>> _gearModPool;
protected BotConfig _botConfig;
public BotEquipmentModPoolService(
ISptLogger<BotEquipmentModPoolService> logger,
ItemHelper itemHelper,
DatabaseService databaseService,
LocalisationService localisationService,
ConfigServer configServer
)
{
_logger = logger;
_itemHelper = itemHelper;
_databaseService = databaseService;
_localisationService = localisationService;
_configServer = configServer;
_botConfig = _configServer.GetConfig<BotConfig>();
_weaponModPool = new Dictionary<string, Dictionary<string, HashSet<string>>>();
_gearModPool = new Dictionary<string, Dictionary<string, HashSet<string>>>();
}
/**
* Store dictionary of mods for each item passed in
* @param items items to find related mods and store in modPool
*/
protected void GeneratePool(List<TemplateItem> items, string poolType)
protected void GeneratePool(IEnumerable<TemplateItem>? items, string poolType)
{
throw new NotImplementedException();
if (items is null)
{
_logger.Error(_localisationService.GetText("bot-unable_to_generate_item_pool_no_items", poolType));
return;
}
// Get weapon or gear pool
var pool = poolType == "weapon" ? _weaponModPool : _gearModPool;
foreach (var item in items) {
if (item.Properties is null)
{
_logger.Error(_localisationService.GetText("bot-item_missing_props_property", new {
itemTpl = item.Id,
name = item.Name,
}));
continue;
}
// Skip item without slots
if (item.Properties.Slots is null || item.Properties.Slots.Count == 0)
{
continue;
}
// Add base item (weapon/armor) to pool
if (!pool.ContainsKey(item.Id))
{
pool[item.Id] = new Dictionary<string, HashSet<string>>();
}
// iterate over each items mod slots e.g. mod_muzzle
foreach (var slot in item.Properties.Slots) {
// Get mods that fit into the current mod slot
var itemsThatFit = slot.Props.Filters.FirstOrDefault().Filter;
// Get weapon/armor pool to add mod slots + mod tpls to
foreach (var itemToAddTpl in itemsThatFit)
{
if (!pool[item.Id].ContainsKey(slot.Name))
{
// Ensure Mod slot key + blank dict value exist
pool[item.Id][slot.Name] = new();
}
if (!pool[item.Id][slot.Name].Contains(itemToAddTpl))
{
// Add tpl to list keyed by mod slot
pool[item.Id][slot.Name].Add(itemToAddTpl);
}
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);
}
}
}
//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);
// }
// }
// }
//}
}
}
/**
@@ -31,7 +157,13 @@ public class BotEquipmentModPoolService
*/
public List<string> GetCompatibleModsForWeaponSlot(string itemTpl, string slotName)
{
throw new NotImplementedException();
if (!_weaponPoolGenerated)
{
// Get every weapon in db and generate mod pool
GenerateWeaponPool();
}
return _weaponModPool[itemTpl][slotName].ToList();
}
/**
@@ -70,7 +202,12 @@ public class BotEquipmentModPoolService
*/
protected void GenerateWeaponPool()
{
throw new NotImplementedException();
var weapons = _databaseService.GetItems().Values.Where(
(item) => item.Type == "Item" && _itemHelper.IsOfBaseclass(item.Id, BaseClasses.WEAPON));
GeneratePool(weapons, "weapon");
// Flag pool as being complete
_weaponPoolGenerated = true;
}
/**
+1 -1
View File
@@ -71,7 +71,7 @@ public class ItemFilterService(
*/
public List<string> GetBlacklistedItems()
{
throw new NotImplementedException();
return _cloner.Clone(_itemConfig.Blacklist);
}
/**
+14 -1
View File
@@ -1,16 +1,29 @@
using System.Text.Json.Serialization;
using System.Text.Json.Serialization;
using Core.Helpers;
using SptCommon.Annotations;
using Core.Models.Eft.Common;
using Core.Models.Eft.Common.Tables;
using Core.Models.Eft.ItemEvent;
using Core.Models.Eft.Repair;
using Core.Models.Enums;
using Core.Utils;
namespace Core.Services;
[Injectable(InjectionType.Singleton)]
public class RepairService
{
private readonly RandomUtil _randomUtil;
private readonly WeightedRandomHelper _weightedRandomHelper;
public RepairService(
RandomUtil randomUtil,
WeightedRandomHelper weightedRandomHelper)
{
_randomUtil = randomUtil;
_weightedRandomHelper = weightedRandomHelper;
}
/// <summary>
/// Use trader to repair an items durability
/// </summary>