diff --git a/PkmnLib.Dynamic/Models/BattleRandom.cs b/PkmnLib.Dynamic/Models/BattleRandom.cs
index 9f2dccd..85c80d9 100644
--- a/PkmnLib.Dynamic/Models/BattleRandom.cs
+++ b/PkmnLib.Dynamic/Models/BattleRandom.cs
@@ -6,7 +6,7 @@ namespace PkmnLib.Dynamic.Models;
///
/// Random number generator for battles.
///
-public interface IBattleRandom : IRandom
+public interface IBattleRandom : IRandom, IDeepCloneable
{
///
/// Gets whether or not a move triggers its secondary effect. This takes its chance, and
diff --git a/PkmnLib.Static/Utils/DeepClone.cs b/PkmnLib.Static/Utils/DeepClone.cs
index f99971d..1d506ba 100644
--- a/PkmnLib.Static/Utils/DeepClone.cs
+++ b/PkmnLib.Static/Utils/DeepClone.cs
@@ -2,6 +2,7 @@ using System.Collections;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.Serialization;
+using Pcg;
namespace PkmnLib.Static.Utils;
@@ -25,11 +26,16 @@ public static class DeepCloneHandler
/// references.
///
public static T DeepClone(this T? obj, Dictionary<(Type, int), object>? objects = null) where T : IDeepCloneable
+ {
+ return (T)DeepClone((object?)obj, objects)!;
+ }
+
+ private static object? DeepClone(this object? obj, Dictionary<(Type, int), object>? objects = null)
{
if (obj == null)
- return default!;
+ return null;
if (objects != null && objects.TryGetValue((obj.GetType(), obj.GetHashCode()), out var value))
- return (T)value;
+ return value;
var type = obj.GetType();
// We use GetUninitializedObject to create an object without calling the constructor. This is necessary to prevent
@@ -52,24 +58,30 @@ public static class DeepCloneHandler
setter.Invoke(newObj, cloned);
}
- return (T)newObj;
+ return newObj;
}
- private static object DeepCloneInternal(object? obj, Type type, Dictionary<(Type, int), object> objects)
+ private static readonly HashSet ExternalDeepCloneTypes = new()
+ {
+ typeof(PcgRandom),
+ typeof(Pcg32Single),
+ };
+
+ private static object? DeepCloneInternal(object? obj, Type type, Dictionary<(Type, int), object> objects)
{
if (obj == null)
- return null!;
+ return null;
// If the object is a value type or a string, we can just return it.
if (type.IsValueType || type == typeof(string))
return obj;
// If the object is marked as deep cloneable, we will clone it.
- if (type.GetInterface(nameof(IDeepCloneable)) != null)
+ if (type.GetInterface(nameof(IDeepCloneable)) != null || ExternalDeepCloneTypes.Contains(type))
{
// If the object is already cloned, we return the cloned object to prevent infinite loops and invalid references.
if (objects.TryGetValue((obj.GetType(), obj.GetHashCode()), out var value))
return value;
- var o = DeepClone((IDeepCloneable)obj, objects);
+ var o = DeepClone(obj, objects);
return o;
}
@@ -104,7 +116,7 @@ public static class DeepCloneHandler
var newDictionary = (IDictionary)Activator.CreateInstance(type);
foreach (DictionaryEntry entry in dictionary)
newDictionary.Add(
- DeepCloneInternal(entry.Key, type.GetGenericArguments()[0], objects),
+ DeepCloneInternal(entry.Key, type.GetGenericArguments()[0], objects)!,
DeepCloneInternal(entry.Value, type.GetGenericArguments()[1], objects));
return newDictionary;
}
@@ -121,7 +133,7 @@ public static class DeepCloneHandler
/// This method is thread safe, and will only create the expressions once for each type. It returns compiled expressions for
/// each field in the type, so that we can get high performance deep cloning.
///
- private static (Func