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:
parent
84cbd52a2a
commit
360143478a
53 changed files with 627 additions and 464 deletions
|
|
@ -182,8 +182,8 @@ namespace SerializationGenerator
|
|||
var attrCtorArgs = serializableFieldAttr.ConstructorArguments;
|
||||
|
||||
var order = (int)attrCtorArgs[0].Value!;
|
||||
var getterAccessor = Helpers.GetAccessibility(attrCtorArgs[1].Value!.ToString());
|
||||
var setterAccessor = Helpers.GetAccessibility(attrCtorArgs[2].Value!.ToString());
|
||||
var getterAccessor = Helpers.GetAccessibility(attrCtorArgs[1].Value?.ToString());
|
||||
var setterAccessor = Helpers.GetAccessibility(attrCtorArgs[2].Value?.ToString());
|
||||
var virtualProperty = (bool)attrCtorArgs[3].Value!;
|
||||
|
||||
if (fieldOrPropertySymbol is IFieldSymbol fieldSymbol)
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ namespace SerializationGenerator
|
|||
var genericReaderInterface = compilation.GetTypeByMetadataName(SymbolMetadata.GENERIC_READER_INTERFACE);
|
||||
|
||||
source.GenerateMethodStart(
|
||||
" ",
|
||||
"Deserialize",
|
||||
Accessibility.Public,
|
||||
isOverride,
|
||||
|
|
@ -120,7 +121,7 @@ namespace SerializationGenerator
|
|||
source.AppendLine($"{indent}Timer.DelayCall({afterDeserialization.Name});");
|
||||
}
|
||||
|
||||
source.GenerateMethodEnd();
|
||||
source.GenerateMethodEnd(" ");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ namespace SerializationGenerator
|
|||
);
|
||||
|
||||
const string indent = " ";
|
||||
const string innerIndent = " ";
|
||||
const string propertyIndent = " ";
|
||||
|
||||
var propertyAccessor = setter > getter ? setter : getter;
|
||||
|
|
@ -59,7 +60,6 @@ namespace SerializationGenerator
|
|||
|
||||
// Setter
|
||||
source.GeneratePropertySetterStart(propertyIndent, false, setterAccessor.Value);
|
||||
const string innerIndent = " ";
|
||||
source.AppendLine($"{innerIndent}if (value != {fieldName})");
|
||||
source.AppendLine($"{innerIndent}{{");
|
||||
source.AppendLine($"{innerIndent} {fieldName} = value;");
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ namespace SerializationGenerator
|
|||
var serialType = (ITypeSymbol)compilation.GetTypeByMetadataName("Server.Serial");
|
||||
|
||||
source.GenerateConstructorStart(
|
||||
" ",
|
||||
className,
|
||||
Accessibility.Public,
|
||||
new []{ (serialType, "serial") }.ToImmutableArray(),
|
||||
|
|
@ -44,7 +45,7 @@ namespace SerializationGenerator
|
|||
SetTypeRef(typeof({className}));");
|
||||
}
|
||||
|
||||
source.GenerateMethodEnd();
|
||||
source.GenerateMethodEnd(" ");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ namespace SerializationGenerator
|
|||
var genericWriterInterface = compilation.GetTypeByMetadataName(SymbolMetadata.GENERIC_WRITER_INTERFACE);
|
||||
|
||||
source.GenerateMethodStart(
|
||||
" ",
|
||||
"Serialize",
|
||||
Accessibility.Public,
|
||||
isOverride,
|
||||
|
|
@ -61,7 +62,7 @@ namespace SerializationGenerator
|
|||
);
|
||||
}
|
||||
|
||||
source.GenerateMethodEnd();
|
||||
source.GenerateMethodEnd(" ");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using SerializationGenerator;
|
||||
|
|
@ -52,11 +53,18 @@ namespace SerializableMigration
|
|||
parentSymbol
|
||||
);
|
||||
|
||||
var extraOptions = "";
|
||||
if (attributes.Any(a => a.IsTidy(compilation)))
|
||||
{
|
||||
extraOptions += "@Tidy";
|
||||
}
|
||||
|
||||
var length = serializableSetType.RuleArguments.Length;
|
||||
ruleArguments = new string[length + 2];
|
||||
ruleArguments[0] = setTypeSymbol.ToDisplayString();
|
||||
ruleArguments[1] = serializableSetType.Rule;
|
||||
Array.Copy(serializableSetType.RuleArguments, 0, ruleArguments, 2, length);
|
||||
ruleArguments = new string[length + 3];
|
||||
ruleArguments[0] = extraOptions;
|
||||
ruleArguments[1] = setTypeSymbol.ToDisplayString();
|
||||
ruleArguments[2] = serializableSetType.Rule;
|
||||
Array.Copy(serializableSetType.RuleArguments, 0, ruleArguments, 3, length);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -71,9 +79,12 @@ namespace SerializableMigration
|
|||
}
|
||||
|
||||
var ruleArguments = property.RuleArguments;
|
||||
var setElementRule = SerializableMigrationRulesEngine.Rules[ruleArguments[1]];
|
||||
var setElementRuleArguments = new string[ruleArguments.Length - 2];
|
||||
Array.Copy(ruleArguments, 2, setElementRuleArguments, 0, ruleArguments.Length - 2);
|
||||
var hasExtraOptions = ruleArguments[0] == "" || ruleArguments[0].StartsWith("@", StringComparison.Ordinal);
|
||||
var argumentsOffset = hasExtraOptions ? 1 : 0;
|
||||
|
||||
var setElementRule = SerializableMigrationRulesEngine.Rules[ruleArguments[1 + argumentsOffset]];
|
||||
var setElementRuleArguments = new string[ruleArguments.Length - 2 - argumentsOffset];
|
||||
Array.Copy(ruleArguments, 2 + argumentsOffset, setElementRuleArguments, 0, ruleArguments.Length - 2 - argumentsOffset);
|
||||
|
||||
var propertyName = property.Name;
|
||||
var propertyVarPrefix = $"{char.ToLower(propertyName[0])}{propertyName.Substring(1, propertyName.Length - 1)}";
|
||||
|
|
@ -81,16 +92,16 @@ namespace SerializableMigration
|
|||
var propertyEntry = $"{propertyVarPrefix}Entry";
|
||||
var propertyCount = $"{propertyVarPrefix}Count";
|
||||
|
||||
source.AppendLine($"{indent}{ruleArguments[0]} {propertyEntry};");
|
||||
source.AppendLine($"{indent}{ruleArguments[argumentsOffset]} {propertyEntry};");
|
||||
source.AppendLine($"{indent}var {propertyCount} = reader.ReadInt();");
|
||||
source.AppendLine($"{indent}{property.Name} = new System.Collections.Generic.HashSet<{ruleArguments[0]}>({propertyCount});");
|
||||
source.AppendLine($"{indent}{property.Name} = new System.Collections.Generic.HashSet<{ruleArguments[argumentsOffset]}>({propertyCount});");
|
||||
source.AppendLine($"{indent}for (var {propertyIndex} = 0; i < {propertyCount}; {propertyIndex}++)");
|
||||
source.AppendLine($"{indent}{{");
|
||||
|
||||
var serializableSetElement = new SerializableProperty
|
||||
{
|
||||
Name = propertyEntry,
|
||||
Type = ruleArguments[0],
|
||||
Type = ruleArguments[argumentsOffset],
|
||||
Rule = setElementRule.RuleName,
|
||||
RuleArguments = setElementRuleArguments
|
||||
};
|
||||
|
|
@ -111,14 +122,23 @@ namespace SerializableMigration
|
|||
}
|
||||
|
||||
var ruleArguments = property.RuleArguments;
|
||||
var setElementRule = SerializableMigrationRulesEngine.Rules[ruleArguments[1]];
|
||||
var setElementRuleArguments = new string[ruleArguments.Length - 2];
|
||||
Array.Copy(ruleArguments, 2, setElementRuleArguments, 0, ruleArguments.Length - 2);
|
||||
var hasExtraOptions = ruleArguments[0] == "" || ruleArguments[0].StartsWith("@", StringComparison.Ordinal);
|
||||
var shouldTidy = hasExtraOptions && ruleArguments[0].Contains("@Tidy");
|
||||
var argumentsOffset = hasExtraOptions ? 1 : 0;
|
||||
|
||||
var setElementRule = SerializableMigrationRulesEngine.Rules[ruleArguments[1 + argumentsOffset]];
|
||||
var setElementRuleArguments = new string[ruleArguments.Length - 2 - argumentsOffset];
|
||||
Array.Copy(ruleArguments, 2 + argumentsOffset, setElementRuleArguments, 0, ruleArguments.Length - 2 - argumentsOffset);
|
||||
|
||||
var propertyName = property.Name;
|
||||
var propertyVarPrefix = $"{char.ToLower(propertyName[0])}{propertyName.Substring(1, propertyName.Length - 1)}";
|
||||
var propertyEntry = $"{propertyVarPrefix}Entry";
|
||||
var propertyCount = $"{propertyVarPrefix}Count";
|
||||
|
||||
if (shouldTidy)
|
||||
{
|
||||
source.AppendLine($"{indent}{property.Name}?.Tidy();");
|
||||
}
|
||||
source.AppendLine($"{indent}var {propertyCount} = {property.Name}?.Count ?? 0;");
|
||||
source.AppendLine($"{indent}writer.Write({propertyCount});");
|
||||
source.AppendLine($"{indent}if ({propertyCount} > 0)");
|
||||
|
|
@ -129,7 +149,7 @@ namespace SerializableMigration
|
|||
var serializableSetElement = new SerializableProperty
|
||||
{
|
||||
Name = propertyEntry,
|
||||
Type = ruleArguments[0],
|
||||
Type = ruleArguments[argumentsOffset],
|
||||
Rule = setElementRule.RuleName,
|
||||
RuleArguments = setElementRuleArguments
|
||||
};
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using SerializationGenerator;
|
||||
|
|
@ -52,11 +53,18 @@ namespace SerializableMigration
|
|||
parentSymbol
|
||||
);
|
||||
|
||||
var extraOptions = "";
|
||||
if (attributes.Any(a => a.IsTidy(compilation)))
|
||||
{
|
||||
extraOptions += "@Tidy";
|
||||
}
|
||||
|
||||
var length = serializableListType.RuleArguments.Length;
|
||||
ruleArguments = new string[length + 2];
|
||||
ruleArguments[0] = listTypeSymbol.ToDisplayString();
|
||||
ruleArguments[1] = serializableListType.Rule;
|
||||
Array.Copy(serializableListType.RuleArguments, 0, ruleArguments, 2, length);
|
||||
ruleArguments = new string[length + 3];
|
||||
ruleArguments[0] = extraOptions;
|
||||
ruleArguments[1] = listTypeSymbol.ToDisplayString();
|
||||
ruleArguments[2] = serializableListType.Rule;
|
||||
Array.Copy(serializableListType.RuleArguments, 0, ruleArguments, 3, length);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -71,9 +79,13 @@ namespace SerializableMigration
|
|||
}
|
||||
|
||||
var ruleArguments = property.RuleArguments;
|
||||
var listElementRule = SerializableMigrationRulesEngine.Rules[ruleArguments[1]];
|
||||
var listElementRuleArguments = new string[ruleArguments.Length - 2];
|
||||
Array.Copy(ruleArguments, 2, listElementRuleArguments, 0, ruleArguments.Length - 2);
|
||||
var hasExtraOptions = ruleArguments[0] == "" || ruleArguments[0].StartsWith("@", StringComparison.Ordinal);
|
||||
var argumentsOffset = hasExtraOptions ? 1 : 0;
|
||||
|
||||
var listElementRule = SerializableMigrationRulesEngine.Rules[ruleArguments[argumentsOffset + 1]];
|
||||
|
||||
var listElementRuleArguments = new string[ruleArguments.Length - 2 - argumentsOffset];
|
||||
Array.Copy(ruleArguments, 2 + argumentsOffset, listElementRuleArguments, 0, ruleArguments.Length - 2 - argumentsOffset);
|
||||
|
||||
var propertyName = property.Name;
|
||||
var propertyVarPrefix = $"{char.ToLower(propertyName[0])}{propertyName.Substring(1, propertyName.Length - 1)}";
|
||||
|
|
@ -81,16 +93,16 @@ namespace SerializableMigration
|
|||
var propertyEntry = $"{propertyVarPrefix}Entry";
|
||||
var propertyCount = $"{propertyVarPrefix}Count";
|
||||
|
||||
source.AppendLine($"{indent}{ruleArguments[0]} {propertyEntry};");
|
||||
source.AppendLine($"{indent}{ruleArguments[argumentsOffset]} {propertyEntry};");
|
||||
source.AppendLine($"{indent}var {propertyCount} = reader.ReadInt();");
|
||||
source.AppendLine($"{indent}{propertyName} = new System.Collections.Generic.List<{ruleArguments[0]}>({propertyCount});");
|
||||
source.AppendLine($"{indent}{propertyName} = new System.Collections.Generic.List<{ruleArguments[argumentsOffset]}>({propertyCount});");
|
||||
source.AppendLine($"{indent}for (var {propertyIndex} = 0; {propertyIndex} < {propertyCount}; {propertyIndex}++)");
|
||||
source.AppendLine($"{indent}{{");
|
||||
|
||||
var serializableListElement = new SerializableProperty
|
||||
{
|
||||
Name = propertyEntry,
|
||||
Type = ruleArguments[0],
|
||||
Type = ruleArguments[argumentsOffset],
|
||||
Rule = listElementRule.RuleName,
|
||||
RuleArguments = listElementRuleArguments
|
||||
};
|
||||
|
|
@ -111,14 +123,23 @@ namespace SerializableMigration
|
|||
}
|
||||
|
||||
var ruleArguments = property.RuleArguments;
|
||||
var listElementRule = SerializableMigrationRulesEngine.Rules[ruleArguments[1]];
|
||||
var listElementRuleArguments = new string[ruleArguments.Length - 2];
|
||||
Array.Copy(ruleArguments, 2, listElementRuleArguments, 0, ruleArguments.Length - 2);
|
||||
var hasExtraOptions = ruleArguments[0] == "" || ruleArguments[0].StartsWith("@", StringComparison.Ordinal);
|
||||
var shouldTidy = hasExtraOptions && ruleArguments[0].Contains("@Tidy");
|
||||
var argumentsOffset = hasExtraOptions ? 1 : 0;
|
||||
|
||||
var listElementRule = SerializableMigrationRulesEngine.Rules[ruleArguments[1 + argumentsOffset]];
|
||||
var listElementRuleArguments = new string[ruleArguments.Length - 2 - argumentsOffset];
|
||||
Array.Copy(ruleArguments, 2 + argumentsOffset, listElementRuleArguments, 0, ruleArguments.Length - 2 - argumentsOffset);
|
||||
|
||||
var propertyName = property.Name;
|
||||
var propertyVarPrefix = $"{char.ToLower(propertyName[0])}{propertyName.Substring(1, propertyName.Length - 1)}";
|
||||
var propertyEntry = $"{propertyVarPrefix}Entry";
|
||||
var propertyCount = $"{propertyVarPrefix}Count";
|
||||
|
||||
if (shouldTidy)
|
||||
{
|
||||
source.AppendLine($"{indent}{property.Name}?.Tidy();");
|
||||
}
|
||||
source.AppendLine($"{indent}var {propertyCount} = {property.Name}?.Count ?? 0;");
|
||||
source.AppendLine($"{indent}writer.Write({propertyCount});");
|
||||
source.AppendLine($"{indent}if ({propertyCount} > 0)");
|
||||
|
|
@ -129,7 +150,7 @@ namespace SerializableMigration
|
|||
var serializableListElement = new SerializableProperty
|
||||
{
|
||||
Name = propertyEntry,
|
||||
Type = ruleArguments[0],
|
||||
Type = ruleArguments[argumentsOffset],
|
||||
Rule = listElementRule.RuleName,
|
||||
RuleArguments = listElementRuleArguments
|
||||
};
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ namespace SerializationGenerator
|
|||
|
||||
public static string ToFriendlyString(this Accessibility accessibility) => SyntaxFacts.GetText(accessibility);
|
||||
|
||||
public static Accessibility GetAccessibility(string value) =>
|
||||
public static Accessibility GetAccessibility(string? value) =>
|
||||
value switch
|
||||
{
|
||||
"private" => Accessibility.Private,
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ namespace SerializationGenerator
|
|||
for (var i = 0; i < parameters.Length; i++)
|
||||
{
|
||||
var (t, v) = parameters[i];
|
||||
source.AppendFormat("{0} {1}", t.Name, v);
|
||||
source.AppendFormat("{0} {1}", t.ToDisplayString(), v);
|
||||
if (i < parameters.Length - 1)
|
||||
{
|
||||
source.Append(", ");
|
||||
|
|
|
|||
|
|
@ -88,5 +88,10 @@ namespace SerializationGenerator
|
|||
|
||||
source.AppendLine("]");
|
||||
}
|
||||
|
||||
public static void AggressiveInline(this StringBuilder source, string indent) =>
|
||||
source.AppendLine(
|
||||
$"{indent}[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,22 +21,24 @@ namespace SerializationGenerator
|
|||
{
|
||||
public static partial class SourceGeneration
|
||||
{
|
||||
public static void GenerateMethodStart(this StringBuilder source, string methodName, Accessibility accessors, bool isOverride, string returnType, ImmutableArray<(ITypeSymbol, string)> parameters)
|
||||
public static void GenerateMethodStart(
|
||||
this StringBuilder source, string indent, string methodName, Accessibility accessors, bool isOverride,
|
||||
string returnType, ImmutableArray<(ITypeSymbol, string)> parameters
|
||||
)
|
||||
{
|
||||
source.Append($" {accessors.ToFriendlyString()}{(isOverride ? " override" : "")} {returnType} {methodName}(");
|
||||
source.Append($"{indent}{accessors.ToFriendlyString()}{(isOverride ? " override" : "")} {returnType} {methodName}(");
|
||||
source.GenerateSignatureArguments(parameters);
|
||||
source.AppendLine(@")
|
||||
{");
|
||||
source.AppendLine($")\n{indent}{{");
|
||||
}
|
||||
|
||||
public static void GenerateMethodEnd(this StringBuilder source) => source.AppendLine(@" }");
|
||||
public static void GenerateMethodEnd(this StringBuilder source, string indent) => source.AppendLine($"{indent}}}");
|
||||
|
||||
public static void GenerateConstructorStart(
|
||||
this StringBuilder source, string className, Accessibility accessors, ImmutableArray<(ITypeSymbol, string)> parameters,
|
||||
this StringBuilder source, string indent, string className, Accessibility accessors, ImmutableArray<(ITypeSymbol, string)> parameters,
|
||||
ImmutableArray<string> baseParameters, bool isOverload = false
|
||||
)
|
||||
{
|
||||
source.Append($" {accessors.ToFriendlyString()} {className}(");
|
||||
source.Append($"{indent}{accessors.ToFriendlyString()} {className}(");
|
||||
source.GenerateSignatureArguments(parameters);
|
||||
source.Append(')');
|
||||
bool hasBaseParams = baseParameters.Length > 0;
|
||||
|
|
@ -54,7 +56,7 @@ namespace SerializationGenerator
|
|||
source.Append(')');
|
||||
}
|
||||
|
||||
source.AppendLine("\n {");
|
||||
source.AppendLine($"\n{indent}{{");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ namespace SerializationGenerator
|
|||
public const string DELTA_DATE_TIME_ATTRIBUTE = "Server.DeltaDateTimeAttribute";
|
||||
public const string INTERN_STRING_ATTRIBUTE = "Server.InternStringAttribute";
|
||||
public const string ENCODED_INT_ATTRIBUTE = "Server.EncodedIntAttribute";
|
||||
public const string TIDY_ATTRIBUTE = "Server.TidyAttribute";
|
||||
public const string POINT2D_STRUCT = "Server.Point2D";
|
||||
public const string POINT3D_STRUCT = "Server.Point3D";
|
||||
public const string RECTANGLE2D_STRUCT = "Server.Rectangle2D";
|
||||
|
|
@ -48,6 +49,9 @@ namespace SerializationGenerator
|
|||
public static bool IsInternString(this AttributeData attr, Compilation compilation) =>
|
||||
attr?.IsAttribute(compilation.GetTypeByMetadataName(INTERN_STRING_ATTRIBUTE)) == true;
|
||||
|
||||
public static bool IsTidy(this AttributeData attr, Compilation compilation) =>
|
||||
attr?.IsAttribute(compilation.GetTypeByMetadataName(TIDY_ATTRIBUTE)) == true;
|
||||
|
||||
public static bool IsAttribute(this AttributeData attr, ISymbol symbol) =>
|
||||
attr?.AttributeClass?.Equals(symbol, SymbolEqualityComparer.Default) == true;
|
||||
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ namespace Server.Collections
|
|||
private int _version;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static PooledRefQueue<T> Create() => new(32);
|
||||
public static PooledRefQueue<T> Create(int capacity = 32) => new(capacity);
|
||||
|
||||
// Creates a queue with room for capacity objects. The default grow factor
|
||||
// is used.
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -124,7 +124,7 @@ namespace Server.Network
|
|||
|
||||
public static void Initialize()
|
||||
{
|
||||
Timer.StartTimer(TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(1.5), CheckAllAlive);
|
||||
Timer.DelayCall(TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(1.5), CheckAllAlive);
|
||||
}
|
||||
|
||||
public NetState(ISocket connection)
|
||||
|
|
|
|||
|
|
@ -66,76 +66,28 @@ namespace Server
|
|||
|
||||
public int Y { get; }
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static void Add<T>(ref List<T> list, T value)
|
||||
{
|
||||
list ??= new List<T>();
|
||||
|
||||
list.Add(value);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static void Remove<T>(ref List<T> list, T value)
|
||||
{
|
||||
if (list != null)
|
||||
{
|
||||
list.Remove(value);
|
||||
|
||||
if (list.Count == 0)
|
||||
{
|
||||
list = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static void Replace<T>(ref List<T> list, T oldValue, T newValue)
|
||||
{
|
||||
if (oldValue != null && newValue != null)
|
||||
{
|
||||
var index = list?.IndexOf(oldValue) ?? -1;
|
||||
|
||||
if (index >= 0)
|
||||
{
|
||||
list![index] = newValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
Add(ref list, newValue);
|
||||
}
|
||||
}
|
||||
else if (oldValue != null)
|
||||
{
|
||||
Remove(ref list, oldValue);
|
||||
}
|
||||
else if (newValue != null)
|
||||
{
|
||||
Add(ref list, newValue);
|
||||
}
|
||||
}
|
||||
|
||||
public void OnClientChange(NetState oldState, NetState newState)
|
||||
{
|
||||
Replace(ref m_Clients, oldState, newState);
|
||||
Utility.Replace(ref m_Clients, oldState, newState);
|
||||
}
|
||||
|
||||
public void OnEnter(Item item)
|
||||
{
|
||||
Add(ref m_Items, item);
|
||||
Utility.Add(ref m_Items, item);
|
||||
}
|
||||
|
||||
public void OnLeave(Item item)
|
||||
{
|
||||
Remove(ref m_Items, item);
|
||||
Utility.Remove(ref m_Items, item);
|
||||
}
|
||||
|
||||
public void OnEnter(Mobile mob)
|
||||
{
|
||||
Add(ref m_Mobiles, mob);
|
||||
Utility.Add(ref m_Mobiles, mob);
|
||||
|
||||
if (mob.NetState != null)
|
||||
{
|
||||
Add(ref m_Clients, mob.NetState);
|
||||
Utility.Add(ref m_Clients, mob.NetState);
|
||||
|
||||
Owner.ActivateSectors(X, Y);
|
||||
}
|
||||
|
|
@ -143,11 +95,11 @@ namespace Server
|
|||
|
||||
public void OnLeave(Mobile mob)
|
||||
{
|
||||
Remove(ref m_Mobiles, mob);
|
||||
Utility.Remove(ref m_Mobiles, mob);
|
||||
|
||||
if (mob.NetState != null)
|
||||
{
|
||||
Remove(ref m_Clients, mob.NetState);
|
||||
Utility.Remove(ref m_Clients, mob.NetState);
|
||||
|
||||
Owner.DeactivateSectors(X, Y);
|
||||
}
|
||||
|
|
@ -155,7 +107,7 @@ namespace Server
|
|||
|
||||
public void OnEnter(Region region, Rectangle3D rect)
|
||||
{
|
||||
Add(ref m_RegionRects, new RegionRect(region, rect));
|
||||
Utility.Add(ref m_RegionRects, new RegionRect(region, rect));
|
||||
|
||||
m_RegionRects.Sort();
|
||||
|
||||
|
|
@ -200,12 +152,12 @@ namespace Server
|
|||
|
||||
public void OnMultiEnter(BaseMulti multi)
|
||||
{
|
||||
Add(ref m_Multis, multi);
|
||||
Utility.Add(ref m_Multis, multi);
|
||||
}
|
||||
|
||||
public void OnMultiLeave(BaseMulti multi)
|
||||
{
|
||||
Remove(ref m_Multis, multi);
|
||||
Utility.Remove(ref m_Multis, multi);
|
||||
}
|
||||
|
||||
public void Activate()
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ namespace Server
|
|||
/// <summary>
|
||||
/// Hints to the source generator that this field or property should be serialized.
|
||||
/// When used on a field, the source generator will generate the property entirely.
|
||||
/// When used on a property, the user must call ((ISerializable)this).MarkDirty().
|
||||
/// When used on a property, the user must call this.MarkDirty() after reassigning the value or modifying the value internally.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
|
||||
public sealed class SerializableFieldAttribute : Attribute
|
||||
27
Projects/Server/Serialization/Attributes/TidyAttribute.cs
Normal file
27
Projects/Server/Serialization/Attributes/TidyAttribute.cs
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
/*************************************************************************
|
||||
* ModernUO *
|
||||
* Copyright 2019-2021 - ModernUO Development Team *
|
||||
* Email: hi@modernuo.com *
|
||||
* File: TidyAttribute.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;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
/// <summary>
|
||||
/// Hints to the source generator that a serializable list should be tidied up
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
|
||||
public class TidyAttribute : Attribute
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -20,7 +20,7 @@ namespace Server
|
|||
{
|
||||
public interface ISerializable
|
||||
{
|
||||
long SavePosition { get; protected set; }
|
||||
long SavePosition { get; protected internal set; }
|
||||
BufferWriter SaveBuffer { get; protected internal set; }
|
||||
int TypeRef { get; }
|
||||
Serial Serial { get; }
|
||||
|
|
@ -29,11 +29,6 @@ namespace Server
|
|||
void Delete();
|
||||
bool Deleted { get; }
|
||||
|
||||
void MarkDirty()
|
||||
{
|
||||
SavePosition = -1;
|
||||
}
|
||||
|
||||
void SetTypeRef(Type type);
|
||||
|
||||
public void InitializeSaveBuffer(byte[] buffer)
|
||||
|
|
|
|||
135
Projects/Server/Serialization/ISerializableExtensions.cs
Normal file
135
Projects/Server/Serialization/ISerializableExtensions.cs
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
/*************************************************************************
|
||||
* ModernUO *
|
||||
* Copyright 2019-2021 - ModernUO Development Team *
|
||||
* Email: hi@modernuo.com *
|
||||
* File: ISerializableExtensions.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.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public static class ISerializableExtensions
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void MarkDirty(this ISerializable entity)
|
||||
{
|
||||
entity.SavePosition = -1;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Add<T>(this ISerializable entity, ICollection<T> list, T value)
|
||||
{
|
||||
list.Add(value);
|
||||
entity.MarkDirty();
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Add<K, V>(this ISerializable entity, IDictionary<K, V> dict, K key, V value)
|
||||
{
|
||||
dict[key] = value;
|
||||
entity.MarkDirty();
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Insert<T>(this ISerializable entity, IList<T> list, T value, int index)
|
||||
{
|
||||
list.Insert(index, value);
|
||||
entity.MarkDirty();
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool Remove<T>(this ISerializable entity, ICollection<T> list, T value)
|
||||
{
|
||||
if (list.Remove(value))
|
||||
{
|
||||
entity.MarkDirty();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool Remove<K, V>(this ISerializable entity, IDictionary<K, V> dict, K key, out V value)
|
||||
{
|
||||
if (dict.Remove(key, out value))
|
||||
{
|
||||
entity.MarkDirty();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void RemoveAt<T>(this ISerializable entity, IList<T> list, int index)
|
||||
{
|
||||
list.RemoveAt(index);
|
||||
entity.MarkDirty();
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Clear<T>(this ISerializable entity, ICollection<T> list)
|
||||
{
|
||||
list.Clear();
|
||||
entity.MarkDirty();
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Add<T>(this ISerializable entity, ref List<T> list, T value)
|
||||
{
|
||||
Utility.Add(ref list, value);
|
||||
entity.MarkDirty();
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Add<K, V>(this ISerializable entity, ref Dictionary<K, V> dict, K key, V value)
|
||||
{
|
||||
Utility.Add(ref dict, key, value);
|
||||
entity.MarkDirty();
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool Remove<T>(this ISerializable entity, ref List<T> list, T value)
|
||||
{
|
||||
if (Utility.Remove(ref list, value))
|
||||
{
|
||||
entity.MarkDirty();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Clear<T>(this ISerializable entity, ref List<T> list)
|
||||
{
|
||||
Utility.Clear(ref list);
|
||||
entity.MarkDirty();
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Clear<T>(this ISerializable entity, ref HashSet<T> set)
|
||||
{
|
||||
Utility.Clear(ref set);
|
||||
entity.MarkDirty();
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Clear<K, V>(this ISerializable entity, ref Dictionary<K, V> dict)
|
||||
{
|
||||
Utility.Clear(ref dict);
|
||||
entity.MarkDirty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -133,7 +133,7 @@ namespace Server
|
|||
internal DelayCallTimer(TimeSpan delay) : base(delay)
|
||||
{
|
||||
#if DEBUG_TIMERS
|
||||
t._allowFinalization = true;
|
||||
_allowFinalization = true;
|
||||
#endif
|
||||
Start();
|
||||
}
|
||||
|
|
@ -164,12 +164,15 @@ namespace Server
|
|||
|
||||
Version++; // Increment the version so if this is called from OnTick() and another timer is started, we don't have a problem
|
||||
|
||||
#if DEBUG_TIMERS
|
||||
_stackTraces.Remove(GetHashCode());
|
||||
#endif
|
||||
|
||||
if (_poolCount >= _poolCapacity)
|
||||
{
|
||||
#if DEBUG_TIMERS
|
||||
logger.Warning($"DelayCallTimer pool reached maximum of {_poolSize} timers");
|
||||
logger.Warning($"DelayCallTimer pool reached maximum of {_poolCapacity} timers");
|
||||
_allowFinalization = true;
|
||||
_stackTraces.Remove(GetHashCode());
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
|
@ -184,7 +187,7 @@ namespace Server
|
|||
{
|
||||
_poolCount--;
|
||||
#if DEBUG_TIMERS
|
||||
logger.Information($"Pool count changed: {_poolCount} ({_poolCapacity})");
|
||||
logger.Information($"Pool count: {_poolCount} / {_poolCapacity}");
|
||||
#endif
|
||||
|
||||
var timer = GetFromPool();
|
||||
|
|
@ -202,7 +205,7 @@ namespace Server
|
|||
_timerPoolDepletionAmount++;
|
||||
|
||||
#if DEBUG_TIMERS
|
||||
logger.Warning($"Timer pool depleted and timer was allocated.\n{new StackTrace()});
|
||||
logger.Warning($"Timer pool depleted and timer was allocated.\n{new StackTrace()}");
|
||||
#endif
|
||||
return new DelayCallTimer(delay, interval, count, callback);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ namespace Server
|
|||
_poolHead = head;
|
||||
_poolCount += amount;
|
||||
#if DEBUG_TIMERS
|
||||
logger.Information($"Pool count changed: {_poolCount} ({_poolCapacity})");
|
||||
logger.Information($"Pool count: {_poolCount} / {_poolCapacity}");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -203,9 +203,7 @@ namespace Server
|
|||
|
||||
public static void DumpInfo(TextWriter tw)
|
||||
{
|
||||
var now = DateTime.UtcNow;
|
||||
|
||||
tw.WriteLine("Date: {0}\n", now);
|
||||
tw.WriteLine("Date: {0}\n", Core.Now.ToLocalTime());
|
||||
tw.WriteLine("Pool - Count: {0}; Size {1}\n", _poolCount - _timerPoolDepletionAmount, _poolCapacity);
|
||||
|
||||
var total = 0.0;
|
||||
|
|
@ -216,6 +214,10 @@ namespace Server
|
|||
for (var j = 0; j < _ringSize; j++)
|
||||
{
|
||||
var t = _rings[i][j];
|
||||
if (t == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var name = t.ToString();
|
||||
|
||||
|
|
@ -230,9 +232,22 @@ namespace Server
|
|||
|
||||
foreach (var (name, count) in hash.OrderByDescending(o => o.Value))
|
||||
{
|
||||
tw.WriteLine($"- Type: {name}; Count: {count}; Percent: {count / total}%");
|
||||
var percent = count / total;
|
||||
var line = $"{count:#,0} ({percent:P1})";
|
||||
// 6 - 15 / 8 = 1
|
||||
var tabs = new string('\t', line.Length < 12 ? 2 : 1);
|
||||
tw.WriteLine($"{line}{tabs}{name}");
|
||||
}
|
||||
|
||||
#if DEBUG_TIMERS
|
||||
tw.WriteLine("\nStack Traces:");
|
||||
foreach (var kvp in DelayCallTimer._stackTraces)
|
||||
{
|
||||
tw.WriteLine(kvp.Value);
|
||||
tw.WriteLine();
|
||||
}
|
||||
#endif
|
||||
|
||||
tw.WriteLine();
|
||||
tw.WriteLine();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,165 +0,0 @@
|
|||
/*************************************************************************
|
||||
* ModernUO *
|
||||
* Copyright 2019-2020 - ModernUO Development Team *
|
||||
* Email: hi@modernuo.com *
|
||||
* File: RefPool.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;
|
||||
|
||||
namespace Server.Utilities
|
||||
{
|
||||
/// <summary> A resource reference object that can be disposed. </summary>
|
||||
/// <remarks>
|
||||
/// Disposing the reference is expected to return itself back into the
|
||||
/// original pool that created it.
|
||||
/// </remarks>
|
||||
public interface IRef : IDisposable
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Base implementation of the <see cref="IRef" /> interface.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// New implementations of <see cref="IRef" /> should either derive from, or mirror
|
||||
/// the functionality of this base implementation.
|
||||
/// </remarks>
|
||||
/// <typeparam name="TDerived"></typeparam>
|
||||
public abstract class BaseRef<TDerived> : IRef where TDerived : IRef
|
||||
{
|
||||
private readonly RefPool<TDerived> m_Pool;
|
||||
public BaseRef(RefPool<TDerived> pool) => m_Pool = pool;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
OnDispose();
|
||||
m_Pool.Return((TDerived)(object)this);
|
||||
}
|
||||
|
||||
protected abstract void OnDispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A resource reference pool that manages a collection of reusable resources.
|
||||
/// </summary>
|
||||
/// <typeparam name="TRef">The <see cref="IRef" /> resource type the pool will contain.</typeparam>
|
||||
public class RefPool<TRef> where TRef : IRef
|
||||
{
|
||||
public delegate TRef Generator(RefPool<TRef> targetPool);
|
||||
|
||||
public const int DEFAULT_RESOURCE_RETENTION = 10;
|
||||
private readonly Generator m_Generator;
|
||||
|
||||
private readonly Stack<TRef> m_Resources = new();
|
||||
private int m_MaxRefrenceRetention;
|
||||
|
||||
/// <param name="generator">The generator function for creating new resources.</param>
|
||||
/// <param name="preGenerateCount">
|
||||
/// An amount of resources that should be pre-generated during initialization of the resource
|
||||
/// pool.
|
||||
/// </param>
|
||||
public RefPool(Generator generator, int preGenerateCount = 0, int maxRefrenceRetention = DEFAULT_RESOURCE_RETENTION)
|
||||
{
|
||||
if (generator == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(generator));
|
||||
}
|
||||
|
||||
if (preGenerateCount > maxRefrenceRetention)
|
||||
{
|
||||
throw new IndexOutOfRangeException(
|
||||
$"{nameof(preGenerateCount)} greater than {nameof(maxRefrenceRetention)}"
|
||||
);
|
||||
}
|
||||
|
||||
m_Generator = generator;
|
||||
m_MaxRefrenceRetention = maxRefrenceRetention;
|
||||
while (--preGenerateCount >= 0)
|
||||
{
|
||||
m_Resources.Push(generator(this));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The maximum number of unused resources to hold in the pool.
|
||||
/// </summary>
|
||||
public int MaxRefrenceRetention
|
||||
{
|
||||
get => m_MaxRefrenceRetention;
|
||||
set
|
||||
{
|
||||
m_MaxRefrenceRetention = value;
|
||||
while (m_Resources.Count > value)
|
||||
{
|
||||
m_Resources.Pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves a resource reference that is managed by this <see cref="RefPool{TRef}" />. If the pool is has unused
|
||||
/// resources,
|
||||
/// it will remove one from the pool and return it; otherwise, a new resource will be generated.
|
||||
/// </summary>
|
||||
/// <returns>Unused resource, or a new resource if no unused resources available.</returns>
|
||||
public TRef Get() => m_Resources.TryPop(out var item) ? item : m_Generator(this);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a resource reference to the pool of unused resources.
|
||||
/// </summary>
|
||||
/// <param name="queueRef">Resource to be returned.</param>
|
||||
public void Return(TRef queueRef)
|
||||
{
|
||||
if (m_Resources.Count < MaxRefrenceRetention)
|
||||
{
|
||||
m_Resources.Push(queueRef);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class QueueRef<T> : Queue<T>, IRef
|
||||
{
|
||||
/// <summary>
|
||||
/// Generator function for creating instances of the <see cref="QueueRef{T}" /> resource.
|
||||
/// </summary>
|
||||
public static RefPool<QueueRef<T>>.Generator Generate = targetPool => new QueueRef<T>(targetPool);
|
||||
|
||||
private readonly RefPool<QueueRef<T>> m_Pool;
|
||||
private QueueRef(RefPool<QueueRef<T>> pool) => m_Pool = pool;
|
||||
|
||||
/// <summary>Clears the queue and returns this resource to its parent resource pool.</summary>
|
||||
public void Dispose()
|
||||
{
|
||||
Clear();
|
||||
m_Pool.Return(this);
|
||||
}
|
||||
}
|
||||
|
||||
public class StackRef<T> : Stack<T>, IRef
|
||||
{
|
||||
/// <summary>
|
||||
/// Generator function for creating instances of the <see cref="StackRef{T}" /> resource.
|
||||
/// </summary>
|
||||
public static RefPool<StackRef<T>>.Generator Generate = targetPool => new StackRef<T>(targetPool);
|
||||
|
||||
private readonly RefPool<StackRef<T>> m_Pool;
|
||||
private StackRef(RefPool<StackRef<T>> pool) => m_Pool = pool;
|
||||
|
||||
/// <summary>Clears the stack and returns this resource to its parent resource pool.</summary>
|
||||
public void Dispose()
|
||||
{
|
||||
Clear();
|
||||
m_Pool.Return(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1492,5 +1492,159 @@ namespace Server
|
|||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static string GetTimeStamp() => Core.Now.ToString("yyyy-MM-dd-HH-mm-ss");
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Add<T>(ref List<T> list, T value)
|
||||
{
|
||||
list ??= new List<T>();
|
||||
list.Add(value);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Add<T>(ref HashSet<T> set, T value)
|
||||
{
|
||||
set ??= new HashSet<T>();
|
||||
set.Add(value);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Add<K, V>(ref Dictionary<K, V> dict, K key, V value)
|
||||
{
|
||||
dict ??= new Dictionary<K, V>();
|
||||
dict.Add(key, value);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool Remove<T>(ref List<T> list, T value)
|
||||
{
|
||||
if (list != null)
|
||||
{
|
||||
var removed = list.Remove(value);
|
||||
|
||||
if (list.Count == 0)
|
||||
{
|
||||
list = null;
|
||||
}
|
||||
|
||||
return removed;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool Remove<T>(ref HashSet<T> set, T value)
|
||||
{
|
||||
if (set != null)
|
||||
{
|
||||
var removed = set.Remove(value);
|
||||
|
||||
if (set.Count == 0)
|
||||
{
|
||||
set = null;
|
||||
}
|
||||
|
||||
return removed;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool Remove<K, V>(ref Dictionary<K, V> dict, K key)
|
||||
{
|
||||
if (dict != null)
|
||||
{
|
||||
var removed = dict.Remove(key);
|
||||
|
||||
if (dict.Count == 0)
|
||||
{
|
||||
dict = null;
|
||||
}
|
||||
|
||||
return removed;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool Remove<K, V>(ref Dictionary<K, V> dict, K key, out V value)
|
||||
{
|
||||
if (dict != null)
|
||||
{
|
||||
var removed = dict.Remove(key, out value);
|
||||
|
||||
if (dict.Count == 0)
|
||||
{
|
||||
dict = null;
|
||||
}
|
||||
|
||||
return removed;
|
||||
}
|
||||
|
||||
value = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Replace<T>(ref List<T> list, T oldValue, T newValue)
|
||||
{
|
||||
if (oldValue != null && newValue != null)
|
||||
{
|
||||
var index = list?.IndexOf(oldValue) ?? -1;
|
||||
|
||||
if (index >= 0)
|
||||
{
|
||||
list![index] = newValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
Add(ref list, newValue);
|
||||
}
|
||||
}
|
||||
else if (oldValue != null)
|
||||
{
|
||||
Remove(ref list, oldValue);
|
||||
}
|
||||
else if (newValue != null)
|
||||
{
|
||||
Add(ref list, newValue);
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Replace<K, V>(ref Dictionary<K, V> dict, K key, V oldValue, V newValue)
|
||||
{
|
||||
if (newValue != null)
|
||||
{
|
||||
Add(ref dict, key, newValue);
|
||||
}
|
||||
else if (oldValue != null)
|
||||
{
|
||||
Remove(ref dict, key);
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Clear<T>(ref List<T> list)
|
||||
{
|
||||
list.Clear();
|
||||
list = null;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Clear<T>(ref HashSet<T> set)
|
||||
{
|
||||
set.Clear();
|
||||
set = null;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Clear<K, V>(ref Dictionary<K, V> dict)
|
||||
{
|
||||
dict.Clear();
|
||||
dict = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ namespace Server.Accounting
|
|||
private set
|
||||
{
|
||||
_comments = value;
|
||||
((ISerializable)this).MarkDirty();
|
||||
this.MarkDirty();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -83,7 +83,7 @@ namespace Server.Accounting
|
|||
private set
|
||||
{
|
||||
_tags = value;
|
||||
((ISerializable)this).MarkDirty();
|
||||
this.MarkDirty();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -121,7 +121,7 @@ namespace Server.Accounting
|
|||
private set
|
||||
{
|
||||
_totalGameTime = value;
|
||||
((ISerializable)this).MarkDirty();
|
||||
this.MarkDirty();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -148,7 +148,7 @@ namespace Server.Accounting
|
|||
_loginIPs = Array.Empty<IPAddress>();
|
||||
|
||||
Accounts.Add(this);
|
||||
((ISerializable)this).MarkDirty();
|
||||
this.MarkDirty();
|
||||
}
|
||||
|
||||
public Account(XmlElement node)
|
||||
|
|
@ -224,7 +224,7 @@ namespace Server.Accounting
|
|||
}
|
||||
|
||||
Accounts.Add(this);
|
||||
((ISerializable)this).MarkDirty();
|
||||
this.MarkDirty();
|
||||
}
|
||||
|
||||
public void SetTypeRef(Type type)
|
||||
|
|
@ -527,7 +527,7 @@ namespace Server.Accounting
|
|||
// outside of an entire account deletion.
|
||||
m.Account = null;
|
||||
_mobiles[index] = null;
|
||||
((ISerializable)this).MarkDirty();
|
||||
this.MarkDirty();
|
||||
}
|
||||
|
||||
return null;
|
||||
|
|
@ -542,7 +542,7 @@ namespace Server.Accounting
|
|||
}
|
||||
|
||||
_mobiles[index] = value;
|
||||
((ISerializable)this).MarkDirty();
|
||||
this.MarkDirty();
|
||||
|
||||
if (_mobiles[index] != null)
|
||||
{
|
||||
|
|
@ -677,7 +677,7 @@ namespace Server.Accounting
|
|||
public void AddTag(string name, string value)
|
||||
{
|
||||
Tags.Add(new AccountTag(name, value));
|
||||
((ISerializable)this).MarkDirty();
|
||||
this.MarkDirty();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -698,7 +698,7 @@ namespace Server.Accounting
|
|||
if (tag.Name == name)
|
||||
{
|
||||
_tags?.RemoveAt(i);
|
||||
((ISerializable)this).MarkDirty();
|
||||
this.MarkDirty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -717,7 +717,7 @@ namespace Server.Accounting
|
|||
if (tag.Name == name)
|
||||
{
|
||||
tag.Value = value;
|
||||
((ISerializable)this).MarkDirty();
|
||||
this.MarkDirty();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -78,6 +78,7 @@ namespace Server.Commands
|
|||
{
|
||||
using var sw = new StreamWriter("timerdump.log", true);
|
||||
Timer.DumpInfo(sw);
|
||||
e.Mobile.SendMessage("Timers dumped to timerdump.log");
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ namespace Server.Factions
|
|||
public static readonly TimeSpan CampaignPeriod = TimeSpan.FromDays(1.0);
|
||||
public static readonly TimeSpan VotingPeriod = TimeSpan.FromDays(3.0);
|
||||
|
||||
private TimerExecutionToken _timerToken;
|
||||
private Timer _timer;
|
||||
|
||||
public Election(Faction faction)
|
||||
{
|
||||
|
|
@ -109,7 +109,7 @@ namespace Server.Factions
|
|||
|
||||
public void StartTimer()
|
||||
{
|
||||
Timer.StartTimer(TimeSpan.FromMinutes(1.0), TimeSpan.FromMinutes(1.0), Slice, out _timerToken);
|
||||
_timer = Timer.DelayCall(TimeSpan.FromMinutes(1.0), TimeSpan.FromMinutes(1.0), Slice);
|
||||
}
|
||||
|
||||
public void Serialize(IGenericWriter writer)
|
||||
|
|
@ -274,7 +274,8 @@ namespace Server.Factions
|
|||
{
|
||||
if (Faction.Election != this)
|
||||
{
|
||||
_timerToken.Cancel();
|
||||
_timer?.Stop();
|
||||
_timer = null;
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -621,9 +621,8 @@ namespace Server.Factions
|
|||
EventSink.Login += EventSink_Login;
|
||||
EventSink.Logout += EventSink_Logout;
|
||||
|
||||
Timer.StartTimer(TimeSpan.FromMinutes(1.0), TimeSpan.FromMinutes(10.0), HandleAtrophy);
|
||||
|
||||
Timer.StartTimer(TimeSpan.FromSeconds(30.0), TimeSpan.FromSeconds(30.0), ProcessTick);
|
||||
Timer.DelayCall(TimeSpan.FromMinutes(1.0), TimeSpan.FromMinutes(10.0), HandleAtrophy);
|
||||
Timer.DelayCall(TimeSpan.FromSeconds(30.0), TimeSpan.FromSeconds(30.0), ProcessTick);
|
||||
|
||||
CommandSystem.Register("FactionElection", AccessLevel.GameMaster, FactionElection_OnCommand);
|
||||
CommandSystem.Register("FactionCommander", AccessLevel.Administrator, FactionCommander_OnCommand);
|
||||
|
|
|
|||
|
|
@ -91,10 +91,9 @@ namespace Server.Items
|
|||
return;
|
||||
}
|
||||
|
||||
_from = from.Name;
|
||||
_to = m.Name;
|
||||
From = from.Name;
|
||||
To = m.Name;
|
||||
|
||||
((ISerializable)this).MarkDirty();
|
||||
InvalidateProperties();
|
||||
|
||||
from.SendMessage("You inscribe the arrow.");
|
||||
|
|
|
|||
|
|
@ -7,7 +7,8 @@ using Server.Prompts;
|
|||
|
||||
namespace Server.Items
|
||||
{
|
||||
public class BallotBox : AddonComponent
|
||||
[Serializable(0)]
|
||||
public partial class BallotBox : AddonComponent
|
||||
{
|
||||
public static readonly int MaxTopicLines = 6;
|
||||
|
||||
|
|
@ -19,17 +20,18 @@ namespace Server.Items
|
|||
No = new List<Mobile>();
|
||||
}
|
||||
|
||||
public BallotBox(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override int LabelNumber => 1041006; // a ballot box
|
||||
|
||||
public string[] Topic { get; private set; }
|
||||
[SerializableField(0, setter: "private")]
|
||||
private string[] _topic;
|
||||
|
||||
public List<Mobile> Yes { get; private set; }
|
||||
[Tidy]
|
||||
[SerializableField(1, setter: "private")]
|
||||
private List<Mobile> _yes;
|
||||
|
||||
public List<Mobile> No { get; private set; }
|
||||
[Tidy]
|
||||
[SerializableField(2, setter: "private")]
|
||||
private List<Mobile> _no;
|
||||
|
||||
public void ClearTopic()
|
||||
{
|
||||
|
|
@ -56,8 +58,11 @@ namespace Server.Items
|
|||
|
||||
public void ClearVotes()
|
||||
{
|
||||
Yes.Clear();
|
||||
No.Clear();
|
||||
if (Yes.Count > 0 || No.Count > 0)
|
||||
{
|
||||
this.Clear(_yes);
|
||||
this.Clear(_no);
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsOwner(Mobile from)
|
||||
|
|
@ -92,43 +97,6 @@ namespace Server.Items
|
|||
}
|
||||
}
|
||||
|
||||
public override void Serialize(IGenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.WriteEncodedInt(0); // version
|
||||
|
||||
writer.WriteEncodedInt(Topic.Length);
|
||||
|
||||
for (var i = 0; i < Topic.Length; i++)
|
||||
{
|
||||
writer.Write(Topic[i]);
|
||||
}
|
||||
|
||||
Yes.Tidy();
|
||||
writer.Write(Yes);
|
||||
|
||||
No.Tidy();
|
||||
writer.Write(No);
|
||||
}
|
||||
|
||||
public override void Deserialize(IGenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
var version = reader.ReadEncodedInt();
|
||||
|
||||
Topic = new string[reader.ReadEncodedInt()];
|
||||
|
||||
for (var i = 0; i < Topic.Length; i++)
|
||||
{
|
||||
Topic[i] = reader.ReadString();
|
||||
}
|
||||
|
||||
Yes = reader.ReadEntityList<Mobile>();
|
||||
No = reader.ReadEntityList<Mobile>();
|
||||
}
|
||||
|
||||
private class InternalGump : Gump
|
||||
{
|
||||
private readonly BallotBox m_Box;
|
||||
|
|
@ -259,7 +227,7 @@ namespace Server.Items
|
|||
}
|
||||
else
|
||||
{
|
||||
m_Box.Yes.Add(from);
|
||||
m_Box.Add(m_Box._yes, from);
|
||||
from.SendLocalizedMessage(500373); // Your vote has been registered.
|
||||
}
|
||||
}
|
||||
|
|
@ -276,7 +244,7 @@ namespace Server.Items
|
|||
}
|
||||
else
|
||||
{
|
||||
m_Box.No.Add(from);
|
||||
m_Box.Add(m_Box._no, from);
|
||||
from.SendLocalizedMessage(500373); // Your vote has been registered.
|
||||
}
|
||||
}
|
||||
|
|
@ -344,61 +312,25 @@ namespace Server.Items
|
|||
}
|
||||
}
|
||||
|
||||
public class BallotBoxAddon : BaseAddon
|
||||
[Serializable(0)]
|
||||
public partial class BallotBoxAddon : BaseAddon
|
||||
{
|
||||
public BallotBoxAddon()
|
||||
{
|
||||
AddComponent(new BallotBox(), 0, 0, 0);
|
||||
}
|
||||
|
||||
public BallotBoxAddon(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override BaseAddonDeed Deed => new BallotBoxDeed();
|
||||
|
||||
public override void Serialize(IGenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.WriteEncodedInt(0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(IGenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
var version = reader.ReadEncodedInt();
|
||||
}
|
||||
}
|
||||
|
||||
public class BallotBoxDeed : BaseAddonDeed
|
||||
[Serializable(0)]
|
||||
public partial class BallotBoxDeed : BaseAddonDeed
|
||||
{
|
||||
[Constructible]
|
||||
public BallotBoxDeed()
|
||||
{
|
||||
}
|
||||
|
||||
public BallotBoxDeed(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override BaseAddon Addon => new BallotBoxAddon();
|
||||
|
||||
public override int LabelNumber => 1044327; // ballot box
|
||||
|
||||
public override void Serialize(IGenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.WriteEncodedInt(0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(IGenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
var version = reader.ReadEncodedInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ namespace Server.Items
|
|||
Hue = CraftResources.GetHue(m_Resource);
|
||||
|
||||
InvalidateProperties();
|
||||
((ISerializable)this).MarkDirty();
|
||||
this.MarkDirty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ namespace Server.Items
|
|||
protected FillableContent m_Content;
|
||||
|
||||
protected DateTime m_NextRespawnTime;
|
||||
protected TimerExecutionToken _respawnTimerToken;
|
||||
protected Timer _respawnTimer;
|
||||
|
||||
public FillableContainer(int itemID) : base(itemID) => Movable = false;
|
||||
|
||||
|
|
@ -96,7 +96,8 @@ namespace Server.Items
|
|||
{
|
||||
base.OnAfterDelete();
|
||||
|
||||
_respawnTimerToken.Cancel();
|
||||
_respawnTimer?.Stop();
|
||||
_respawnTimer = null;
|
||||
}
|
||||
|
||||
public int GetItemsCount()
|
||||
|
|
@ -118,24 +119,26 @@ namespace Server.Items
|
|||
|
||||
if (canSpawn)
|
||||
{
|
||||
if (!_respawnTimerToken.Running)
|
||||
if (_respawnTimer?.Running != true)
|
||||
{
|
||||
var mins = Utility.RandomMinMax(MinRespawnMinutes, MaxRespawnMinutes);
|
||||
var delay = TimeSpan.FromMinutes(mins);
|
||||
|
||||
m_NextRespawnTime = Core.Now + delay;
|
||||
Timer.StartTimer(delay, Respawn, out _respawnTimerToken);
|
||||
_respawnTimer = Timer.DelayCall(delay, Respawn);
|
||||
}
|
||||
}
|
||||
else if (_respawnTimerToken.Running)
|
||||
else
|
||||
{
|
||||
_respawnTimerToken.Cancel();
|
||||
_respawnTimer?.Stop();
|
||||
_respawnTimer = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void Respawn()
|
||||
{
|
||||
_respawnTimerToken.Cancel();
|
||||
_respawnTimer?.Stop();
|
||||
_respawnTimer = null;
|
||||
|
||||
if (m_Content == null || Deleted)
|
||||
{
|
||||
|
|
@ -217,7 +220,7 @@ namespace Server.Items
|
|||
{
|
||||
var subItem = list[j];
|
||||
|
||||
if (!(subItem is Container) && subItem.StackWith(null, item, false))
|
||||
if (subItem is not Container && subItem.StackWith(null, item, false))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
|
@ -238,7 +241,7 @@ namespace Server.Items
|
|||
|
||||
writer.Write((int)ContentType);
|
||||
|
||||
if (_respawnTimerToken.Running)
|
||||
if (_respawnTimer?.Running == true)
|
||||
{
|
||||
writer.Write(true);
|
||||
writer.WriteDeltaTime(m_NextRespawnTime);
|
||||
|
|
@ -269,7 +272,7 @@ namespace Server.Items
|
|||
m_NextRespawnTime = reader.ReadDeltaTime();
|
||||
|
||||
var delay = m_NextRespawnTime - Core.Now;
|
||||
Timer.StartTimer(delay, Respawn, out _respawnTimerToken);
|
||||
Timer.DelayCall(delay, Respawn);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -275,7 +275,7 @@ namespace Server.Items
|
|||
}
|
||||
}
|
||||
|
||||
Timer.StartTimer(TimeSpan.FromMinutes(1.0), TimeSpan.FromMinutes(1.0), CheckEnd_OnTick);
|
||||
Timer.DelayCall(TimeSpan.FromMinutes(1.0), TimeSpan.FromMinutes(1.0), CheckEnd_OnTick);
|
||||
}
|
||||
|
||||
public bool ValidLocation() =>
|
||||
|
|
|
|||
|
|
@ -70,6 +70,7 @@
|
|||
"type": "System.Collections.Generic.List\u003CServer.Accounting.AccountComment\u003E",
|
||||
"rule": "ListMigrationRule",
|
||||
"ruleArguments": [
|
||||
"",
|
||||
"Server.Accounting.AccountComment",
|
||||
"SerializationMethodSignatureMigrationRule"
|
||||
]
|
||||
|
|
@ -79,6 +80,7 @@
|
|||
"type": "System.Collections.Generic.List\u003CServer.Accounting.AccountTag\u003E",
|
||||
"rule": "ListMigrationRule",
|
||||
"ruleArguments": [
|
||||
"",
|
||||
"Server.Accounting.AccountTag",
|
||||
"SerializationMethodSignatureMigrationRule"
|
||||
]
|
||||
|
|
|
|||
35
Projects/UOContent/Migrations/Server.Items.BallotBox.v0.json
Normal file
35
Projects/UOContent/Migrations/Server.Items.BallotBox.v0.json
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Items.BallotBox",
|
||||
"properties": [
|
||||
{
|
||||
"name": "Topic",
|
||||
"type": "string[]",
|
||||
"rule": "ArrayMigrationRule",
|
||||
"ruleArguments": [
|
||||
"string",
|
||||
"PrimitiveTypeMigrationRule"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Yes",
|
||||
"type": "System.Collections.Generic.List\u003CServer.Mobile\u003E",
|
||||
"rule": "ListMigrationRule",
|
||||
"ruleArguments": [
|
||||
"@Tidy",
|
||||
"Server.Mobile",
|
||||
"SerializableInterfaceMigrationRule"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "No",
|
||||
"type": "System.Collections.Generic.List\u003CServer.Mobile\u003E",
|
||||
"rule": "ListMigrationRule",
|
||||
"ruleArguments": [
|
||||
"@Tidy",
|
||||
"Server.Mobile",
|
||||
"SerializableInterfaceMigrationRule"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Items.BallotBoxAddon",
|
||||
"properties": []
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Items.BallotBoxDeed",
|
||||
"properties": []
|
||||
}
|
||||
|
|
@ -7,6 +7,7 @@
|
|||
"type": "System.Collections.Generic.List\u003CServer.Items.AddonComponent\u003E",
|
||||
"rule": "ListMigrationRule",
|
||||
"ruleArguments": [
|
||||
"",
|
||||
"Server.Items.AddonComponent",
|
||||
"SerializableInterfaceMigrationRule"
|
||||
]
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ namespace Server.Misc
|
|||
|
||||
list?.Add(this);
|
||||
|
||||
Timer.StartTimer(
|
||||
Timer.DelayCall(
|
||||
TimeSpan.FromSeconds((0.2 + Utility.RandomDouble() * 0.8) * interval.TotalSeconds),
|
||||
interval,
|
||||
OnTick
|
||||
|
|
|
|||
|
|
@ -151,7 +151,7 @@ namespace Server.Mobiles
|
|||
SetResistance(ResistanceType.Energy, 40, 60);
|
||||
}
|
||||
|
||||
Timer.StartTimer(RemoveDisguise);
|
||||
Timer.StartTimer(RemoveDisguise, out _disguiseTimerToken);
|
||||
}
|
||||
|
||||
public void Disguise()
|
||||
|
|
@ -208,6 +208,8 @@ namespace Server.Mobiles
|
|||
|
||||
public void RemoveDisguise()
|
||||
{
|
||||
_disguiseTimerToken.Cancel();
|
||||
|
||||
if (!IsBodyMod)
|
||||
{
|
||||
return;
|
||||
|
|
@ -224,8 +226,6 @@ namespace Server.Mobiles
|
|||
|
||||
DeleteItemOnLayer(Layer.OuterTorso);
|
||||
DeleteItemOnLayer(Layer.Shoes);
|
||||
|
||||
_disguiseTimerToken.Cancel();
|
||||
}
|
||||
|
||||
public void DeleteItemOnLayer(Layer layer)
|
||||
|
|
|
|||
|
|
@ -1067,7 +1067,7 @@ namespace Server.Mobiles
|
|||
|
||||
public static void UnequipMacro(Mobile m, List<Layer> layers)
|
||||
{
|
||||
if (m is PlayerMobile pm && pm.Backpack != null && pm.Alive)
|
||||
if (m is PlayerMobile { Alive: true } pm && pm.Backpack != null)
|
||||
{
|
||||
var pack = pm.Backpack;
|
||||
var eq = m.Items;
|
||||
|
|
|
|||
|
|
@ -30,6 +30,18 @@ namespace Server.Mobiles
|
|||
private readonly List<IBuyItemInfo> _buyInfo = new();
|
||||
private readonly List<IShopSellInfo> _sellInfo = new();
|
||||
|
||||
public static void Initialize()
|
||||
{
|
||||
// This is technically more work than making timers, but we don't to deplete the timer pool immediately.
|
||||
foreach (var m in World.Mobiles.Values)
|
||||
{
|
||||
if (m is BaseVendor bv)
|
||||
{
|
||||
bv.CheckMorph();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public BaseVendor(string title = null)
|
||||
: base(AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2)
|
||||
{
|
||||
|
|
@ -1360,8 +1372,6 @@ namespace Server.Mobiles
|
|||
{
|
||||
IsParagon = false;
|
||||
}
|
||||
|
||||
Timer.StartTimer(CheckMorph);
|
||||
}
|
||||
|
||||
public override void AddCustomContextEntries(Mobile from, List<ContextMenuEntry> list)
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ namespace Server.Multis
|
|||
{
|
||||
private TimeSpan m_DecayDelay;
|
||||
private DateTime m_DecayTime;
|
||||
private TimerExecutionToken _decayTimerToken;
|
||||
private Timer _decayTimer;
|
||||
private List<Item> m_Items;
|
||||
private List<Mobile> m_Mobiles;
|
||||
|
||||
|
|
@ -55,6 +55,12 @@ namespace Server.Multis
|
|||
{
|
||||
}
|
||||
|
||||
public override void OnDelete()
|
||||
{
|
||||
_decayTimer?.Stop();
|
||||
_decayTimer = null;
|
||||
}
|
||||
|
||||
public virtual void RefreshDecay(bool setDecayTime)
|
||||
{
|
||||
if (Deleted)
|
||||
|
|
@ -67,8 +73,8 @@ namespace Server.Multis
|
|||
m_DecayTime = Core.Now + DecayDelay;
|
||||
}
|
||||
|
||||
_decayTimerToken.Cancel();
|
||||
Timer.StartTimer(DecayDelay, Delete, out _decayTimerToken);
|
||||
_decayTimer?.Stop();
|
||||
_decayTimer = Timer.DelayCall(DecayDelay, Delete);
|
||||
}
|
||||
|
||||
public virtual void AddItem(Item item, int xOffset, int yOffset, int zOffset)
|
||||
|
|
|
|||
|
|
@ -1197,7 +1197,7 @@ namespace Server.Multis
|
|||
LockedDownFlag = 1;
|
||||
SecureFlag = 2;
|
||||
|
||||
Timer.StartTimer(TimeSpan.FromMinutes(1.0), TimeSpan.FromMinutes(1.0), Decay_OnTick);
|
||||
Timer.DelayCall(TimeSpan.FromMinutes(1.0), TimeSpan.FromMinutes(1.0), Decay_OnTick);
|
||||
}
|
||||
|
||||
public virtual int GetAosCurLockdowns()
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Server.Collections;
|
||||
using Server.Items;
|
||||
using Server.Misc;
|
||||
using Server.Mobiles;
|
||||
|
|
@ -192,7 +193,6 @@ namespace Server.Spells.Fifth
|
|||
|
||||
private class InternalTimer : Timer
|
||||
{
|
||||
private static Queue<Mobile> m_Queue;
|
||||
private readonly bool m_CanFit;
|
||||
private readonly bool m_InLOS;
|
||||
private readonly InternalItem m_Item;
|
||||
|
|
@ -259,21 +259,21 @@ namespace Server.Spells.Fifth
|
|||
)
|
||||
);
|
||||
|
||||
using var queue = PooledRefQueue<Mobile>.Create();
|
||||
foreach (var m in eable)
|
||||
{
|
||||
if (m.Z + 16 > m_Item.Z && m_Item.Z + 12 > m.Z && (!Core.AOS || m != caster) &&
|
||||
SpellHelper.ValidIndirectTarget(caster, m) && caster.CanBeHarmful(m, false))
|
||||
{
|
||||
m_Queue ??= new Queue<Mobile>();
|
||||
m_Queue.Enqueue(m);
|
||||
queue.Enqueue(m);
|
||||
}
|
||||
}
|
||||
|
||||
eable.Free();
|
||||
|
||||
while (m_Queue?.Count > 0)
|
||||
while (queue.Count > 0)
|
||||
{
|
||||
var m = m_Queue.Dequeue();
|
||||
var m = queue.Dequeue();
|
||||
|
||||
caster.DoHarmful(m);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Server.Collections;
|
||||
using Server.Items;
|
||||
using Server.Misc;
|
||||
using Server.Mobiles;
|
||||
|
|
@ -199,7 +200,6 @@ namespace Server.Spells.Fourth
|
|||
|
||||
private class InternalTimer : Timer
|
||||
{
|
||||
private static Queue<Mobile> m_Queue;
|
||||
private readonly bool m_CanFit;
|
||||
private readonly bool m_InLOS;
|
||||
private readonly FireFieldItem m_Item;
|
||||
|
|
@ -256,19 +256,19 @@ namespace Server.Spells.Fourth
|
|||
return;
|
||||
}
|
||||
|
||||
using var queue = PooledRefQueue<Mobile>.Create();
|
||||
foreach (var m in m_Item.GetMobilesInRange(0))
|
||||
{
|
||||
if (m.Z + 16 > m_Item.Z && m_Item.Z + 12 > m.Z && (!Core.AOS || m != caster) &&
|
||||
SpellHelper.ValidIndirectTarget(caster, m) && caster.CanBeHarmful(m, false))
|
||||
{
|
||||
m_Queue ??= new Queue<Mobile>();
|
||||
m_Queue.Enqueue(m);
|
||||
queue.Enqueue(m);
|
||||
}
|
||||
}
|
||||
|
||||
while (m_Queue?.Count > 0)
|
||||
while (queue.Count > 0)
|
||||
{
|
||||
var m = m_Queue.Dequeue();
|
||||
var m = queue.Dequeue();
|
||||
if (m == null)
|
||||
{
|
||||
continue;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue