Merge branch 'main' of https://github.com/sp-tarkov/server-csharp
This commit is contained in:
@@ -61,7 +61,7 @@ public class BotEquipmentModGenerator(
|
||||
}
|
||||
|
||||
// Iterate over mod pool and choose mods to add to item
|
||||
foreach (var (modSlotName, modPool) in compatibleModsPool)
|
||||
foreach (var (modSlotName, modPool) in compatibleModsPool ?? [])
|
||||
{
|
||||
// Get the templates slot object from db
|
||||
var itemSlotTemplate = GetModItemSlotFromDb(modSlotName, parentTemplate);
|
||||
|
||||
@@ -393,7 +393,7 @@ public class BotInventoryGenerator(
|
||||
|
||||
// Roll dice on equipment item
|
||||
var shouldSpawn = _randomUtil.GetChance100(spawnChance ?? 0);
|
||||
if (shouldSpawn && !settings.RootEquipmentPool.Any())
|
||||
if (shouldSpawn && settings.RootEquipmentPool.Any())
|
||||
{
|
||||
var pickedItemDb = new TemplateItem();
|
||||
var found = false;
|
||||
@@ -469,7 +469,8 @@ public class BotInventoryGenerator(
|
||||
);
|
||||
|
||||
// Edge case: Filter the armor items mod pool if bot exists in config dict + config has armor slot
|
||||
if (_botConfig.Equipment[settings.BotData.EquipmentRole] is not null &&
|
||||
if (_botConfig.Equipment.ContainsKey(settings.BotData.EquipmentRole) &&
|
||||
settings.RandomisationDetails is not null &&
|
||||
settings.RandomisationDetails.RandomisedArmorSlots.Contains(settings.RootEquipmentSlot.ToString()))
|
||||
{
|
||||
// Filter out mods from relevant blacklist
|
||||
@@ -480,7 +481,8 @@ public class BotInventoryGenerator(
|
||||
}
|
||||
|
||||
// Does item have slots for sub-mods to be inserted into
|
||||
if (pickedItemDb.Properties.Slots.Any() && settings.GenerateModsBlacklist.Contains(pickedItemDb.Id))
|
||||
if (pickedItemDb.Properties?.Slots?.Count > 0
|
||||
&& settings.GenerateModsBlacklist.Contains(pickedItemDb.Id))
|
||||
{
|
||||
var childItemsToAdd = _botEquipmentModGenerator.GenerateModsForEquipment(
|
||||
[item],
|
||||
|
||||
@@ -474,13 +474,13 @@ public class BotGeneratorHelper(
|
||||
}
|
||||
|
||||
// Get container to put item into
|
||||
var container = (inventory.Items ?? []).FirstOrDefault(item => item.SlotId == equipmentSlotId.ToString());
|
||||
var container = (inventory.Items).FirstOrDefault(item => item.SlotId == equipmentSlotId.ToString());
|
||||
if (container is null)
|
||||
{
|
||||
missingContainerCount++;
|
||||
if (missingContainerCount == equipmentSlots.Count)
|
||||
{
|
||||
// Bot doesnt have any containers we want to add item to
|
||||
// Bot doesn't have any containers we want to add item to
|
||||
_logger.Debug(
|
||||
$"Unable to add item: {itemWithChildren.FirstOrDefault()?.Template} to bot as it lacks the following containers: {string.Join(",", equipmentSlots)}"
|
||||
);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Text.Json.Serialization;
|
||||
using SptCommon.Annotations;
|
||||
|
||||
namespace Core.Helpers;
|
||||
@@ -13,9 +13,59 @@ public class ContainerHelper
|
||||
/// <param name="itemWidth">Width of item</param>
|
||||
/// <param name="itemHeight">Height of item</param>
|
||||
/// <returns>Location to place item in container</returns>
|
||||
public FindSlotResult FindSlotForItem(List<List<int>> container2D, int itemWidth, int itemHeight)
|
||||
public FindSlotResult FindSlotForItem(int[][] container2D, int itemWidth, int itemHeight)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
var rotation = false;
|
||||
var minVolume = (itemWidth < itemHeight ? itemWidth : itemHeight) - 1;
|
||||
var containerY = container2D.Length;
|
||||
var containerX = container2D[0].Length;
|
||||
var limitY = containerY - minVolume;
|
||||
var limitX = containerX - minVolume;
|
||||
|
||||
// Every x+y slot taken up in container, exit
|
||||
if (container2D.All((x) => x.All((y) =>y == 1)))
|
||||
{
|
||||
return new FindSlotResult(false);
|
||||
}
|
||||
|
||||
// Down
|
||||
for (var y = 0; y < limitY; y++)
|
||||
{
|
||||
// Across
|
||||
if (container2D[y].All((x) => x == 1))
|
||||
{
|
||||
// Every item in row is full, skip row
|
||||
continue;
|
||||
}
|
||||
|
||||
for (var x = 0; x < limitX; x++)
|
||||
{
|
||||
var foundSlot = LocateSlot(container2D, containerX, containerY, x, y, itemWidth, itemHeight);
|
||||
|
||||
// Failed to find slot, rotate item and try again
|
||||
if (!foundSlot && itemWidth * itemHeight > 1)
|
||||
{
|
||||
// Bigger than 1x1
|
||||
foundSlot = LocateSlot(container2D, containerX, containerY, x, y, itemHeight, itemWidth); // Height/Width swapped
|
||||
if (foundSlot)
|
||||
{
|
||||
// Found a slot for it when rotated
|
||||
rotation = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!foundSlot)
|
||||
{
|
||||
// Didn't fit this hole, try again
|
||||
continue;
|
||||
}
|
||||
|
||||
return new FindSlotResult(true, x, y, rotation);
|
||||
}
|
||||
}
|
||||
|
||||
// Tried all possible holes, nothing big enough for the item
|
||||
return new FindSlotResult(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -30,7 +80,7 @@ public class ContainerHelper
|
||||
/// <param name="itemH">Items height</param>
|
||||
/// <returns>True - slot found</returns>
|
||||
protected bool LocateSlot(
|
||||
List<List<int>> container2D,
|
||||
int[][] container2D,
|
||||
int containerX,
|
||||
int containerY,
|
||||
int x,
|
||||
@@ -51,7 +101,7 @@ public class ContainerHelper
|
||||
/// <param name="itemH">Items height</param>
|
||||
/// <param name="rotate">is item rotated</param>
|
||||
public void FillContainerMapWithItem(
|
||||
List<List<int>> container2D,
|
||||
int[][] container2D,
|
||||
int x,
|
||||
int y,
|
||||
int itemW,
|
||||
@@ -64,14 +114,31 @@ public class ContainerHelper
|
||||
|
||||
public class FindSlotResult
|
||||
{
|
||||
public FindSlotResult(bool success)
|
||||
{
|
||||
Success = success;
|
||||
}
|
||||
|
||||
public FindSlotResult(bool success, int x, int y, bool rotation)
|
||||
{
|
||||
Success = success;
|
||||
X = x;
|
||||
Y = y;
|
||||
Rotation = rotation;
|
||||
}
|
||||
|
||||
public FindSlotResult()
|
||||
{
|
||||
}
|
||||
|
||||
[JsonPropertyName("success")]
|
||||
public bool? Success { get; set; }
|
||||
|
||||
[JsonPropertyName("x")]
|
||||
public double? X { get; set; }
|
||||
public int? X { get; set; }
|
||||
|
||||
[JsonPropertyName("y")]
|
||||
public double? Y { get; set; }
|
||||
public int? Y { get; set; }
|
||||
|
||||
[JsonPropertyName("rotation")]
|
||||
public bool? Rotation { get; set; }
|
||||
|
||||
@@ -8,6 +8,12 @@ using Core.Models.Spt.Config;
|
||||
using Core.Models.Spt.Inventory;
|
||||
using Core.Models.Utils;
|
||||
using Core.Services;
|
||||
using Core.Models.Eft.Player;
|
||||
using System.ComponentModel;
|
||||
using Core.Models.Eft.Hideout;
|
||||
using Core.Models.Enums;
|
||||
using Core.Models.Spt.Bots;
|
||||
using Core.Models.Spt.Services;
|
||||
|
||||
namespace Core.Helpers;
|
||||
|
||||
@@ -16,6 +22,7 @@ public class InventoryHelper(
|
||||
ISptLogger<InventoryHelper> _logger,
|
||||
ProfileHelper _profileHelper,
|
||||
DialogueHelper _dialogueHelper,
|
||||
ItemHelper _itemHelper,
|
||||
LocalisationService _localisationService
|
||||
)
|
||||
{
|
||||
@@ -187,7 +194,8 @@ public class InventoryHelper(
|
||||
/// <returns>[width, height]</returns>
|
||||
public List<int> GetItemSize(string? itemTpl, string itemId, List<Item> inventoryItems)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
// -> Prepares item Width and height returns [sizeX, sizeY]
|
||||
return GetSizeByInventoryItemHash(itemTpl, itemId, GetInventoryItemHash(inventoryItems));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -198,9 +206,126 @@ public class InventoryHelper(
|
||||
/// <param name="itemId">Items id</param>
|
||||
/// <param name="inventoryItemHash">Hashmap of inventory items</param>
|
||||
/// <returns>An array representing the [width, height] of the item</returns>
|
||||
protected List<int> GetSizeByInventoryItemHash(string itemTpl, string itemId, InventoryItemHash inventoryItemHash)
|
||||
protected List<int> GetSizeByInventoryItemHash(string itemTpl, string itemID, InventoryItemHash inventoryItemHash)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
var toDo = new List<string> { itemID };
|
||||
var result = _itemHelper.GetItem(itemTpl);
|
||||
var tmpItem = result.Value;
|
||||
|
||||
// Invalid item
|
||||
if (!result.Key)
|
||||
{
|
||||
_logger.Error(_localisationService.GetText("inventory-invalid_item_missing_from_db", itemTpl));
|
||||
}
|
||||
|
||||
// Item found but no _props property
|
||||
if (tmpItem is not null && tmpItem.Properties is null)
|
||||
{
|
||||
_localisationService.GetText("inventory-item_missing_props_property", new {
|
||||
itemTpl = itemTpl,
|
||||
itemName = tmpItem?.Name
|
||||
});
|
||||
}
|
||||
|
||||
// No item object or getItem() returned false
|
||||
if (tmpItem is null && result.Value is null)
|
||||
{
|
||||
// return default size of 1x1
|
||||
_logger.Error(_localisationService.GetText("inventory-return_default_size", itemTpl));
|
||||
|
||||
return [1, 1]; // Invalid input data, return defaults
|
||||
}
|
||||
|
||||
var rootItem = inventoryItemHash.ByItemId[itemID];
|
||||
var foldableWeapon = tmpItem.Properties.Foldable;
|
||||
var foldedSlot = tmpItem.Properties.FoldedSlot;
|
||||
|
||||
var sizeUp = 0;
|
||||
var sizeDown = 0;
|
||||
var sizeLeft = 0;
|
||||
var sizeRight = 0;
|
||||
|
||||
var forcedUp = 0;
|
||||
var forcedDown = 0;
|
||||
var forcedLeft = 0;
|
||||
var forcedRight = 0;
|
||||
var outX = (int)tmpItem.Properties.Width;
|
||||
var outY = (int)tmpItem.Properties.Height;
|
||||
|
||||
// Item types to ignore
|
||||
var skipThisItems = new List<string> { BaseClasses.BACKPACK, BaseClasses.SEARCHABLE_ITEM, BaseClasses.SIMPLE_CONTAINER };
|
||||
|
||||
var rootFolded = rootItem?.Upd?.Foldable?.Folded == true;
|
||||
|
||||
// The item itself is collapsible
|
||||
if (foldableWeapon is not null && string.IsNullOrEmpty(foldedSlot) && rootFolded)
|
||||
{
|
||||
outX -= tmpItem.Properties.SizeReduceRight.Value;
|
||||
}
|
||||
|
||||
// Calculate size contribution from child items/attachments
|
||||
if (!skipThisItems.Contains(tmpItem.Parent))
|
||||
{
|
||||
while (toDo.Count > 0)
|
||||
{
|
||||
if (inventoryItemHash.ByParentId.ContainsKey(toDo[0])) {
|
||||
foreach (var item in inventoryItemHash.ByParentId[toDo[0]]) {
|
||||
// Filtering child items outside of mod slots, such as those inside containers, without counting their ExtraSize attribute
|
||||
if (item.SlotId.IndexOf("mod_") < 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
toDo.Add(item.Id);
|
||||
|
||||
// If the barrel is folded the space in the barrel is not counted
|
||||
var itemResult = _itemHelper.GetItem(item.Template);
|
||||
if (!itemResult.Key)
|
||||
{
|
||||
_logger.Error(
|
||||
_localisationService.GetText("inventory-get_item_size_item_not_found_by_tpl", item.Template));
|
||||
}
|
||||
|
||||
var itm = itemResult.Value;
|
||||
var childFoldable = itm.Properties.Foldable.GetValueOrDefault(false);
|
||||
var childFolded = item.Upd?.Foldable is not null && item.Upd.Foldable.Folded == true;
|
||||
|
||||
if (foldableWeapon is true && foldedSlot == item.SlotId && (rootFolded || childFolded))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (childFoldable && rootFolded && childFolded)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Calculating child ExtraSize
|
||||
if (itm.Properties.ExtraSizeForceAdd == true)
|
||||
{
|
||||
forcedUp += itm.Properties.ExtraSizeUp.Value;
|
||||
forcedDown += itm.Properties.ExtraSizeDown.Value;
|
||||
forcedLeft += itm.Properties.ExtraSizeLeft.Value;
|
||||
forcedRight += itm.Properties.ExtraSizeRight.Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
sizeUp = sizeUp < itm.Properties.ExtraSizeUp ? itm.Properties.ExtraSizeUp.Value : sizeUp;
|
||||
sizeDown = sizeDown < itm.Properties.ExtraSizeDown ? itm.Properties.ExtraSizeDown.Value : sizeDown;
|
||||
sizeLeft = sizeLeft < itm.Properties.ExtraSizeLeft ? itm.Properties.ExtraSizeLeft.Value : sizeLeft;
|
||||
sizeRight = sizeRight < itm.Properties.ExtraSizeRight ? itm.Properties.ExtraSizeRight.Value : sizeRight;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
toDo.RemoveAt(0);
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
outX + sizeLeft + sizeRight + forcedLeft + forcedRight,
|
||||
outY + sizeUp + sizeDown + forcedUp + forcedDown,
|
||||
];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -209,9 +334,9 @@ public class InventoryHelper(
|
||||
/// <param name="containerH">Horizontal size of container</param>
|
||||
/// <param name="containerY">Vertical size of container</param>
|
||||
/// <returns>Two-dimensional representation of container</returns>
|
||||
protected List<List<int>> GetBlankContainerMap(int containerH, int containerY)
|
||||
protected int[][] GetBlankContainerMap(int containerH, int containerY)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
return Enumerable.Repeat(Enumerable.Repeat(0, containerH).ToArray(), containerY).ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -222,9 +347,68 @@ public class InventoryHelper(
|
||||
/// <param name="itemList">Players inventory items</param>
|
||||
/// <param name="containerId">Id of the container</param>
|
||||
/// <returns>Two-dimensional representation of container</returns>
|
||||
public List<List<int>> GetContainerMap(double containerH, double containerV, List<Item> itemList, string containerId)
|
||||
public int[][] GetContainerMap(int containerH, int containerV, List<Item> itemList, string containerId)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
// Create blank 2d map of container
|
||||
var container2D = GetBlankContainerMap(containerH, containerV);
|
||||
|
||||
// Get all items in players inventory keyed by their parentId and by ItemId
|
||||
var inventoryItemHash = GetInventoryItemHash(itemList);
|
||||
|
||||
// Get subset of items that belong to the desired container
|
||||
if (!inventoryItemHash.ByParentId.TryGetValue(containerId, out List<Item> containerItemHash))
|
||||
{
|
||||
// No items in container, exit early
|
||||
return container2D;
|
||||
}
|
||||
|
||||
// Check each item in container
|
||||
foreach (var item in containerItemHash) {
|
||||
var itemLocation = item?.Location as ItemLocation;
|
||||
if (itemLocation is null)
|
||||
{
|
||||
// item has no location property
|
||||
_logger.Error("Unable to find 'location' property on item with id: ${ item._id}, skipping");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get x/y size of item
|
||||
var tmpSize = GetSizeByInventoryItemHash(item.Template, item.Id, inventoryItemHash);
|
||||
var iW = tmpSize[0]; // x
|
||||
var iH = tmpSize[1]; // y
|
||||
var fH = IsVertical(itemLocation) ? iW : iH;
|
||||
var fW = IsVertical(itemLocation) ? iH : iW;
|
||||
|
||||
// Find the ending x coord of container
|
||||
var fillTo = itemLocation.X + fW;
|
||||
|
||||
for (var y = 0; y < fH; y++)
|
||||
{
|
||||
try
|
||||
{
|
||||
var rowIndex = itemLocation.Y + y;
|
||||
var containerRow = container2D[rowIndex.Value];
|
||||
if (containerRow is null)
|
||||
{
|
||||
_logger.Error("Unable to find container: { containerId} row line: { itemLocation.y + y}");
|
||||
}
|
||||
|
||||
// Fill the corresponding cells in the container map to show the slot is taken
|
||||
Array.Fill(containerRow, 1, itemLocation.X.Value, fillTo.Value);
|
||||
} catch (Exception ex) {
|
||||
_logger.Error(
|
||||
_localisationService.GetText("inventory-unable_to_fill_container", new {
|
||||
id = item.Id,
|
||||
error = ex.Message
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return container2D;
|
||||
}
|
||||
|
||||
protected bool IsVertical(ItemLocation itemLocation)
|
||||
@@ -234,7 +418,25 @@ public class InventoryHelper(
|
||||
|
||||
protected InventoryItemHash GetInventoryItemHash(List<Item> inventoryItems)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
var inventoryItemHash = new InventoryItemHash
|
||||
{
|
||||
ByItemId = new(),
|
||||
ByParentId = new()
|
||||
};
|
||||
foreach (var item in inventoryItems)
|
||||
{
|
||||
inventoryItemHash.ByItemId.TryAdd(item.Id, item);
|
||||
|
||||
if (item.ParentId is null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!inventoryItemHash.ByParentId.ContainsKey(item.ParentId)) {
|
||||
inventoryItemHash.ByParentId[item.ParentId] = [];
|
||||
}
|
||||
inventoryItemHash.ByParentId[item.ParentId].Add(item);
|
||||
}
|
||||
return inventoryItemHash;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -29,8 +29,8 @@ public record Item
|
||||
|
||||
public record ItemLocation
|
||||
{
|
||||
public double? X { get; set; }
|
||||
public double? Y { get; set; }
|
||||
public int? X { get; set; }
|
||||
public int? Y { get; set; }
|
||||
public object? R { get; set; } // TODO: Can be string or number
|
||||
public bool? IsSearched { get; set; }
|
||||
|
||||
|
||||
@@ -153,19 +153,19 @@ public record Props
|
||||
public double? RepairSpeed { get; set; }
|
||||
|
||||
[JsonPropertyName("ExtraSizeLeft")]
|
||||
public double? ExtraSizeLeft { get; set; }
|
||||
public int? ExtraSizeLeft { get; set; }
|
||||
|
||||
[JsonPropertyName("ExtraSizeRight")]
|
||||
public double? ExtraSizeRight { get; set; }
|
||||
public int? ExtraSizeRight { get; set; }
|
||||
|
||||
[JsonPropertyName("ExtraSizeUp")]
|
||||
public double? ExtraSizeUp { get; set; }
|
||||
public int? ExtraSizeUp { get; set; }
|
||||
|
||||
[JsonPropertyName("FlareTypes")]
|
||||
public List<string>? FlareTypes { get; set; }
|
||||
|
||||
[JsonPropertyName("ExtraSizeDown")]
|
||||
public double? ExtraSizeDown { get; set; }
|
||||
public int? ExtraSizeDown { get; set; }
|
||||
|
||||
[JsonPropertyName("ExtraSizeForceAdd")]
|
||||
public bool? ExtraSizeForceAdd { get; set; }
|
||||
@@ -474,7 +474,7 @@ public record Props
|
||||
public bool? Retractable { get; set; }
|
||||
|
||||
[JsonPropertyName("SizeReduceRight")]
|
||||
public double? SizeReduceRight { get; set; }
|
||||
public int? SizeReduceRight { get; set; }
|
||||
|
||||
[JsonPropertyName("CenterOfImpact")]
|
||||
public double? CenterOfImpact { get; set; }
|
||||
@@ -1512,10 +1512,10 @@ public record GridProps
|
||||
public List<GridFilter>? Filters { get; set; }
|
||||
|
||||
[JsonPropertyName("cellsH")]
|
||||
public double? CellsH { get; set; }
|
||||
public int? CellsH { get; set; }
|
||||
|
||||
[JsonPropertyName("cellsV")]
|
||||
public double? CellsV { get; set; }
|
||||
public int? CellsV { get; set; }
|
||||
|
||||
[JsonPropertyName("minCount")]
|
||||
public double? MinCount { get; set; }
|
||||
|
||||
Reference in New Issue
Block a user