Decompiled source of MonsterDB v0.1.1

MonsterDB.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Cryptography;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using JetBrains.Annotations;
using Microsoft.CodeAnalysis;
using MonsterDB.Solution;
using MonsterDB.Solution.Behaviors;
using MonsterDB.Solution.Methods;
using ServerSync;
using TMPro;
using UnityEngine;
using YamlDotNet.Core;
using YamlDotNet.Core.Events;
using YamlDotNet.Core.Tokens;
using YamlDotNet.Helpers;
using YamlDotNet.Serialization;
using YamlDotNet.Serialization.BufferedDeserialization;
using YamlDotNet.Serialization.BufferedDeserialization.TypeDiscriminators;
using YamlDotNet.Serialization.Converters;
using YamlDotNet.Serialization.EventEmitters;
using YamlDotNet.Serialization.NamingConventions;
using YamlDotNet.Serialization.NodeDeserializers;
using YamlDotNet.Serialization.NodeTypeResolvers;
using YamlDotNet.Serialization.ObjectFactories;
using YamlDotNet.Serialization.ObjectGraphTraversalStrategies;
using YamlDotNet.Serialization.ObjectGraphVisitors;
using YamlDotNet.Serialization.Schemas;
using YamlDotNet.Serialization.TypeInspectors;
using YamlDotNet.Serialization.TypeResolvers;
using YamlDotNet.Serialization.Utilities;
using YamlDotNet.Serialization.ValueDeserializers;

[assembly: AssemblyFileVersion("0.1.1")]
[assembly: Guid("4358610B-F3F4-4843-B7AF-98B7BC60DCDE")]
[assembly: ComVisible(false)]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCopyright("Copyright ©  2021")]
[assembly: AssemblyProduct("MonsterDB")]
[assembly: AssemblyCompany("RustyMods")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyTitle("MonsterDB")]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: CompilationRelaxations(8)]
[assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.1.1.0")]
[module: UnverifiableCode]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[<f6024122-3fbc-47fa-8a4c-3dbc1f9fe35a>Embedded]
	internal sealed class <f6024122-3fbc-47fa-8a4c-3dbc1f9fe35a>EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[<f6024122-3fbc-47fa-8a4c-3dbc1f9fe35a>Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	[CompilerGenerated]
	internal sealed class <391b7e1c-21ce-4cd7-b9cc-6b18bf5eb6e4>NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public <391b7e1c-21ce-4cd7-b9cc-6b18bf5eb6e4>NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public <391b7e1c-21ce-4cd7-b9cc-6b18bf5eb6e4>NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[<f6024122-3fbc-47fa-8a4c-3dbc1f9fe35a>Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class <280c4705-4a7b-4139-8a59-78254fb4951c>NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public <280c4705-4a7b-4139-8a59-78254fb4951c>NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
}
namespace MonsterDB
{
	[<280c4705-4a7b-4139-8a59-78254fb4951c>NullableContext(1)]
	[<391b7e1c-21ce-4cd7-b9cc-6b18bf5eb6e4>Nullable(0)]
	[BepInPlugin("RustyMods.MonsterDB", "MonsterDB", "0.1.1")]
	public class MonsterDBPlugin : BaseUnityPlugin
	{
		[<280c4705-4a7b-4139-8a59-78254fb4951c>NullableContext(0)]
		private enum Toggle
		{
			On = 1,
			Off = 0
		}

		[<280c4705-4a7b-4139-8a59-78254fb4951c>NullableContext(0)]
		private class ConfigurationManagerAttributes
		{
			[UsedImplicitly]
			public int? Order;

			[UsedImplicitly]
			public bool? Browsable;

			[<391b7e1c-21ce-4cd7-b9cc-6b18bf5eb6e4>Nullable(2)]
			[UsedImplicitly]
			public string Category;

			[<391b7e1c-21ce-4cd7-b9cc-6b18bf5eb6e4>Nullable(new byte[] { 2, 1 })]
			[UsedImplicitly]
			public Action<ConfigEntryBase> CustomDrawer;
		}

		internal const string ModName = "MonsterDB";

		internal const string ModVersion = "0.1.1";

		internal const string Author = "RustyMods";

		private const string ModGUID = "RustyMods.MonsterDB";

		private static readonly string ConfigFileName = "RustyMods.MonsterDB.cfg";

		private static readonly string ConfigFileFullPath;

		internal static string ConnectionError;

		private readonly Harmony _harmony = new Harmony("RustyMods.MonsterDB");

		public static readonly ManualLogSource MonsterDBLogger;

		public static readonly ConfigSync ConfigSync;

		public static GameObject m_root;

		public static MonsterDBPlugin m_plugin;

		private static ConfigEntry<Toggle> _serverConfigLocked;

		private static ConfigEntry<Toggle> _shareTextures;

		private static ConfigEntry<Toggle> _useRandomNames;

		private static ConfigEntry<Toggle> _autoUpdate;

		public static bool ShareTextures()
		{
			return _shareTextures.Value == Toggle.On;
		}

		public static bool UseNames()
		{
			return _useRandomNames.Value == Toggle.On;
		}

		public static bool AutoUpdate()
		{
			return _autoUpdate.Value == Toggle.On;
		}

		private void InitConfigs()
		{
			_serverConfigLocked = config("1 - General", "Lock Configuration", Toggle.On, "If on, the configuration is locked and can be changed by server admins only.");
			ConfigSync.AddLockingConfigEntry<Toggle>(_serverConfigLocked);
			_shareTextures = config("2 - Settings", "Server Sync Textures", Toggle.Off, "If on, clients can download textures from server, experimental");
			_useRandomNames = config("2 - Settings", "Use Viking Names", Toggle.Off, "If on, any creatures based on Human, will use random names");
			_autoUpdate = config("2 - Settings", "Auto Update", Toggle.On, "If on, any changes made to files will automatically update creature");
		}

		public void Awake()
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Expected O, but got Unknown
			m_plugin = this;
			m_root = new GameObject("root");
			Object.DontDestroyOnLoad((Object)(object)m_root);
			m_root.SetActive(false);
			InitConfigs();
			Tutorial.Write();
			SpawnMan.Setup();
			TextureManager.ReadLocalTextures();
			CreatureManager.Setup();
			Initialization.ReadLocalFiles();
			Assembly executingAssembly = Assembly.GetExecutingAssembly();
			_harmony.PatchAll(executingAssembly);
			SetupWatcher();
		}

		private void OnDestroy()
		{
			((BaseUnityPlugin)this).Config.Save();
		}

		private void SetupWatcher()
		{
			FileSystemWatcher fileSystemWatcher = new FileSystemWatcher(Paths.ConfigPath, ConfigFileName);
			fileSystemWatcher.Changed += ReadConfigValues;
			fileSystemWatcher.Created += ReadConfigValues;
			fileSystemWatcher.Renamed += ReadConfigValues;
			fileSystemWatcher.IncludeSubdirectories = true;
			fileSystemWatcher.SynchronizingObject = ThreadingHelper.SynchronizingObject;
			fileSystemWatcher.EnableRaisingEvents = true;
		}

		private void ReadConfigValues(object sender, FileSystemEventArgs e)
		{
			if (!File.Exists(ConfigFileFullPath))
			{
				return;
			}
			try
			{
				MonsterDBLogger.LogDebug((object)"ReadConfigValues called");
				((BaseUnityPlugin)this).Config.Reload();
			}
			catch
			{
				MonsterDBLogger.LogError((object)("There was an issue loading your " + ConfigFileName));
				MonsterDBLogger.LogError((object)"Please check your config entries for spelling and format!");
			}
		}

		private ConfigEntry<T> config<[<391b7e1c-21ce-4cd7-b9cc-6b18bf5eb6e4>Nullable(2)] T>(string group, string name, T value, ConfigDescription description, bool synchronizedSetting = true)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Expected O, but got Unknown
			ConfigDescription val = new ConfigDescription(description.Description + (synchronizedSetting ? " [Synced with Server]" : " [Not Synced with Server]"), description.AcceptableValues, description.Tags);
			ConfigEntry<T> val2 = ((BaseUnityPlugin)this).Config.Bind<T>(group, name, value, val);
			SyncedConfigEntry<T> syncedConfigEntry = ConfigSync.AddConfigEntry<T>(val2);
			syncedConfigEntry.SynchronizedConfig = synchronizedSetting;
			return val2;
		}

		private ConfigEntry<T> config<[<391b7e1c-21ce-4cd7-b9cc-6b18bf5eb6e4>Nullable(2)] T>(string group, string name, T value, string description, bool synchronizedSetting = true)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Expected O, but got Unknown
			return config(group, name, value, new ConfigDescription(description, (AcceptableValueBase)null, Array.Empty<object>()), synchronizedSetting);
		}

		static MonsterDBPlugin()
		{
			string configPath = Paths.ConfigPath;
			char directorySeparatorChar = Path.DirectorySeparatorChar;
			ConfigFileFullPath = configPath + directorySeparatorChar + ConfigFileName;
			ConnectionError = "";
			MonsterDBLogger = Logger.CreateLogSource("MonsterDB");
			ConfigSync = new ConfigSync("RustyMods.MonsterDB")
			{
				DisplayName = "MonsterDB",
				CurrentVersion = "0.1.1",
				MinimumRequiredVersion = "0.1.1"
			};
			m_root = null;
			m_plugin = null;
			_serverConfigLocked = null;
			_shareTextures = null;
			_useRandomNames = null;
			_autoUpdate = null;
		}
	}
	[HarmonyPatch(typeof(ZNet), "OnNewConnection")]
	public static class RegisterAndCheckVersion
	{
		[<280c4705-4a7b-4139-8a59-78254fb4951c>NullableContext(1)]
		private static void Prefix(ZNetPeer peer, ref ZNet __instance)
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Expected O, but got Unknown
			MonsterDBPlugin.MonsterDBLogger.LogDebug((object)"Registering version RPC handler");
			peer.m_rpc.Register<ZPackage>("MonsterDB_VersionCheck", (Action<ZRpc, ZPackage>)RpcHandlers.RPC_MonsterDB_Version);
			MonsterDBPlugin.MonsterDBLogger.LogInfo((object)"Invoking version check");
			ZPackage val = new ZPackage();
			val.Write("0.1.1");
			peer.m_rpc.Invoke("MonsterDB_VersionCheck", new object[1] { val });
		}
	}
	[<391b7e1c-21ce-4cd7-b9cc-6b18bf5eb6e4>Nullable(0)]
	[<280c4705-4a7b-4139-8a59-78254fb4951c>NullableContext(1)]
	[HarmonyPatch(typeof(ZNet), "RPC_PeerInfo")]
	public static class VerifyClient
	{
		private static bool Prefix(ZRpc rpc, ZPackage pkg, ref ZNet __instance)
		{
			if (!__instance.IsServer() || RpcHandlers.ValidatedPeers.Contains(rpc))
			{
				return true;
			}
			MonsterDBPlugin.MonsterDBLogger.LogWarning((object)("Peer (" + rpc.m_socket.GetHostName() + ") never sent version or couldn't due to previous disconnect, disconnecting"));
			rpc.Invoke("Error", new object[1] { 3 });
			return false;
		}

		private static void Postfix(ZNet __instance)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Expected O, but got Unknown
			ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.instance.GetServerPeerID(), "MonsterDBRequestAdminSync", new object[1] { (object)new ZPackage() });
		}
	}
	[HarmonyPatch(typeof(FejdStartup), "ShowConnectError")]
	public class ShowConnectionError
	{
		[<280c4705-4a7b-4139-8a59-78254fb4951c>NullableContext(1)]
		private static void Postfix(FejdStartup __instance)
		{
			if (__instance.m_connectionFailedPanel.activeSelf)
			{
				__instance.m_connectionFailedError.fontSizeMax = 25f;
				__instance.m_connectionFailedError.fontSizeMin = 15f;
				TMP_Text connectionFailedError = __instance.m_connectionFailedError;
				connectionFailedError.text = connectionFailedError.text + "\n" + MonsterDBPlugin.ConnectionError;
			}
		}
	}
	[HarmonyPatch(typeof(ZNet), "Disconnect")]
	public static class RemoveDisconnectedPeerFromVerified
	{
		[<280c4705-4a7b-4139-8a59-78254fb4951c>NullableContext(1)]
		private static void Prefix(ZNetPeer peer, ref ZNet __instance)
		{
			if (__instance.IsServer())
			{
				MonsterDBPlugin.MonsterDBLogger.LogInfo((object)("Peer (" + peer.m_rpc.m_socket.GetHostName() + ") disconnected, removing from validated list"));
				RpcHandlers.ValidatedPeers.Remove(peer.m_rpc);
			}
		}
	}
	[<280c4705-4a7b-4139-8a59-78254fb4951c>NullableContext(1)]
	[<391b7e1c-21ce-4cd7-b9cc-6b18bf5eb6e4>Nullable(0)]
	public static class RpcHandlers
	{
		public static readonly List<ZRpc> ValidatedPeers = new List<ZRpc>();

		public static void RPC_MonsterDB_Version(ZRpc rpc, ZPackage pkg)
		{
			string text = pkg.ReadString();
			MonsterDBPlugin.MonsterDBLogger.LogInfo((object)("Version check, local: 0.1.1,  remote: " + text));
			if (text != "0.1.1")
			{
				MonsterDBPlugin.ConnectionError = "MonsterDB Installed: 0.1.1\n Needed: " + text;
				if (ZNet.instance.IsServer())
				{
					MonsterDBPlugin.MonsterDBLogger.LogWarning((object)("Peer (" + rpc.m_socket.GetHostName() + ") has incompatible version, disconnecting..."));
					rpc.Invoke("Error", new object[1] { 3 });
				}
			}
			else if (!ZNet.instance.IsServer())
			{
				MonsterDBPlugin.MonsterDBLogger.LogInfo((object)"Received same version from server!");
			}
			else
			{
				MonsterDBPlugin.MonsterDBLogger.LogInfo((object)("Adding peer (" + rpc.m_socket.GetHostName() + ") to validated list"));
				ValidatedPeers.Add(rpc);
			}
		}

		public static string ComputeHashForMod()
		{
			using SHA256 sHA = SHA256.Create();
			byte[] array = sHA.ComputeHash(File.ReadAllBytes(Assembly.GetExecutingAssembly().Location));
			StringBuilder stringBuilder = new StringBuilder();
			byte[] array2 = array;
			foreach (byte b in array2)
			{
				stringBuilder.Append(b.ToString("X2"));
			}
			return stringBuilder.ToString();
		}
	}
}
namespace MonsterDB.Solution
{
	[<280c4705-4a7b-4139-8a59-78254fb4951c>NullableContext(1)]
	[<391b7e1c-21ce-4cd7-b9cc-6b18bf5eb6e4>Nullable(0)]
	public static class Commands
	{
		[<280c4705-4a7b-4139-8a59-78254fb4951c>NullableContext(0)]
		[HarmonyPatch(typeof(Terminal), "updateSearch")]
		private static class Terminal_UpdateSearch_Patch
		{
			[<280c4705-4a7b-4139-8a59-78254fb4951c>NullableContext(1)]
			private static bool Prefix(Terminal __instance, string word)
			{
				if (!Object.op_Implicit((Object)(object)ZNetScene.instance))
				{
					return true;
				}
				if ((Object)(object)__instance.m_search == (Object)null)
				{
					return true;
				}
				string[] array = ((TMP_InputField)__instance.m_input).text.Split(new char[1] { ' ' });
				if (array.Length < 3)
				{
					return true;
				}
				if (array[0] != "monsterdb")
				{
					return true;
				}
				HandleSearch(__instance, word, array);
				return false;
			}
		}

		[HarmonyPatch(typeof(Terminal), "Awake")]
		[<280c4705-4a7b-4139-8a59-78254fb4951c>NullableContext(0)]
		private static class Terminal_Awake_Patch
		{
			[Serializable]
			[CompilerGenerated]
			private sealed class <>c
			{
				public static readonly <>c <>9 = new <>c();

				[<391b7e1c-21ce-4cd7-b9cc-6b18bf5eb6e4>Nullable(new byte[] { 0, 1 })]
				public static Action<ConsoleEventArgs> <>9__0_0;

				[<391b7e1c-21ce-4cd7-b9cc-6b18bf5eb6e4>Nullable(new byte[] { 0, 1 })]
				public static Action<ConsoleEventArgs> <>9__0_1;

				[<391b7e1c-21ce-4cd7-b9cc-6b18bf5eb6e4>Nullable(new byte[] { 0, 1 })]
				public static Action<ConsoleEventArgs> <>9__0_2;

				[<391b7e1c-21ce-4cd7-b9cc-6b18bf5eb6e4>Nullable(new byte[] { 0, 1 })]
				public static Action<ConsoleEventArgs> <>9__0_3;

				[<391b7e1c-21ce-4cd7-b9cc-6b18bf5eb6e4>Nullable(new byte[] { 0, 1 })]
				public static Action<ConsoleEventArgs> <>9__0_4;

				[<391b7e1c-21ce-4cd7-b9cc-6b18bf5eb6e4>Nullable(new byte[] { 0, 1 })]
				public static Action<ConsoleEventArgs> <>9__0_5;

				[<391b7e1c-21ce-4cd7-b9cc-6b18bf5eb6e4>Nullable(new byte[] { 0, 1 })]
				public static Action<ConsoleEventArgs> <>9__0_6;

				[<391b7e1c-21ce-4cd7-b9cc-6b18bf5eb6e4>Nullable(new byte[] { 0, 1 })]
				public static Action<ConsoleEventArgs> <>9__0_7;

				[<391b7e1c-21ce-4cd7-b9cc-6b18bf5eb6e4>Nullable(new byte[] { 0, 1 })]
				public static Action<ConsoleEventArgs> <>9__0_8;

				[<391b7e1c-21ce-4cd7-b9cc-6b18bf5eb6e4>Nullable(new byte[] { 0, 1 })]
				public static Action<ConsoleEventArgs> <>9__0_9;

				[<391b7e1c-21ce-4cd7-b9cc-6b18bf5eb6e4>Nullable(new byte[] { 0, 1 })]
				public static Action<ConsoleEventArgs> <>9__0_10;

				[<391b7e1c-21ce-4cd7-b9cc-6b18bf5eb6e4>Nullable(new byte[] { 0, 1 })]
				public static Action<ConsoleEventArgs> <>9__0_11;

				public static ConsoleEventFailable <>9__0_12;

				[<280c4705-4a7b-4139-8a59-78254fb4951c>NullableContext(1)]
				internal void <Postfix>b__0_0(ConsoleEventArgs _)
				{
					foreach (CommandInfo value in m_commands.Values)
					{
						if (value.m_show)
						{
							MonsterDBPlugin.MonsterDBLogger.LogInfo((object)(value.m_input + " - " + value.m_description));
						}
					}
				}

				[<280c4705-4a7b-4139-8a59-78254fb4951c>NullableContext(1)]
				internal void <Postfix>b__0_1(ConsoleEventArgs _)
				{
					Initialization.RemoveAllClones();
					Initialization.CloneAll();
					Initialization.UpdateAll();
				}

				[<280c4705-4a7b-4139-8a59-78254fb4951c>NullableContext(1)]
				internal void <Postfix>b__0_2(ConsoleEventArgs _)
				{
					CreatureManager.Import();
					Initialization.RemoveAllClones();
					Initialization.CloneAll();
					Initialization.UpdateAll();
				}

				[<280c4705-4a7b-4139-8a59-78254fb4951c>NullableContext(1)]
				internal void <Postfix>b__0_3(ConsoleEventArgs _)
				{
					if (!Object.op_Implicit((Object)(object)ZNetScene.instance))
					{
						return;
					}
					foreach (GameObject prefab in ZNetScene.instance.m_prefabs)
					{
						if (Object.op_Implicit((Object)(object)prefab.GetComponent<Character>()))
						{
							Write(prefab, writeAll: true);
						}
					}
				}

				[<280c4705-4a7b-4139-8a59-78254fb4951c>NullableContext(1)]
				internal void <Postfix>b__0_4(ConsoleEventArgs args)
				{
					if (args.Length >= 3 && Object.op_Implicit((Object)(object)ZNetScene.instance))
					{
						string text = args[2];
						GameObject val = DataBase.TryGetGameObject(text);
						if ((Object)(object)val == (Object)null)
						{
							MonsterDBPlugin.MonsterDBLogger.LogInfo((object)("Failed to find prefab: " + text));
						}
						else
						{
							Write(val);
						}
					}
				}

				[<280c4705-4a7b-4139-8a59-78254fb4951c>NullableContext(1)]
				internal void <Postfix>b__0_5(ConsoleEventArgs args)
				{
					if (args.Length >= 3 && Object.op_Implicit((Object)(object)ZNetScene.instance))
					{
						string text = args[2];
						GameObject val = DataBase.TryGetGameObject(text);
						if ((Object)(object)val == (Object)null)
						{
							MonsterDBPlugin.MonsterDBLogger.LogInfo((object)("Failed to find prefab: " + text));
							return;
						}
						CreatureManager.Read(((Object)val).name, CreatureManager.IsClone(val));
						CreatureManager.Update(val);
						MonsterDBPlugin.MonsterDBLogger.LogInfo((object)("Updated " + ((Object)val).name));
					}
				}

				[<280c4705-4a7b-4139-8a59-78254fb4951c>NullableContext(1)]
				internal void <Postfix>b__0_6(ConsoleEventArgs args)
				{
					if (args.Length >= 4 && Object.op_Implicit((Object)(object)ZNetScene.instance))
					{
						string text = args[2];
						GameObject val = DataBase.TryGetGameObject(text);
						if ((Object)(object)val == (Object)null)
						{
							MonsterDBPlugin.MonsterDBLogger.LogInfo((object)("Failed to find prefab: " + text));
							return;
						}
						string name = args[3];
						CreatureManager.Clone(val, name);
					}
				}

				[<280c4705-4a7b-4139-8a59-78254fb4951c>NullableContext(1)]
				internal void <Postfix>b__0_7(ConsoleEventArgs args)
				{
					if (args.Length >= 3 && Object.op_Implicit((Object)(object)ZNetScene.instance))
					{
						string text = args[2];
						GameObject val = DataBase.TryGetGameObject(text);
						if ((Object)(object)val == (Object)null)
						{
							MonsterDBPlugin.MonsterDBLogger.LogInfo((object)("Failed to find prefab: " + text));
						}
						else
						{
							CreatureManager.Reset(val);
						}
					}
				}

				[<280c4705-4a7b-4139-8a59-78254fb4951c>NullableContext(1)]
				internal void <Postfix>b__0_8(ConsoleEventArgs args)
				{
					if (args.Length >= 3 && Object.op_Implicit((Object)(object)ZNetScene.instance))
					{
						string text = args[2];
						GameObject val = DataBase.TryGetGameObject(text);
						if ((Object)(object)val == (Object)null)
						{
							MonsterDBPlugin.MonsterDBLogger.LogInfo((object)("Failed to find prefab: " + text));
						}
						else if (Object.op_Implicit((Object)(object)val.GetComponent<ItemDrop>()))
						{
							ItemDataMethods.Write(val);
						}
					}
				}

				[<280c4705-4a7b-4139-8a59-78254fb4951c>NullableContext(1)]
				internal void <Postfix>b__0_9(ConsoleEventArgs args)
				{
					if (args.Length >= 4 && Object.op_Implicit((Object)(object)ZNetScene.instance))
					{
						string text = args[2];
						GameObject val = DataBase.TryGetGameObject(text);
						if ((Object)(object)val == (Object)null)
						{
							MonsterDBPlugin.MonsterDBLogger.LogInfo((object)("Failed to find prefab: " + text));
							return;
						}
						string name = args[3];
						ItemDataMethods.Clone(val, name);
					}
				}

				[<280c4705-4a7b-4139-8a59-78254fb4951c>NullableContext(1)]
				internal void <Postfix>b__0_10(ConsoleEventArgs args)
				{
					if (args.Length >= 3 && Object.op_Implicit((Object)(object)ZNetScene.instance))
					{
						string text = args[2];
						GameObject val = DataBase.TryGetGameObject(text);
						if ((Object)(object)val == (Object)null)
						{
							MonsterDBPlugin.MonsterDBLogger.LogInfo((object)("Failed to find prefab: " + text));
						}
						else
						{
							MonsterDBPlugin.MonsterDBLogger.LogInfo((object)(SpawnMan.Write(val) ? "Wrote spawn data to disk" : "Failed to find spawn data"));
						}
					}
				}

				[<280c4705-4a7b-4139-8a59-78254fb4951c>NullableContext(1)]
				internal void <Postfix>b__0_11(ConsoleEventArgs args)
				{
					if (args.Length >= 3 && Object.op_Implicit((Object)(object)ZNetScene.instance))
					{
						string text = args[2];
						GameObject val = DataBase.TryGetGameObject(text);
						if ((Object)(object)val == (Object)null)
						{
							MonsterDBPlugin.MonsterDBLogger.LogInfo((object)("Failed to find prefab: " + text));
						}
						else
						{
							CreatureManager.Export(text);
						}
					}
				}

				internal object <Postfix>b__0_12(ConsoleEventArgs args)
				{
					if (args.Length < 2)
					{
						return false;
					}
					if (!m_commands.TryGetValue(args[1], out var value))
					{
						return false;
					}
					value.m_command(args);
					return true;
				}
			}

			private static void Postfix()
			{
				//IL_0287: Unknown result type (might be due to invalid IL or missing references)
				//IL_0294: Expected O, but got Unknown
				//IL_028f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0296: Expected O, but got Unknown
				//IL_0267: Unknown result type (might be due to invalid IL or missing references)
				//IL_026c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0272: Expected O, but got Unknown
				CommandInfo commandInfo = new CommandInfo("help", "Use to list out MonsterDB commands", [<280c4705-4a7b-4139-8a59-78254fb4951c>NullableContext(1)] (ConsoleEventArgs _) =>
				{
					foreach (CommandInfo value2 in m_commands.Values)
					{
						if (value2.m_show)
						{
							MonsterDBPlugin.MonsterDBLogger.LogInfo((object)(value2.m_input + " - " + value2.m_description));
						}
					}
				});
				CommandInfo commandInfo2 = new CommandInfo("reload", "Reloads all MonsterDB files", [<280c4705-4a7b-4139-8a59-78254fb4951c>NullableContext(1)] (ConsoleEventArgs _) =>
				{
					Initialization.RemoveAllClones();
					Initialization.CloneAll();
					Initialization.UpdateAll();
				});
				CommandInfo commandInfo3 = new CommandInfo("import", "Imports all creature files from Import folder, and reloads data", [<280c4705-4a7b-4139-8a59-78254fb4951c>NullableContext(1)] (ConsoleEventArgs _) =>
				{
					CreatureManager.Import();
					Initialization.RemoveAllClones();
					Initialization.CloneAll();
					Initialization.UpdateAll();
				});
				CommandInfo commandInfo4 = new CommandInfo("write_all", "Writes all creatures data to disk", [<280c4705-4a7b-4139-8a59-78254fb4951c>NullableContext(1)] (ConsoleEventArgs _) =>
				{
					if (!Object.op_Implicit((Object)(object)ZNetScene.instance))
					{
						return;
					}
					foreach (GameObject prefab in ZNetScene.instance.m_prefabs)
					{
						if (Object.op_Implicit((Object)(object)prefab.GetComponent<Character>()))
						{
							Write(prefab, writeAll: true);
						}
					}
				});
				CommandInfo commandInfo5 = new CommandInfo("write", "[prefabName] Writes creature data to disk", [<280c4705-4a7b-4139-8a59-78254fb4951c>NullableContext(1)] (ConsoleEventArgs args) =>
				{
					if (args.Length >= 3 && Object.op_Implicit((Object)(object)ZNetScene.instance))
					{
						string text8 = args[2];
						GameObject val10 = DataBase.TryGetGameObject(text8);
						if ((Object)(object)val10 == (Object)null)
						{
							MonsterDBPlugin.MonsterDBLogger.LogInfo((object)("Failed to find prefab: " + text8));
						}
						else
						{
							Write(val10);
						}
					}
				});
				CommandInfo commandInfo6 = new CommandInfo("update", "[prefabName] Reads files and updates creature", [<280c4705-4a7b-4139-8a59-78254fb4951c>NullableContext(1)] (ConsoleEventArgs args) =>
				{
					if (args.Length >= 3 && Object.op_Implicit((Object)(object)ZNetScene.instance))
					{
						string text7 = args[2];
						GameObject val9 = DataBase.TryGetGameObject(text7);
						if ((Object)(object)val9 == (Object)null)
						{
							MonsterDBPlugin.MonsterDBLogger.LogInfo((object)("Failed to find prefab: " + text7));
						}
						else
						{
							CreatureManager.Read(((Object)val9).name, CreatureManager.IsClone(val9));
							CreatureManager.Update(val9);
							MonsterDBPlugin.MonsterDBLogger.LogInfo((object)("Updated " + ((Object)val9).name));
						}
					}
				});
				CommandInfo commandInfo7 = new CommandInfo("clone", "[prefabName] [cloneName] Clones creature, and saves to disk", [<280c4705-4a7b-4139-8a59-78254fb4951c>NullableContext(1)] (ConsoleEventArgs args) =>
				{
					if (args.Length >= 4 && Object.op_Implicit((Object)(object)ZNetScene.instance))
					{
						string text6 = args[2];
						GameObject val8 = DataBase.TryGetGameObject(text6);
						if ((Object)(object)val8 == (Object)null)
						{
							MonsterDBPlugin.MonsterDBLogger.LogInfo((object)("Failed to find prefab: " + text6));
						}
						else
						{
							string name2 = args[3];
							CreatureManager.Clone(val8, name2);
						}
					}
				});
				CommandInfo commandInfo8 = new CommandInfo("reset", "[prefabName] Resets creature data to original state", [<280c4705-4a7b-4139-8a59-78254fb4951c>NullableContext(1)] (ConsoleEventArgs args) =>
				{
					if (args.Length >= 3 && Object.op_Implicit((Object)(object)ZNetScene.instance))
					{
						string text5 = args[2];
						GameObject val7 = DataBase.TryGetGameObject(text5);
						if ((Object)(object)val7 == (Object)null)
						{
							MonsterDBPlugin.MonsterDBLogger.LogInfo((object)("Failed to find prefab: " + text5));
						}
						else
						{
							CreatureManager.Reset(val7);
						}
					}
				});
				CommandInfo commandInfo9 = new CommandInfo("write_item", "[prefabName] Saves itemData to file for reference", [<280c4705-4a7b-4139-8a59-78254fb4951c>NullableContext(1)] (ConsoleEventArgs args) =>
				{
					if (args.Length >= 3 && Object.op_Implicit((Object)(object)ZNetScene.instance))
					{
						string text4 = args[2];
						GameObject val6 = DataBase.TryGetGameObject(text4);
						if ((Object)(object)val6 == (Object)null)
						{
							MonsterDBPlugin.MonsterDBLogger.LogInfo((object)("Failed to find prefab: " + text4));
						}
						else if (Object.op_Implicit((Object)(object)val6.GetComponent<ItemDrop>()))
						{
							ItemDataMethods.Write(val6);
						}
					}
				});
				CommandInfo commandInfo10 = new CommandInfo("clone_item", "[prefabName] [cloneName] Clones item to use as a new attack for creatures", [<280c4705-4a7b-4139-8a59-78254fb4951c>NullableContext(1)] (ConsoleEventArgs args) =>
				{
					if (args.Length >= 4 && Object.op_Implicit((Object)(object)ZNetScene.instance))
					{
						string text3 = args[2];
						GameObject val5 = DataBase.TryGetGameObject(text3);
						if ((Object)(object)val5 == (Object)null)
						{
							MonsterDBPlugin.MonsterDBLogger.LogInfo((object)("Failed to find prefab: " + text3));
						}
						else
						{
							string name = args[3];
							ItemDataMethods.Clone(val5, name);
						}
					}
				});
				CommandInfo commandInfo11 = new CommandInfo("write_spawn", "[prefabName] Writes to disk spawn data, of current spawn system", [<280c4705-4a7b-4139-8a59-78254fb4951c>NullableContext(1)] (ConsoleEventArgs args) =>
				{
					if (args.Length >= 3 && Object.op_Implicit((Object)(object)ZNetScene.instance))
					{
						string text2 = args[2];
						GameObject val4 = DataBase.TryGetGameObject(text2);
						if ((Object)(object)val4 == (Object)null)
						{
							MonsterDBPlugin.MonsterDBLogger.LogInfo((object)("Failed to find prefab: " + text2));
						}
						else
						{
							MonsterDBPlugin.MonsterDBLogger.LogInfo((object)(SpawnMan.Write(val4) ? "Wrote spawn data to disk" : "Failed to find spawn data"));
						}
					}
				});
				CommandInfo commandInfo12 = new CommandInfo("export", "[prefabName] Writes creature data to a single YML document to share", [<280c4705-4a7b-4139-8a59-78254fb4951c>NullableContext(1)] (ConsoleEventArgs args) =>
				{
					if (args.Length >= 3 && Object.op_Implicit((Object)(object)ZNetScene.instance))
					{
						string text = args[2];
						GameObject val3 = DataBase.TryGetGameObject(text);
						if ((Object)(object)val3 == (Object)null)
						{
							MonsterDBPlugin.MonsterDBLogger.LogInfo((object)("Failed to find prefab: " + text));
						}
						else
						{
							CreatureManager.Export(text);
						}
					}
				});
				object obj = <>c.<>9__0_12;
				if (obj == null)
				{
					ConsoleEventFailable val = delegate(ConsoleEventArgs args)
					{
						if (args.Length < 2)
						{
							return false;
						}
						if (!m_commands.TryGetValue(args[1], out var value))
						{
							return false;
						}
						value.m_command(args);
						return true;
					};
					<>c.<>9__0_12 = val;
					obj = (object)val;
				}
				ConsoleCommand val2 = new ConsoleCommand("monsterdb", "use help to list out commands", (ConsoleEventFailable)obj, false, false, false, false, false, new ConsoleOptionsFetcher(Enumerable.ToList), false, false, true);
			}
		}

		[<391b7e1c-21ce-4cd7-b9cc-6b18bf5eb6e4>Nullable(0)]
		private class CommandInfo
		{
			public readonly string m_input;

			public readonly string m_description;

			public readonly bool m_show;

			public readonly Action<ConsoleEventArgs> m_command;

			public CommandInfo(string input, string description, Action<ConsoleEventArgs> command, bool show = true)
			{
				m_input = input;
				m_description = description;
				m_command = command;
				m_show = show;
				m_commands[m_input] = this;
			}
		}

		private static readonly Dictionary<string, CommandInfo> m_commands = new Dictionary<string, CommandInfo>();

		private static List<string> MonsterNames = new List<string>();

		private static List<string> ItemNames = new List<string>();

		private static void HandleSearch(Terminal __instance, string word, string[] strArray)
		{
			bool flag;
			switch (word)
			{
			case "reload":
			case "import":
			case "write_spawn":
			case "help":
				flag = true;
				break;
			default:
				flag = false;
				break;
			}
			if (flag)
			{
				TMP_Text search = __instance.m_search;
				if (1 == 0)
				{
				}
				string text = word switch
				{
					"reload" => "<color=red>Reloads all MonsterDB files</color>", 
					"import" => "<color=yellow>Imports all creature files from Import folder, and reload data</color>", 
					"write_spawn" => "<color=yellow>Tries to export spawn system data of creature</color>, <color=red>location dependant</color>", 
					"help" => "<color=white>Lists out MonsterDB commands and descriptions</color>", 
					_ => "", 
				};
				if (1 == 0)
				{
				}
				search.text = text;
				return;
			}
			if (1 == 0)
			{
			}
			List<string> list;
			switch (word)
			{
			case "write":
			case "clone":
				list = GetMonsterList();
				break;
			case "update":
			case "reset":
				list = GetUpdateList();
				break;
			case "write_item":
			case "clone_item":
				list = GetItemList();
				break;
			default:
				list = new List<string>();
				break;
			}
			if (1 == 0)
			{
			}
			List<string> list2 = list;
			list2.Sort();
			string currentSearch = strArray[2];
			List<string> list3;
			if (!Utility.IsNullOrWhiteSpace(currentSearch))
			{
				int num = list2.IndexOf(currentSearch);
				list3 = ((num != -1) ? list2.GetRange(num, list2.Count - num) : list2);
				list3 = list3.FindAll((string x) => x.ToLower().Contains(currentSearch.ToLower()));
			}
			else
			{
				list3 = list2;
			}
			__instance.m_lastSearch.Clear();
			__instance.m_lastSearch.AddRange(list3);
			__instance.m_lastSearch.Remove(word);
			__instance.m_search.text = "";
			int num2 = 10;
			int num3 = Math.Min(__instance.m_lastSearch.Count, num2);
			for (int i = 0; i < num3; i++)
			{
				string text2 = __instance.m_lastSearch[i];
				int num4 = text2.ToLower().IndexOf(word.ToLower(), StringComparison.Ordinal);
				TMP_Text search2 = __instance.m_search;
				search2.text = search2.text + __instance.safeSubstring(text2, 0, num4) + "  ";
			}
			if (__instance.m_lastSearch.Count > num2)
			{
				int num5 = __instance.m_lastSearch.Count - num2;
				TMP_Text search3 = __instance.m_search;
				search3.text += $"... {num5} more.";
			}
		}

		private static void Write(GameObject prefab, bool writeAll = false)
		{
			if (!Object.op_Implicit((Object)(object)prefab.GetComponent<Player>()))
			{
				string folderPath;
				if (CreatureManager.IsClone(prefab))
				{
					MonsterDBPlugin.MonsterDBLogger.LogInfo((object)"Creature is a MonsterDB clone, will not write to disk");
				}
				else if (CreatureManager.Write(prefab, out folderPath, clone: false, "", writeAll))
				{
					MonsterDBPlugin.MonsterDBLogger.LogInfo((object)("Saved " + ((Object)prefab).name + " at:"));
					MonsterDBPlugin.MonsterDBLogger.LogInfo((object)folderPath);
				}
			}
		}

		private static List<string> GetMonsterList()
		{
			if (MonsterNames.Count > 0)
			{
				return MonsterNames;
			}
			List<string> list = new List<string>();
			foreach (GameObject prefab in ZNetScene.instance.m_prefabs)
			{
				if (!CreatureManager.IsClone(prefab) && Object.op_Implicit((Object)(object)prefab.GetComponent<Character>()))
				{
					list.Add(((Object)prefab).name);
				}
			}
			MonsterNames = list;
			return list;
		}

		private static List<string> GetItemList()
		{
			if (ItemNames.Count > 0)
			{
				return ItemNames;
			}
			List<string> list = new List<string>();
			foreach (GameObject value in DataBase.m_allObjects.Values)
			{
				if (!((Object)(object)value == (Object)null) && !ItemDataMethods.IsClone(value) && Object.op_Implicit((Object)(object)value.GetComponent<ItemDrop>()))
				{
					list.Add(((Object)value).name);
				}
			}
			ItemNames = list;
			return list;
		}

		private static List<string> GetUpdateList()
		{
			return CreatureManager.m_data.Keys.ToList();
		}
	}
	[Serializable]
	[<280c4705-4a7b-4139-8a59-78254fb4951c>NullableContext(1)]
	[<391b7e1c-21ce-4cd7-b9cc-6b18bf5eb6e4>Nullable(0)]
	public class CharacterData
	{
		public string ClonedFrom = "";

		public string PrefabName = "";

		public string Name = "";

		public string Group = "";

		public string Faction = "";

		public bool Boss;

		public bool DoNotHideBossHUD;

		public string BossEvent = "";

		public string DefeatSetGlobalKey = "";

		public bool AISkipTarget;

		public float CrouchSpeed;

		public float WalkSpeed;

		public float Speed;

		public float TurnSpeed;

		public float RunSpeed;

		public float RunTurnSpeed;

		public float FlySlowSpeed;

		public float FlyFastSpeed;

		public float FlyTurnSpeed;

		public float Acceleration;

		public float JumpForce;

		public float JumpForceForward;

		public float JumpForceTiredFactor;

		public float AirControl;

		public bool CanSwim;

		public float SwimDepth;

		public float SwimSpeed;

		public float SwimTurnSpeed;

		public float SwimAcceleration;

		public string GroundTilt = "";

		public float GroundTiltSpeed;

		public bool Flying;

		public float JumpStaminaUsage;

		public bool DisableWhileSleeping;

		public bool TolerateWater;

		public bool TolerateFire;

		public bool TolerateSmoke;

		public bool TolerateTar;

		public float Health;

		public string BluntResistance = "Normal";

		public string SlashResistance = "Normal";

		public string PierceResistance = "Normal";

		public string ChopResistance = "Normal";

		public string PickaxeResistance = "Normal";

		public string FireResistance = "Normal";

		public string FrostResistance = "Normal";

		public string LightningResistance = "Normal";

		public string PoisonResistance = "Normal";

		public string SpiritResistance = "Normal";

		public bool StaggerWhenBlocked;

		public float StaggerDamageFactor;
	}
	[Serializable]
	[<391b7e1c-21ce-4cd7-b9cc-6b18bf5eb6e4>Nullable(0)]
	[<280c4705-4a7b-4139-8a59-78254fb4951c>NullableContext(1)]
	public class EffectInfo
	{
		public string PrefabName = "";

		public bool Enabled;

		public int Variant = -1;

		public bool Attach;

		public bool Follow;

		public bool InheritParentRotation;

		public bool InheritParentScale;

		public bool MultiplyParentVisualScale;

		public bool RandomRotation;

		public bool Scale;

		public string ChildTransform = "";
	}
	[Serializable]
	[<280c4705-4a7b-4139-8a59-78254fb4951c>NullableContext(1)]
	[<391b7e1c-21ce-4cd7-b9cc-6b18bf5eb6e4>Nullable(0)]
	public class AttackData
	{
		public string OriginalPrefab = "";

		public string Name = "";

		public string AnimationState = "";

		public int ToolTier;

		public float Damage;

		public float Blunt;

		public float Slash;

		public float Pierce;

		public float Chop;

		public float Pickaxe;

		public float Fire;

		public float Frost;

		public float Lightning;

		public float Poison;

		public float Spirit;

		public float AttackForce;

		public bool Dodgeable;

		public bool Blockable;

		public string SpawnOnHit = "";

		public string SpawnOnHitTerrain = "";

		public string AttackStatusEffect = "";

		public float AttackStatusEffectChance;

		public string AttackType = "";

		public string AttackAnimation = "";

		public bool HitTerrain;

		public bool HitFriendly;

		public float DamageMultiplier;

		public float DamageMultiplierPerMissingHP;

		public float DamageMultiplierByTotalHealthMissing;

		public float ForceMultiplier;

		public float StaggerMultiplier;

		public float RecoilPushback;

		public int SelfDamage;

		public string AttackOriginJoint = "";

		public float AttackRange;

		public float AttackHeight;

		public float AttackOffset;

		public string SpawnOnTrigger = "";

		public bool ToggleFlying;

		public bool Attach;

		public float AttackAngle;

		public float AttackRayWidth;

		public float MaxYAngle;

		public bool LowerDamagePerHit;

		public bool HitThroughWalls;

		public float AttackRangeMinimum;

		public float AttackInterval;

		public float AttackMaxAngle;

		public string Projectile = "";
	}
	[Serializable]
	public class RandomItemData
	{
		[<391b7e1c-21ce-4cd7-b9cc-6b18bf5eb6e4>Nullable(1)]
		public string PrefabName = "";

		public float Chance;
	}
	[Serializable]
	[<391b7e1c-21ce-4cd7-b9cc-6b18bf5eb6e4>Nullable(0)]
	[<280c4705-4a7b-4139-8a59-78254fb4951c>NullableContext(1)]
	public class ProjectileData
	{
		public string Name = "";

		public float Damage;

		public float Blunt;

		public float Slash;

		public float Pierce;

		public float Chop;

		public float Pickaxe;

		public float Fire;

		public float Frost;

		public float Lightning;

		public float Poison;

		public float Spirit;

		public float AOE;

		public bool Dodgeable;

		public bool Blockable;

		public float AttackForce;

		public float BackstabBonus;

		public string StatusEffect = "";

		public float HealthReturn;

		public bool CanHitWater;

		public float Duration;

		public float Gravity;

		public float Drag;

		public float RayRadius;

		public bool StayAfterHitStatic;

		public bool StayAfterHitDynamic;

		public float StayDuration;

		public bool Bounce;

		public bool BounceOnWater;

		public float BouncePower;

		public float BounceRoughness;

		public int MaxBounces;

		public float MinBounceVelocity;

		public bool RespawnItemOnHit;

		public bool SpawnOnDuration;

		public string SpawnOnHit = "";

		public float SpawnOnHitChance;

		public int SpawnCount;

		public List<string> RandomSpawnOnHit = new List<string>();

		public int RandomSpawnOnHitCount;

		public bool RandomSpawnSkipLava;

		public bool StaticHitOnly;

		public bool GroundHitOnly;

		public bool SpawnRandomRotation;
	}
	[Serializable]
	[<280c4705-4a7b-4139-8a59-78254fb4951c>NullableContext(1)]
	[<391b7e1c-21ce-4cd7-b9cc-6b18bf5eb6e4>Nullable(0)]
	public class MonsterAIData
	{
		public float ViewRange;

		public float ViewAngle;

		public float HearRange;

		public bool MistVision;

		public float IdleSoundInterval;

		public float IdleSoundChance;

		public string PathAgentType = "";

		public float MoveMinAngle;

		public bool SmoothMovement;

		public bool SerpentMovement;

		public float SerpentTurnRadius;

		public float JumpInterval;

		public float RandomCircleInterval;

		public float RandomMoveInterval;

		public float RandomMoveRange;

		public bool RandomFly;

		public float ChanceToTakeOff;

		public float ChanceToLand;

		public float GroundDuration;

		public float AirDuration;

		public float MaxLandAltitude;

		public float TakeoffTime;

		public float FlyAltitudeMin;

		public float FlyAltitudeMax;

		public float FlyAbsMinAltitude;

		public bool AvoidFire;

		public bool AfraidOfFire;

		public bool AvoidWater;

		public bool AvoidLava;

		public bool SkipLavaTargets;

		public bool Aggravatable;

		public bool PassiveAggressive;

		public string SpawnMessage = "";

		public string DeathMessage = "";

		public string AlertedMessage = "";

		public float FleeRange;

		public float FleeAngle;

		public float FleeInterval;

		public float AlertRange;

		public bool FleeIfHurtWhenTargetCannotBeReached;

		public float FleeUnreachableSinceAttack;

		public float FleeUnreachableSinceHurt;

		public bool FleeIfNotAlerted;

		public float FleeIfLowHealth;

		public float FleeTimeSinceHurt;

		public bool FleeInLava;

		public bool CirculateWhileCharging;

		public bool CirculateWhileChargingFlying;

		public bool EnableHuntPlayer;

		public bool AttackPlayerObjects;

		public int PrivateAreaTriggerThreshold;

		public float InterceptTimeMax;

		public float InterceptTimeMin;

		public float MaxChaseDistance;

		public float MinAttackInterval;

		public float CircleTargetInterval;

		public float CircleTargetDuration;

		public float CircleTargetDistance;

		public bool Sleeping;

		public float WakeupRange;

		public bool NoiseWakeup;

		public float MaxNoiseWakeupRange;

		public float WakeupDelayMin;

		public float WakeupDelayMax;

		public bool AvoidLand;

		public List<string> ConsumeItems = new List<string>();

		public float ConsumeRange;

		public float ConsumeSearchRange;

		public float ConsumeSearchInterval;
	}
	[Serializable]
	[<280c4705-4a7b-4139-8a59-78254fb4951c>NullableContext(1)]
	[<391b7e1c-21ce-4cd7-b9cc-6b18bf5eb6e4>Nullable(0)]
	public class AnimalAIData
	{
		public float ViewRange;

		public float ViewAngle;

		public float HearRange;

		public bool MistVision;

		public float IdleSoundInterval;

		public float IdleSoundChance;

		public string PathAgentType = "";

		public float MoveMinAngle;

		public bool SmoothMovement;

		public bool SerpentMovement;

		public float SerpentTurnRadius;

		public float JumpInterval;

		public float RandomCircleInterval;

		public float RandomMoveInterval;

		public float RandomMoveRange;

		public bool RandomFly;

		public float ChanceToTakeOff;

		public float ChanceToLand;

		public float GroundDuration;

		public float AirDuration;

		public float MaxLandAltitude;

		public float TakeoffTime;

		public float FlyAltitudeMin;

		public float FlyAltitudeMax;

		public float FlyAbsMinAltitude;

		public bool AvoidFire;

		public bool AfraidOfFire;

		public bool AvoidWater;

		public bool AvoidLava;

		public bool SkipLavaTargets;

		public bool Aggravatable;

		public bool PassiveAggressive;

		public string SpawnMessage = "";

		public string DeathMessage = "";

		public string AlertedMessage = "";

		public float FleeRange;

		public float FleeAngle;

		public float FleeInterval;
	}
	[Serializable]
	public class CharacterDropData
	{
		[<391b7e1c-21ce-4cd7-b9cc-6b18bf5eb6e4>Nullable(1)]
		public string PrefabName = "";

		public int AmountMin;

		public int AmountMax;

		public float Chance;

		public bool OnePerPlayer;

		public bool LevelMultiplier;

		public bool DoNotScale;
	}
	[Serializable]
	[<391b7e1c-21ce-4cd7-b9cc-6b18bf5eb6e4>Nullable(0)]
	[<280c4705-4a7b-4139-8a59-78254fb4951c>NullableContext(1)]
	public class TameableData
	{
		public float FedDuration;

		public float TamingTime;

		public bool StartTamed;

		public bool Commandable;

		public float UnsummonDistance;

		public float UnsummonOnOwnerLogoutSeconds;

		public string LevelUpOwnerSkill = "";

		public float LevelUpFactor;

		public bool DropSaddleOnDeath;

		public List<string> RandomStartingName = new List<string>();
	}
	[Serializable]
	public class ProcreationData
	{
		public float UpdateInterval;

		public float TotalCheckRange;

		public int MaxCreatures;

		public float PartnerCheckRange;

		public float PregnancyChance;

		public float PregnancyDuration;

		public int RequiredLovePoints;

		[<391b7e1c-21ce-4cd7-b9cc-6b18bf5eb6e4>Nullable(1)]
		public string Offspring = "";

		public int MinOffspringLevel;

		public float SpawnOffset;
	}
	[Serializable]
	[<280c4705-4a7b-4139-8a59-78254fb4951c>NullableContext(1)]
	[<391b7e1c-21ce-4cd7-b9cc-6b18bf5eb6e4>Nullable(0)]
	public class NPCTalkData
	{
		public string Name = "";

		public float MaxRange;

		public float GreetRange;

		public float ByeRange;

		public float Offset;

		public float MinTalkInterval;

		public float HideDialogueDelay;

		public float RandomTalkInterval;

		public float RandomTalkChance;

		public List<string> RandomTalk = new List<string>();

		public List<string> RandomTalkInFactionBase = new List<string>();

		public List<string> RandomGreets = new List<string>();

		public List<string> RandomGoodbye = new List<string>();

		public List<string> PrivateAreaAlarm = new List<string>();

		public List<string> Aggravated = new List<string>();
	}
	[Serializable]
	[<280c4705-4a7b-4139-8a59-78254fb4951c>NullableContext(1)]
	[<391b7e1c-21ce-4cd7-b9cc-6b18bf5eb6e4>Nullable(0)]
	public class GrowUpData
	{
		public float GrowTime;

		public bool InheritTame;

		public string GrownPrefab = "";

		public List<AltGrownData> AltGrownPrefabs = new List<AltGrownData>();
	}
	[Serializable]
	public class AltGrownData
	{
		[<391b7e1c-21ce-4cd7-b9cc-6b18bf5eb6e4>Nullable(1)]
		public string GrownPrefab = "";

		public float Weight;
	}
	[Serializable]
	[<391b7e1c-21ce-4cd7-b9cc-6b18bf5eb6e4>Nullable(0)]
	[<280c4705-4a7b-4139-8a59-78254fb4951c>NullableContext(1)]
	public class LevelEffectData
	{
		public float Scale;

		public float Hue;

		public float Saturation;

		public float Value;

		public bool SetEmissiveColor;

		public VisualMethods.ColorData EmissiveColor = new VisualMethods.ColorData();

		public string EnableObject = "";
	}
	[Serializable]
	[<391b7e1c-21ce-4cd7-b9cc-6b18bf5eb6e4>Nullable(0)]
	[<280c4705-4a7b-4139-8a59-78254fb4951c>NullableContext(1)]
	public class CreatureData
	{
		public VisualMethods.ScaleData m_scale = new VisualMethods.ScaleData();

		public VisualMethods.ScaleData m_ragdollScale = new VisualMethods.ScaleData();

		public Dictionary<string, VisualMethods.MaterialData> m_materials = new Dictionary<string, VisualMethods.MaterialData>();

		public CharacterData m_characterData = new CharacterData();

		public CharacterEffects m_effects = new CharacterEffects();

		public List<ItemAttackData> m_defaultItems = new List<ItemAttackData>();

		public List<ItemAttackData> m_randomWeapons = new List<ItemAttackData>();

		public List<ItemAttackData> m_randomArmors = new List<ItemAttackData>();

		public List<ItemAttackData> m_randomShields = new List<ItemAttackData>();

		public List<RandomItemData> m_randomItems = new List<RandomItemData>();

		public List<RandomItemSetsData> m_randomSets = new List<RandomItemSetsData>();

		public MonsterAIData m_monsterAIData = new MonsterAIData();

		public AnimalAIData m_animalAIData = new AnimalAIData();

		public List<CharacterDropData> m_characterDrops = new List<CharacterDropData>();

		public TameableData m_tameable = new TameableData();

		public ProcreationData m_procreation = new ProcreationData();

		public NPCTalkData m_npcTalk = new NPCTalkData();

		public GrowUpData m_growUp = new GrowUpData();

		public List<LevelEffectData> m_levelEffects = new List<LevelEffectData>();

		public Dictionary<string, bool> m_particles = new Dictionary<string, bool>();

		public VisualMethods.HumanData m_humanData = new VisualMethods.HumanData();
	}
	[Serializable]
	[<391b7e1c-21ce-4cd7-b9cc-6b18bf5eb6e4>Nullable(0)]
	[<280c4705-4a7b-4139-8a59-78254fb4951c>NullableContext(1)]
	public class ItemAttackData
	{
		public AttackData m_attackData = new AttackData();

		public ItemEffects m_effects = new ItemEffects();
	}
	[Serializable]
	[<391b7e1c-21ce-4cd7-b9cc-6b18bf5eb6e4>Nullable(0)]
	[<280c4705-4a7b-4139-8a59-78254fb4951c>NullableContext(1)]
	public class RandomItemSetsData
	{
		public string m_name = "";

		public List<ItemAttackData> m_items = new List<ItemAttackData>();
	}
	[Serializable]
	[<391b7e1c-21ce-4cd7-b9cc-6b18bf5eb6e4>Nullable(0)]
	[<280c4705-4a7b-4139-8a59-78254fb4951c>NullableContext(1)]
	public class CharacterEffects
	{
		public List<EffectInfo> m_hitEffects = new List<EffectInfo>();

		public List<EffectInfo> m_critHitEffects = new List<EffectInfo>();

		public List<EffectInfo> m_backstabHitEffects = new List<EffectInfo>();

		public List<EffectInfo> m_deathEffects = new List<EffectInfo>();

		public List<EffectInfo> m_waterEffects = new List<EffectInfo>();

		public List<EffectInfo> m_tarEffects = new List<EffectInfo>();

		public List<EffectInfo> m_slideEffects = new List<EffectInfo>();

		public List<EffectInfo> m_jumpEffects = new List<EffectInfo>();

		public List<EffectInfo> m_flyingContinuousEffects = new List<EffectInfo>();

		public List<EffectInfo> m_pickupEffects = new List<EffectInfo>();

		public List<EffectInfo> m_dropEffects = new List<EffectInfo>();

		public List<EffectInfo> m_consumeItemEffects = new List<EffectInfo>();

		public List<EffectInfo> m_equipEffects = new List<EffectInfo>();

		public List<EffectInfo> m_perfectBlockEffects = new List<EffectInfo>();

		public List<EffectInfo> m_alertedEffects = new List<EffectInfo>();

		public List<EffectInfo> m_idleSounds = new List<EffectInfo>();

		public List<EffectInfo> m_wakeupEffects = new List<EffectInfo>();

		public List<EffectInfo> m_birthEffects = new List<EffectInfo>();

		public List<EffectInfo> m_loveEffects = new List<EffectInfo>();

		public List<EffectInfo> m_tamedEffects = new List<EffectInfo>();

		public List<EffectInfo> m_soothEffects = new List<EffectInfo>();

		public List<EffectInfo> m_petEffects = new List<EffectInfo>();

		public List<EffectInfo> m_unSummonEffects = new List<EffectInfo>();

		public List<EffectInfo> m_randomTalkFX = new List<EffectInfo>();

		public List<EffectInfo> m_randomGreetFX = new List<EffectInfo>();

		public List<EffectInfo> m_randomGoodbyeFX = new List<EffectInfo>();
	}
	[Serializable]
	[<280c4705-4a7b-4139-8a59-78254fb4951c>NullableContext(1)]
	[<391b7e1c-21ce-4cd7-b9cc-6b18bf5eb6e4>Nullable(0)]
	public class ItemEffects
	{
		public List<EffectInfo> m_hitEffects = new List<EffectInfo>();

		public List<EffectInfo> m_hitTerrainEffects = new List<EffectInfo>();

		public List<EffectInfo> m_blockEffects = new List<EffectInfo>();

		public List<EffectInfo> m_startEffects = new List<EffectInfo>();

		public List<EffectInfo> m_holdStartEffects = new List<EffectInfo>();

		public List<EffectInfo> m_equipEffects = new List<EffectInfo>();

		public List<EffectInfo> m_unEquipEffects = new List<EffectInfo>();

		public List<EffectInfo> m_triggerEffects = new List<EffectInfo>();

		public List<EffectInfo> m_trailStartEffects = new List<EffectInfo>();
	}
	[<280c4705-4a7b-4139-8a59-78254fb4951c>NullableContext(1)]
	[<391b7e1c-21ce-4cd7-b9cc-6b18bf5eb6e4>Nullable(0)]
	public static class CreatureManager
	{
		[<280c4705-4a7b-4139-8a59-78254fb4951c>NullableContext(0)]
		[HarmonyPatch(typeof(ZNet), "Awake")]
		private static class ZNet_Awake_Patch
		{
			private static void Postfix()
			{
				UpdateServer();
			}
		}

		public static readonly string m_folderPath;

		public static readonly string m_creatureFolderPath;

		public static readonly string m_cloneFolderPath;

		private static readonly string m_exportFolderPath;

		private static readonly string m_importFolderPath;

		private static readonly CustomSyncedValue<string> m_serverDataFiles;

		private static readonly Dictionary<string, CreatureData> m_originalData;

		public static Dictionary<string, CreatureData> m_data;

		public static readonly Dictionary<string, CreatureData> m_localData;

		public static readonly Dictionary<string, GameObject> m_clones;

		private static FileSystemWatcher m_creatureWatcher;

		private static FileSystemWatcher m_cloneWatcher;

		private static bool m_writing;

		private static void UpdateServer()
		{
			if (Object.op_Implicit((Object)(object)ZNet.instance) && ZNet.instance.IsServer())
			{
				MonsterDBPlugin.MonsterDBLogger.LogDebug((object)"Server: Updating server sync creature & clones");
				ISerializer serializer = new SerializerBuilder().Build();
				m_serverDataFiles.Value = serializer.Serialize(m_data);
			}
		}

		public static bool IsClone(GameObject creature)
		{
			return m_clones.ContainsKey(((Object)creature).name);
		}

		public static void Setup()
		{
			m_serverDataFiles.ValueChanged += ReadServerFiles;
			SetupFileWatch();
			if (!Directory.Exists(m_folderPath))
			{
				Directory.CreateDirectory(m_folderPath);
			}
			if (!Directory.Exists(m_creatureFolderPath))
			{
				Directory.CreateDirectory(m_creatureFolderPath);
			}
			if (!Directory.Exists(m_cloneFolderPath))
			{
				Directory.CreateDirectory(m_cloneFolderPath);
			}
			if (!Directory.Exists(m_importFolderPath))
			{
				Directory.CreateDirectory(m_importFolderPath);
			}
			if (!Directory.Exists(m_exportFolderPath))
			{
				Directory.CreateDirectory(m_exportFolderPath);
			}
		}

		private static void SetupFileWatch()
		{
			if (!Directory.Exists(m_folderPath))
			{
				Directory.CreateDirectory(m_folderPath);
			}
			if (!Directory.Exists(m_creatureFolderPath))
			{
				Directory.CreateDirectory(m_creatureFolderPath);
			}
			if (!Directory.Exists(m_cloneFolderPath))
			{
				Directory.CreateDirectory(m_cloneFolderPath);
			}
			if (!Directory.Exists(m_importFolderPath))
			{
				Directory.CreateDirectory(m_importFolderPath);
			}
			m_creatureWatcher = new FileSystemWatcher(m_creatureFolderPath, "*.yml")
			{
				EnableRaisingEvents = true,
				IncludeSubdirectories = true,
				SynchronizingObject = ThreadingHelper.SynchronizingObject,
				NotifyFilter = NotifyFilters.LastWrite
			};
			m_creatureWatcher.Changed += OnCreatureFileChange;
			m_cloneWatcher = new FileSystemWatcher(m_cloneFolderPath, "*.yml")
			{
				EnableRaisingEvents = true,
				IncludeSubdirectories = true,
				SynchronizingObject = ThreadingHelper.SynchronizingObject,
				NotifyFilter = NotifyFilters.LastWrite
			};
			m_cloneWatcher.Changed += OnCloneFileChange;
			FileSystemWatcher fileSystemWatcher = new FileSystemWatcher(m_importFolderPath, "*.yml")
			{
				EnableRaisingEvents = true,
				IncludeSubdirectories = true,
				SynchronizingObject = ThreadingHelper.SynchronizingObject,
				NotifyFilter = NotifyFilters.LastWrite
			};
			fileSystemWatcher.Changed += OnImportFileChange;
		}

		private static void OnImportFileChange(object sender, FileSystemEventArgs e)
		{
			if (!MonsterDBPlugin.AutoUpdate() || m_writing || !Object.op_Implicit((Object)(object)ZNet.instance) || !ZNet.instance.IsServer())
			{
				return;
			}
			try
			{
				string fileName = Path.GetFileName(e.Name);
				IDeserializer deserializer = new DeserializerBuilder().Build();
				string input = File.ReadAllText(e.FullPath);
				CreatureData creatureData = deserializer.Deserialize<CreatureData>(input);
				GameObject val = DataBase.TryGetGameObject(creatureData.m_characterData.PrefabName);
				if (!((Object)(object)val == (Object)null))
				{
					m_data[creatureData.m_characterData.PrefabName] = creatureData;
					UpdateServer();
					Update(val);
					MonsterDBPlugin.MonsterDBLogger.LogDebug((object)(((Object)val).name + " data changed: " + fileName));
				}
			}
			catch
			{
				Helpers.LogParseFailure(e.FullPath);
			}
		}

		private static void OnCloneFileChange(object sender, FileSystemEventArgs e)
		{
			if (MonsterDBPlugin.AutoUpdate() && !m_writing && Object.op_Implicit((Object)(object)ZNet.instance) && ZNet.instance.IsServer())
			{
				string fileName = Path.GetFileName(e.Name);
				string cloneFolderName = GetCloneFolderName(e.FullPath);
				GameObject val = DataBase.TryGetGameObject(cloneFolderName);
				if (!((Object)(object)val == (Object)null))
				{
					Read(cloneFolderName, isClone: true);
					Update(val);
					MonsterDBPlugin.MonsterDBLogger.LogDebug((object)(cloneFolderName + " data changed: " + fileName));
				}
			}
		}

		private static void OnCreatureFileChange(object sender, FileSystemEventArgs e)
		{
			if (MonsterDBPlugin.AutoUpdate() && !m_writing && Object.op_Implicit((Object)(object)ZNet.instance) && ZNet.instance.IsServer())
			{
				string fileName = Path.GetFileName(e.Name);
				string creatureFolderName = GetCreatureFolderName(e.FullPath);
				GameObject val = DataBase.TryGetGameObject(creatureFolderName);
				if (!((Object)(object)val == (Object)null))
				{
					Read(creatureFolderName);
					Update(val);
					MonsterDBPlugin.MonsterDBLogger.LogDebug((object)(creatureFolderName + " data changed: " + fileName));
				}
			}
		}

		private static string GetCloneFolderName(string fullPath)
		{
			return fullPath.Replace(m_cloneFolderPath, string.Empty).Split(new char[1] { Path.DirectorySeparatorChar })[1];
		}

		private static string GetCreatureFolderName(string fullPath)
		{
			return fullPath.Replace(m_creatureFolderPath, string.Empty).Split(new char[1] { Path.DirectorySeparatorChar })[1];
		}

		private static void ReadServerFiles()
		{
			if (!Object.op_Implicit((Object)(object)ZNet.instance) || ZNet.instance.IsServer() || Utility.IsNullOrWhiteSpace(m_serverDataFiles.Value))
			{
				return;
			}
			IDeserializer deserializer = new DeserializerBuilder().Build();
			try
			{
				Initialization.ResetAll();
				m_data = deserializer.Deserialize<Dictionary<string, CreatureData>>(m_serverDataFiles.Value);
				Initialization.RemoveAllClones();
				Initialization.CloneAll();
				Initialization.UpdateAll();
				MonsterDBPlugin.MonsterDBLogger.LogDebug((object)"Server updated MonsterDB Files");
			}
			catch
			{
				MonsterDBPlugin.MonsterDBLogger.LogDebug((object)"Failed to parse server synced data");
			}
		}

		public static void Delete(GameObject critter, bool loop = true)
		{
			string prefabName = ((Object)critter).name + "_ragdoll";
			GameObject val = DataBase.TryGetGameObject(prefabName);
			if ((Object)(object)val != (Object)null)
			{
				Delete(val, loop);
			}
			Helpers.RemoveFromZNetScene(critter);
			Helpers.RemoveFromObjectDB(critter);
			if (!loop)
			{
				m_clones.Remove(((Object)critter).name);
			}
			Transform val2 = MonsterDBPlugin.m_root.transform.Find(((Object)critter).name);
			if (Object.op_Implicit((Object)(object)val2))
			{
				Object.Destroy((Object)(object)((Component)val2).gameObject);
			}
		}

		private static void Save(GameObject critter, string cloneFrom)
		{
			if (!m_originalData.ContainsKey(((Object)critter).name))
			{
				CreatureData creatureData = new CreatureData();
				VisualMethods.Save(critter, ref creatureData);
				HumanoidMethods.Save(critter, cloneFrom, ref creatureData);
				CharacterMethods.Save(critter, cloneFrom, ref creatureData);
				MonsterAIMethods.Save(critter, ref creatureData);
				AnimalAIMethods.Save(critter, ref creatureData);
				CharacterDropMethods.Save(critter, ref creatureData);
				TameableMethods.Save(critter, ref creatureData);
				ProcreationMethods.Save(critter, ref creatureData);
				NPCTalkMethods.Save(critter, ref creatureData);
				GrowUpMethods.Save(critter, ref creatureData);
				LevelEffectsMethods.Save(critter, ref creatureData);
				m_originalData[((Object)critter).name] = creatureData;
			}
		}

		public static bool Write(GameObject critter, out string folderPath, bool clone = false, string clonedFrom = "", bool writeAll = false)
		{
			m_writing = true;
			if (!Directory.Exists(m_folderPath))
			{
				Directory.CreateDirectory(m_folderPath);
			}
			if (!Directory.Exists(m_creatureFolderPath))
			{
				Directory.CreateDirectory(m_creatureFolderPath);
			}
			string obj = (clone ? m_cloneFolderPath : m_creatureFolderPath);
			char directorySeparatorChar = Path.DirectorySeparatorChar;
			folderPath = obj + directorySeparatorChar + ((Object)critter).name;
			if (writeAll && Directory.Exists(folderPath))
			{
				MonsterDBPlugin.MonsterDBLogger.LogDebug((object)(((Object)critter).name + " files already exist, skipping"));
				m_writing = false;
				return false;
			}
			if (Directory.Exists(folderPath))
			{
				Directory.Delete(folderPath, recursive: true);
			}
			Directory.CreateDirectory(folderPath);
			VisualMethods.Write(critter, folderPath);
			HumanoidMethods.Write(critter, folderPath, clonedFrom);
			CharacterMethods.Write(critter, folderPath, clonedFrom);
			MonsterAIMethods.Write(critter, folderPath);
			AnimalAIMethods.Write(critter, folderPath);
			CharacterDropMethods.Write(critter, folderPath);
			TameableMethods.Write(critter, folderPath);
			ProcreationMethods.Write(critter, folderPath);
			NPCTalkMethods.Write(critter, folderPath);
			GrowUpMethods.Write(critter, folderPath);
			LevelEffectsMethods.Write(critter, folderPath);
			m_writing = false;
			return true;
		}

		public static void Read(string creatureName, bool isClone = false)
		{
			string obj = (isClone ? m_cloneFolderPath : m_creatureFolderPath);
			char directorySeparatorChar = Path.DirectorySeparatorChar;
			string text = obj + directorySeparatorChar + creatureName;
			if (Directory.Exists(text))
			{
				CreatureData creatureData = new CreatureData();
				VisualMethods.Read(text, ref creatureData);
				HumanoidMethods.Read(text, ref creatureData);
				CharacterMethods.Read(text, ref creatureData);
				MonsterAIMethods.Read(text, ref creatureData);
				AnimalAIMethods.Read(text, ref creatureData);
				CharacterDropMethods.Read(text, ref creatureData);
				TameableMethods.Read(text, ref creatureData);
				ProcreationMethods.Read(text, ref creatureData);
				NPCTalkMethods.Read(text, ref creatureData);
				GrowUpMethods.Read(text, ref creatureData);
				LevelEffectsMethods.Read(text, ref creatureData);
				m_data[creatureName] = creatureData;
				m_localData[creatureName] = creatureData;
				UpdateServer();
			}
		}

		public static void Update(GameObject critter, bool local = false)
		{
			CreatureData value2;
			if (local)
			{
				if (m_localData.TryGetValue(((Object)critter).name, out var value))
				{
					Save(critter, value.m_characterData.ClonedFrom);
					Update(critter, value);
				}
			}
			else if (m_data.TryGetValue(((Object)critter).name, out value2))
			{
				Save(critter, value2.m_characterData.ClonedFrom);
				Update(critter, value2);
			}
		}

		private static void Update(GameObject critter, CreatureData data)
		{
			VisualMethods.Update(critter, data);
			TameableMethods.Update(critter, data);
			HumanoidMethods.Update(critter, data);
			CharacterMethods.Update(critter, data);
			MonsterAIMethods.Update(critter, data);
			AnimalAIMethods.Update(critter, data);
			CharacterDropMethods.Update(critter, data);
			ProcreationMethods.Update(critter, data);
			NPCTalkMethods.Update(critter, data);
			GrowUpMethods.Update(critter, data);
			LevelEffectsMethods.Update(critter, data);
		}

		public static void Reset(GameObject critter)
		{
			if (m_originalData.TryGetValue(((Object)critter).name, out var value))
			{
				Update(critter, value);
				MonsterDBPlugin.MonsterDBLogger.LogInfo((object)("Reset: " + ((Object)critter).name));
			}
		}

		public static void Clone(GameObject critter, string name, bool saveToDisk = true, bool cloneAttacks = true)
		{
			if (!Directory.Exists(m_folderPath))
			{
				Directory.CreateDirectory(m_folderPath);
			}
			if (!Directory.Exists(m_cloneFolderPath))
			{
				Directory.CreateDirectory(m_cloneFolderPath);
			}
			GameObject val;
			if (((Object)critter).name == "Human")
			{
				val = HumanMan.Create(name);
				if ((Object)(object)val == (Object)null)
				{
					return;
				}
			}
			else
			{
				val = Object.Instantiate<GameObject>(critter, MonsterDBPlugin.m_root.transform, false);
				((Object)val).name = name;
				Dictionary<string, Material> ragDollMats = VisualMethods.CloneMaterials(val);
				CharacterMethods.CloneRagDoll(val, ragDollMats);
				HumanoidMethods.CloneRagDoll(val, ragDollMats);
				m_clones[((Object)val).name] = val;
				Helpers.RegisterToZNetScene(val);
			}
			if (cloneAttacks)
			{
				HumanoidMethods.CloneItems(val);
			}
			if (saveToDisk)
			{
				Write(val, out var folderPath, clone: true, ((Object)critter).name);
				Read(((Object)val).name, isClone: true);
				MonsterDBPlugin.MonsterDBLogger.LogInfo((object)("Cloned " + ((Object)critter).name + " as " + ((Object)val).name));
				MonsterDBPlugin.MonsterDBLogger.LogInfo((object)folderPath);
			}
		}

		public static void Export(string creatureName)
		{
			if (!Directory.Exists(m_folderPath))
			{
				Directory.CreateDirectory(m_folderPath);
			}
			if (!Directory.Exists(m_exportFolderPath))
			{
				Directory.CreateDirectory(m_exportFolderPath);
			}
			if (!Directory.Exists(m_importFolderPath))
			{
				Directory.CreateDirectory(m_importFolderPath);
			}
			if (m_data.TryGetValue(creatureName, out var value))
			{
				ISerializer serializer = new SerializerBuilder().Build();
				string contents = serializer.Serialize(value);
				string exportFolderPath = m_exportFolderPath;
				char directorySeparatorChar = Path.DirectorySeparatorChar;
				string text = exportFolderPath + directorySeparatorChar + creatureName + ".yml";
				File.WriteAllText(text, contents);
				MonsterDBPlugin.MonsterDBLogger.LogDebug((object)"Exported creature data: ");
				MonsterDBPlugin.MonsterDBLogger.LogDebug((object)text);
			}
		}

		public static void Import()
		{
			if (!Directory.Exists(m_folderPath))
			{
				Directory.CreateDirectory(m_folderPath);
			}
			if (!Directory.Exists(m_importFolderPath))
			{
				Directory.CreateDirectory(m_importFolderPath);
			}
			string[] files = Directory.GetFiles(m_importFolderPath);
			if (files.Length == 0)
			{
				return;
			}
			IDeserializer deserializer = new DeserializerBuilder().Build();
			int num = 0;
			string[] array = files;
			foreach (string text in array)
			{
				try
				{
					string input = File.ReadAllText(text);
					CreatureData creatureData = deserializer.Deserialize<CreatureData>(input);
					string prefabName = creatureData.m_characterData.PrefabName;
					m_data[prefabName] = creatureData;
					num++;
				}
				catch
				{
					Helpers.LogParseFailure(text);
				}
			}
			MonsterDBPlugin.MonsterDBLogger.LogDebug((object)$"Imported {num} creature data files");
		}

		static CreatureManager()
		{
			string configPath = Paths.ConfigPath;
			char directorySeparatorChar = Path.DirectorySeparatorChar;
			m_folderPath = configPath + directorySeparatorChar + "MonsterDB";
			string folderPath = m_folderPath;
			directorySeparatorChar = Path.DirectorySeparatorChar;
			m_creatureFolderPath = folderPath + directorySeparatorChar + "Creatures";
			string folderPath2 = m_folderPath;
			directorySeparatorChar = Path.DirectorySeparatorChar;
			m_cloneFolderPath = folderPath2 + directorySeparatorChar + "Clones";
			string folderPath3 = m_folderPath;
			directorySeparatorChar = Path.DirectorySeparatorChar;
			m_exportFolderPath = folderPath3 + directorySeparatorChar + "Export";
			string folderPath4 = m_folderPath;
			directorySeparatorChar = Path.DirectorySeparatorChar;
			m_importFolderPath = folderPath4 + directorySeparatorChar + "Import";
			m_serverDataFiles = new CustomSyncedValue<string>(MonsterDBPlugin.ConfigSync, "MonsterDB_ServerFiles", "");
			m_originalData = new Dictionary<string, CreatureData>();
			m_data = new Dictionary<string, CreatureData>();
			m_localData = new Dictionary<string, CreatureData>();
			m_clones = new Dictionary<string, GameObject>();
			m_creatureWatcher = null;
			m_cloneWatcher = null;
		}
	}
	[<280c4705-4a7b-4139-8a59-78254fb4951c>NullableContext(1)]
	[<391b7e1c-21ce-4cd7-b9cc-6b18bf5eb6e4>Nullable(0)]
	public static class DataBase
	{
		[HarmonyPatch(typeof(ZNetScene), "Awake")]
		[<280c4705-4a7b-4139-8a59-78254fb4951c>NullableContext(0)]
		[HarmonyPriority(800)]
		private static class CacheResources_Patch
		{
			private static void Postfix()
			{
				CacheResources();
			}
		}

		public static readonly Dictionary<string, GameObject> m_allObjects = new Dictionary<string, GameObject>();

		public static readonly Dictionary<string, Texture2D> m_textures = new Dictionary<string, Texture2D>();

		private static void CacheResources()
		{
			List<GameObject> list = Resources.FindObjectsOfTypeAll<GameObject>().ToList();
			foreach (GameObject item in list)
			{
				m_allObjects[((Object)item).name] = item;
			}
			List<Texture2D> source = Resources.FindObjectsOfTypeAll<Texture2D>().ToList();
			foreach (Texture2D item2 in source.Where([<280c4705-4a7b-4139-8a59-78254fb4951c>NullableContext(0)] (Texture2D texture) => !Utility.IsNullOrWhiteSpace(((Object)texture).name)))
			{
				m_textures[((Object)item2).name] = item2;
			}
			string texturePath = TextureManager.m_texturePath;
			char directorySeparatorChar = Path.DirectorySeparatorChar;
			string path = texturePath + directorySeparatorChar + "Resources.txt";
			if (!File.Exists(path))
			{
				List<string> contents = m_textures.Keys.ToList();
				File.WriteAllLines(path, contents);
			}
		}

		[return: <391b7e1c-21ce-4cd7-b9cc-6b18bf5eb6e4>Nullable(2)]
		public static GameObject TryGetGameObject(string prefabName)
		{
			if (!Object.op_Implicit((Object)(object)ZNetScene.instance) || !Object.op_Implicit((Object)(object)ObjectDB.instance))
			{
				return null;
			}
			GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(prefabName);
			if ((Object)(object)itemPrefab != (Object)null)
			{
				return itemPrefab;
			}
			itemPrefab = ZNetScene.instance.GetPrefab(prefabName);
			if ((Object)(object)itemPrefab != (Object)null)
			{
				return itemPrefab;
			}
			if (HumanMan.m_newHumans.TryGetValue(prefabName, out var value))
			{
				return value;
			}
			if (ItemDataMethods.m_clonedItems.TryGetValue(prefabName, out var value2))
			{
				return value2;
			}
			GameObject value3;
			return (!m_allObjects.TryGetValue(prefabName, out value3)) ? null : value3;
		}

		public static bool TryGetTexture(string textureName, out Texture2D texture)
		{
			if (TextureManager.m_customTextures.TryGetValue(textureName, out texture))
			{
				return true;
			}
			return m_textures.TryGetValue(textureName, out texture);
		}
	}
	[<280c4705-4a7b-4139-8a59-78254fb4951c>NullableContext(1)]
	[<391b7e1c-21ce-4cd7-b9cc-6b18bf5eb6e4>Nullable(0)]
	public static class HumanMan
	{
		public static readonly Dictionary<string, GameObject> m_newHumans = new Dictionary<string, GameObject>();

		[return: <391b7e1c-21ce-4cd7-b9cc-6b18bf5eb6e4>Nullable(2)]
		public static GameObject Create(string name)
		{
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01be: Expected O, but got Unknown
			//IL_01c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ea: Expected O, but got Unknown
			//IL_01ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0201: Expected O, but got Unknown
			//IL_0228: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0391: Unknown result type (might be due to invalid IL or missing references)
			//IL_0396: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f5: Expected O, but got Unknown
			//IL_0449: Unknown result type (might be due to invalid IL or missing references)
			//IL_0450: Expected O, but got Unknown
			//IL_0553: Unknown result type (might be due to invalid IL or missing references)
			//IL_062c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0631: Unknown result type (might be due to invalid IL or missing references)
			//IL_0646: Unknown result type (might be due to invalid IL or missing references)
			//IL_064d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0655: Unknown result type (might be due to invalid IL or missing references)
			//IL_0660: Unknown result type (might be due to invalid IL or missing references)
			//IL_066c: Expected O, but got Unknown
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_0149: Expected O, but got Unknown
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_016d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0175: Expected O, but got Unknown
			if (!Object.op_Implicit((Object)(object)ZNetScene.instance))
			{
				return null;
			}
			GameObject prefab = ZNetScene.instance.GetPrefab("Player");
			if (!Object.op_Implicit((Object)(object)prefab))
			{
				return null;
			}
			Player val = default(Player);
			if (!prefab.TryGetComponent<Player>(ref val))
			{
				return null;
			}
			GameObject val2 = Object.Instantiate<GameObject>(prefab, MonsterDBPlugin.m_root.transform, false);
			((Object)val2).name = name;
			Object.Destroy((Object)(object)val2.GetComponent<Player>());
			Object.Destroy((Object)(object)val2.GetComponent<PlayerController>());
			Object.Destroy((Object)(object)val2.GetComponent<Talker>());
			Object.Destroy((Object)(object)val2.GetComponent<Skills>());
			ZNetView val3 = default(ZNetView);
			if (val2.TryGetComponent<ZNetView>(ref val3))
			{
				val3.m_persistent = true;
				val3.m_type = (ObjectType)0;
			}
			Human human = val2.AddComponent<Human>();
			((Character)human).m_eye = Utils.FindChild(val2.transform, "EyePos", (IterativeSearchType)0);
			MonsterAI val4 = val2.AddComponent<MonsterAI>();
			CharacterDrop val5 = val2.AddComponent<CharacterDrop>();
			Tameable val6 = val2.AddComponent<Tameable>();
			val2.AddComponent<Visuals>();
			GameObject val7 = Object.Instantiate<GameObject>(ZNetScene.instance.GetPrefab("Player_ragdoll"), MonsterDBPlugin.m_root.transform, false);
			Ragdoll val8 = default(Ragdoll);
			EffectList val9;
			if (val7.TryGetComponent<Ragdoll>(ref val8))
			{
				val8.m_ttl = 8f;
				Ragdoll obj = val8;
				val9 = new EffectList();
				val9.m_effectPrefabs = (EffectData[])(object)new EffectData[1]
				{
					new EffectData
					{
						m_prefab = ZNetScene.instance.GetPrefab("vfx_corpse_destruction_small"),
						m_enabled = true
					}
				};
				obj.m_removeEffect = val9;
				val8.m_float = true;
				val8.m_dropItems = true;
			}
			((Object)val7).name = name + "_ragdoll";
			val7.AddComponent<Visuals>();
			Helpers.RegisterToZNetScene(val7);
			val9 = new EffectList();
			val9.m_effectPrefabs = (EffectData[])(object)new EffectData[2]
			{
				new EffectData
				{
					m_prefab = ZNetScene.instance.GetPrefab("vfx_player_death"),
					m_enabled = true
				},
				new EffectData
				{
					m_prefab = val7,
					m_enabled = true
				}
			};
			((Character)human).m_deathEffects = val9;
			((Character)human).m_name = "Human";
			((Character)human).m_group = "Humans";
			((Character)human).m_faction = (Faction)2;
			((Character)human).m_crouchSpeed = ((Character)val).m_crouchSpeed;
			((Character)human).m_walkSpeed = ((Character)val).m_walkSpeed;
			((Character)human).m_speed = ((Character)val).m_speed;
			((Character)human).m_runSpeed = ((Character)val).m_runSpeed;
			((Character)human).m_runTurnSpeed = ((Character)val).m_runTurnSpeed;
			((Character)human).m_acceleration = ((Character)val).m_acceleration;
			((Character)human).m_jumpForce = ((Character)val).m_jumpForce;
			((Character)human).m_jumpForceForward = ((Character)val).m_jumpForceForward;
			((Character)human).m_jumpForceTiredFactor = ((Character)val).m_jumpForceForward;
			((Character)human).m_airControl = ((Character)val).m_airControl;
			((Character)human).m_canSwim = true;
			((Character)human).m_swimDepth = ((Character)val).m_swimDepth;
			((Character)human).m_swimSpeed = ((Character)val).m_swimSpeed;
			((Character)human).m_swimTurnSpeed = ((Character)val).m_swimTurnSpeed;
			((Character)human).m_swimAcceleration = ((Character)val).m_swimAcceleration;
			((Character)human).m_groundTilt = ((Character)val).m_groundTilt;
			((Character)human).m_groundTiltSpeed = ((Character)val).m_groundTiltSpeed;
			((Character)human).m_jumpStaminaUsage = ((Character)val).m_jumpStaminaUsage;
			((Character)human).m_hitEffects = ((Character)val).m_hitEffects;
			((Character)human).m_critHitEffects = ((Character)val).m_critHitEffects;
			((Character)human).m_backstabHitEffects = ((Character)val).m_backstabHitEffects;
			((Character)human).m_waterEffects = ((Character)val).m_waterEffects;
			((Character)human).m_tarEffects = ((Character)val).m_tarEffects;
			((Character)human).m_slideEffects = ((Character)val).m_slideEffects;
			((Character)human).m_jumpEffects = ((Character)val).m_jumpEffects;
			((Character)human).m_flyingContinuousEffect = ((Character)val).m_flyingContinuousEffect;
			((Character)human).m_tolerateWater = true;
			((Character)human).m_health = 100f;
			((Character)human).m_damageModifiers = ((Character)val).m_damageModifiers;
			((Character)human).m_staggerWhenBlocked = true;
			((Character)human).m_staggerDamageFactor = ((Character)val).m_staggerDamageFactor;
			((Humanoid)human).m_defaultItems = ((Humanoid)val).m_defaultItems;
			((Humanoid)human).m_randomWeapon = ((Humanoid)val).m_randomWeapon;
			((Humanoid)human).m_randomArmor = ((Humanoid)val).m_randomArmor;
			((Humanoid)human).m_randomShield = ((Humanoid)val).m_randomShield;
			ItemSet[] array = new ItemSet[2];
			ItemSet val10 = new ItemSet();
			val10.m_name = "Leather";
			val10.m_items = (GameObject[])(object)new GameObject[3]
			{
				ZNetScene.instance.GetPrefab("ArmorLeatherChest"),
				ZNetScene.instance.GetPrefab("ArmorLeatherLegs"),
				ZNetScene.instance.GetPrefab("Torch")
			};
			array[0] = val10;
			val10 = new ItemSet();
			val10.m_name = "Bronze";
			val10.m_items = (GameObject[])(object)new GameObject[4]
			{
				ZNetScene.instance.GetPrefab("ArmorBronzeChest"),
				ZNetScene.instance.GetPrefab("ArmorBronzeLegs"),
				ZNetScene.instance.GetPrefab("ShieldBronzeBuckler"),
				ZNetScene.instance.GetPrefab("KnifeCopper")
			};
			array[1] = val10;
			((Humanoid)human).m_randomSets = (ItemSet[])(object)array;
			((Humanoid)human).m_randomItems = ((Humanoid)val).m_randomItems;
			((Humanoid)human).m_unarmedWeapon = ((Humanoid)val).m_unarmedWeapon;
			((Humanoid)human).m_pickupEffects = val.m_autopickupEffects;
			((Humanoid)human).m_dropEffects = ((Humanoid)val).m_dropEffects;
			((Humanoid)human).m_consumeItemEffects = ((Humanoid)val).m_consumeItemEffects;
			((Humanoid)human).m_equipEffects = val.m_equipStartEffects;
			((Humanoid)human).m_perfectBlockEffect = ((Humanoid)val).m_perfectBlockEffect;
			((BaseAI)val4).m_viewRange = 30f;
			((BaseAI)val4).m_viewAngle = 90f;
			((BaseAI)val4).m_hearRange = 9999f;
			((BaseAI)val4).m_idleSoundInterval = 10f;
			((BaseAI)val4).m_idleSoundChance = 0f;
			((BaseAI)val4).m_pathAgentType = (AgentType)1;
			((BaseAI)val4).m_moveMinAngle = 90f;
			((BaseAI)val4).m_smoothMovement = true;
			((BaseAI)val4).m_jumpInterval = 10f;
			((BaseAI)val4).m_randomCircleInterval = 2f;
			((BaseAI)val4).m_randomMoveInterval = 30f;
			((BaseAI)val4).m_randomMoveRange = 3f;
			val4.m_alertRange = 20f;
			val4.m_circulateWhileCharging = true;
			val4.m_privateAreaTriggerTreshold = 4;
			val4.m_interceptTimeMax = 2f;
			val4.m_maxChaseDistance = 300f;
			val4.m_circleTargetInterval = 8f;
			val4.m_circleTargetDuration = 6f;
			val4.m_circleTargetDistance = 8f;
			val4.m_consumeRange = 2f;
			val4.m_consumeSearchRange = 5f;
			val4.m_consumeSearchInterval = 10f;
			val4.m_consumeItems = new List<ItemDrop>();
			val5.m_drops = new List<Drop>
			{
				new Drop
				{
					m_prefab = ZNetScene.instance.GetPrefab("Coins"),
					m_amountMin = 1,
					m_amountMax = 10,
					m_chance = 0.25f,
					m_levelMultiplier = true
				}
			};
			GameObject prefab2 = ZNetScene.instance.GetPrefab("Boar");
			Tameable val11 = default(Tameable);
			if (prefab2.TryGetComponent<Tameable>(ref val11))
			{
				val6.m_fedDuration = 600f;
				val6.m_tamingTime = 1800f;
				val6.m_commandable = true;
				val6.m_tamedEffect = val11.m_tamedEffect;
				val6.m_sootheEffect = val11.m_sootheEffect;
				val6.m_petEffect = val11.m_petEffect;
				val6.m_commandable = true;
				val6.m_unsummonDistance = 0f;
				val6.m_randomStartingName = new List<string>();
			}
			Helpers.RegisterToZNetScene(val2);
			if (name != "Human")
			{
				CreatureManager.m_clones[((Object)val2).name] = val2;
			}
			m_newHumans[((Object)val2).name] = val2;
			return val2;
		}
	}
	public static class Initialization
	{
		[HarmonyPriority(0)]
		[HarmonyPatch(typeof(ObjectDB), "Awake")]
		private static class ObjectDB_Awake_Patch
		{
			[<280c4705-4a7b-4139-8a59-78254fb4951c>NullableContext(1)]
			private static void Postfix(ObjectDB __instance)
			{
				if (!Object.op_Implicit((Object)(object)__instance) || !Object.op_Implicit((Object)(object)ZNetScene.instance))
				{
					return;
				}
				HumanMan.Create("Human");
				CloneAll(local: true);
				UpdateAll(local: true);
				SpawnMan.UpdateSpawnData();
				List<string> list = new List<string>();
				foreach (StatusEffect statusEffect in __instance.m_StatusEffects)
				{
					list.Add(((Object)statusEffect).name);
				}
				File.WriteAllLines(m_statusEffectsPath, list);
			}
		}

		[HarmonyPatch(typeof(Game), "Logout")]
		private static class Game_Logout_Patch
		{
			private static void Prefix()
			{
				ResetAll();
				RemoveAllClones();
				SpawnMan.ClearSpawns();
			}
		}

		[<391b7e1c-21ce-4cd7-b9cc-6b18bf5eb6e4>Nullable(1)]
		private static readonly string m_statusEffectsPath;

		public static void ReadLocalFiles()
		{
			if (!Directory.Exists(CreatureManager.m_folderPath))
			{
				Directory.CreateDirectory(CreatureManager.m_folderPath);
			}
			if (!Directory.Exists(CreatureManager.m_creatureFolderPath))
			{
				Directory.CreateDirectory(CreatureManager.m_creatureFolderPath);
			}
			if (!Directory.Exists(CreatureManager.m_cloneFolderPath))
			{
				Directory.CreateDirectory(CreatureManager.m_cloneFolderPath);
			}
			CreatureManager.Import();
			ReadCreatureDirectory();
			ReadCloneDirectory();
		}

		private static void ReadCreatureDirectory()
		{
			string[] directories = Directory.GetDirectories(CreatureManager.m_creatureFolderPath);
			int num = 0;
			string[] array = directories;
			foreach (string path in array)
			{
				string fileName = Path.GetFileName(path);
				CreatureManager.Read(fileName);
				num++;
			}
			MonsterDBPlugin.MonsterDBLogger.LogDebug((object)$"Registered {num} creature directories");
		}

		private static void ReadCloneDirectory()
		{
			int num = 0;
			string[] directories = Directory.GetDirectories(CreatureManager.m_cloneFolderPath);
			string[] array = directories;
			foreach (string path in array)
			{
				string fileName = Path.GetFileName(path);
				CreatureManager.Read(fileName, isClone: true);
				num++;
			}
			MonsterDBPlugin.MonsterDBLogger.LogDebug((object)$"Registered {num} cloned creature directories");
		}

		public static void ResetAll()
		{
			int num = 0;
			foreach (KeyValuePair<string, CreatureData> datum in CreatureManager.m_data)
			{
				GameObject val = DataBase.TryGetGameObject(datum.Value.m_characterData.PrefabName);
				if (!((Object)(object)val == (Object)null))
				{
					CreatureManager.Reset(val);
					num++;
				}
			}
			MonsterDBPlugin.MonsterDBLogger.LogDebug((object)$"Reset {num} creature data");
		}

		public static void RemoveAllClones()
		{
			int num = 0;
			foreach (KeyValuePair<string, GameObject> clone in CreatureManager.m_clones)
			{
				CreatureManager.Delete(clone.Value);
				num++;
			}
			CreatureManager.m_clones.Clear();
			MonsterDBPlugin.MonsterDBLogger.LogDebug((object)$"Removed {num} clones");
		}

		public static void CloneAll(bool local = false)
		{
			int num = 0;
			foreach (KeyValuePair<string, CreatureData> item in local ? CreatureManager.m_localData : CreatureManager.m_data)
			{
				CloneAllItems(item.Value);
				string clonedFrom = item.Value.m_characterData.ClonedFrom;
				if (!Utility.IsNullOrWhiteSpace(clonedFrom))
				{
					GameObject val = DataBase.TryGetGameObject(clonedFrom);
					if (!((Object)(object)val == (Object)null))
					{
						string prefabName = item.Value.m_characterData.PrefabName;
						CreatureManager.Clone(val, prefabName, saveToDisk: false, cloneAttacks: false);
						num++;
					}
				}
			}
			MonsterDBPlugin.MonsterDBLogger.LogDebug((object)$"Cloned {num} creatures");
		}

		[<280c4705-4a7b-4139-8a59-78254fb4951c>NullableContext(1)]
		private static void CloneAllItems(CreatureData data)
		{
			CloneItems(data.m_defaultItems);
			CloneItems(data.m_randomWeapons);
			CloneItems(data.m_randomShields);
			CloneItems(data.m_randomArmors);
			foreach (RandomItemSetsData randomSet in data.m_randomSets)
			{
				CloneItems(randomSet.m_items);
			}
		}

		[<280c4705-4a7b-4139-8a59-78254fb4951c>NullableContext(1)]
		private static void CloneItems(List<ItemAttackData> data)
		{
			foreach (ItemAttackData datum in data)
			{
				if (!Utility.IsNullOrWhiteSpace(datum.m_attackData.OriginalPrefab))
				{
					GameObject val = DataBase.TryGetGameObject(datum.m_attackData.OriginalPrefab);
					if (!((Object)(object)val == (Object)null))
					{
						ItemDataMethods.Clone(val, datum.m_attackData.Name, write: false);
					}
				}
			}
		}

		public static void UpdateAll(bool local = false)
		{
			if (!Object.op_Implicit((Object)(object)ZNetScene.instance) || !Object.op_Implicit((Object)(object)ObjectDB.instance))
			{
				return;
			}
			int num = 0;
			foreach (KeyValuePair<string, CreatureData> item in local ? CreatureManager.m_localData : CreatureManager.m_data)
			{
				GameObject val = DataBase.TryGetGameObject(item.Value.m_characterData.PrefabName);
				if (!((Object)(object)val == (Object)null))
				{
					CreatureManager.Update(val, local);
					num++;
				}
			}
			MonsterDBPlugin.MonsterDBLogger.LogDebug((object)$"Updated {num} creatures");
		}

		static Initialization()
		{
			string folderPath = CreatureManager.m_folderPath;
			char directorySeparatorChar = Path.DirectorySeparatorChar;
			m_statusEffectsPath = folderPath + directorySeparatorChar + "StatusEffects.txt";
		}
	}
	[<391b7e1c-21ce-4cd7-b9cc-6b18bf5eb6e4>Nullable(0)]
	[<280c4705-4a7b-4139-8a59-78254fb4951c>NullableContext(1)]
	public static class SpawnMan
	{
		[<280c4705-4a7b-4139-8a59-78254fb4951c>NullableContext(0)]
		[HarmonyPatch(typeof(SpawnSystem), "Awake")]
		private static class SpawnSystem_Awake_Patch
		{
			[<280c4705-4a7b-4139-8a59-78254fb4951c>NullableContext(1)]
			private static void Postfix(SpawnSystem __instance)
			{
				if (Object.op_Implicit((Object)(object)__instance) && !__instance.m_spawnLists.Contains(m_spawnSystemList))
				{
					__instance.m_spawnLists.Add(m_spawnSystemList);
				}
			}
		}

		[<280c4705-4a7b-4139-8a59-78254fb4951c>NullableContext(0)]
		[HarmonyPatch(typeof(ZNet), "Awake")]
		private static class ZNet_Awake_Patch
		{
			private static void Postfix()
			{
				UpdateServerFiles();
			}
		}

		[<391b7e1c-21ce-4cd7-b9cc-6b18bf5eb6e4>Nullable(0)]
		private class CreatureSpawnData
		{
			public string m_name = "";

			public bool m_enabled = false;

			public bool m_devDisabled;

			public string m_prefab = null;

			public string m_biome = null;

			public string m_biomeArea = "Everything";

			public int m_maxSpawned = 1;

			public float m_spawnInterval = 4f;

			public float m_spawnChance = 100f;

			public float m_spawnDistance = 10f;

			public float m_spawnRadiusMin;

			public float m_spawnRadiusMax;

			public string m_requiredGlobalKey = "";

			public List<string> m_requiredEnvironments = new List<string>();

			public int m_groupSizeMin = 1;

			public int m_groupSizeMax = 1;

			public float m_groupRadius = 3f;

			public bool m_spawnAtNight = true;

			public bool m_spawnAtDay = true;

			public float m_minAltitude = -1000f;

			public float m_maxAltitude = 1000f;

			public float m_minTilt;

			public float m_maxTilt = 35f;

			public bool m_inForest = true;

			public bool m_outsideForest = true;

			public bool m_inLava;

			public bool m_outsideLava = true;

			public bool m_canSpawnCloseToPlayer;

			public bool m_insidePlayerBase;

			public float m_minOceanDepth;

			public float m_maxOceanDepth;

			public bool m_huntPlayer;

			public float m_groundOffset = 0.5f;

			public float m_groundOffsetRandom;

			public int m_maxLevel = 1;

			public int m_minLevel = 1;

			public float m_levelUpMinCenterDistance;

			public float m_overrideLevelupChance = -1f;

			public bool m_foldout;
		}

		private static readonly CustomSyncedValue<string> ServerSpawnSystem = new CustomSyncedValue<string>(MonsterDBPlugin.ConfigSync, "MonsterDB_SpawnSystemData", "");

		private static readonly string m_spawnFolderPath;

		private static readonly string m_referenceFolderPath;

		private static SpawnSystemList m_spawnSystemList;

		private static Dictionary<string, CreatureSpawnData> m_spawnData;

		public static void Setup()
		{
			m_spawnSystemList = MonsterDBPlugin.m_root.AddComponent<SpawnSystemList>();
			ReadSpawnFiles();
			string spawnFolderPath = m_spawnFolderPath;
			char directorySeparatorChar = Path.DirectorySeparatorChar;
			string path = spawnFolderPath + directorySeparatorChar + "Example.yml";
			if (!File.Exists(path))
			{
				CreatureSpawnData graph = new CreatureSpawnData();
				ISerializer serializer = new SerializerBuilder().Build();
				string contents = serializer.Serialize(graph);
				File.WriteAllText(path, contents);
			}
			ServerSpawnSystem.ValueChanged += delegate
			{
				if (Object.op_Implicit((Object)(object)ZNet.instance) && !ZNet.instance.IsServer())
				{
					UpdateSpawnData();
				}
			};
			SetupFileWatch();
			if (!Directory.Exists(CreatureManager.m_folderPath))
			{
				Directory.CreateDirectory(CreatureManager.m_folderPath);
			}
			if (!Directory.Exists(m_spawnFolderPath))
			{
				Directory.CreateDirectory(m_spawnFolderPath);
			}
		}

		private static void SetupFileWatch()
		{
			FileSystemWatcher fileSystemWatcher = new FileSystemWatcher(m_spawnFolderPath, "*.yml")
			{
				EnableRaisingEvents = true,
				IncludeSubdirectories = false,
				SynchronizingObject = ThreadingHelper.SynchronizingObject,
				NotifyFilter = NotifyFilters.LastWrite
			};
			fileSystemWatcher.Created += OnSpawnChange;
			fileSystemWatcher.Deleted += OnSpawnChange;
			fileSystemWatcher.Changed += OnSpawnChange;
		}

		private static void OnSpawnChange(object sender, FileSystemEventArgs e)
		{
			if (Object.op_Implicit((Object)(object)ZNet.instance) && ZNet.instance.IsServer())
			{
				string fileName = Path.GetFileName(e.Name);
				if (!(fileName == "Example.yml"))
				{
					MonsterDBPlugin.MonsterDBLogger.LogDebug((object)"Spawn files changed");
					ClearSpawnData();
					ReadSpawnFiles();
				}
			}
		}

		public static void ClearSpawns()
		{
			if (!((Object)(object)m_spawnSystemList == (Object)null))
			{
				m_spawnSystemList.m_spawners.Clear();
				ServerSpawnSystem.Value = "";
				ClearSpawnData();
			}
		}

		private static void ReadFile(string filePath)
		{
			try
			{
				IDeserializer deserializer = new DeserializerBuilder().Build();
				string input = File.ReadAllText(filePath);
				CreatureSpawnData creatureSpawnData = deserializer.Deserialize<CreatureSpawnData>(input);
				m_spawnData[creatureSpawnData.m_name] = creatureSpawnData;
				UpdateSpawnList();
				UpdateServerFiles();
			}
			catch
			{
				Helpers.LogParseFailure(filePath);
			}
		}

		private static void ReadSpawnFiles()
		{
			if (!Directory.Exists(m_spawnFolderPath))
			{
				Directory.CreateDirectory(m_spawnFolderPath);
			}
			string[] files = Directory.GetFiles(m_spawnFolderPath, "*.yml");
			IDeserializer deserializer = new DeserializerBuilder().Build();
			int num = 0;
			string[] array = files;
			foreach (string text in array)
			{
				string fileName = Path.GetFileName(text);
				if (!(fileName == "Example.yml"))
				{
					string input = File.ReadAllText(text);
					try
					{
						CreatureSpawnData creatureSpawnData = deserializer.Deserialize<CreatureSpawnData>(input);
						m_spawnData[creatureSpawnData.m_name] = creatureSpawnData;
						num++;
					}
					catch
					{
						Helpers.LogParseFailure(text);
					}
				}
			}
			MonsterDBPlugin.MonsterDBLogger.LogDebug((object)$"Registered {num} spawn files");
		}

		public static void UpdateSpawnData()
		{
			if (Utility.IsNullOrWhiteSpace(ServerSpawnSystem.Value))
			{
				return;
			}
			try
			{
				IDeserializer deserializer = new DeserializerBuilder().Build();
				Dictionary<string, CreatureSpawnData> dictionary = deserializer.Deserialize<Dictionary<string, CreatureSpawnData>>(ServerSpawnSystem.Value);
				ClearSpawnData();
				AddSpawnData(dictionary);
				UpdateSpawnList();
				MonsterDBPlugin.MonsterDBLogger.LogDebug((object)$"Loaded {dictionary.Count} spawn files");
			}
			catch
			{
				MonsterDBPlugin.MonsterDBLogger.LogDebug((object)"Failed to parse server spawn files");
			}
		}

		private static void ClearSpawnData()
		{
			m_spawnData.Clear();
		}

		private static void AddSpawnData(Dictionary<string, CreatureSpawnData> data)
		{
			m_spawnData = data;
		}

		private static void UpdateSpawnList()
		{
			m_spawnSystemList.m_spawners = (from info in m_spawnData.Values.Select(FormatSpawnData)
				where info != null
				select info).ToList();
		}

		public static bool Write(GameObject critter)
		{
			if (!Directory.Exists(m_spawnFolderPath))
			{
				Directory.CreateDirectory(m_spawnFolderPath);
			}
			if (!Directory.Exists(m_referenceFolderPath))
			{
				Directory.CreateDirectory(m_referenceFolderPath);
			}
			CreatureSpawnData creatureSpawnData = new CreatureSpawnData();
			foreach (SpawnSystemList item in SpawnSystem.m_instances.SelectMany([<280c4705-4a7b-4139-8a59-78254fb4951c>NullableContext(0)] (SpawnSystem instance) => instance.m_spawnLists))
			{
				using IEnumerator<SpawnData> enumerator2 = item.m_spawners.Where([<280c4705-4a7b-4139-8a59-78254fb4951c>NullableContext(0)] (SpawnData stream) => (Object)(object)stream.m_prefab == (Object)(object)critter).GetEnumerator();
				if (enumerator2.MoveNext())
				{
					SpawnData current2 = enumerator2.Current;
					creatureSpawnData.m_name = current2.m_name;
					creatureSpawnData.m_enabled = current2.m_enabled;
					creatureSpawnData.m_prefab = ((Object)current2.m_prefab).name;
					creatureSpawnData.m_biome = ((object)(Biome)(ref current2.m_biome)).ToString();
					creatureSpawnData.m_biomeArea = ((object)(BiomeArea)(ref current2.m_biomeArea)).ToString();
					creatureSpawnData.m_maxSpawned = current2.m_maxSpawned;
					creatureSpawnData.m_spawnInterval = current2.m_spawnInterval;
					creatureSpawnData.m_spawnChance = current2.m_spawnChance;
					creatureSpawnData.m_spawnDistance = current2.m_spawnDistance;
					creatureSpawnData.m_spawnRadiusMin = current2.m_spawnRadiusMin;
					creatureSpawnData.m_spawnRadiusMax = current2.m_spawnRadiusMax;
					creatureSpawnData.m_requiredGlobalKey = current2.m_requiredGlobalKey;
					creatureSpawnData.m_requiredEnvironments = current2.m_requiredEnvironments;
					creatureSpawnData.m_groupSizeMin = current2.m_groupSizeMin;
					creatureSpawnData.m_groupSizeMax = current2.m_groupSizeMax;
					creatureSpawnData.m_groupRadius = current2.m_groupRadius;
					creatureSpawnData.m_spawnAtNight = current2.m_spawnAtNight;
					creatureSpawnData.m_spawnAtDay = current2.m_spawnAtDay;
					creatureSpawnData.m_minAltitude = current2.m_minAltitude;
					creatureSpawnData.m_maxAltitude = current2.m_maxAltitude;
					creatureSpawnData.m_minTilt = current2.m_minTilt;
					creatureSpawnData.m_maxTilt = current2.m_maxTilt;
					creatureSpawnData.m_inForest = current2.m_inForest;
					creatureSpawnData.m_outsideForest = current2.m_outsideForest;
					creatureSpawnData.m_inLava = current2.m_inLava;
					creatureSpawnData.m_outsideLava = current2.m_outsideLava;
					creatureSpawnData.m_canSpawnCloseToPlayer = current2.m_canSpawnCloseToPlayer;
					creatureSpawnData.m_insidePlayerBase = current2.m_insidePlayerBase;
					creatureSpawnData.m_minOceanDepth = current2.m_minOceanDepth;
					creatureSpawnData.m_maxOceanDepth = current2.m_maxOceanDepth;
					creatureSpawnData.m_huntPlayer = current2.m_huntPlayer;
					creatureSpawnData.m_groundOffset = current2.m_groundOffset;
					creatureSpawnData.m_groundOffsetRandom = current2.m_groundOffsetRandom;
					creatureSpawnData.m_maxLevel = current2.m_maxLevel;
					creatureSpawnData.m_minLevel = current2.m_minLevel;
					creatureSpawnData.m_levelUpMinCenterDistance = current2.m_levelUpMinCenterDistance;
					creatureSpawnData.m_overrideLevelupChance = current2.m_overrideLevelupChance;
					creatureSpawnData.m_foldout = current2.m_foldout;
				}
			}
			if (Utility.IsNullOrWhiteSpace(creatureSpawnData.m_prefab))
			{
				return false;
			}
			string text = creatureSpawnData.m_prefab + ".yml";
			string referenceFolderPath = m_referenceFolderPath;
			char directorySeparatorChar = Path.DirectorySeparatorChar;
			string path = referenceFolderPath + directorySeparatorChar + text;
			ISerializer serializer = new SerializerBuilder().Build();
			string contents = serializer.Serialize(creatureSpawnData);
			File.WriteAllText(path, contents);
			return true;
		}

		[return: <391b7e1c-21ce-4cd7-b9cc-6b18bf5eb6e4>Nullable(2)]
		private static SpawnData FormatSpawnData(CreatureSpawnData input)
		{
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: 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_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: 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_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might b