diff --git a/FrEee.Assets/CommonProjectProperties.xml b/FrEee.Assets/CommonProjectProperties.xml
index f0ffa0fe1..3e37b36ab 100644
--- a/FrEee.Assets/CommonProjectProperties.xml
+++ b/FrEee.Assets/CommonProjectProperties.xml
@@ -4,7 +4,7 @@
FrEee
0.0.9
Copyright © 2013-2024
- FrEee.ico
+ ../FrEee.Assets/FrEee.ico
enable
\ No newline at end of file
diff --git a/FrEee.Assets/GameSetups/Quickstart.gsu b/FrEee.Assets/GameSetups/Quickstart.gsu
index ba6e1f651..50c91d3d0 100644
--- a/FrEee.Assets/GameSetups/Quickstart.gsu
+++ b/FrEee.Assets/GameSetups/Quickstart.gsu
@@ -1,4 +1,4 @@
-FrEee.Setup.GameSetup, FrEee.Core:
+FrEee.Processes.Setup.GameSetup, FrEee.Core:
p31:
AllowedTrades:
:All;
@@ -7,7 +7,7 @@ p31:
EmpirePoints:
:2000;
EmpireTemplates:
- System.Collections.Generic.List`1[[FrEee.Setup.EmpireTemplate, FrEee.Core]], System.Private.CoreLib:
+ System.Collections.Generic.List`1[[FrEee.Processes.Setup.EmpireTemplate, FrEee.Core]], System.Private.CoreLib:
c1:
:p10:
AIName:
@@ -181,7 +181,7 @@ p31:
;
;
WarpPointPlacementStrategy:
- FrEee.Setup.WarpPointPlacementStrategies.EdgeAlignedWarpPointPlacementStrategy, FrEee.Core:
+ FrEee.Processes.Setup.WarpPointPlacementStrategies.EdgeAlignedWarpPointPlacementStrategy, FrEee.Core:
p2:
Description:
:"Places warp points along the edge of the system, aligned with the star systems they lead to.";
diff --git a/FrEee/Extensions/EnumerableExtensions.cs b/FrEee.Core.Utility/Extensions/EnumerableExtensions.cs
similarity index 99%
rename from FrEee/Extensions/EnumerableExtensions.cs
rename to FrEee.Core.Utility/Extensions/EnumerableExtensions.cs
index 0c20133c6..0041872f4 100644
--- a/FrEee/Extensions/EnumerableExtensions.cs
+++ b/FrEee.Core.Utility/Extensions/EnumerableExtensions.cs
@@ -2,7 +2,9 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
+using FrEee.Extensions;
using FrEee.Utility;
+
namespace FrEee.Extensions;
///
diff --git a/FrEee/Extensions/MathExtensions.cs b/FrEee.Core.Utility/Extensions/MathExtensions.cs
similarity index 97%
rename from FrEee/Extensions/MathExtensions.cs
rename to FrEee.Core.Utility/Extensions/MathExtensions.cs
index 98cdecd28..b9656b357 100644
--- a/FrEee/Extensions/MathExtensions.cs
+++ b/FrEee.Core.Utility/Extensions/MathExtensions.cs
@@ -4,6 +4,10 @@
using System.Linq;
using System.Numerics;
using FrEee.Utility;
+using FrEee.Extensions;
+using FrEee.Extensions;
+using FrEee.Utility;
+using FrEee.Extensions;
namespace FrEee.Extensions;
public static class MathExtensions
diff --git a/FrEee/Extensions/Parser.cs b/FrEee.Core.Utility/Extensions/Parser.cs
similarity index 98%
rename from FrEee/Extensions/Parser.cs
rename to FrEee.Core.Utility/Extensions/Parser.cs
index 0f85493f4..2197366c4 100644
--- a/FrEee/Extensions/Parser.cs
+++ b/FrEee.Core.Utility/Extensions/Parser.cs
@@ -3,6 +3,8 @@
using System.Linq;
using System.Reflection;
using FrEee.Utility;
+using FrEee.Extensions;
+using FrEee.Extensions;
namespace FrEee.Extensions;
///
diff --git a/FrEee/Extensions/StringHandlingExtensions.cs b/FrEee.Core.Utility/Extensions/StringHandlingExtensions.cs
similarity index 97%
rename from FrEee/Extensions/StringHandlingExtensions.cs
rename to FrEee.Core.Utility/Extensions/StringHandlingExtensions.cs
index 083b8c20b..df67e03bf 100644
--- a/FrEee/Extensions/StringHandlingExtensions.cs
+++ b/FrEee.Core.Utility/Extensions/StringHandlingExtensions.cs
@@ -1,4 +1,6 @@
using System.Linq;
+using FrEee.Extensions;
+using FrEee.Extensions;
namespace FrEee.Extensions;
@@ -90,4 +92,4 @@ public static string Possessive(this string s, bool isStart = false)
return s + "'";
return s + "'s";
}
-}
\ No newline at end of file
+}
diff --git a/FrEee.Core.Utility/Extensions/TypeExtensions.cs b/FrEee.Core.Utility/Extensions/TypeExtensions.cs
new file mode 100644
index 000000000..0b78de217
--- /dev/null
+++ b/FrEee.Core.Utility/Extensions/TypeExtensions.cs
@@ -0,0 +1,174 @@
+using System;
+using System.Collections.Generic;
+using System.Dynamic;
+using System.Linq;
+using System.Reflection;
+using System.Runtime.Serialization;
+using System.Text;
+using System.Threading.Tasks;
+using FrEee.Extensions;
+using FrEee.Extensions;
+using FrEee.Utility;
+
+namespace FrEee.Extensions;
+
+public static class TypeExtensions
+{
+ private static SafeDictionary> attributeCache = new SafeDictionary>();
+
+ private static SafeDictionary> interfaceCache = new SafeDictionary>();
+
+ private static SafeDictionary> memberCache = new SafeDictionary>();
+
+ public static object Instantiate(this Type type, params object[] args)
+ {
+ if (type.GetConstructors().Where(c => c.GetParameters().Length == (args == null ? 0 : args.Length)).Any())
+ return Activator.CreateInstance(type, args) ?? throw new NullReferenceException($"Couldn't create instance of type {type}.");
+ else
+ return FormatterServices.GetSafeUninitializedObject(type);
+ }
+
+ public static T Instantiate(params object[] args)
+ {
+ return (T)typeof(T).Instantiate(args);
+ }
+
+ ///
+ /// Equals method that doesn't throw an exception when objects are null.
+ /// Null is not equal to anything else, except other nulls.
+ ///
+ ///
+ ///
+ ///
+ public static bool SafeEquals(this object o1, object o2)
+ {
+ if (o1 == null && o2 == null)
+ return true;
+ if (o1 == null || o2 == null)
+ return false;
+ return o1.Equals(o2);
+ }
+
+ public static bool SafeSequenceEqual(this IEnumerable e1, IEnumerable e2)
+ {
+ if (e1.SafeEquals(null) && e2.SafeEquals(null))
+ return true;
+ if (e1.SafeEquals(null) || e2.SafeEquals(null))
+ return false;
+ return e1.SequenceEqual(e2);
+ }
+
+ ///
+ /// Checks for attributes in a class or its interfaces.
+ ///
+ ///
+ ///
+ ///
+ public static bool HasAttribute(this MemberInfo mi)
+ {
+ return mi.HasAttribute(typeof(T));
+ }
+
+ ///
+ /// Checks for attributes in a class or its interfaces.
+ ///
+ ///
+ ///
+ ///
+ public static bool HasAttribute(this MemberInfo mi, Type attributeType, bool checkInterfaces = true)
+ {
+ if (attributeCache[mi] == null)
+ attributeCache[mi] = Attribute.GetCustomAttributes(mi).ToArray();
+ if (attributeCache[mi].Where(a => attributeType.IsAssignableFrom(a.GetType())).Any())
+ return true;
+ var dt = mi is Type ? mi as Type : mi.DeclaringType;
+ if (checkInterfaces)
+ {
+ if (interfaceCache[dt] == null)
+ interfaceCache[dt] = dt.GetInterfaces();
+ foreach (var i in interfaceCache[dt])
+ {
+ if (memberCache[i] == null)
+ memberCache[i] = i.GetMembers(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).ToArray(); // TODO - refactor into method
+ if (memberCache[i].Any(m => m.Name == mi.Name && m.MemberType == mi.MemberType && m.HasAttribute(attributeType, false))) // no need to check interfaces of interfaces, they're already listed by GetInterfaces
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public static bool HasProperty(this ExpandoObject obj, string propertyName)
+ {
+ return obj.GetType().GetProperty(propertyName) != null;
+ }
+
+ ///
+ /// Checks for attributes in a class or its interfaces.
+ ///
+ ///
+ ///
+ ///
+ public static IEnumerable GetAttributes(this MemberInfo mi) where T : Attribute
+ {
+ if (attributeCache[mi] == null)
+ attributeCache[mi] = Attribute.GetCustomAttributes(mi).ToArray();
+ var atts = attributeCache[mi].OfType();
+ foreach (var att in atts)
+ yield return att;
+ if (interfaceCache[mi.DeclaringType] == null)
+ interfaceCache[mi.DeclaringType] = mi.DeclaringType.GetInterfaces();
+ foreach (var i in interfaceCache[mi.DeclaringType])
+ {
+ if (memberCache[i] == null)
+ memberCache[i] = i.GetMembers(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).ToArray(); // TODO - refactor into method
+ var mi2 = memberCache[i].SingleOrDefault(x => x.MemberType == mi.MemberType && x.Name == mi.Name);
+ if (mi2 != null)
+ {
+ foreach (var att2 in mi2.GetAttributes())
+ yield return att2;
+ }
+ }
+ }
+
+ ///
+ /// Gets all names for a property, class, etc. including custom names and the actual item name.
+ ///
+ ///
+ ///
+ public static IEnumerable GetNames(this MemberInfo m)
+ {
+ return m.GetAttributes().Select(a => a.Name).UnionSingle(m.Name);
+ }
+
+ ///
+ /// Gets the canonical name for a property, class, etc.
+ /// This is taken from the [CanonicalName] attribute if present, otherwise the name of the item itself.
+ ///
+ ///
+ ///
+ public static string GetCanonicalName(this MemberInfo m)
+ {
+ // TODO - use most derived class's attribute?
+ var name = m.GetAttributes().Select(a => a.Name).SingleOrDefault();
+ if (name == null)
+ return m.Name;
+ return name;
+ }
+
+ ///
+ /// Gets a property value from an object using reflection.
+ /// If the property does not exist, returns null.
+ ///
+ ///
+ ///
+ ///
+ public static object GetPropertyValue(this object o, string propertyName)
+ {
+ if (o == null)
+ return null;
+ var prop = o.GetType().GetProperty(propertyName);
+ if (prop == null)
+ return null;
+ return prop.GetValue(o, new object[0]);
+ }
+}
diff --git a/FrEee/Extensions/UnitHandlingExtensions.cs b/FrEee.Core.Utility/Extensions/UnitHandlingExtensions.cs
similarity index 98%
rename from FrEee/Extensions/UnitHandlingExtensions.cs
rename to FrEee.Core.Utility/Extensions/UnitHandlingExtensions.cs
index 3c1ed1eb5..1aa187a61 100644
--- a/FrEee/Extensions/UnitHandlingExtensions.cs
+++ b/FrEee.Core.Utility/Extensions/UnitHandlingExtensions.cs
@@ -1,6 +1,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using FrEee.Extensions;
+using FrEee.Extensions;
+using FrEee.Extensions;
namespace FrEee.Extensions;
@@ -247,4 +250,4 @@ public static string ToUnitString(this double? value, bool bForBillions = false,
return undefinedValue;
return value.Value.ToUnitString(bForBillions, sigfigs);
}
-}
\ No newline at end of file
+}
diff --git a/FrEee.Core.Utility/FrEee.Core.Utility.csproj b/FrEee.Core.Utility/FrEee.Core.Utility.csproj
new file mode 100644
index 000000000..cd07aa838
--- /dev/null
+++ b/FrEee.Core.Utility/FrEee.Core.Utility.csproj
@@ -0,0 +1,20 @@
+
+
+ net8.0
+ Library
+ FrEee.Core.Utility
+ Utility code for FrEee. This is low level utility code that doesn't need to know about any game objects.
+
+
+
+
+
+ false
+ FrEee
+
+
+
+
+
+
+
diff --git a/FrEee.Core.Utility/Serialization/DoNotSerializeAttribute.cs b/FrEee.Core.Utility/Serialization/DoNotSerializeAttribute.cs
new file mode 100644
index 000000000..93502e795
--- /dev/null
+++ b/FrEee.Core.Utility/Serialization/DoNotSerializeAttribute.cs
@@ -0,0 +1,22 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using FrEee.Utility;
+using FrEee.Serialization;
+
+namespace FrEee.Serialization
+{
+ ///
+ /// Prevents a property from being serialized, or copied when the containing object is copied.
+ ///
+ [AttributeUsage(AttributeTargets.Property, Inherited = true, AllowMultiple = false)]
+ public sealed class DoNotSerializeAttribute : DoNotCopyAttribute
+ {
+ public DoNotSerializeAttribute(bool allowSafeCopy = true)
+ : base(allowSafeCopy)
+ {
+ }
+ }
+}
diff --git a/FrEee/Serialization/IData.cs b/FrEee.Core.Utility/Serialization/IData.cs
similarity index 92%
rename from FrEee/Serialization/IData.cs
rename to FrEee.Core.Utility/Serialization/IData.cs
index dcc532105..14aa11a95 100644
--- a/FrEee/Serialization/IData.cs
+++ b/FrEee.Core.Utility/Serialization/IData.cs
@@ -1,4 +1,5 @@
using Newtonsoft.Json;
+using FrEee.Serialization;
namespace FrEee.Serialization;
diff --git a/FrEee/Serialization/IDataObject.cs b/FrEee.Core.Utility/Serialization/IDataObject.cs
similarity index 92%
rename from FrEee/Serialization/IDataObject.cs
rename to FrEee.Core.Utility/Serialization/IDataObject.cs
index 4b4fb0bae..35155dda6 100644
--- a/FrEee/Serialization/IDataObject.cs
+++ b/FrEee.Core.Utility/Serialization/IDataObject.cs
@@ -1,4 +1,7 @@
using FrEee.Utility;
+using FrEee.Serialization;
+using FrEee.Serialization;
+using FrEee.Utility;
namespace FrEee.Serialization;
///
diff --git a/FrEee/Serialization/IReferenceEnumerable.cs b/FrEee.Core.Utility/Serialization/IReferenceEnumerable.cs
similarity index 74%
rename from FrEee/Serialization/IReferenceEnumerable.cs
rename to FrEee.Core.Utility/Serialization/IReferenceEnumerable.cs
index b613c64a4..39a632e29 100644
--- a/FrEee/Serialization/IReferenceEnumerable.cs
+++ b/FrEee.Core.Utility/Serialization/IReferenceEnumerable.cs
@@ -1,8 +1,9 @@
-namespace FrEee.Serialization;
+using FrEee.Serialization;
+namespace FrEee.Serialization;
///
/// Flag interface for enumerables that should not be serialized as enumerables because they contain references.
///
public interface IReferenceEnumerable
{
-}
\ No newline at end of file
+}
diff --git a/FrEee/Serialization/JsonContractResolver.cs b/FrEee.Core.Utility/Serialization/JsonContractResolver.cs
similarity index 92%
rename from FrEee/Serialization/JsonContractResolver.cs
rename to FrEee.Core.Utility/Serialization/JsonContractResolver.cs
index 4d0969b53..f41fd4632 100644
--- a/FrEee/Serialization/JsonContractResolver.cs
+++ b/FrEee.Core.Utility/Serialization/JsonContractResolver.cs
@@ -3,6 +3,8 @@
using System;
using System.Linq;
using System.Reflection;
+using FrEee.Serialization;
+using FrEee.Serialization;
namespace FrEee.Serialization;
diff --git a/FrEee/Serialization/Stringifiers/IStringifier.cs b/FrEee.Core.Utility/Serialization/Stringifiers/IStringifier.cs
similarity index 78%
rename from FrEee/Serialization/Stringifiers/IStringifier.cs
rename to FrEee.Core.Utility/Serialization/Stringifiers/IStringifier.cs
index 409a466b4..750d61f18 100644
--- a/FrEee/Serialization/Stringifiers/IStringifier.cs
+++ b/FrEee.Core.Utility/Serialization/Stringifiers/IStringifier.cs
@@ -1,4 +1,6 @@
using System;
+using FrEee.Serialization.Stringifiers;
+using FrEee.Serialization.Stringifiers;
namespace FrEee.Serialization.Stringifiers;
diff --git a/FrEee/Serialization/Stringifiers/PointStringifier.cs b/FrEee.Core.Utility/Serialization/Stringifiers/PointStringifier.cs
similarity index 85%
rename from FrEee/Serialization/Stringifiers/PointStringifier.cs
rename to FrEee.Core.Utility/Serialization/Stringifiers/PointStringifier.cs
index 37cea331c..4acc39bc4 100644
--- a/FrEee/Serialization/Stringifiers/PointStringifier.cs
+++ b/FrEee.Core.Utility/Serialization/Stringifiers/PointStringifier.cs
@@ -1,6 +1,8 @@
using System.ComponentModel.Composition;
using System.Drawing;
using System.Linq;
+using FrEee.Serialization.Stringifiers;
+using FrEee.Serialization.Stringifiers;
namespace FrEee.Serialization.Stringifiers;
diff --git a/FrEee/Serialization/Stringifiers/SizeStringifier.cs b/FrEee.Core.Utility/Serialization/Stringifiers/SizeStringifier.cs
similarity index 85%
rename from FrEee/Serialization/Stringifiers/SizeStringifier.cs
rename to FrEee.Core.Utility/Serialization/Stringifiers/SizeStringifier.cs
index 0b708bc59..3e7a91c37 100644
--- a/FrEee/Serialization/Stringifiers/SizeStringifier.cs
+++ b/FrEee.Core.Utility/Serialization/Stringifiers/SizeStringifier.cs
@@ -1,6 +1,8 @@
using System.ComponentModel.Composition;
using System.Drawing;
using System.Linq;
+using FrEee.Serialization.Stringifiers;
+using FrEee.Serialization.Stringifiers;
namespace FrEee.Serialization.Stringifiers;
diff --git a/FrEee/Serialization/Stringifiers/Stringifier.cs b/FrEee.Core.Utility/Serialization/Stringifiers/Stringifier.cs
similarity index 87%
rename from FrEee/Serialization/Stringifiers/Stringifier.cs
rename to FrEee.Core.Utility/Serialization/Stringifiers/Stringifier.cs
index 230454527..6793e8b69 100644
--- a/FrEee/Serialization/Stringifiers/Stringifier.cs
+++ b/FrEee.Core.Utility/Serialization/Stringifiers/Stringifier.cs
@@ -1,4 +1,6 @@
using System;
+using FrEee.Serialization.Stringifiers;
+using FrEee.Serialization.Stringifiers;
namespace FrEee.Serialization.Stringifiers;
diff --git a/FrEee/Serialization/Stringifiers/StringifierLibrary.cs b/FrEee.Core.Utility/Serialization/Stringifiers/StringifierLibrary.cs
similarity index 89%
rename from FrEee/Serialization/Stringifiers/StringifierLibrary.cs
rename to FrEee.Core.Utility/Serialization/Stringifiers/StringifierLibrary.cs
index bcc27a6bd..b67dc13fb 100644
--- a/FrEee/Serialization/Stringifiers/StringifierLibrary.cs
+++ b/FrEee.Core.Utility/Serialization/Stringifiers/StringifierLibrary.cs
@@ -1,6 +1,8 @@
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
+using FrEee.Serialization.Stringifiers;
+using FrEee.Serialization.Stringifiers;
namespace FrEee.Serialization.Stringifiers;
diff --git a/FrEee/Utility/ClientSafeAttribute.cs b/FrEee.Core.Utility/Utility/ClientSafeAttribute.cs
similarity index 94%
rename from FrEee/Utility/ClientSafeAttribute.cs
rename to FrEee.Core.Utility/Utility/ClientSafeAttribute.cs
index 8f293a74a..ce4c6a668 100644
--- a/FrEee/Utility/ClientSafeAttribute.cs
+++ b/FrEee.Core.Utility/Utility/ClientSafeAttribute.cs
@@ -1,12 +1,13 @@
-using System;
-
-namespace FrEee.Utility;
-
-///
-/// Marks a type as safe to pass from the client to the server.
-///
-[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface, Inherited = true, AllowMultiple = false)]
-[Obsolete("ClientSafeAttribute is obsolete; please implement IPromotable instead.")]
-internal sealed class ClientSafeAttribute : Attribute
-{
-}
\ No newline at end of file
+using System;
+using FrEee.Utility;
+
+namespace FrEee.Utility;
+
+///
+/// Marks a type as safe to pass from the client to the server.
+///
+[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface, Inherited = true, AllowMultiple = false)]
+[Obsolete("ClientSafeAttribute is obsolete; please implement IPromotable instead.")]
+internal sealed class ClientSafeAttribute : Attribute
+{
+}
diff --git a/FrEee/Utility/ClientUtilities.cs b/FrEee.Core.Utility/Utility/ClientUtilities.cs
similarity index 94%
rename from FrEee/Utility/ClientUtilities.cs
rename to FrEee.Core.Utility/Utility/ClientUtilities.cs
index 857e2c03f..881b1d681 100644
--- a/FrEee/Utility/ClientUtilities.cs
+++ b/FrEee.Core.Utility/Utility/ClientUtilities.cs
@@ -1,22 +1,23 @@
-using System;
-using System.IO;
-
-namespace FrEee.Utility;
-
-public static class ClientUtilities
-{
- ///
- /// The path to FrEee's user roaming application data folder.
- ///
- public static string ApplicationDataPath
- {
- get
- {
- return Path.Combine
- (
- Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
- "FrEee"
- );
- }
- }
-}
\ No newline at end of file
+using System;
+using System.IO;
+using FrEee.Utility;
+
+namespace FrEee.Utility;
+
+public static class ClientUtilities
+{
+ ///
+ /// The path to FrEee's user roaming application data folder.
+ ///
+ public static string ApplicationDataPath
+ {
+ get
+ {
+ return Path.Combine
+ (
+ Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
+ "FrEee"
+ );
+ }
+ }
+}
diff --git a/FrEee.Core.Utility/Utility/DoNotCopyAttribute.cs b/FrEee.Core.Utility/Utility/DoNotCopyAttribute.cs
new file mode 100644
index 000000000..bbc7186ac
--- /dev/null
+++ b/FrEee.Core.Utility/Utility/DoNotCopyAttribute.cs
@@ -0,0 +1,28 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FrEee.Utility
+{
+ ///
+ /// Prevents an property or class's value from being copied when the containing object is copied.
+ /// Instead, the original value will be used, or the known copy if the value has already been copied.
+ ///
+ [AttributeUsage(AttributeTargets.Property | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface, Inherited = true, AllowMultiple = false)]
+ public class DoNotCopyAttribute : Attribute
+ {
+ public DoNotCopyAttribute(bool allowSafeCopy = true)
+ {
+ AllowSafeCopy = allowSafeCopy;
+ }
+
+ ///
+ /// Is "safe" copying (using the original property value) allowed?
+ /// If false, even this will not be attempted, and the property will be completely ignored.
+ /// Setting to false is useful for properties whose setters throw NotSupportedException.
+ ///
+ public bool AllowSafeCopy { get; private set; }
+ }
+}
diff --git a/FrEee/Utility/DynamicDictionary.cs b/FrEee.Core.Utility/Utility/DynamicDictionary.cs
similarity index 95%
rename from FrEee/Utility/DynamicDictionary.cs
rename to FrEee.Core.Utility/Utility/DynamicDictionary.cs
index da40dda08..1995041d7 100644
--- a/FrEee/Utility/DynamicDictionary.cs
+++ b/FrEee.Core.Utility/Utility/DynamicDictionary.cs
@@ -1,156 +1,158 @@
-using System.Collections.Generic;
-using System.Dynamic;
-using System.Linq;
-
-namespace FrEee.Utility;
-
-///
-/// A dynamic dictionary that's dynamic dictionaries all the way down.
-/// About as close as you can get to a Perl hash in C#.
-///
-public class DynamicDictionary : DynamicObject, IDictionary