Converted RemoveFiRStatusFromItemsInContainer into extension method

Improved performance of method by using breadth-first search to find children instead of loop
Wrote tests for method
This commit is contained in:
Chomp
2025-07-30 23:13:09 +01:00
parent 503967935b
commit c89c84dff3
4 changed files with 186 additions and 29 deletions
@@ -416,5 +416,37 @@ namespace SPTarkov.Server.Core.Extensions
return new InventoryItemHash { ByItemId = inventoryItems.ToDictionary(item => item.Id), ByParentId = byParentId };
}
/// <summary>
/// Remove spawned in session (FiR) status from items inside a container
/// </summary>
/// <param name="pmcData">Player profile</param>
/// <param name="containerSlotId">Container slot id to find items for and remove FiR from e.g. "Backpack"</param>
public static void RemoveFiRStatusFromItemsInContainer(this PmcData pmcData, string containerSlotId)
{
var container = pmcData?.Inventory?.Items?.FirstOrDefault(item => item.SlotId == containerSlotId);
if (container is null)
{
return;
}
var parentItemLookup = pmcData.Inventory.Items.ToLookup(item => item.ParentId);
var parentIdsToSearch = new Queue<string>();
parentIdsToSearch.Enqueue(container.Id);
while (parentIdsToSearch.Count > 0)
{
var currentParentId = parentIdsToSearch.Dequeue();
foreach (var childItem in parentItemLookup[currentParentId])
{
if (childItem.Upd?.SpawnedInSession != null && childItem.Upd.SpawnedInSession.Value)
{
childItem.Upd.SpawnedInSession = false;
}
parentIdsToSearch.Enqueue(childItem.Id);
}
}
}
}
}
@@ -144,34 +144,6 @@ public class InRaidHelper(InventoryHelper inventoryHelper, ConfigServer configSe
pmcData.Inventory.FastPanel = new();
}
/// <summary>
/// Remove FiR status from designated container.
/// </summary>
/// <param name="sessionId">Session id</param>
/// <param name="pmcData">Player profile</param>
/// <param name="secureContainerSlotId">Container slot id to find items for and remove FiR from</param>
public void RemoveFiRStatusFromItemsInContainer(MongoId sessionId, PmcData pmcData, string secureContainerSlotId)
{
if (!pmcData.Inventory.Items.Any(item => item.SlotId == secureContainerSlotId))
{
return;
}
List<Item> itemsInsideContainer = [];
foreach (var inventoryItem in pmcData.Inventory.Items.Where(item => item.Upd is not null && item.SlotId != "hideout"))
{
if (inventoryItem.ItemIsInsideContainer(secureContainerSlotId, pmcData.Inventory.Items))
{
itemsInsideContainer.Add(inventoryItem);
}
}
foreach (var item in itemsInsideContainer.Where(item => item.Upd?.SpawnedInSession ?? false))
{
item.Upd.SpawnedInSession = false;
}
}
/// <summary>
/// Get a list of items from a profile that will be lost on death.
/// </summary>
@@ -777,7 +777,7 @@ public class LocationLifecycleService(
inRaidHelper.DeleteInventory(serverPmcProfile, sessionId);
inRaidHelper.RemoveFiRStatusFromItemsInContainer(sessionId, serverPmcProfile, "SecuredContainer");
serverPmcProfile.RemoveFiRStatusFromItemsInContainer("SecuredContainer");
}
// Must occur AFTER killer messages have been sent
+153
View File
@@ -1,6 +1,7 @@
using NUnit.Framework;
using SPTarkov.Server.Core.Extensions;
using SPTarkov.Server.Core.Models.Common;
using SPTarkov.Server.Core.Models.Eft.Common;
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
namespace UnitTests.Tests.Extensions;
@@ -139,4 +140,156 @@ public class ItemTests
Assert.AreEqual(result[0].Id, rootItem.Id);
Assert.AreEqual(result.Count, 1);
}
[Test]
public void RemoveFiRStatusFromItemsInContainer_twoItemsInBackpack()
{
var profile = new PmcData() { Inventory = new BotBaseInventory() { Items = [] } };
profile.Inventory.Equipment = new MongoId();
// Add backpack
var backpackId = new MongoId();
profile.Inventory.Items.Add(
new Item
{
Id = backpackId,
Template = ItemTpl.BACKPACK_HAZARD_4_PILLBOX_BACKPACK_BLACK,
ParentId = profile.Inventory.Equipment,
SlotId = "Backpack",
}
);
// Add ifak to first slot in backpack
var item1Id = new MongoId();
profile.Inventory.Items.Add(
new Item
{
Id = item1Id,
Template = ItemTpl.MEDKIT_AFAK_TACTICAL_INDIVIDUAL_FIRST_AID_KIT,
ParentId = backpackId,
SlotId = "main",
Upd = new Upd { SpawnedInSession = true },
Location = new ItemLocation
{
X = 0,
Y = 0,
R = ItemRotation.Horizontal,
},
}
);
// Add wrench to first slot of ifak
var item2Id = new MongoId();
profile.Inventory.Items.Add(
new Item
{
Id = item2Id,
Template = ItemTpl.BARTER_WRENCH,
ParentId = backpackId,
SlotId = "main",
Upd = new Upd { SpawnedInSession = true },
Location = new ItemLocation
{
X = 1,
Y = 0,
R = ItemRotation.Horizontal,
},
}
);
// Add armband to armband slot as root
var item3Id = new MongoId();
profile.Inventory.Items.Add(
new Item
{
Id = item3Id,
Template = ItemTpl.ARMBAND_RED,
ParentId = profile.Inventory.Equipment,
SlotId = "Armband",
Upd = new Upd { SpawnedInSession = true },
}
);
profile.RemoveFiRStatusFromItemsInContainer("Backpack");
Assert.AreEqual(false, profile.Inventory.Items.FirstOrDefault(item => item.Id == item1Id).Upd.SpawnedInSession);
Assert.AreEqual(false, profile.Inventory.Items.FirstOrDefault(item => item.Id == item2Id).Upd.SpawnedInSession);
Assert.AreEqual(true, profile.Inventory.Items.FirstOrDefault(item => item.Id == item3Id).Upd.SpawnedInSession);
}
[Test]
public void RemoveFiRStatusFromItemsInContainer_oneItemWithChildInBackpack()
{
var profile = new PmcData { Inventory = new BotBaseInventory { Items = [] } };
profile.Inventory.Equipment = new MongoId();
// Add backpack
var backpackId = new MongoId();
profile.Inventory.Items.Add(
new Item
{
Id = backpackId,
Template = ItemTpl.BACKPACK_HAZARD_4_PILLBOX_BACKPACK_BLACK,
ParentId = profile.Inventory.Equipment,
SlotId = "Backpack",
}
);
// Add ifak to first slot in backpack
var item1Id = new MongoId();
profile.Inventory.Items.Add(
new Item
{
Id = item1Id,
Template = ItemTpl.MEDKIT_AFAK_TACTICAL_INDIVIDUAL_FIRST_AID_KIT,
ParentId = backpackId,
SlotId = "main",
Upd = new Upd { SpawnedInSession = true },
Location = new ItemLocation
{
X = 0,
Y = 0,
R = ItemRotation.Horizontal,
},
}
);
// Add wrench to first slot of ifak as child
var item2Id = new MongoId();
profile.Inventory.Items.Add(
new Item
{
Id = item2Id,
Template = ItemTpl.BARTER_WRENCH,
ParentId = item1Id,
SlotId = "main",
Upd = new Upd { SpawnedInSession = true },
Location = new ItemLocation
{
X = 1,
Y = 0,
R = ItemRotation.Horizontal,
},
}
);
// Add armband to armband slot as root
var item3Id = new MongoId();
profile.Inventory.Items.Add(
new Item
{
Id = item3Id,
Template = ItemTpl.ARMBAND_RED,
ParentId = profile.Inventory.Equipment,
SlotId = "Armband",
Upd = new Upd { SpawnedInSession = true },
}
);
profile.RemoveFiRStatusFromItemsInContainer("Backpack");
Assert.AreEqual(false, profile.Inventory.Items.FirstOrDefault(item => item.Id == item1Id).Upd.SpawnedInSession);
Assert.AreEqual(false, profile.Inventory.Items.FirstOrDefault(item => item.Id == item2Id).Upd.SpawnedInSession);
Assert.AreEqual(true, profile.Inventory.Items.FirstOrDefault(item => item.Id == item3Id).Upd.SpawnedInSession);
}
}