fix: Moves container enumerables to Item. (#2238)
This commit is contained in:
parent
1e2f4b1171
commit
c2e44a58f6
4 changed files with 87 additions and 67 deletions
|
|
@ -8,12 +8,14 @@ namespace Server.Tests;
|
|||
[Collection("Sequential Server Tests")]
|
||||
public class ContainerTests
|
||||
{
|
||||
[Fact]
|
||||
public void TestFindItemsByType()
|
||||
[Theory]
|
||||
[InlineData(typeof(Container))]
|
||||
[InlineData(typeof(Item))]
|
||||
public void TestFindItemsByType(Type itemType)
|
||||
{
|
||||
var staticSerial = (Serial)0x3;
|
||||
|
||||
var container = new Container((Serial)0x1);
|
||||
var container = itemType.CreateInstance<Item>((Serial)0x1);
|
||||
container.AddItem(new Item((Serial)0x2));
|
||||
container.AddItem(new Static(staticSerial));
|
||||
|
||||
|
|
@ -27,18 +29,20 @@ public class ContainerTests
|
|||
Assert.Equal(staticSerial, staticItem.Serial);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestFindItemsByTypeNested()
|
||||
[Theory]
|
||||
[InlineData(typeof(Container))]
|
||||
[InlineData(typeof(Item))]
|
||||
public void TestFindItemsByTypeNested(Type itemType)
|
||||
{
|
||||
var static1 = new Static((Serial)0x3);
|
||||
var static2 = new Static((Serial)0x6);
|
||||
|
||||
var container = new Container((Serial)0x1);
|
||||
var container = itemType.CreateInstance<Item>((Serial)0x1);
|
||||
container.AddItem(new Item((Serial)0x2));
|
||||
var container2 = new Container((Serial)0x4);
|
||||
var container2 = itemType.CreateInstance<Item>((Serial)0x4);
|
||||
container.AddItem(container2);
|
||||
|
||||
var container3 = new Container((Serial)0x5);
|
||||
var container3 = itemType.CreateInstance<Item>((Serial)0x5);
|
||||
container2.AddItem(container3);
|
||||
container3.AddItem(static2);
|
||||
|
||||
|
|
@ -55,12 +59,14 @@ public class ContainerTests
|
|||
Assert.Equal(static2, statics[1]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestFindItemsByTypeNotMatching()
|
||||
[Theory]
|
||||
[InlineData(typeof(Container))]
|
||||
[InlineData(typeof(Item))]
|
||||
public void TestFindItemsByTypeNotMatching(Type itemType)
|
||||
{
|
||||
var container = new Container((Serial)0x1);
|
||||
var container = itemType.CreateInstance<Item>((Serial)0x1);
|
||||
container.AddItem(new Item((Serial)0x2));
|
||||
var container2 = new Container((Serial)0x4);
|
||||
var container2 = itemType.CreateInstance<Item>((Serial)0x4);
|
||||
container.AddItem(container2);
|
||||
container2.AddItem(new Item((Serial)0x5));
|
||||
|
||||
|
|
@ -73,10 +79,12 @@ public class ContainerTests
|
|||
Assert.Null(staticItem);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestFindItemsByTypeShouldThrowWhenModified()
|
||||
[Theory]
|
||||
[InlineData(typeof(Container))]
|
||||
[InlineData(typeof(Item))]
|
||||
public void TestFindItemsByTypeShouldThrowWhenModified(Type itemType)
|
||||
{
|
||||
var container = new Container((Serial)0x1);
|
||||
var container = itemType.CreateInstance<Item>((Serial)0x1);
|
||||
container.AddItem(new Item((Serial)0x2));
|
||||
var staticItem = new Static((Serial)0x3);
|
||||
container.AddItem(staticItem);
|
||||
|
|
@ -96,10 +104,12 @@ public class ContainerTests
|
|||
);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestEnumerateItemsByTypeWhenModified()
|
||||
[Theory]
|
||||
[InlineData(typeof(Container))]
|
||||
[InlineData(typeof(Item))]
|
||||
public void TestEnumerateItemsByTypeWhenModified(Type itemType)
|
||||
{
|
||||
var container = new Container((Serial)0x1);
|
||||
var container = itemType.CreateInstance<Item>((Serial)0x1);
|
||||
|
||||
var item1 = new Item((Serial)0x2);
|
||||
container.AddItem(item1);
|
||||
|
|
|
|||
|
|
@ -1,3 +1,18 @@
|
|||
/*************************************************************************
|
||||
* ModernUO *
|
||||
* Copyright 2019-2025 - ModernUO Development Team *
|
||||
* Email: hi@modernuo.com *
|
||||
* File: Container.cs *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
*************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
|
@ -25,7 +40,7 @@ public partial class Container : Item
|
|||
|
||||
private int m_TotalItems;
|
||||
private int m_TotalWeight;
|
||||
private int _version;
|
||||
internal int _version;
|
||||
|
||||
[SerializableField(3)]
|
||||
[SerializedCommandProperty(AccessLevel.GameMaster)]
|
||||
|
|
@ -281,16 +296,6 @@ public partial class Container : Item
|
|||
return true;
|
||||
}
|
||||
|
||||
private static void SetSaveFlag(ref SaveFlag flags, SaveFlag toSet, bool setIf)
|
||||
{
|
||||
if (setIf)
|
||||
{
|
||||
flags |= toSet;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool GetSaveFlag(SaveFlag flags, SaveFlag toGet) => (flags & toGet) != 0;
|
||||
|
||||
[AfterDeserialization]
|
||||
private void AfterDeserialization()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
/*************************************************************************
|
||||
* ModernUO *
|
||||
* Copyright 2019-2023 - ModernUO Development Team *
|
||||
* Copyright 2019-2025 - ModernUO Development Team *
|
||||
* Email: hi@modernuo.com *
|
||||
* File: Container.Enumerable.cs *
|
||||
* File: Item.Enumerable.cs *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
|
|
@ -18,13 +18,13 @@ using System.Runtime.CompilerServices;
|
|||
using System.Runtime.InteropServices;
|
||||
using Server.Collections;
|
||||
|
||||
namespace Server.Items;
|
||||
namespace Server;
|
||||
|
||||
public partial class Container
|
||||
public partial class Item
|
||||
{
|
||||
/// <summary>
|
||||
/// Performs a breadth-first search through all the <see cref="Item" />s and
|
||||
/// nested <see cref="Container" />s within this <see cref="Container" />.
|
||||
/// nested <see cref="Item" />s within this <see cref="Item" />.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// DO NOT consume, delete, or move items while iterating with any FindItemByType or FindItems overloads
|
||||
|
|
@ -42,8 +42,8 @@ public partial class Container
|
|||
/// <typeparam name="T">Type of objects being searched for</typeparam>
|
||||
/// <param name="recurse">
|
||||
/// Optional: If true, the search will recursively
|
||||
/// check any nested <see cref="Container" />s; otherwise, nested
|
||||
/// <see cref="Container" />s will not be searched.
|
||||
/// check any nested <see cref="Item" />s; otherwise, nested
|
||||
/// <see cref="Item" />s will not be searched.
|
||||
/// </param>
|
||||
/// <param name="predicate">
|
||||
/// Optional: A predicate to check if the <see cref="Item" />
|
||||
|
|
@ -71,7 +71,7 @@ public partial class Container
|
|||
|
||||
/// <summary>
|
||||
/// Safely enumerates items using a breadth-first search through all the <see cref="Item" />s and
|
||||
/// nested <see cref="Container" />s within this <see cref="Container" />.
|
||||
/// nested <see cref="Item" />s within this <see cref="Item" />.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Use EnumerateItemsByType for situations where the item might be manipulated, consumed, or moved.
|
||||
|
|
@ -92,8 +92,8 @@ public partial class Container
|
|||
/// <typeparam name="T">Type of objects being searched for</typeparam>
|
||||
/// <param name="recurse">
|
||||
/// Optional: If true, the search will recursively
|
||||
/// check any nested <see cref="Container" />s; otherwise, nested
|
||||
/// <see cref="Container" />s will not be searched.
|
||||
/// check any nested <see cref="Item" />s; otherwise, nested
|
||||
/// <see cref="Item" />s will not be searched.
|
||||
/// </param>
|
||||
/// <param name="predicate">
|
||||
/// Optional: A predicate to check if the <see cref="Item" />
|
||||
|
|
@ -203,30 +203,31 @@ public partial class Container
|
|||
public ref struct FindItemsByTypeEnumerator<T> where T : Item
|
||||
{
|
||||
private const string InvalidOperation_EnumFailedVersion =
|
||||
"Container was modified after enumerator was instantiated. Use Container.EnumerateItems method instead for safe enumerations.";
|
||||
"Item was modified after enumerator was instantiated. Use Item.EnumerateItems method instead for safe enumerations.";
|
||||
|
||||
private PooledRefQueue<Container> _containers;
|
||||
private PooledRefQueue<Item> _containers;
|
||||
private Span<Item> _items;
|
||||
private int _index;
|
||||
private T _current;
|
||||
private readonly bool _recurse;
|
||||
private readonly Predicate<T> _predicate;
|
||||
private Container _currentContainer;
|
||||
private Item _currentContainer;
|
||||
private int _version;
|
||||
|
||||
public FindItemsByTypeEnumerator(Container container, bool recurse, Predicate<T> predicate)
|
||||
public FindItemsByTypeEnumerator(Item container, bool recurse, Predicate<T> predicate)
|
||||
{
|
||||
_containers = PooledRefQueue<Container>.Create(_recurse ? 64 : 0);
|
||||
_containers = PooledRefQueue<Item>.Create(_recurse ? 64 : 0);
|
||||
|
||||
if (container != null)
|
||||
{
|
||||
if (container.m_Items != null)
|
||||
var items = container.LookupItems();
|
||||
if (items != null)
|
||||
{
|
||||
_items = CollectionsMarshal.AsSpan(container.m_Items);
|
||||
_items = CollectionsMarshal.AsSpan(items);
|
||||
}
|
||||
|
||||
_currentContainer = container;
|
||||
_version = container._version;
|
||||
_version = container.LookupContainerVersion();
|
||||
}
|
||||
|
||||
_current = default;
|
||||
|
|
@ -244,9 +245,9 @@ public partial class Container
|
|||
while (_containers.TryDequeue(out var c))
|
||||
{
|
||||
_currentContainer = c;
|
||||
_items = CollectionsMarshal.AsSpan(c.m_Items);
|
||||
_items = CollectionsMarshal.AsSpan(c.LookupItems());
|
||||
_index = 0;
|
||||
_version = c._version;
|
||||
_version = c.LookupContainerVersion();
|
||||
|
||||
if (SetNextItem())
|
||||
{
|
||||
|
|
@ -260,7 +261,7 @@ public partial class Container
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private bool SetNextItem()
|
||||
{
|
||||
if (_version != _currentContainer._version)
|
||||
if (_version != _currentContainer.LookupContainerVersion())
|
||||
{
|
||||
throw new InvalidOperationException(InvalidOperation_EnumFailedVersion);
|
||||
}
|
||||
|
|
@ -268,14 +269,14 @@ public partial class Container
|
|||
while (_index < _items.Length)
|
||||
{
|
||||
Item item = _items[_index++];
|
||||
if (_recurse && item is Container { m_Items.Count: > 0 } c)
|
||||
if (_recurse && item.LookupItems() is { Count: > 0 } items)
|
||||
{
|
||||
_containers.Enqueue(c);
|
||||
_containers.Enqueue(item);
|
||||
}
|
||||
|
||||
if (item is T t && _predicate?.Invoke(t) != false)
|
||||
{
|
||||
if (_version != _currentContainer._version)
|
||||
if (_version != _currentContainer.LookupContainerVersion())
|
||||
{
|
||||
throw new InvalidOperationException(InvalidOperation_EnumFailedVersion);
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
/*************************************************************************
|
||||
* ModernUO *
|
||||
* Copyright 2019-2024 - ModernUO Development Team *
|
||||
* Copyright 2019-2025 - ModernUO Development Team *
|
||||
* Email: hi@modernuo.com *
|
||||
* File: Item.cs *
|
||||
* *
|
||||
|
|
@ -192,7 +192,7 @@ public enum ExpandFlag
|
|||
Spawner = 0x100
|
||||
}
|
||||
|
||||
public class Item : IHued, IComparable<Item>, ISpawnable, IObjectPropertyListEntity, IValueLinkListNode<Item>
|
||||
public partial class Item : IHued, IComparable<Item>, ISpawnable, IObjectPropertyListEntity, IValueLinkListNode<Item>
|
||||
{
|
||||
private static readonly ILogger logger = LogFactory.GetLogger(typeof(Item));
|
||||
|
||||
|
|
@ -534,6 +534,8 @@ public class Item : IHued, IComparable<Item>, ISpawnable, IObjectPropertyListEnt
|
|||
|
||||
public List<Item> Items => LookupItems() ?? EmptyItems;
|
||||
|
||||
public int LookupContainerVersion() => (this as Container)?._version ?? LookupCompactInfo()?.Version ?? 0;
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public IEntity RootParent
|
||||
{
|
||||
|
|
@ -1696,11 +1698,11 @@ public class Item : IHued, IComparable<Item>, ISpawnable, IObjectPropertyListEnt
|
|||
{
|
||||
if (this is Container cont)
|
||||
{
|
||||
return cont.m_Items ?? (cont.m_Items = new List<Item>());
|
||||
return cont.m_Items ??= new List<Item>();
|
||||
}
|
||||
|
||||
var info = AcquireCompactInfo();
|
||||
return info.m_Items ?? (info.m_Items = new List<Item>());
|
||||
return info.m_Items ??= new List<Item>();
|
||||
}
|
||||
|
||||
private void SetFlag(ImplFlag flag, bool value)
|
||||
|
|
@ -2471,15 +2473,6 @@ public class Item : IHued, IComparable<Item>, ISpawnable, IObjectPropertyListEnt
|
|||
{
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static void SetSaveFlag(ref SaveFlag flags, SaveFlag toSet, bool setIf)
|
||||
{
|
||||
if (setIf)
|
||||
{
|
||||
flags |= toSet;
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static bool GetSaveFlag(SaveFlag flags, SaveFlag toGet) => (flags & toGet) != 0;
|
||||
|
||||
|
|
@ -3195,9 +3188,13 @@ public class Item : IHued, IComparable<Item>, ISpawnable, IObjectPropertyListEnt
|
|||
item.Map = m_Map;
|
||||
|
||||
var items = AcquireItems();
|
||||
|
||||
items.Add(item);
|
||||
|
||||
if (this is not Container)
|
||||
{
|
||||
AcquireCompactInfo().Version++;
|
||||
}
|
||||
|
||||
if (!item.IsVirtualItem)
|
||||
{
|
||||
UpdateTotal(item, TotalType.Gold, item.TotalGold);
|
||||
|
|
@ -3360,6 +3357,11 @@ public class Item : IHued, IComparable<Item>, ISpawnable, IObjectPropertyListEnt
|
|||
|
||||
if (items.Remove(item))
|
||||
{
|
||||
if (this is not Container)
|
||||
{
|
||||
AcquireCompactInfo().Version++;
|
||||
}
|
||||
|
||||
item.SendRemovePacket();
|
||||
|
||||
if (!item.IsVirtualItem)
|
||||
|
|
@ -4321,6 +4323,8 @@ public class Item : IHued, IComparable<Item>, ISpawnable, IObjectPropertyListEnt
|
|||
public int m_TempFlags;
|
||||
|
||||
public double m_Weight = -1;
|
||||
|
||||
public int Version;
|
||||
}
|
||||
|
||||
[Flags]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue