From 966b36715b7e76f51004cf569728948aa6bc6674 Mon Sep 17 00:00:00 2001 From: Chomp Date: Tue, 21 Jan 2025 10:59:04 +0000 Subject: [PATCH] More bot generation implementation --- Libraries/Core/Controllers/BotController.cs | 2 +- .../Generators/BotEquipmentModGenerator.cs | 2 +- .../ExternalInventoryMagGen.cs | 3 +- Libraries/Core/Helpers/ContainerHelper.cs | 20 +++- Libraries/Core/Helpers/InventoryHelper.cs | 94 +++++++++++++++++-- Libraries/Core/Helpers/ItemHelper.cs | 9 +- Libraries/Core/Services/BotNameService.cs | 2 +- Tools/ItemTplGenerator/ItemTplGenerator.cs | 3 +- 8 files changed, 117 insertions(+), 18 deletions(-) diff --git a/Libraries/Core/Controllers/BotController.cs b/Libraries/Core/Controllers/BotController.cs index dc1de088..89b21fb4 100644 --- a/Libraries/Core/Controllers/BotController.cs +++ b/Libraries/Core/Controllers/BotController.cs @@ -183,7 +183,7 @@ public class BotController( if (botCacheCount >= botGenerationDetails.BotCountToGenerate) { - _logger.Debug($"Cache already has sufficient bots: {botCacheCount}"); + _logger.Debug($"Cache already has sufficient {cacheKey} bots: {botCacheCount}"); return; } diff --git a/Libraries/Core/Generators/BotEquipmentModGenerator.cs b/Libraries/Core/Generators/BotEquipmentModGenerator.cs index ca2531ef..1405f2fe 100644 --- a/Libraries/Core/Generators/BotEquipmentModGenerator.cs +++ b/Libraries/Core/Generators/BotEquipmentModGenerator.cs @@ -1384,7 +1384,7 @@ public class BotEquipmentModGenerator( ); } - if (modPool[modTemplate.Id] is null) + if (!modPool.ContainsKey(modTemplate.Id)) { modPool[modTemplate.Id] = new(); } diff --git a/Libraries/Core/Generators/WeaponGen/Implementations/ExternalInventoryMagGen.cs b/Libraries/Core/Generators/WeaponGen/Implementations/ExternalInventoryMagGen.cs index d5fcf315..044c498e 100644 --- a/Libraries/Core/Generators/WeaponGen/Implementations/ExternalInventoryMagGen.cs +++ b/Libraries/Core/Generators/WeaponGen/Implementations/ExternalInventoryMagGen.cs @@ -40,8 +40,9 @@ public class ExternalInventoryMagGen( var weapon = inventoryMagGen.GetWeaponTemplate(); List attemptedMagBlacklist = []; var defaultMagazineTpl = _botWeaponGeneratorHelper.GetWeaponsDefaultMagazineTpl(weapon); - var randomizedMagazineCount = _botWeaponGeneratorHelper.GetRandomizedMagazineCount(inventoryMagGen.GetMagCount()); var isShotgun = _itemHelper.IsOfBaseclass(weapon.Id, BaseClasses.SHOTGUN); + + var randomizedMagazineCount = _botWeaponGeneratorHelper.GetRandomizedMagazineCount(inventoryMagGen.GetMagCount()); for (var i = 0; i < randomizedMagazineCount; i++) { var magazineWithAmmo = _botWeaponGeneratorHelper.CreateMagazineWithAmmo( diff --git a/Libraries/Core/Helpers/ContainerHelper.cs b/Libraries/Core/Helpers/ContainerHelper.cs index 03c46552..6da9610a 100644 --- a/Libraries/Core/Helpers/ContainerHelper.cs +++ b/Libraries/Core/Helpers/ContainerHelper.cs @@ -144,7 +144,25 @@ public class ContainerHelper int itemH, bool rotate) { - throw new NotImplementedException(); + // Swap height/width if we want to fit it in rotated + var itemWidth = rotate ? itemH : itemW; + var itemHeight = rotate ? itemW : itemH; + + for (var tmpY = y; tmpY < y + itemHeight; tmpY++) + { + for (var tmpX = x; tmpX < x + itemWidth; tmpX++) + { + if (container2D[tmpY][tmpX] == 0) + { + // Flag slot as used + container2D[tmpY][tmpX] = 1; + } + else + { + throw new Exception($"Slot at({ x }, { y}) is already filled. Cannot fit a { itemW} by { itemH} item"); + } + } + } } } diff --git a/Libraries/Core/Helpers/InventoryHelper.cs b/Libraries/Core/Helpers/InventoryHelper.cs index 34f258ee..20b51589 100644 --- a/Libraries/Core/Helpers/InventoryHelper.cs +++ b/Libraries/Core/Helpers/InventoryHelper.cs @@ -14,6 +14,7 @@ using Core.Models.Eft.Hideout; using Core.Models.Enums; using Core.Models.Spt.Bots; using Core.Models.Spt.Services; +using System.Xml.Linq; namespace Core.Helpers; @@ -22,6 +23,7 @@ public class InventoryHelper( ISptLogger _logger, ProfileHelper _profileHelper, DialogueHelper _dialogueHelper, + ContainerHelper _containerHelper, ItemHelper _itemHelper, LocalisationService _localisationService ) @@ -94,9 +96,9 @@ public class InventoryHelper( /// Container grid to fit items into /// Items to try and fit into grid /// True all fit - public bool CanPlaceItemsInContainer(List>? containerFS2D, List> itemsWithChildren) + public bool CanPlaceItemsInContainer(int[][] containerFS2D, List> itemsWithChildren) { - throw new NotImplementedException(); + return itemsWithChildren.All(itemWithChildren => CanPlaceItemInContainer(containerFS2D, itemWithChildren)); } /// @@ -105,9 +107,38 @@ public class InventoryHelper( /// Container grid /// Item to check fits /// True it fits - public bool CanPlaceItemInContainer(List>? containerFS2D, List itemWithChildren) + public bool CanPlaceItemInContainer(int[][] containerFS2D, List itemWithChildren) { - throw new NotImplementedException(); + // Get x/y size of item + var rootItem = itemWithChildren[0]; + var itemSize = GetItemSize(rootItem.Template, rootItem.Id, itemWithChildren); + + // Look for a place to slot item into + var findSlotResult = _containerHelper.FindSlotForItem(containerFS2D, itemSize[0], itemSize[1]); + if (findSlotResult.Success.GetValueOrDefault(false)) + { + try + { + _containerHelper.FillContainerMapWithItem( + containerFS2D, + findSlotResult.X.Value, + findSlotResult.Y.Value, + itemSize[0], + itemSize[1], + findSlotResult.Rotation.Value); + } + catch (Exception ex) + { + _logger.Error(_localisationService.GetText("inventory-unable_to_fit_item_into_inventory", ex.Message)); + + return false; + } + + // Success! exit + return true; + } + + return false; } /// @@ -118,12 +149,49 @@ public class InventoryHelper( /// Id of the container we're fitting item into /// Slot id value to use, default is "hideout" public void PlaceItemInContainer( - List> containerFS2D, + int[][] containerFS2D, List itemWithChildren, string containerId, string desiredSlotId = "hideout") { - throw new NotImplementedException(); + // Get x/y size of item + var rootItemAdded = itemWithChildren[0]; + var itemSize = GetItemSize(rootItemAdded.Template, rootItemAdded.Id, itemWithChildren); + + // Look for a place to slot item into + var findSlotResult = _containerHelper.FindSlotForItem(containerFS2D, itemSize[0], itemSize[1]); + if (findSlotResult.Success.GetValueOrDefault(false)) + { + try + { + _containerHelper.FillContainerMapWithItem( + containerFS2D, + findSlotResult.X.Value, + findSlotResult.Y.Value, + itemSize[0], + itemSize[1], + findSlotResult.Rotation.Value); + } + catch (Exception ex) + { + _logger.Error(_localisationService.GetText("inventory-fill_container_failed", ex.Message)); + + return; + } + // Store details for object, incuding container item will be placed in + rootItemAdded.ParentId = containerId; + rootItemAdded.SlotId = desiredSlotId; + rootItemAdded.Location = new ItemLocation + { + X = findSlotResult.X, + Y = findSlotResult.Y, + R = findSlotResult.Rotation.GetValueOrDefault(false) ? 1 : 0, + Rotation = findSlotResult.Rotation, + }; + + // Success! exit + return; + } } /// @@ -515,7 +583,7 @@ public class InventoryHelper( /// Player profile /// session id /// 2-dimensional array - protected int[,] GetStashSlotMap(PmcData pmcData, string sessionID) + protected int[][] GetStashSlotMap(PmcData pmcData, string sessionID) { throw new NotImplementedException(); } @@ -525,9 +593,15 @@ public class InventoryHelper( /// /// Container to get data for /// blank two-dimensional array - public List> GetContainerSlotMap(string containerTpl) + public int[][] GetContainerSlotMap(string containerTpl) { - throw new NotImplementedException(); + var containerTemplate = _itemHelper.GetItem(containerTpl).Value; + + var firstContainerGrid = containerTemplate.Properties.Grids.FirstOrDefault(); + var containerH = firstContainerGrid.Props.CellsH; + var containerV = firstContainerGrid.Props.CellsV; + + return GetBlankContainerMap(containerH.Value, containerV.Value); } /// @@ -535,7 +609,7 @@ public class InventoryHelper( /// /// Player profile /// two-dimensional array - protected List> GetSortingTableSlotMap(PmcData pmcData) + protected int[][] GetSortingTableSlotMap(PmcData pmcData) { throw new NotImplementedException(); } diff --git a/Libraries/Core/Helpers/ItemHelper.cs b/Libraries/Core/Helpers/ItemHelper.cs index 4bf7caf5..a597f205 100644 --- a/Libraries/Core/Helpers/ItemHelper.cs +++ b/Libraries/Core/Helpers/ItemHelper.cs @@ -1450,6 +1450,13 @@ public class ItemHelper( double minSizeMultiplier = 0.25 ) { + var isUBGL = IsOfBaseclass(magTemplate.Id, BaseClasses.UBGL); + if (isUBGL) + { + // UBGL don't have mags + return; + } + // Get cartridge properties and max allowed stack size var cartridgeDetails = GetItem(cartridgeTpl); if (!cartridgeDetails.Key) @@ -1467,7 +1474,7 @@ public class ItemHelper( var magProps = magTemplate.Properties; var magazineCartridgeMaxCount = IsOfBaseclass(magTemplate.Id, BaseClasses.SPRING_DRIVEN_CYLINDER) ? magProps?.Slots?.Count // Edge case for rotating grenade launcher magazine - : magProps?.Cartridges.FirstOrDefault()?.MaxCount; + : magProps?.Cartridges?.FirstOrDefault()?.MaxCount; if (magazineCartridgeMaxCount is null) { diff --git a/Libraries/Core/Services/BotNameService.cs b/Libraries/Core/Services/BotNameService.cs index ca2ddb08..9e4f14df 100644 --- a/Libraries/Core/Services/BotNameService.cs +++ b/Libraries/Core/Services/BotNameService.cs @@ -56,7 +56,7 @@ public class BotNameService( // Get bot name with leading/trailing whitespace removed var name = (isPmc.GetValueOrDefault(false)) // Explicit handling of PMCs, all other bots will get "first_name last_name" ? _botHelper.GetPmcNicknameOfMaxLength(_botConfig.BotNameLengthLimit, botGenerationDetails.Side) - : $"{_randomUtil.GetArrayValue(botJsonTemplate.FirstNames)} {_randomUtil.GetArrayValue(botJsonTemplate.LastNames)}"; + : $"{_randomUtil.GetArrayValue(botJsonTemplate.FirstNames)} {(botJsonTemplate.LastNames.Count > 0 ? _randomUtil.GetArrayValue(botJsonTemplate.LastNames) : "")}"; name = name.Trim(); diff --git a/Tools/ItemTplGenerator/ItemTplGenerator.cs b/Tools/ItemTplGenerator/ItemTplGenerator.cs index 0fd47f7a..ddccc091 100644 --- a/Tools/ItemTplGenerator/ItemTplGenerator.cs +++ b/Tools/ItemTplGenerator/ItemTplGenerator.cs @@ -5,7 +5,6 @@ using Core.Models.Enums; using Core.Models.Utils; using Core.Servers; using Core.Services; -using Microsoft.Extensions.Logging; using SptCommon.Annotations; using SptCommon.Extensions; using Path = System.IO.Path; @@ -14,9 +13,9 @@ namespace ItemTplGenerator; [Injectable] public class ItemTplGenerator( + ISptLogger _logger, DatabaseServer _databaseServer, LocaleService _localeService, - ISptLogger _logger, ItemHelper _itemHelper, // @inject("FileSystemSync") protected fileSystemSync: FileSystemSync, IEnumerable _onLoadComponents