Refactor Item collections for thread safety and performance

Replaces static Item.ItemList and related collections with thread-safe data structures using ConcurrentDictionary and ImmutableHashSet. Adds thread-safe helpers for marking items for deconstruction and managing item lists. Updates all usages of Item.ItemList and DeconstructItems to use new APIs, improving performance and safety in multi-threaded contexts. Also refactors MeleeWeapon and Projectile impact queues to use ConcurrentQueue, and updates related logic throughout the codebase.
This commit is contained in:
Eero
2025-12-28 03:57:04 +08:00
parent edd50ef181
commit 90962b2328
22 changed files with 232 additions and 92 deletions
@@ -119,7 +119,7 @@ namespace Barotrauma
protected override bool CheckObjectiveState()
{
if (item.IgnoreByAI(character) || Item.DeconstructItems.Contains(item))
if (item.IgnoreByAI(character) || Item.IsMarkedForDeconstruction(item))
{
Abandon = true;
}
@@ -114,7 +114,7 @@ namespace Barotrauma
if (!allowUnloading) { return false; }
if (requireValidContainer && !IsValidContainer(item.Container, character)) { return false; }
}
if (ignoreItemsMarkedForDeconstruction && Item.DeconstructItems.Contains(item)) { return false; }
if (ignoreItemsMarkedForDeconstruction && Item.IsMarkedForDeconstruction(item)) { return false; }
if (!item.HasAccess(character)) { return false; }
if (character != null && !IsItemInsideValidSubmarine(item, character)) { return false; }
if (item.HasBallastFloraInHull) { return false; }
@@ -440,7 +440,7 @@ namespace Barotrauma
if (Identifier == Tags.DeconstructThis && item.AllowDeconstruct)
{
if (item.AllowDeconstruct && !Item.DeconstructItems.Contains(item) &&
if (item.AllowDeconstruct && !Item.IsMarkedForDeconstruction(item) &&
//only allow deconstructing if there are no deconstruction recipes (= deconstructing yields nothing), or deconstruction recipes that
(item.Prefab.DeconstructItems.None() ||
item.Prefab.DeconstructItems.Any(deconstructItem =>
@@ -454,7 +454,7 @@ namespace Barotrauma
}
else if (Identifier == Tags.DontDeconstructThis)
{
if (Item.DeconstructItems.Contains(item)) { return true; }
if (Item.IsMarkedForDeconstruction(item)) { return true; }
}
ImmutableArray<Identifier> targetItems = GetTargetItems(option);
@@ -2761,10 +2761,11 @@ namespace Barotrauma
}
int itemsPerFrame = IsOnPlayerTeam ? 100 : 10;
int checkedItemCount = 0;
for (int i = 0; i < itemsPerFrame && itemIndex < Item.ItemList.Count; i++, itemIndex++)
var cachedItems = Item.GetCachedItemList();
for (int i = 0; i < itemsPerFrame && itemIndex < cachedItems.Count; i++, itemIndex++)
{
checkedItemCount++;
var item = Item.ItemList[itemIndex];
var item = cachedItems[itemIndex];
if (!item.IsInteractable(this)) { continue; }
if (ignoredItems != null && ignoredItems.Contains(item)) { continue; }
if (item.Submarine == null) { continue; }
@@ -2800,10 +2801,10 @@ namespace Barotrauma
}
}
targetItem = _foundItem;
bool completed = itemIndex >= Item.ItemList.Count - 1;
bool completed = itemIndex >= cachedItems.Count - 1;
if (HumanAIController.DebugAI && checkedItemCount > 0 && targetItem != null && StopWatch.ElapsedMilliseconds > 1)
{
var msg = $"Went through {checkedItemCount} of total {Item.ItemList.Count} items. Found item {targetItem.Name} in {StopWatch.ElapsedMilliseconds} ms. Completed: {completed}";
var msg = $"Went through {checkedItemCount} of total {cachedItems.Count} items. Found item {targetItem.Name} in {StopWatch.ElapsedMilliseconds} ms. Completed: {completed}";
if (StopWatch.ElapsedMilliseconds > 5)
{
DebugConsole.ThrowError(msg);