Decompiled source of SmoothSave v1.0.5

SmoothSave.dll

Decompiled 2 years ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("SmoothSave")]
[assembly: AssemblyDescription("https://valheim.thunderstore.io/package/Smoothbrain/SmoothSave")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("SmoothSave")]
[assembly: AssemblyCopyright("Copyright ©  2022")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("15C530A2-65CF-42AA-83C3-AC862F358667")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace SmoothSave
{
	[BepInPlugin("org.bepinex.plugins.smoothsave", "Smooth Save", "1.0.5")]
	[BepInIncompatibility("org.bepinex.plugins.valheim_plus")]
	public class SmoothSave : BaseUnityPlugin
	{
		private enum Logging
		{
			Off,
			Simple,
			Detailed
		}

		[HarmonyPatch(typeof(ZNet), "SaveWorldThread")]
		public class SplitSaveWorld
		{
			private static bool Prefix()
			{
				Task<bool> task = customZDOCopyTask.Task;
				task.Wait();
				return task.Result;
			}
		}

		[HarmonyPatch(typeof(ZDO), "IncreaseDataRevision")]
		public class TrackZDOChanges
		{
			private static void CloneUpdatedZDO(ZDO zdo)
			{
				//IL_0007: Unknown result type (might be due to invalid IL or missing references)
				//IL_002b: Unknown result type (might be due to invalid IL or missing references)
				if (copiedZdoIndices.TryGetValue(zdo.m_uid, out var value))
				{
					copiedZdos[value] = zdo.Clone();
					UpdateZDOExtraData(zdo.m_uid);
				}
			}

			private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator ilg)
			{
				foreach (CodeInstruction instruction in instructions)
				{
					if (instruction.opcode == OpCodes.Ret)
					{
						Label endLabel = ilg.DefineLabel();
						yield return new CodeInstruction(OpCodes.Ldsfld, (object)AccessTools.DeclaredField(typeof(SmoothSave), "copiedZdoIndices"));
						yield return new CodeInstruction(OpCodes.Brtrue, (object)endLabel);
						yield return new CodeInstruction(OpCodes.Ret, (object)null);
						yield return new CodeInstruction(OpCodes.Ldarg_0, (object)null)
						{
							labels = { endLabel }
						};
						yield return new CodeInstruction(OpCodes.Call, (object)AccessTools.DeclaredMethod(typeof(TrackZDOChanges), "CloneUpdatedZDO", (Type[])null, (Type[])null));
					}
					yield return instruction;
				}
			}
		}

		[HarmonyPatch(typeof(ZDOMan), "RPC_ZDOData")]
		public class TrackZDORPCChanges
		{
			private static ZDO CloneUpdatedZDO(ZDO zdo)
			{
				//IL_0007: Unknown result type (might be due to invalid IL or missing references)
				//IL_002b: Unknown result type (might be due to invalid IL or missing references)
				if (copiedZdoIndices.TryGetValue(zdo.m_uid, out var value))
				{
					copiedZdos[value] = zdo.Clone();
					UpdateZDOExtraData(zdo.m_uid);
				}
				return zdo;
			}

			private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> _instructions, ILGenerator ilg)
			{
				//IL_0084: Unknown result type (might be due to invalid IL or missing references)
				//IL_008a: Expected O, but got Unknown
				//IL_0098: Unknown result type (might be due to invalid IL or missing references)
				//IL_009e: Expected O, but got Unknown
				//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
				//IL_00c1: Expected O, but got Unknown
				//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
				//IL_00dd: Expected O, but got Unknown
				//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f7: Expected O, but got Unknown
				List<CodeInstruction> list = _instructions.ToList();
				MethodInfo methodInfo = AccessTools.DeclaredMethod(typeof(ZDO), "Deserialize", (Type[])null, (Type[])null);
				for (int i = 0; i < list.Count; i++)
				{
					if (list[i].opcode == OpCodes.Callvirt && CodeInstructionExtensions.OperandIs(list[i], (MemberInfo)methodInfo))
					{
						Label label = ilg.DefineLabel();
						list.InsertRange(i + 1, (IEnumerable<CodeInstruction>)(object)new CodeInstruction[4]
						{
							new CodeInstruction(OpCodes.Ldsfld, (object)AccessTools.DeclaredField(typeof(SmoothSave), "copiedZdoIndices")),
							new CodeInstruction(OpCodes.Brfalse, (object)label),
							new CodeInstruction(OpCodes.Call, (object)AccessTools.DeclaredMethod(typeof(TrackZDOChanges), "CloneUpdatedZDO", (Type[])null, (Type[])null)),
							new CodeInstruction(OpCodes.Pop, (object)null)
							{
								labels = { label }
							}
						});
						list.Insert(i - 1, new CodeInstruction(OpCodes.Dup, (object)null));
						i += 6;
					}
				}
				return list;
			}
		}

		[HarmonyPatch(typeof(ZDOMan), "RemoveFromSector")]
		public class TrackRemovedZDOs
		{
			private static bool RemoveZDO(List<ZDO> zdos, ZDO zdo, int index)
			{
				//IL_007c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0090: Unknown result type (might be due to invalid IL or missing references)
				//IL_0095: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
				//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
				//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
				//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
				//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
				//IL_0100: Unknown result type (might be due to invalid IL or missing references)
				int num = zdos.IndexOf(zdo);
				if (num < 0)
				{
					return false;
				}
				zdos.RemoveAt(num);
				Dictionary<ZDOID, int> copiedZdoIndices = SmoothSave.copiedZdoIndices;
				if (copiedZdoIndices != null)
				{
					if (copyingSectorId == index && num <= copyingSectorOffset)
					{
						copyingSectorOffset--;
					}
					else if (copyingSectorId <= index)
					{
						return true;
					}
					if (copiedZdoIndices.TryGetValue(zdo.m_uid, out var value))
					{
						ZDOID uid = zdo.m_uid;
						removedIndices.Add(value);
						copiedZdoIndices.Remove(uid);
						copiedZdo_floats.Remove(uid);
						copiedZdo_vec3.Remove(uid);
						copiedZdo_quats.Remove(uid);
						copiedZdo_ints.Remove(uid);
						copiedZdo_longs.Remove(uid);
						copiedZdo_strings.Remove(uid);
						copiedZdo_byteArrays.Remove(uid);
					}
				}
				return true;
			}

			private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
			{
				MethodInfo listRemove = AccessTools.DeclaredMethod(typeof(List<ZDO>), "Remove", new Type[1] { typeof(ZDO) }, (Type[])null);
				bool first = true;
				foreach (CodeInstruction instruction in instructions)
				{
					if (first && instruction.opcode == OpCodes.Callvirt && CodeInstructionExtensions.OperandIs(instruction, (MemberInfo)listRemove))
					{
						first = false;
						yield return new CodeInstruction(OpCodes.Ldloc_0, (object)null);
						yield return new CodeInstruction(OpCodes.Call, (object)AccessTools.DeclaredMethod(typeof(TrackRemovedZDOs), "RemoveZDO", (Type[])null, (Type[])null));
					}
					else
					{
						yield return instruction;
					}
				}
			}
		}

		[HarmonyPatch(typeof(ZDOMan), "AddToSector")]
		public class TrackAddedZDOs
		{
			private static void AddZdo(ZDO zdo, int index)
			{
				//IL_0024: Unknown result type (might be due to invalid IL or missing references)
				//IL_0046: Unknown result type (might be due to invalid IL or missing references)
				if (copiedZdoIndices != null && index < copyingSectorId && zdo.Persistent)
				{
					copiedZdoIndices.Add(zdo.m_uid, copiedZdos.Count);
					copiedZdos.Add(zdo);
					UpdateZDOExtraData(zdo.m_uid);
				}
			}

			private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
			{
				MethodInfo listAdd = AccessTools.DeclaredMethod(typeof(List<ZDO>), "Add", new Type[1] { typeof(ZDO) }, (Type[])null);
				int firsts = 2;
				foreach (CodeInstruction instruction in instructions)
				{
					yield return instruction;
					if (firsts > 0 && instruction.opcode == OpCodes.Callvirt && CodeInstructionExtensions.OperandIs(instruction, (MemberInfo)listAdd))
					{
						int num = firsts - 1;
						firsts = num;
						yield return new CodeInstruction(OpCodes.Ldarg_1, (object)null);
						yield return new CodeInstruction(OpCodes.Ldloc_0, (object)null);
						yield return new CodeInstruction(OpCodes.Call, (object)AccessTools.DeclaredMethod(typeof(TrackAddedZDOs), "AddZdo", (Type[])null, (Type[])null));
					}
				}
			}
		}

		[HarmonyPatch(typeof(ZNet), "SaveWorld")]
		public class ReplaceZDOCopying
		{
			private static void CustomZDOCopy(ZDOMan zdoMan)
			{
				ZDOMan zdoMan2 = zdoMan;
				TaskCompletionSource<bool> task = new TaskCompletionSource<bool>();
				customZDOCopyTask = task;
				IEnumerator saveCoroutine = save();
				((MonoBehaviour)ZNet.instance).StartCoroutine(saveCoroutine);
				customZDOCopyTask.Task.ContinueWith(delegate
				{
					((MonoBehaviour)ZNet.instance).StopCoroutine(saveCoroutine);
				});
				IEnumerator save()
				{
					yield return null;
					Dictionary<ZDOID, int> zdoIndex = new Dictionary<ZDOID, int>();
					List<ZDO> saveZDOs = new List<ZDO>();
					Dictionary<ZDOID, BinarySearchDictionary<int, float>> zdo_floats = new Dictionary<ZDOID, BinarySearchDictionary<int, float>>();
					Dictionary<ZDOID, BinarySearchDictionary<int, Vector3>> zdo_vec3 = new Dictionary<ZDOID, BinarySearchDictionary<int, Vector3>>();
					Dictionary<ZDOID, BinarySearchDictionary<int, Quaternion>> zdo_quats = new Dictionary<ZDOID, BinarySearchDictionary<int, Quaternion>>();
					Dictionary<ZDOID, BinarySearchDictionary<int, int>> zdo_ints = new Dictionary<ZDOID, BinarySearchDictionary<int, int>>();
					Dictionary<ZDOID, BinarySearchDictionary<int, long>> zdo_longs = new Dictionary<ZDOID, BinarySearchDictionary<int, long>>();
					Dictionary<ZDOID, BinarySearchDictionary<int, string>> zdo_strings = new Dictionary<ZDOID, BinarySearchDictionary<int, string>>();
					Dictionary<ZDOID, BinarySearchDictionary<int, byte[]>> zdo_byteArrays = new Dictionary<ZDOID, BinarySearchDictionary<int, byte[]>>();
					zdoMan2.m_saveData = new SaveData
					{
						m_sessionID = zdoMan2.m_sessionID,
						m_zdos = saveZDOs
					};
					yield return null;
					copiedZdos = saveZDOs;
					copiedZdoIndices = zdoIndex;
					copiedZdo_floats = zdo_floats;
					copiedZdo_vec3 = zdo_vec3;
					copiedZdo_quats = zdo_quats;
					copiedZdo_ints = zdo_ints;
					copiedZdo_longs = zdo_longs;
					copiedZdo_strings = zdo_strings;
					copiedZdo_byteArrays = zdo_byteArrays;
					Stopwatch stopwatch = Stopwatch.StartNew();
					long longestBlockingTime = 0L;
					long lastElapsed = 0L;
					int currentBatch = zdoBatchSize.Value;
					List<ZDO>?[] objectsBySector = zdoMan2.m_objectsBySector;
					int index = 0;
					int end = objectsBySector.Length;
					while (index < end)
					{
						List<ZDO> zdos = objectsBySector[index];
						int num;
						if (zdos != null)
						{
							for (int j = 0; j < zdos.Count; j = num)
							{
								ZDO zdo = zdos[j];
								if (zdo.Persistent)
								{
									ZDOID zdoid = zdo.m_uid;
									zdoIndex.Add(zdoid, saveZDOs.Count);
									saveZDOs.Add(zdo.Clone());
									if (ZDOExtraData.s_floats.TryGetValue(zdoid, out var value_floats))
									{
										zdo_floats.Add(zdoid, (BinarySearchDictionary<int, float>)value_floats.Clone());
									}
									if (ZDOExtraData.s_vec3.TryGetValue(zdoid, out var value_vec3))
									{
										zdo_vec3.Add(zdoid, (BinarySearchDictionary<int, Vector3>)value_vec3.Clone());
									}
									if (ZDOExtraData.s_quats.TryGetValue(zdoid, out var value_quats))
									{
										zdo_quats.Add(zdoid, (BinarySearchDictionary<int, Quaternion>)value_quats.Clone());
									}
									if (ZDOExtraData.s_ints.TryGetValue(zdoid, out var value_ints))
									{
										zdo_ints.Add(zdoid, (BinarySearchDictionary<int, int>)value_ints.Clone());
									}
									if (ZDOExtraData.s_longs.TryGetValue(zdoid, out var value_longs))
									{
										zdo_longs.Add(zdoid, (BinarySearchDictionary<int, long>)value_longs.Clone());
									}
									if (ZDOExtraData.s_strings.TryGetValue(zdoid, out BinarySearchDictionary<int, string> value_strings))
									{
										zdo_strings.Add(zdoid, (BinarySearchDictionary<int, string>)value_strings.Clone());
									}
									if (ZDOExtraData.s_byteArrays.TryGetValue(zdoid, out BinarySearchDictionary<int, byte[]> value_byteArrays))
									{
										zdo_byteArrays.Add(zdoid, (BinarySearchDictionary<int, byte[]>)value_byteArrays.Clone());
									}
									num = currentBatch - 1;
									currentBatch = num;
									if (num <= 0)
									{
										currentBatch = zdoBatchSize.Value;
										copyingSectorId = index;
										copyingSectorOffset = j;
										stopwatch.Stop();
										longestBlockingTime = Math.Max(longestBlockingTime, stopwatch.ElapsedMilliseconds - lastElapsed);
										lastElapsed = stopwatch.ElapsedMilliseconds;
										yield return null;
										stopwatch.Start();
										j = copyingSectorOffset;
									}
									value_floats = null;
									value_vec3 = null;
									value_quats = null;
									value_ints = null;
									value_longs = null;
									value_strings = null;
									value_byteArrays = null;
								}
								num = j + 1;
							}
						}
						num = index + 1;
						index = num;
					}
					foreach (int removedIndex in removedIndices.OrderByDescending((int i) => i))
					{
						int lastIndex = saveZDOs.Count - 1;
						saveZDOs[removedIndex] = saveZDOs[lastIndex];
						saveZDOs.RemoveAt(lastIndex);
					}
					removedIndices.Clear();
					long outsideSectorStart = stopwatch.ElapsedMilliseconds;
					foreach (List<ZDO> zdoList in zdoMan2.m_objectsByOutsideSector.Values)
					{
						foreach (ZDO zdo2 in zdoList)
						{
							if (zdo2.Persistent)
							{
								saveZDOs.Add(zdo2.Clone());
							}
						}
					}
					stopwatch.Stop();
					zdoMan2.m_saveData.m_nextUid = zdoMan2.m_nextUid;
					ZDOExtraData.s_saveFloats = zdo_floats;
					ZDOExtraData.s_saveVec3s = zdo_vec3;
					ZDOExtraData.s_saveQuats = zdo_quats;
					ZDOExtraData.s_saveInts = zdo_ints;
					ZDOExtraData.s_saveLongs = zdo_longs;
					ZDOExtraData.s_saveStrings = zdo_strings;
					ZDOExtraData.s_saveByteArrays = zdo_byteArrays;
					long outsideSectorTime = stopwatch.ElapsedMilliseconds - outsideSectorStart;
					long connectionHashDataStart = stopwatch.ElapsedMilliseconds;
					ZDOExtraData.RegenerateConnectionHashData();
					ZDOExtraData.s_saveConnections = ZDOHelper.Clone(ZDOExtraData.s_connectionsHashData);
					long connectionHashDataTime = stopwatch.ElapsedMilliseconds - connectionHashDataStart;
					if (saveLoggingOutput.Value == Logging.Simple)
					{
						Log($"World saved: Estimated blocking time without the mod: {stopwatch.ElapsedMilliseconds} ms. Blocking time now: {longestBlockingTime} ms.");
					}
					else if (saveLoggingOutput.Value == Logging.Detailed)
					{
						Log($"Copying ZDOs into internal buffer took {stopwatch.ElapsedMilliseconds} ms. (Longest blocking time: {longestBlockingTime} ms, copying ZDOs outside sector time: {outsideSectorTime} ms, saving connections: {connectionHashDataTime} ms).");
					}
					ZoneSystem.instance.PrepareSave();
					RandEventSystem.instance.PrepareSave();
					copiedZdos = null;
					copiedZdoIndices = null;
					ZNet.instance.m_saveThreadStartTime = Time.realtimeSinceStartup;
					task.SetResult(result: true);
				}
			}

			public static bool Prefix(bool sync)
			{
				if (customZDOCopyTask.Task.IsCompleted)
				{
					return true;
				}
				if (sync)
				{
					AbortSave();
					return true;
				}
				return false;
			}

			public static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator ilg)
			{
				MethodInfo PrepareSave = AccessTools.DeclaredMethod(typeof(ZDOMan), "PrepareSave", (Type[])null, (Type[])null);
				bool insertCustomSave = false;
				Label doCustomSaveLabel = ilg.DefineLabel();
				foreach (CodeInstruction instruction in instructions)
				{
					if (insertCustomSave)
					{
						insertCustomSave = false;
						Label endCustomSaveLabel = ilg.DefineLabel();
						yield return new CodeInstruction(OpCodes.Br, (object)endCustomSaveLabel);
						yield return new CodeInstruction(OpCodes.Call, (object)AccessTools.DeclaredMethod(typeof(ReplaceZDOCopying), "CustomZDOCopy", (Type[])null, (Type[])null))
						{
							labels = { doCustomSaveLabel }
						};
						instruction.labels.Add(endCustomSaveLabel);
					}
					if (instruction.opcode == OpCodes.Callvirt && CodeInstructionExtensions.OperandIs(instruction, (MemberInfo)PrepareSave))
					{
						yield return new CodeInstruction(OpCodes.Ldarg_1, (object)null);
						yield return new CodeInstruction(OpCodes.Brfalse, (object)doCustomSaveLabel);
						insertCustomSave = true;
					}
					yield return instruction;
				}
			}
		}

		[HarmonyPatch(typeof(ZNet), "StopAll")]
		private class InterceptSaveThreadJoinOnStop
		{
			public static void Prefix(ZNet __instance)
			{
				if (!__instance.m_haveStoped && !customZDOCopyTask.Task.IsCompleted)
				{
					__instance.SaveWorld(true);
				}
			}
		}

		private const string ModName = "Smooth Save";

		private const string ModVersion = "1.0.5";

		private const string ModGUID = "org.bepinex.plugins.smoothsave";

		private static SmoothSave selfReference;

		private static ConfigEntry<int> zdoBatchSize;

		private static ConfigEntry<Logging> saveLoggingOutput;

		private static TaskCompletionSource<bool> customZDOCopyTask;

		private static readonly List<int> removedIndices;

		private static Dictionary<ZDOID, int>? copiedZdoIndices;

		private static List<ZDO> copiedZdos;

		private static Dictionary<ZDOID, BinarySearchDictionary<int, float>> copiedZdo_floats;

		private static Dictionary<ZDOID, BinarySearchDictionary<int, Vector3>> copiedZdo_vec3;

		private static Dictionary<ZDOID, BinarySearchDictionary<int, Quaternion>> copiedZdo_quats;

		private static Dictionary<ZDOID, BinarySearchDictionary<int, int>> copiedZdo_ints;

		private static Dictionary<ZDOID, BinarySearchDictionary<int, long>> copiedZdo_longs;

		private static Dictionary<ZDOID, BinarySearchDictionary<int, string>> copiedZdo_strings;

		private static Dictionary<ZDOID, BinarySearchDictionary<int, byte[]>> copiedZdo_byteArrays;

		private static int copyingSectorId;

		private static int copyingSectorOffset;

		private static ManualLogSource logger => ((BaseUnityPlugin)selfReference).Logger;

		public void Awake()
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Expected O, but got Unknown
			selfReference = this;
			Assembly executingAssembly = Assembly.GetExecutingAssembly();
			Harmony val = new Harmony("org.bepinex.plugins.smoothsave");
			val.PatchAll(executingAssembly);
			zdoBatchSize = ((BaseUnityPlugin)this).Config.Bind<int>("1 - General", "ZDOs to copy at once", 3000, "The number of ZDOs that are copied at the same time. You can increase this, if you have powerful hardware.");
			saveLoggingOutput = ((BaseUnityPlugin)this).Config.Bind<Logging>("1 - General", "World save output", Logging.Simple, "Log level for world saves.");
		}

		static SmoothSave()
		{
			selfReference = null;
			zdoBatchSize = null;
			saveLoggingOutput = null;
			customZDOCopyTask = new TaskCompletionSource<bool>();
			removedIndices = new List<int>();
			copiedZdos = null;
			copiedZdo_floats = new Dictionary<ZDOID, BinarySearchDictionary<int, float>>();
			copiedZdo_vec3 = new Dictionary<ZDOID, BinarySearchDictionary<int, Vector3>>();
			copiedZdo_quats = new Dictionary<ZDOID, BinarySearchDictionary<int, Quaternion>>();
			copiedZdo_ints = new Dictionary<ZDOID, BinarySearchDictionary<int, int>>();
			copiedZdo_longs = new Dictionary<ZDOID, BinarySearchDictionary<int, long>>();
			copiedZdo_strings = new Dictionary<ZDOID, BinarySearchDictionary<int, string>>();
			copiedZdo_byteArrays = new Dictionary<ZDOID, BinarySearchDictionary<int, byte[]>>();
			customZDOCopyTask.SetResult(result: true);
		}

		private static void Log(string message)
		{
			logger.LogMessage((object)message);
		}

		private static void UpdateZDOExtraData(ZDOID zdoid)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			if (ZDOExtraData.s_floats.TryGetValue(zdoid, out var value))
			{
				copiedZdo_floats[zdoid] = (BinarySearchDictionary<int, float>)value.Clone();
			}
			if (ZDOExtraData.s_vec3.TryGetValue(zdoid, out var value2))
			{
				copiedZdo_vec3[zdoid] = (BinarySearchDictionary<int, Vector3>)value2.Clone();
			}
			if (ZDOExtraData.s_quats.TryGetValue(zdoid, out var value3))
			{
				copiedZdo_quats[zdoid] = (BinarySearchDictionary<int, Quaternion>)value3.Clone();
			}
			if (ZDOExtraData.s_ints.TryGetValue(zdoid, out var value4))
			{
				copiedZdo_ints[zdoid] = (BinarySearchDictionary<int, int>)value4.Clone();
			}
			if (ZDOExtraData.s_longs.TryGetValue(zdoid, out var value5))
			{
				copiedZdo_longs[zdoid] = (BinarySearchDictionary<int, long>)value5.Clone();
			}
			if (ZDOExtraData.s_strings.TryGetValue(zdoid, out var value6))
			{
				copiedZdo_strings[zdoid] = (BinarySearchDictionary<int, string>)value6.Clone();
			}
			if (ZDOExtraData.s_byteArrays.TryGetValue(zdoid, out var value7))
			{
				copiedZdo_byteArrays[zdoid] = (BinarySearchDictionary<int, byte[]>)value7.Clone();
			}
		}

		private static void AbortSave()
		{
			customZDOCopyTask.SetResult(result: false);
			Log("Aborted saving due to new save request while ZDOs for saving are being collected.");
		}
	}
}