feat: Adds tidy option for serialization. Codegens ballotbox. Fixes pooled timer leaking (#681)

* Fixes pooled timer leaking
* Fixes `[dumptimers` command so it outputs properly, adds spacing, and stacktraces
* Adds `[Tidy]` for serializing Lists. This will remove deleted entities during world save before serializing the list.
* Adds helpers for managing Lists/Sets/Dictionaries


### New API

```cs
// Creates the list if it is null, then adds
Utility.Add(ref list, value);
Utility.Add(ref set, value);
Utility.Add(ref dict, key, value);

// Nulls the variable if the count is zero
Utility.Remove(ref list, value);
Utility.Remove(ref set, value);
Utility.Remove(ref dict, key);

// Marks entity as dirty in addition to doing the action
entity.Add(list, value);
// Marks entity as dirty, and will create list if it doesn't exist
entity.Add(ref list, value);

// Marks entity as dirty in addition to doing the action
entity.Remove(list, value);
// Marks entity as dirty, and will null the list count is zero
entity.Remove(ref list, value);
```


### Updates to [dumptimers
<img width="825" alt="Screen Shot 2021-08-14 at 2 55 10 AM" src="https://user-images.githubusercontent.com/3953314/129442449-ccf7fe14-29d6-4f3f-9366-c8eb7b9828a7.png">
This commit is contained in:
Kamron Batman 2021-08-14 03:02:53 -07:00 • committed by GitHub
parent 84cbd52a2a
commit 360143478a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
53 changed files with 627 additions and 464 deletions

View file

@ -1,10 +1,9 @@
using System;
using System.Collections.Generic;
using System.IO;
using Server.Collections;
using Server.Logging;
using Server.Network;
using Server.Utilities;
using QueuePool = Server.Utilities.RefPool<Server.Utilities.QueueRef<Server.Items.Container>>;
namespace Server.Items
{
@ -16,7 +15,6 @@ namespace Server.Items
public class Container : Item
{
private static readonly QueuePool m_QueuePool = new(QueueRef<Container>.Generate, 2, 5);
private static readonly List<Item> m_FindItemsList = new();
private ContainerData m_ContainerData;
@ -1299,8 +1297,7 @@ namespace Server.Items
{
var consumed = 0;
var toDelete = new Queue<Item>();
using var toDelete = PooledRefQueue<Item>.Create();
RecurseConsumeUpTo(this, type, amount, recurse, ref consumed, toDelete);
while (toDelete.Count > 0)
@ -1313,7 +1310,7 @@ namespace Server.Items
private static void RecurseConsumeUpTo(
Item current, Type type, int amount, bool recurse, ref int consumed,
Queue<Item> toDelete
PooledRefQueue<Item> toDelete
)
{
if (current == null || current.Items.Count == 0)
@ -1721,28 +1718,26 @@ namespace Server.Items
/// </returns>
public List<T> FindItemsByType<T>(bool recurse = true, Predicate<T> predicate = null) where T : Item
{
using (var queue = m_QueuePool.Get())
using var queue = PooledRefQueue<Container>.Create(128);
queue.Enqueue(this);
var items = new List<T>();
while (queue.Count > 0)
{
queue.Enqueue(this);
var items = new List<T>();
while (queue.Count > 0)
var container = queue.Dequeue();
foreach (var item in container.Items)
{
var container = queue.Dequeue();
foreach (var item in container.Items)
if (item is T typedItem && predicate?.Invoke(typedItem) != false)
{
if (item is T typedItem && predicate?.Invoke(typedItem) != false)
{
items.Add(typedItem);
}
else if (recurse && item is Container itemContainer)
{
queue.Enqueue(itemContainer);
}
items.Add(typedItem);
}
else if (recurse && item is Container itemContainer)
{
queue.Enqueue(itemContainer);
}
}
return items;
}
return items;
}
/// <summary>
@ -1765,28 +1760,26 @@ namespace Server.Items
/// </returns>
public T FindItemByType<T>(bool recurse = true, Predicate<T> predicate = null) where T : Item
{
using (var queue = m_QueuePool.Get())
using var queue = PooledRefQueue<Container>.Create(128);
queue.Enqueue(this);
while (queue.Count > 0)
{
queue.Enqueue(this);
while (queue.Count > 0)
var container = queue.Dequeue();
foreach (var item in container.Items)
{
var container = queue.Dequeue();
foreach (var item in container.Items)
if (item is T typedItem && predicate?.Invoke(typedItem) != false)
{
if (item is T typedItem && predicate?.Invoke(typedItem) != false)
{
return typedItem;
}
return typedItem;
}
if (recurse && item is Container itemContainer)
{
queue.Enqueue(itemContainer);
}
if (recurse && item is Container itemContainer)
{
queue.Enqueue(itemContainer);
}
}
return null;
}
return null;
}
private class GroupComparer : IComparer<Item>