diff --git a/Benchmarks/Benchmarks.csproj b/Benchmarks/Benchmarks.csproj
new file mode 100644
index 00000000..def07bbe
--- /dev/null
+++ b/Benchmarks/Benchmarks.csproj
@@ -0,0 +1,24 @@
+
+
+
+ Exe
+ net9.0
+ enable
+ enable
+
+
+
+
+
+
+
+
+
+
+
+
+ PreserveNewest
+
+
+
+
diff --git a/Benchmarks/ClonerBenchmarks.cs b/Benchmarks/ClonerBenchmarks.cs
new file mode 100644
index 00000000..18925355
--- /dev/null
+++ b/Benchmarks/ClonerBenchmarks.cs
@@ -0,0 +1,50 @@
+using BenchmarkDotNet.Attributes;
+using Benchmarks.Mock;
+using Core.Models.Spt.Templates;
+using Core.Utils;
+using Core.Utils.Cloners;
+
+namespace Benchmarks;
+
+[SimpleJob(warmupCount: 10, iterationCount: 10)]
+[MemoryDiagnoser]
+public class ClonerBenchmarks
+{
+ private Templates? _templates;
+
+ private ICloner _jsonCloner;
+ private ICloner _reflectionsCloner;
+ private ICloner _fastCloner;
+
+ [GlobalSetup]
+ public void Setup()
+ {
+ var jsonUtil = new JsonUtil();
+ var importer = new ImporterUtil(new MockLogger(), new FileUtil(new MockLogger()),
+ jsonUtil);
+ var loadTask = importer.LoadRecursiveAsync("./Assets/database/templates/");
+ loadTask.Wait();
+ _templates = loadTask.Result;
+ _jsonCloner = new JsonCloner(jsonUtil);
+ _reflectionsCloner = new ReflectionsCloner(new MockLogger());
+ _fastCloner = new Core.Utils.Cloners.FastCloner();
+ }
+
+ [Benchmark]
+ public void JsonCloner()
+ {
+ _jsonCloner.Clone(_templates);
+ }
+
+ [Benchmark]
+ public void ReflectionsCloner()
+ {
+ _reflectionsCloner.Clone(_templates);
+ }
+
+ [Benchmark(Baseline = true)]
+ public void FastCloner()
+ {
+ _fastCloner.Clone(_templates);
+ }
+}
diff --git a/Benchmarks/Mock/MockLogger.cs b/Benchmarks/Mock/MockLogger.cs
new file mode 100644
index 00000000..9e363fb3
--- /dev/null
+++ b/Benchmarks/Mock/MockLogger.cs
@@ -0,0 +1,68 @@
+using Core.Models.Logging;
+using Core.Models.Spt.Logging;
+using Core.Models.Utils;
+
+namespace Benchmarks.Mock;
+
+public class MockLogger : ISptLogger
+{
+ public void LogWithColor(string data, LogTextColor? textColor = null, LogBackgroundColor? backgroundColor = null, Exception? ex = null)
+ {
+ throw new NotImplementedException();
+ }
+
+ public void Success(string data, Exception? ex = null)
+ {
+ Console.WriteLine(data);
+ }
+
+ public void Error(string data, Exception? ex = null)
+ {
+ Console.WriteLine(data);
+ }
+
+ public void Warning(string data, Exception? ex = null)
+ {
+ Console.WriteLine(data);
+ }
+
+ public void Info(string data, Exception? ex = null)
+ {
+ Console.WriteLine(data);
+ }
+
+ public void Debug(string data, Exception? ex = null)
+ {
+ Console.WriteLine(data);
+ }
+
+ public void Critical(string data, Exception? ex = null)
+ {
+ Console.WriteLine(data);
+ }
+
+ public void WriteToLogFile(string body, LogLevel level = LogLevel.Info)
+ {
+ throw new NotImplementedException();
+ }
+
+ public bool IsLogEnabled(LogLevel level)
+ {
+ return false;
+ }
+
+ public void LogWithColor(
+ string data,
+ Exception? ex = null,
+ LogTextColor? textColor = null,
+ LogBackgroundColor? backgroundColor = null
+ )
+ {
+ Console.WriteLine(data);
+ }
+
+ public void WriteToLogFile(object body)
+ {
+ Console.WriteLine(body);
+ }
+}
diff --git a/Benchmarks/Program.cs b/Benchmarks/Program.cs
new file mode 100644
index 00000000..f1bfcc65
--- /dev/null
+++ b/Benchmarks/Program.cs
@@ -0,0 +1,12 @@
+using BenchmarkDotNet.Running;
+
+namespace Benchmarks;
+
+public class Program
+{
+ public static void Main(string[] args)
+ {
+ var summary = BenchmarkRunner.Run();
+ Console.WriteLine(summary);
+ }
+}
diff --git a/Libraries/Core/Core.csproj b/Libraries/Core/Core.csproj
index 1462d2b5..462dddde 100644
--- a/Libraries/Core/Core.csproj
+++ b/Libraries/Core/Core.csproj
@@ -13,6 +13,7 @@
+
diff --git a/Libraries/Core/Utils/Cloners/FastCloner.cs b/Libraries/Core/Utils/Cloners/FastCloner.cs
new file mode 100644
index 00000000..2d1095d2
--- /dev/null
+++ b/Libraries/Core/Utils/Cloners/FastCloner.cs
@@ -0,0 +1,12 @@
+using SptCommon.Annotations;
+
+namespace Core.Utils.Cloners;
+
+[Injectable]
+public class FastCloner : ICloner
+{
+ public T? Clone(T? obj)
+ {
+ return global::FastCloner.FastCloner.DeepClone(obj);
+ }
+}
diff --git a/Libraries/Core/Utils/Cloners/JsonCloner.cs b/Libraries/Core/Utils/Cloners/JsonCloner.cs
index b571554c..374c838f 100644
--- a/Libraries/Core/Utils/Cloners/JsonCloner.cs
+++ b/Libraries/Core/Utils/Cloners/JsonCloner.cs
@@ -1,8 +1,8 @@
-using SptCommon.Annotations;
-
namespace Core.Utils.Cloners;
-[Injectable]
+/**
+ * Disabled as FastCloner library is 15% faster and consumes less memory than Json serialization
+ */
public class JsonCloner : ICloner
{
protected JsonUtil _jsonUtil;
diff --git a/Libraries/Core/Utils/Cloners/ReflectionsCloner.cs b/Libraries/Core/Utils/Cloners/ReflectionsCloner.cs
new file mode 100644
index 00000000..e705bdb5
--- /dev/null
+++ b/Libraries/Core/Utils/Cloners/ReflectionsCloner.cs
@@ -0,0 +1,174 @@
+using System.Collections;
+using System.Collections.Concurrent;
+using System.Reflection;
+using Core.Models.Utils;
+using Core.Utils.Json;
+using LogLevel = Core.Models.Spt.Logging.LogLevel;
+
+namespace Core.Utils.Cloners;
+
+/**
+ * Not in use at the moment
+ */
+public class ReflectionsCloner(ISptLogger logger) : ICloner
+{
+ private static Dictionary MemberInfoCache = new();
+ private static Dictionary AddMethodInfoCache = new();
+
+ public T? Clone(T? obj)
+ {
+ return (T?) Clone(obj, typeof(T)).Result;
+ }
+
+ public async Task