Decompiled source of BlackMagicAPI v3.0.1

BepInEx/plugins/BlackMagicAPI/BlackMagicAPI.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Cryptography;
using System.Security.Permissions;
using System.Text;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Logging;
using BlackMagicAPI.Enums;
using BlackMagicAPI.Helpers;
using BlackMagicAPI.Interfaces;
using BlackMagicAPI.Managers;
using BlackMagicAPI.Modules.Items;
using BlackMagicAPI.Modules.Soups;
using BlackMagicAPI.Modules.Spells;
using BlackMagicAPI.Network;
using BlackMagicAPI.Patches.Items;
using BlackMagicAPI.Patches.Managers;
using BlackMagicAPI.Patches.Player;
using FishNet.Connection;
using FishNet.Managing;
using FishNet.Object;
using FishNet.Object.Delegating;
using FishNet.Serializing;
using FishNet.Transporting;
using FishUtilities.Helpers;
using FishUtilities.Managers;
using HarmonyLib;
using MageArena_StealthSpells;
using Microsoft.CodeAnalysis;
using Recognissimo;
using Recognissimo.Components;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: IgnoresAccessChecksTo("BepInEx")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("BlackMagicAPI")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("3.0.0.0")]
[assembly: AssemblyInformationalVersion("3.0.0.0+8a171c82f858d41b35cd37867533ab58c4465dac")]
[assembly: AssemblyProduct("BlackMagicAPI")]
[assembly: AssemblyTitle("BlackMagicAPI")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("3.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

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

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace BlackMagicAPI
{
	[BepInProcess("MageArena")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInPlugin("com.d1gq.black.magic.api", "BlackMagicAPI", "3.0.1")]
	public class BMAPlugin : BaseUnityPlugin
	{
		private static Harmony? Harmony;

		private ManualLogSource? _log;

		public static string modsync = "all";

		internal static BMAPlugin Instance
		{
			get; [param: AllowNull]
			private set;
		}

		internal static ManualLogSource Log => Instance._log;

		public static string BlackMagicSyncHash { get; internal set; } = "";


		private void Awake()
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			_log = ((BaseUnityPlugin)this).Logger;
			Instance = this;
			Harmony = new Harmony("com.d1gq.black.magic.api");
			Harmony.PatchAll();
			Log.LogInfo((object)string.Format("BlackMagicAPI v{0} loaded, (Compatibility -> v{1})", "3.0.1", CompatibilityManager.COMPATIBILITY_VERSION));
			SynchronizeManager.UpdateSyncHash();
			((MonoBehaviour)this).StartCoroutine(CoWaitForChainloaderToLog());
		}

		private IEnumerator CoWaitForChainloaderToLog()
		{
			while (!Chainloader._loaded && !SplashScreen.isFinished)
			{
				yield return null;
			}
			yield return (object)new WaitForSeconds(1f);
			ModSyncManager.LogAll();
		}
	}
	internal static class ModMetaData
	{
		internal const string GUID = "com.d1gq.black.magic.api";

		internal const string PLUGIN_NAME = "BlackMagicAPI";

		internal const string VERSION = "3.0.1";

		internal const string MOD_SYNC_GUID_DEP = "com.magearena.modsync";

		internal const string FISH_UTILITIES_GUID_DEP = "com.d1gq.fish.utilities";
	}
}
namespace BlackMagicAPI.Patches.Soups
{
	[Harmony]
	internal class SoupManPatch
	{
		[HarmonyPatch(typeof(SoupManController))]
		internal class SoupManControllerPatch
		{
			private static readonly ConditionalWeakTable<SoupManController, List<int>> usedIds = new ConditionalWeakTable<SoupManController, List<int>>();

			[HarmonyPatch("Start")]
			[HarmonyPostfix]
			[HarmonyPriority(800)]
			private static void Start_Postfix(SoupManController __instance)
			{
				if (!usedIds.TryGetValue(__instance, out List<int> value))
				{
					value = new List<int>();
					usedIds.Add(__instance, value);
				}
				else
				{
					value.Clear();
				}
				List<GameObject> list = __instance.SoupPrefabs.ToList();
				List<GameObject> list2 = __instance.SoupItems.ToList();
				List<Material> list3 = __instance.matas.ToList();
				int num = __instance.SoupPrefabs.Length + 1;
				list.Add(null);
				list2.Add(null);
				list3.Add(null);
				foreach (var item2 in SoupManager.Mapping.OrderBy<(SoupData, CrystalSoup, GameObject, SoupEffect), int>(((SoupData data, CrystalSoup itemPrefab, GameObject render, SoupEffect effect) m) => m.data.ItemId))
				{
					if (value.Contains(item2.Item1.RequiredItemId))
					{
						item2.Item1.SoupId = -1;
						item2.Item2.stewid = -1;
						continue;
					}
					value.Add(item2.Item1.RequiredItemId);
					item2.Item1.SoupId = num;
					item2.Item2.stewid = num;
					list.Add(((Component)item2.Item2).gameObject);
					list3.Add(((Renderer)item2.Item2.mrend).materials[1]);
					GameObject item = CreateItemDisplay(__instance, item2.Item3);
					list2.Add(item);
					num++;
				}
				SoupManController val = __instance;
				int num2 = 0;
				GameObject[] array = (GameObject[])(object)new GameObject[list.Count];
				foreach (GameObject item3 in list)
				{
					array[num2] = item3;
					num2++;
				}
				val.SoupPrefabs = array;
				val = __instance;
				num2 = 0;
				array = (GameObject[])(object)new GameObject[list2.Count];
				foreach (GameObject item4 in list2)
				{
					array[num2] = item4;
					num2++;
				}
				val.SoupItems = array;
				val = __instance;
				num2 = 0;
				Material[] array2 = (Material[])(object)new Material[list3.Count];
				foreach (Material item5 in list3)
				{
					array2[num2] = item5;
					num2++;
				}
				val.matas = array2;
			}

			private static GameObject CreateItemDisplay(SoupManController __instance, GameObject? render)
			{
				//IL_0008: Unknown result type (might be due to invalid IL or missing references)
				//IL_000f: Expected O, but got Unknown
				if (render == null)
				{
					render = new GameObject("Render");
				}
				GameObject obj = Object.Instantiate<GameObject>(render, __instance.SoupItems.First().transform.parent);
				obj.SetActive(false);
				return obj;
			}
		}

		[HarmonyPatch(typeof(SoupManInteractor))]
		internal class SoupManInteractorPatch
		{
			[HarmonyPatch("DisplayInteractUI")]
			[HarmonyPrefix]
			[HarmonyPriority(800)]
			private static bool DisplayInteractUI_Prefix(SoupManInteractor __instance, GameObject player, ref string __result)
			{
				PlayerInventory val = default(PlayerInventory);
				if (player.TryGetComponent<PlayerInventory>(ref val) && !__instance.smc.isCookingSoup)
				{
					int equippedItemID = val.GetEquippedItemID();
					(SoupData, CrystalSoup, GameObject, SoupEffect) tuple = SoupManager.Mapping.FirstOrDefault<(SoupData, CrystalSoup, GameObject, SoupEffect)>(((SoupData data, CrystalSoup itemPrefab, GameObject render, SoupEffect effect) map) => map.data.RequiredItemId == equippedItemID);
					var (soupData, val2, val3, soupEffect) = tuple;
					if (soupData != null || (Object)(object)val2 != (Object)null || (Object)(object)val3 != (Object)null || (Object)(object)soupEffect != (Object)null)
					{
						__result = "Make " + tuple.Item1.Name;
						return false;
					}
				}
				return true;
			}

			[HarmonyPatch("Interact")]
			[HarmonyPrefix]
			[HarmonyPriority(800)]
			private static bool Interact_Prefix(SoupManInteractor __instance, GameObject player)
			{
				if (Time.time - __instance.cd < 1f)
				{
					return true;
				}
				PlayerInventory val = default(PlayerInventory);
				if (player.TryGetComponent<PlayerInventory>(ref val) && !__instance.smc.isCookingSoup)
				{
					int equippedItemID = val.GetEquippedItemID();
					(SoupData, CrystalSoup, GameObject, SoupEffect) tuple = SoupManager.Mapping.FirstOrDefault<(SoupData, CrystalSoup, GameObject, SoupEffect)>(((SoupData data, CrystalSoup itemPrefab, GameObject render, SoupEffect effect) map) => map.data.RequiredItemId == equippedItemID);
					var (soupData, val2, val3, soupEffect) = tuple;
					if (soupData != null || (Object)(object)val2 != (Object)null || (Object)(object)val3 != (Object)null || (Object)(object)soupEffect != (Object)null)
					{
						__instance.smc.CookSoup(tuple.Item1.SoupId);
						val.destroyHandItem();
						return false;
					}
				}
				return true;
			}
		}

		[HarmonyPatch(typeof(GetSoupFromGuy))]
		internal class GetSoupFromGuyPatch
		{
			[HarmonyPatch("DisplayInteractUI")]
			[HarmonyPrefix]
			[HarmonyPriority(800)]
			private static bool DisplayInteractUI_Prefix(GetSoupFromGuy __instance, GameObject player, ref string __result)
			{
				GetSoupFromGuy __instance2 = __instance;
				(SoupData, CrystalSoup, GameObject, SoupEffect) tuple = SoupManager.Mapping.FirstOrDefault<(SoupData, CrystalSoup, GameObject, SoupEffect)>(((SoupData data, CrystalSoup itemPrefab, GameObject render, SoupEffect effect) map) => map.data.SoupId == __instance2.soupid);
				var (soupData, val, val2, soupEffect) = tuple;
				if (soupData != null || (Object)(object)val != (Object)null || (Object)(object)val2 != (Object)null || (Object)(object)soupEffect != (Object)null)
				{
					__result = "Grasp " + tuple.Item1.Name;
					return false;
				}
				return true;
			}
		}
	}
}
namespace BlackMagicAPI.Patches.Player
{
	[HarmonyPatch(typeof(PlayerInventory))]
	internal class PlayerInventoryPatch
	{
		[HarmonyPatch]
		private static class PlaceOnCraftingTablePatch
		{
			private static MethodBase TargetMethod()
			{
				return Utils.PatchRpcMethod<PlayerInventory>("RpcLogic___PlaceOnCraftingTableObserver");
			}

			[HarmonyPostfix]
			[HarmonyPriority(800)]
			private static void Postfix(GameObject obj, GameObject CrIn)
			{
				ItemBehavior itemBehavior = default(ItemBehavior);
				if (obj.TryGetComponent<ItemBehavior>(ref itemBehavior))
				{
					itemBehavior.SetTransformOnCraftingForge();
				}
			}
		}

		private static readonly Dictionary<int, Sprite?> UiSprites = new Dictionary<int, Sprite>();

		[HarmonyPatch("SwapItemImg")]
		[HarmonyPrefix]
		[HarmonyPriority(800)]
		private static bool SwapItemImg_Prefix(PlayerInventory __instance, int slotid, int itemid)
		{
			if (itemid > __instance.ItemIcons.Length && UiSprites.TryGetValue(itemid, out Sprite value))
			{
				((Component)((Component)__instance.UIImages[slotid]).transform.GetChild(0)).GetComponent<Image>().sprite = value;
				return false;
			}
			return true;
		}

		internal static void SetUiSprite(Sprite? sprite, int itemId)
		{
			if (!((Object)(object)sprite == (Object)null))
			{
				UiSprites[itemId] = sprite;
			}
		}

		[HarmonyPatch(typeof(PlayerInventory), "PlayerDied")]
		[HarmonyPrefix]
		[HarmonyPriority(800)]
		private static bool PlayerDied_Prefix(PlayerInventory __instance)
		{
			__instance.canUseItem = false;
			__instance.canSwapItem = false;
			bool flag = false;
			int equippedIndex = __instance.equippedIndex;
			__instance.equippedIndex = 0;
			int[] array = new int[3];
			MageBookController? itemPrefab = BlackMagicManager.GetItemPrefab<MageBookController>();
			array[0] = ((itemPrefab != null) ? itemPrefab.GetItemID() : (-1));
			TorchController? itemPrefab2 = BlackMagicManager.GetItemPrefab<TorchController>();
			array[1] = ((itemPrefab2 != null) ? itemPrefab2.GetItemID() : (-1));
			ExcaliburController? itemPrefab3 = BlackMagicManager.GetItemPrefab<ExcaliburController>();
			array[2] = ((itemPrefab3 != null) ? ((SwordController)itemPrefab3).GetItemID() : (-1));
			int[] array2 = array;
			ItemBehavior itemBehavior = default(ItemBehavior);
			PageController val2 = default(PageController);
			SpellLogic spellLogic = default(SpellLogic);
			IItemInteraction val3 = default(IItemInteraction);
			for (int i = 0; i < __instance.equippedItems.Length; i++)
			{
				GameObject val = __instance.equippedItems[i];
				if ((Object)(object)val == (Object)null)
				{
					__instance.equippedIndex++;
					continue;
				}
				if (val.TryGetComponent<ItemBehavior>(ref itemBehavior) && itemBehavior.KeepOnDeath)
				{
					__instance.equippedIndex++;
					continue;
				}
				if (val.TryGetComponent<PageController>(ref val2) && (Object)(object)val2.spellprefab != (Object)null && val2.spellprefab.TryGetComponent<SpellLogic>(ref spellLogic) && spellLogic.KeepOnDeath)
				{
					__instance.equippedIndex++;
					continue;
				}
				if (val.TryGetComponent<IItemInteraction>(ref val3))
				{
					int itemID = val3.GetItemID();
					if (!flag)
					{
						flag = itemID == array2[0];
					}
					if (array2.Contains(itemID))
					{
						__instance.equippedIndex++;
						continue;
					}
				}
				__instance.Drop();
				__instance.equippedIndex++;
			}
			__instance.equippedIndex = equippedIndex;
			__instance.LayerMaskSwapZero();
			GameObject val4 = __instance.equippedItems[__instance.equippedIndex];
			if ((Object)(object)val4 != (Object)null)
			{
				__instance.HideObject(val4);
			}
			if (!flag)
			{
				((MonoBehaviour)__instance).StartCoroutine(__instance.DelaySpellbookRespawn());
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(PlayerMovement))]
	internal class PlayerMovementPatch
	{
		[HarmonyPatch]
		private static class ObsDrinkSoupPatch
		{
			private static MethodBase TargetMethod()
			{
				return Utils.PatchRpcMethod<PlayerMovement>("RpcLogic___ObsDrinkSoup");
			}

			[HarmonyPrefix]
			[HarmonyPriority(800)]
			private static bool Prefix(PlayerMovement __instance, int stewid)
			{
				(SoupData, CrystalSoup, GameObject, SoupEffect) tuple = SoupManager.Mapping.FirstOrDefault<(SoupData, CrystalSoup, GameObject, SoupEffect)>(((SoupData data, CrystalSoup itemPrefab, GameObject render, SoupEffect effect) map) => map.data.SoupId == stewid);
				var (soupData, val, val2, soupEffect) = tuple;
				if (soupData != null || (Object)(object)val != (Object)null || (Object)(object)val2 != (Object)null || (Object)(object)soupEffect != (Object)null)
				{
					((Component)Camera.main).GetComponent<PlayerInteract>().leveluptxt(tuple.Item1.ConsumeDescription);
					SoupEffect soupEffect2 = Object.Instantiate<SoupEffect>(tuple.Item4);
					((Component)soupEffect2).gameObject.SetActive(true);
					soupEffect2.ApplyEffect(__instance);
					return false;
				}
				return true;
			}
		}
	}
}
namespace BlackMagicAPI.Patches.Managers
{
	[HarmonyPatch(typeof(ColoseumManager))]
	internal class ColoseumManagerPatch
	{
		[HarmonyPatch("OnStartClient")]
		[HarmonyPrefix]
		[HarmonyPriority(800)]
		private static void OnStartClient_Prefix(ColoseumManager __instance)
		{
			foreach (var (spellData, val) in SpellManager.Mapping)
			{
				if (spellData.CanSpawnInColoseum)
				{
					__instance.LootTable.Add(((Component)val).gameObject);
				}
			}
			foreach (var (itemData, itemBehavior) in ItemManager.Mapping.OrderBy<(ItemData, ItemBehavior), int>(((ItemData data, ItemBehavior behavior) map) => map.data.Id))
			{
				if (itemData.CanSpawnInColoseum)
				{
					__instance.LootTable.Add(((Component)itemBehavior).gameObject);
				}
			}
		}
	}
	[HarmonyPatch(typeof(DuendeManager))]
	internal class DuendeManagerPatch
	{
		[HarmonyPatch]
		private static class ServerCreatePagePatch
		{
			private static MethodBase TargetMethod()
			{
				return Utils.PatchRpcMethod<DuendeManager>("RpcLogic___ServerCreatePage");
			}

			[HarmonyPrefix]
			[HarmonyPriority(800)]
			private static void Prefix(DuendeManager __instance, [HarmonyArgument(1)] ref int rand)
			{
				for (int i = 0; i < __instance.plt.Pages.Length; i++)
				{
					GameObject val = __instance.plt.Pages[i];
					if (!((Object)(object)val == (Object)null))
					{
						PageController component = val.GetComponent<PageController>();
						int num;
						if (component == null)
						{
							PipeItem component2 = val.GetComponent<PipeItem>();
							num = ((component2 != null) ? component2.GetItemID() : 0);
						}
						else
						{
							num = component.ItemID;
						}
						if (num == rand)
						{
							rand = i;
							return;
						}
					}
				}
				rand = 0;
			}
		}

		[HarmonyPatch("Awake")]
		[HarmonyPrefix]
		[HarmonyPriority(800)]
		private static void Awake_Prefix(DuendeManager __instance)
		{
			List<GameObject> list = __instance.DuendeTradeItems.ToList();
			foreach (var item in ItemManager.Mapping.OrderBy<(ItemData, ItemBehavior), int>(((ItemData data, ItemBehavior behavior) m) => m.data.Id))
			{
				if (item.Item1.CanGetFromTrade)
				{
					list.Add(((Component)item.Item2).gameObject);
				}
			}
			int num = 0;
			GameObject[] array = (GameObject[])(object)new GameObject[list.Count];
			foreach (GameObject item2 in list)
			{
				array[num] = item2;
				num++;
			}
			__instance.DuendeTradeItems = array;
		}

		[HarmonyPatch("ServerCreatePage")]
		[HarmonyPrefix]
		[HarmonyPriority(800)]
		private static void ServerCreatePage_Prefix(DuendeManager __instance, ref int rand)
		{
			PageController component = __instance.plt.Pages[rand].GetComponent<PageController>();
			int num;
			if (component == null)
			{
				PipeItem component2 = __instance.plt.Pages[rand].GetComponent<PipeItem>();
				num = ((component2 != null) ? component2.GetItemID() : 0);
			}
			else
			{
				num = component.ItemID;
			}
			rand = num;
		}
	}
	[HarmonyPatch(typeof(MainMenuManagerNetworked))]
	internal class MainMenuManagerNetworkedPatch
	{
		[HarmonyPatch("Start")]
		[HarmonyPrefix]
		[HarmonyPriority(800)]
		private static void Start_Prefix(MainMenuManagerNetworked __instance)
		{
			foreach (SpellData item in SpellManager.Mapping.Select<(SpellData, PageController), SpellData>(((SpellData data, PageController page) value) => value.data))
			{
				AddSpellCommand(__instance, item, item.Name);
				string[] subNames = item.SubNames;
				foreach (string name in subNames)
				{
					AddSpellCommand(__instance, item, name);
				}
			}
		}

		private static void AddSpellCommand(MainMenuManagerNetworked __instance, SpellData spellData, string name)
		{
			CustomSpellCommand customSpellCommand = ComponentHolderProtocol.AddComponent<CustomSpellCommand>((Object)(object)__instance);
			((Behaviour)customSpellCommand).enabled = true;
			customSpellCommand.SpellData = spellData;
			customSpellCommand.SpellName = name;
		}
	}
	[HarmonyPatch(typeof(MainMenuManager))]
	internal class MainMenuManagerPatch
	{
		private static string Hash = "";

		private static Text? text;

		[HarmonyPatch("Start")]
		[HarmonyPostfix]
		[HarmonyPriority(800)]
		private static void Start_Postfix()
		{
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			GameObject? obj = Utils.FindInactive("Canvas (1)/Main/AccentMenu/Text (Legacy) (3)/Text (Legacy) (6)");
			text = Object.Instantiate<Text>((obj != null) ? obj.GetComponent<Text>() : null);
			if ((Object)(object)text != (Object)null)
			{
				Transform transform = ((Component)text).transform;
				GameObject? obj2 = Utils.FindInactive("Canvas (1)/Main/AccentMenu/Text (Legacy) (3)");
				transform.SetParent((obj2 != null) ? obj2.transform : null);
				((Component)text).transform.position = new Vector3(1821f, 90f, 0f);
				text.text = Hash;
			}
		}

		internal static void UpdateHash(string hash)
		{
			Hash = hash;
			if ((Object)(object)text != (Object)null)
			{
				text.text = Hash;
			}
		}
	}
	[HarmonyPatch(typeof(PlayerRespawnManager))]
	internal class PlayerRespawnManagerPatch
	{
		private static List<(string reason, Texture2D icon)> DeathIcons = new List<(string, Texture2D)>();

		[HarmonyPatch("OnStartClient")]
		[HarmonyPostfix]
		[HarmonyPriority(800)]
		private static void OnStartClient_Postfix(PlayerRespawnManager __instance)
		{
			foreach (var deathIcon in DeathIcons)
			{
				if (!((Object)(object)deathIcon.icon == (Object)null))
				{
					__instance.dethicons.Add(deathIcon.reason, deathIcon.icon);
				}
			}
		}

		internal static bool AddDeathIcon(BaseUnityPlugin baseUnity, string deathReason, Texture2D deathIcon)
		{
			string deathReason2 = deathReason;
			if (DeathIcons.Any<(string, Texture2D)>(((string reason, Texture2D icon) data) => data.reason == deathReason2))
			{
				BMAPlugin.Log.LogError((object)("Failed to register " + deathReason2 + " Death Icon from " + baseUnity.Info.Metadata.Name + ": Unable to register the same DeathReason twice!"));
				return false;
			}
			DeathIcons.Add((deathReason2, deathIcon));
			return true;
		}
	}
}
namespace BlackMagicAPI.Patches.Items
{
	[HarmonyPatch(typeof(ChestNetController1))]
	internal class ChestNetController1Patch
	{
		[HarmonyPatch]
		private static class ServerPlaceItemPatch
		{
			private static MethodBase TargetMethod()
			{
				return Utils.PatchRpcMethod<ChestNetController1>("RpcLogic___ServerPlaceItem");
			}

			[HarmonyPrefix]
			[HarmonyPriority(800)]
			private static void Prefix(ChestNetController1 __instance, ref int itemid)
			{
				for (int i = 0; i < __instance.plt.Pages.Length; i++)
				{
					GameObject val = __instance.plt.Pages[i];
					if (!((Object)(object)val == (Object)null))
					{
						PageController component = val.GetComponent<PageController>();
						int num;
						if (component == null)
						{
							PipeItem component2 = val.GetComponent<PipeItem>();
							num = ((component2 != null) ? component2.GetItemID() : 0);
						}
						else
						{
							num = component.ItemID;
						}
						if (num == itemid)
						{
							itemid = i;
							return;
						}
					}
				}
				itemid = 0;
			}
		}

		[HarmonyPatch("PlaceItemIn")]
		[HarmonyPrefix]
		[HarmonyPriority(800)]
		private static void PlaceItemIn_Prefix(ChestNetController1 __instance, ref int itemid)
		{
			PageController component = __instance.plt.Pages[itemid].GetComponent<PageController>();
			int num;
			if (component == null)
			{
				PipeItem component2 = __instance.plt.Pages[itemid].GetComponent<PipeItem>();
				num = ((component2 != null) ? component2.GetItemID() : 0);
			}
			else
			{
				num = component.ItemID;
			}
			itemid = num;
		}
	}
	[HarmonyPatch(typeof(CraftingForge))]
	internal class CraftingForgePatch
	{
		[HarmonyPatch]
		private static class ServerCraftPatch
		{
			private static MethodBase TargetMethod()
			{
				return Utils.PatchRpcMethod<CraftingForge>("RpcLogic___ServerCraft");
			}

			[HarmonyPrefix]
			[HarmonyPriority(800)]
			private static bool Prefix(CraftingForge __instance)
			{
				//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
				//IL_00db: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)__instance.SlotItems[0] == (Object)null || (Object)(object)__instance.SlotItems[1] == (Object)null)
				{
					return true;
				}
				IItemInteraction component = __instance.SlotItems[0].GetComponent<IItemInteraction>();
				IItemInteraction component2 = __instance.SlotItems[1].GetComponent<IItemInteraction>();
				if (component != null && component2 != null && TryGetRecipeByIDs(component.GetItemID(), component2.GetItemID(), out GameObject result) && (Object)(object)result != (Object)null)
				{
					__instance.makepoof();
					((NetworkBehaviour)__instance).ServerManager.Despawn(__instance.SlotItems[0], (DespawnType?)null);
					((NetworkBehaviour)__instance).ServerManager.Despawn(__instance.SlotItems[1], (DespawnType?)null);
					GameObject val = Object.Instantiate<GameObject>(result);
					val.transform.position = __instance.itemSpawnPoint.position;
					((NetworkBehaviour)__instance).ServerManager.Spawn(val, (NetworkConnection)null, default(Scene));
					__instance.SlotItems[0] = null;
					__instance.SlotItems[1] = null;
					__instance.CraftCleanUp();
					__instance.craftingComplete = true;
					return false;
				}
				return true;
			}
		}

		internal static Dictionary<(IItemInteraction firstItem, IItemInteraction secondItem), GameObject> Recipes = new Dictionary<(IItemInteraction, IItemInteraction), GameObject>();

		internal static bool RegisterRecipe(GameObject firstItemPrefap, GameObject secondItemPrefap, GameObject resultPrefap)
		{
			IItemInteraction component = firstItemPrefap.GetComponent<IItemInteraction>();
			IItemInteraction component2 = secondItemPrefap.GetComponent<IItemInteraction>();
			if (!TryGetRecipeByIDs(component.GetItemID(), component2.GetItemID(), out GameObject _))
			{
				Recipes[(component, component2)] = resultPrefap;
				return true;
			}
			return false;
		}

		private static bool TryGetRecipeByIDs(int id1, int id2, out GameObject? result)
		{
			foreach (KeyValuePair<(IItemInteraction, IItemInteraction), GameObject> recipe in Recipes)
			{
				if ((recipe.Key.Item1.GetItemID() == id1 && recipe.Key.Item2.GetItemID() == id2) || (recipe.Key.Item1.GetItemID() == id2 && recipe.Key.Item2.GetItemID() == id1))
				{
					result = recipe.Value;
					return true;
				}
			}
			result = null;
			return false;
		}

		[HarmonyPatch("OnStartClient")]
		[HarmonyPostfix]
		[HarmonyPriority(800)]
		private static void OnStartClient_Postfix(CraftingForge __instance)
		{
			((MonoBehaviour)__instance).StartCoroutine(CoCustomCrafter(__instance));
		}

		private static IEnumerator CoCustomCrafter(CraftingForge __instance)
		{
			while (((Behaviour)__instance).isActiveAndEnabled)
			{
				yield return null;
				if (__instance.SlotItems != null && __instance.SlotItems.Length >= 2 && !((Object)(object)__instance.SlotItems[0] == (Object)null) && !((Object)(object)__instance.SlotItems[1] == (Object)null) && __instance.craftingComplete)
				{
					GameObject obj = __instance.SlotItems[0];
					IItemInteraction val = ((obj != null) ? obj.GetComponent<IItemInteraction>() : null);
					GameObject obj2 = __instance.SlotItems[1];
					IItemInteraction val2 = ((obj2 != null) ? obj2.GetComponent<IItemInteraction>() : null);
					if (val != null && val2 != null && TryGetRecipeByIDs(val.GetItemID(), val2.GetItemID(), out GameObject _))
					{
						__instance.craftingComplete = false;
						__instance.ServerCraft();
					}
				}
			}
		}
	}
	[HarmonyPatch(typeof(CrystalSoup))]
	internal class CrystalSoupPatch
	{
		[HarmonyPatch("DisplayInteractUI")]
		[HarmonyPrefix]
		[HarmonyPriority(800)]
		private static bool DisplayInteractUI_Prefix(CrystalSoup __instance, ref string __result)
		{
			CrystalSoup __instance2 = __instance;
			(SoupData, CrystalSoup, GameObject, SoupEffect) tuple = SoupManager.Mapping.FirstOrDefault<(SoupData, CrystalSoup, GameObject, SoupEffect)>(((SoupData data, CrystalSoup itemPrefab, GameObject render, SoupEffect effect) map) => map.data.SoupId == __instance2.stewid);
			var (soupData, val, val2, soupEffect) = tuple;
			if (soupData != null || (Object)(object)val != (Object)null || (Object)(object)val2 != (Object)null || (Object)(object)soupEffect != (Object)null)
			{
				__result = "Grasp " + tuple.Item1.Name;
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(Generator2D))]
	internal class Generator2DPatch
	{
		[HarmonyPatch]
		private static class ServerPlaceItemPatch
		{
			private static MethodBase TargetMethod()
			{
				return Utils.PatchRpcMethod<Generator2D>("RpcLogic___ServerPlaceItem");
			}

			[HarmonyPrefix]
			[HarmonyPriority(800)]
			private static void Prefix(Generator2D __instance, ref int itemid)
			{
				for (int i = 0; i < __instance.plt.Pages.Length; i++)
				{
					GameObject val = __instance.plt.Pages[i];
					if (!((Object)(object)val == (Object)null))
					{
						PageController component = val.GetComponent<PageController>();
						int num;
						if (component == null)
						{
							PipeItem component2 = val.GetComponent<PipeItem>();
							num = ((component2 != null) ? component2.GetItemID() : 0);
						}
						else
						{
							num = component.ItemID;
						}
						if (num == itemid)
						{
							itemid = i;
							return;
						}
					}
				}
				itemid = 0;
			}
		}

		[HarmonyPatch("PlaceItemIn")]
		[HarmonyPrefix]
		[HarmonyPriority(800)]
		private static void PlaceItemIn_Prefix(Generator2D __instance, ref int itemid)
		{
			PageController component = __instance.plt.Pages[itemid].GetComponent<PageController>();
			int num;
			if (component == null)
			{
				PipeItem component2 = __instance.plt.Pages[itemid].GetComponent<PipeItem>();
				num = ((component2 != null) ? component2.GetItemID() : 0);
			}
			else
			{
				num = component.ItemID;
			}
			itemid = num;
		}
	}
	[HarmonyPatch(typeof(PageController))]
	internal class PageControllerPatch
	{
		[HarmonyPatch]
		private static class RpcReaderServerCastSpellServerPatch
		{
			private static MethodBase TargetMethod()
			{
				return Utils.PatchRpcMethod<PageController>("RpcReader___Server_CastSpellServer");
			}

			[HarmonyPrefix]
			[HarmonyPriority(800)]
			private static bool Prefix(PageController __instance, PooledReader PooledReader0, Channel channel, NetworkConnection conn)
			{
				//IL_0010: Unknown result type (might be due to invalid IL or missing references)
				//IL_0015: Unknown result type (might be due to invalid IL or missing references)
				//IL_001e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0023: Unknown result type (might be due to invalid IL or missing references)
				//IL_003d: Unknown result type (might be due to invalid IL or missing references)
				//IL_003f: Unknown result type (might be due to invalid IL or missing references)
				if (IsCustomSpell(__instance))
				{
					GameObject ownerobj = ((Reader)PooledReader0).ReadGameObject();
					Vector3 fwdVector = ((Reader)PooledReader0).ReadVector3();
					int level = ((Reader)PooledReader0).ReadInt32();
					Vector3 spawnpos = ((Reader)PooledReader0).ReadVector3();
					DataWriter dataWriter = new DataWriter();
					dataWriter.ReadToBuffer(PooledReader0);
					if (((NetworkBehaviour)__instance).IsServerInitialized)
					{
						CastSpellObs_Write(__instance, ownerobj, fwdVector, level, spawnpos, dataWriter);
					}
					return false;
				}
				return true;
			}
		}

		[HarmonyPatch]
		private static class RpcReader___Observers_CastSpellObsPatch
		{
			private static MethodBase TargetMethod()
			{
				return Utils.PatchRpcMethod<PageController>("RpcReader___Observers_CastSpellObs");
			}

			[HarmonyPrefix]
			[HarmonyPriority(800)]
			private static bool Prefix(PageController __instance, PooledReader PooledReader0, Channel channel)
			{
				//IL_0010: Unknown result type (might be due to invalid IL or missing references)
				//IL_0015: Unknown result type (might be due to invalid IL or missing references)
				//IL_001e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0023: Unknown result type (might be due to invalid IL or missing references)
				//IL_002e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0030: Unknown result type (might be due to invalid IL or missing references)
				if (IsCustomSpell(__instance))
				{
					GameObject ownerobj = ((Reader)PooledReader0).ReadGameObject();
					Vector3 fwdVector = ((Reader)PooledReader0).ReadVector3();
					int level = ((Reader)PooledReader0).ReadInt32();
					Vector3 spawnpos = ((Reader)PooledReader0).ReadVector3();
					if (((NetworkBehaviour)__instance).IsClientInitialized)
					{
						CastSpellObs_Logic(__instance, ownerobj, fwdVector, level, spawnpos, PooledReader0);
					}
					return false;
				}
				return true;
			}
		}

		private static bool IsCustomSpell(PageController __instance)
		{
			return (Object)(object)__instance.spellprefab.GetComponent<SpellLogic>() != (Object)null;
		}

		private static SpellLogic GetSpellPrefab(PageController __instance)
		{
			return __instance.spellprefab.GetComponent<SpellLogic>();
		}

		[HarmonyPatch("Interaction")]
		[HarmonyPrefix]
		[HarmonyPriority(800)]
		private static void Interaction_Prefix(PageController __instance, GameObject player)
		{
			if (IsCustomSpell(__instance))
			{
				__instance.spellprefab.GetComponent<SpellLogic>()?.OnPageItemUse(player.GetComponent<PlayerMovement>(), __instance);
			}
		}

		[HarmonyPatch("CastSpellServer")]
		[HarmonyPrefix]
		[HarmonyPriority(800)]
		private static bool CastSpellServer_Prefix(PageController __instance, GameObject ownerobj, Vector3 fwdVector, int level, Vector3 spawnpos)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			if (IsCustomSpell(__instance))
			{
				if (!((NetworkBehaviour)__instance).IsClientInitialized)
				{
					NetworkManagerExtensions.LogWarning(((NetworkBehaviour)__instance).NetworkManager, "Cannot complete action because client is not active. This may also occur if the object is not yet initialized, has deinitialized, or if it does not contain a NetworkObject component.");
					return false;
				}
				Channel val = (Channel)0;
				PooledWriter val2 = WriterPool.Retrieve();
				((Writer)val2).WriteGameObject(ownerobj);
				((Writer)val2).WriteVector3(fwdVector);
				((Writer)val2).WriteInt32(level);
				((Writer)val2).WriteVector3(spawnpos);
				DataWriter dataWriter = new DataWriter();
				GetSpellPrefab(__instance).WriteData(dataWriter, __instance, ownerobj.GetComponent<PlayerMovement>(), spawnpos, fwdVector, level);
				dataWriter.WriteFromBuffer(val2);
				dataWriter.Dispose();
				((NetworkBehaviour)__instance).SendServerRpc(0u, val2, val, (DataOrderType)0);
				val2.Store();
				return false;
			}
			return true;
		}

		private static void CastSpellObs_Write(PageController __instance, GameObject ownerobj, Vector3 fwdVector, int level, Vector3 spawnpos, DataWriter dataWriter)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			if (!((NetworkBehaviour)__instance).IsServerInitialized)
			{
				NetworkManagerExtensions.LogWarning(((NetworkBehaviour)__instance).NetworkManager, "Cannot complete action because server is not active. This may also occur if the object is not yet initialized, has deinitialized, or if it does not contain a NetworkObject component.");
				return;
			}
			Channel val = (Channel)0;
			PooledWriter val2 = WriterPool.Retrieve();
			((Writer)val2).WriteGameObject(ownerobj);
			((Writer)val2).WriteVector3(fwdVector);
			((Writer)val2).WriteInt32(level);
			((Writer)val2).WriteVector3(spawnpos);
			dataWriter.WriteFromBuffer(val2);
			dataWriter.Dispose();
			((NetworkBehaviour)__instance).SendObserversRpc(1u, val2, val, (DataOrderType)0, false, false, false);
			val2.Store();
		}

		private static void CastSpellObs_Logic(PageController __instance, GameObject ownerobj, Vector3 fwdVector, int level, Vector3 spawnpos, PooledReader PooledReader0)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)ownerobj != (Object)null))
			{
				return;
			}
			GameObject obj = Object.Instantiate<GameObject>(__instance.spellprefab, spawnpos, Quaternion.identity);
			obj.SetActive(true);
			SpellLogic spellLogic = default(SpellLogic);
			if (obj.TryGetComponent<SpellLogic>(ref spellLogic))
			{
				spellLogic.IsPrefab = false;
				DataWriter dataWriter = new DataWriter();
				dataWriter.ReadToBuffer(PooledReader0);
				spellLogic.SyncData(dataWriter.GetObjectBuffer());
				dataWriter.Dispose();
				if (!spellLogic.CastSpell(ownerobj.GetComponent<PlayerMovement>(), __instance, spawnpos, fwdVector, level))
				{
					__instance.ReinstatePageEmis();
					__instance.PageCoolDownTimer = Time.time - __instance.CoolDown;
				}
			}
		}
	}
}
namespace BlackMagicAPI.Patches.Generation
{
	[HarmonyPatch(typeof(ChestNetController))]
	internal class ChestNetControllerPatch
	{
		[HarmonyPatch]
		[HarmonyPriority(800)]
		private static class PiseverPatch
		{
			private static MethodBase TargetMethod()
			{
				return Utils.PatchRpcMethod<ChestNetController>("RpcLogic___pisever");
			}

			[HarmonyPrefix]
			private static void Prefix(ChestNetController __instance)
			{
				//IL_0075: Unknown result type (might be due to invalid IL or missing references)
				//IL_0094: Unknown result type (might be due to invalid IL or missing references)
				//IL_009a: Unknown result type (might be due to invalid IL or missing references)
				//IL_014f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0164: Unknown result type (might be due to invalid IL or missing references)
				//IL_016a: Unknown result type (might be due to invalid IL or missing references)
				if (__instance.hasBeenOpened)
				{
					return;
				}
				foreach (var item in ItemManager.Mapping.OrderBy<(ItemData, ItemBehavior), int>(((ItemData data, ItemBehavior behavior) m) => m.data.Id))
				{
					if (item.Item1.DebugForceSpawn)
					{
						ItemBehavior itemBehavior = Object.Instantiate<ItemBehavior>(item.Item2);
						((Component)itemBehavior).transform.position = ((Component)__instance.ItemPoints[__instance.slotnum]).transform.position;
						itemBehavior.SetDefaultTransforms();
						((NetworkBehaviour)__instance).ServerManager.Spawn(((Component)itemBehavior).gameObject, (NetworkConnection)null, default(Scene));
						if (__instance.slotnum >= 4)
						{
							__instance.slotnum = 0;
						}
						else
						{
							__instance.slotnum++;
						}
					}
				}
				foreach (var item2 in SpellManager.Mapping.OrderBy<(SpellData, PageController), int>(((SpellData data, PageController page) m) => m.data.Id))
				{
					if (item2.Item1.DebugForceSpawn)
					{
						GameObject val = Object.Instantiate<GameObject>(((Component)item2.Item2).gameObject);
						val.transform.position = ((Component)__instance.ItemPoints[__instance.slotnum]).transform.position;
						((NetworkBehaviour)__instance).ServerManager.Spawn(val, (NetworkConnection)null, default(Scene));
						if (__instance.slotnum >= 4)
						{
							__instance.slotnum = 0;
						}
						else
						{
							__instance.slotnum++;
						}
					}
				}
			}
		}

		[HarmonyPatch("Awake")]
		[HarmonyPrefix]
		[HarmonyPriority(800)]
		private static void Awake_Prefix(ChestNetController __instance)
		{
			List<GameObject> list = __instance.Items.ToList();
			foreach (var item in ItemManager.Mapping.OrderBy<(ItemData, ItemBehavior), int>(((ItemData data, ItemBehavior behavior) m) => m.data.Id))
			{
				if (item.Item1.CanSpawnInTeamChest)
				{
					list.Add(((Component)item.Item2).gameObject);
				}
			}
			foreach (var item2 in SpellManager.Mapping.OrderBy<(SpellData, PageController), int>(((SpellData data, PageController page) m) => m.data.Id))
			{
				if (item2.Item1.CanSpawnInTeamChest)
				{
					list.Add(((Component)item2.Item2).gameObject);
				}
			}
			int num = 0;
			GameObject[] array = (GameObject[])(object)new GameObject[list.Count];
			foreach (GameObject item3 in list)
			{
				array[num] = item3;
				num++;
			}
			__instance.Items = array;
		}
	}
	[HarmonyPatch(typeof(DungeonGenerator))]
	internal class DungeonGeneratorPatch
	{
		[HarmonyPatch("Start")]
		[HarmonyPrefix]
		[HarmonyPriority(800)]
		private static void Start_Prefix(DungeonGenerator __instance)
		{
			PageLootTable component = ((Component)__instance).GetComponent<PageLootTable>();
			if (!((Object)(object)component != (Object)null))
			{
				return;
			}
			List<GameObject> list = component.Pages.ToList();
			foreach (var item2 in SpellManager.Mapping.OrderBy<(SpellData, PageController), int>(((SpellData data, PageController page) m) => m.page.ItemID))
			{
				PageController item = item2.Item2;
				list.Add(((Component)item).gameObject);
			}
			PageLootTable val = component;
			int num = 0;
			GameObject[] array = (GameObject[])(object)new GameObject[list.Count];
			foreach (GameObject item3 in list)
			{
				array[num] = item3;
				num++;
			}
			val.Pages = array;
		}
	}
	[HarmonyPatch(typeof(PaperInteract))]
	internal class PaperInteractPatch
	{
		[HarmonyPatch("Start")]
		[HarmonyPostfix]
		[HarmonyPriority(800)]
		private static void Start_Postfix(PaperInteract __instance)
		{
		}
	}
}
namespace BlackMagicAPI.Network
{
	public class DataWriter : IDisposable
	{
		private readonly List<(Type type, object value)> _dataBuffer = new List<(Type, object)>();

		public void Write<T>(T value)
		{
			if (value != null)
			{
				_dataBuffer.Add((typeof(T), value));
			}
		}

		public void Write(object value)
		{
			if (value == null)
			{
				throw new ArgumentNullException("value");
			}
			_dataBuffer.Add((value.GetType(), value));
		}

		internal void WriteFromBuffer(PooledWriter writer)
		{
			((Writer)writer).Write<byte>((byte)_dataBuffer.Count);
			foreach (var (type, obj) in _dataBuffer)
			{
				((Writer)writer).Write<string>(type.AssemblyQualifiedName);
				FishUtils.WriteFast(writer, type, obj);
			}
		}

		internal void ReadToBuffer(PooledReader reader)
		{
			ClearBuffer();
			byte b = ((Reader)reader).Read<byte>();
			for (int i = 0; i < b; i++)
			{
				string text = ((Reader)reader).ReadString();
				Type type = Type.GetType(text) ?? throw new InvalidOperationException("Type not found: " + text);
				object obj = FishUtils.ReadFast(reader, type);
				_dataBuffer.Add((obj.GetType(), obj));
			}
		}

		internal object[] GetObjectBuffer()
		{
			object[] array = new object[_dataBuffer.Count];
			for (int i = 0; i < _dataBuffer.Count; i++)
			{
				array[i] = _dataBuffer[i].value;
			}
			return array;
		}

		internal void ClearBuffer()
		{
			_dataBuffer.Clear();
		}

		public void Dispose()
		{
			ClearBuffer();
			GC.SuppressFinalize(this);
		}
	}
}
namespace BlackMagicAPI.Modules.Soups
{
	public abstract class SoupEffect : MonoBehaviour
	{
		internal int Id { get; set; }

		public abstract void ApplyEffect(PlayerMovement player);

		public virtual void OnPrefabCreatedAutomatically(GameObject prefab)
		{
		}

		public void DisposeEffect()
		{
			Object.Destroy((Object)(object)((Component)this).gameObject);
		}
	}
}
namespace BlackMagicAPI.Modules.Spells
{
	public abstract class ItemData : ICompatibility
	{
		public Version CompatibilityVersion => CompatibilityManager.GetReferencedVersion(GetType());

		public abstract string Name { get; }

		public virtual bool DebugForceSpawn => false;

		public virtual bool CanSpawnInTeamChest => false;

		public virtual bool CanSpawnInColoseum => true;

		public virtual bool CanGetFromTrade => false;

		public virtual bool KeepOnDeath => false;

		public int Id { get; internal set; }

		public BaseUnityPlugin? Plugin { get; internal set; }

		internal Sprite? GetUiSprite()
		{
			if ((Object)(object)Plugin == (Object)null)
			{
				return null;
			}
			string path = Path.Combine(Path.GetDirectoryName(Plugin.Info.Location), "Sprites", Name.Replace(" ", "") + "_Ui.png");
			if (File.Exists(path))
			{
				return Utils.LoadSpriteFromDisk(path);
			}
			return Assembly.GetExecutingAssembly().LoadSpriteFromResources("BlackMagicAPI.Resources.Items.Item_Ui.png");
		}

		public virtual AudioClip? GetPickupAudio()
		{
			if ((Object)(object)Plugin == (Object)null)
			{
				return null;
			}
			string text = Path.Combine(Path.GetDirectoryName(Plugin.Info.Location), "Sounds", Name.Replace(" ", "") + "_Pickup.wav");
			if (File.Exists(text))
			{
				return Utils.LoadWavFromDisk(text);
			}
			return null;
		}

		public virtual AudioClip? GetEquipAudio()
		{
			if ((Object)(object)Plugin == (Object)null)
			{
				return null;
			}
			string text = Path.Combine(Path.GetDirectoryName(Plugin.Info.Location), "Sounds", Name.Replace(" ", "") + "_Equip.wav");
			if (File.Exists(text))
			{
				return Utils.LoadWavFromDisk(text);
			}
			return null;
		}

		public virtual Task<ItemBehavior?> GetItemPrefab()
		{
			return Task.FromResult<ItemBehavior>(null);
		}
	}
	public abstract class SoupData : ICompatibility
	{
		public Version CompatibilityVersion => CompatibilityManager.GetReferencedVersion(GetType());

		public abstract string Name { get; }

		public abstract string ConsumeDescription { get; }

		public abstract Color SoupColor { get; }

		public int ItemId { get; internal set; }

		public int SoupId { get; internal set; }

		public BaseUnityPlugin? Plugin { get; internal set; }

		internal int RequiredItemId { get; set; } = -1;


		internal Sprite? GetUiSprite()
		{
			if ((Object)(object)Plugin == (Object)null)
			{
				return null;
			}
			string path = Path.Combine(Path.GetDirectoryName(Plugin.Info.Location), "Sprites", Name.Replace(" ", "") + "_Ui.png");
			if (File.Exists(path))
			{
				return Utils.LoadSpriteFromDisk(path);
			}
			return Assembly.GetExecutingAssembly().LoadSpriteFromResources("BlackMagicAPI.Resources.Items.Empty_Ui.png");
		}

		public virtual Task<SoupEffect?> GetEffectPrefab()
		{
			return Task.FromResult<SoupEffect>(null);
		}

		public virtual void SetObjectVisualTransform(GameObject render)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			render.transform.localPosition = new Vector3(-0.0003f, 0.004f, 0.004f);
			render.transform.rotation = Quaternion.Euler(-3f, 0f, 0f);
			render.transform.localScale = render.transform.localScale * 0.03f;
		}
	}
	internal class CustomSpellCommand : MonoBehaviour, ISpellCommand
	{
		internal string SpellName { get; set; } = "[]";


		internal SpellData SpellData
		{
			get; [param: AllowNull]
			set;
		}

		private PlayerInventory? playerInventory { get; set; }

		private SpeechRecognizer? speechRecognizer { get; set; }

		public void Awake()
		{
			Resources.FindObjectsOfTypeAll<VoiceControlListener>()?.First()?.SpellPages?.Add((ISpellCommand)(object)this);
		}

		public string GetSpellName()
		{
			return SpellName.ToLower();
		}

		public void ResetVoiceDetect()
		{
			if ((Object)(object)speechRecognizer == (Object)null)
			{
				SpeechRecognizer val = default(SpeechRecognizer);
				if (!((Component)this).TryGetComponent<SpeechRecognizer>(ref val))
				{
					Debug.LogError((object)"ResetVoiceDetect: SpeechRecognizer component not found");
					return;
				}
				speechRecognizer = val;
			}
			string text = SpellName.ToLower();
			if (!speechRecognizer.Vocabulary.Contains(text))
			{
				speechRecognizer.Vocabulary.Add(text);
				Debug.Log((object)("Added spell name to vocabulary: " + text));
			}
		}

		public void TryCastSpell()
		{
			if ((Object)(object)playerInventory == (Object)null)
			{
				PlayerInventory val = default(PlayerInventory);
				if (!((Component)((Component)Camera.main).transform.parent).TryGetComponent<PlayerInventory>(ref val))
				{
					Debug.LogError((object)"Failed to find PlayerInventory");
					return;
				}
				playerInventory = val;
			}
			if ((Object)(object)speechRecognizer == (Object)null)
			{
				SpeechRecognizer val2 = default(SpeechRecognizer);
				if (!((Component)this).TryGetComponent<SpeechRecognizer>(ref val2))
				{
					Debug.LogError((object)"Failed to find SpeechRecognizer");
					return;
				}
				speechRecognizer = val2;
			}
			if (playerInventory.GetEquippedItemID() == SpellData.Id)
			{
				playerInventory.cPageSpell();
			}
			((SpeechProcessor)speechRecognizer).StopProcessing();
			((MonoBehaviour)this).StartCoroutine(CoWaitRestartVoiceDetect());
		}

		private IEnumerator CoWaitRestartVoiceDetect()
		{
			while (true)
			{
				SpeechRecognizer? obj = speechRecognizer;
				if (obj != null && (int)((SpeechProcessor)obj).State <= 0)
				{
					break;
				}
				yield return null;
			}
			SpeechRecognizer? obj2 = speechRecognizer;
			if (obj2 != null)
			{
				((SpeechProcessor)obj2).StartProcessing();
			}
		}
	}
	public class Spell<SD> where SD : SpellData
	{
		public static SD? GetData()
		{
			return (SD)SpellManager.Mapping.FirstOrDefault<(SpellData, PageController)>(((SpellData data, PageController page) map) => map.data.GetType() == typeof(SD)).Item1;
		}

		public static PageController? GetPagePrefab()
		{
			return SpellManager.Mapping.FirstOrDefault<(SpellData, PageController)>(((SpellData data, PageController page) map) => map.data.GetType() == typeof(SD)).Item2;
		}

		public static SpellLogic? GetLogicPrefab()
		{
			PageController? pagePrefab = GetPagePrefab();
			if (pagePrefab == null)
			{
				return null;
			}
			return pagePrefab.spellprefab.GetComponent<SpellLogic>();
		}

		public static L? GetLogicPrefab<L>() where L : SpellLogic
		{
			PageController? pagePrefab = GetPagePrefab();
			if (pagePrefab == null)
			{
				return null;
			}
			return pagePrefab.spellprefab.GetComponent<L>();
		}

		public static SpellLogic?[] GetLogicInstances()
		{
			if (SpellLogic.Instances.TryGetValue(typeof(SD).FullName, out List<SpellLogic> value))
			{
				List<SpellLogic> list = value;
				int num = 0;
				SpellLogic[] array = new SpellLogic[list.Count];
				{
					foreach (SpellLogic item in list)
					{
						array[num] = item;
						num++;
					}
					return array;
				}
			}
			return Array.Empty<SpellLogic>();
		}

		public static SL?[] GetLogicInstances<SL>() where SL : SpellLogic
		{
			if (SpellLogic.Instances.TryGetValue(typeof(SD).FullName, out List<SpellLogic> value))
			{
				return (from logic in value
					select logic as SL into logic
					where (Object)(object)logic != (Object)null
					select logic).ToArray();
			}
			return Array.Empty<SL>();
		}
	}
	public abstract class SpellData : ICompatibility
	{
		public Version CompatibilityVersion => CompatibilityManager.GetReferencedVersion(GetType());

		public virtual SpellType SpellType => SpellType.Page;

		public virtual bool DebugForceSpawn => false;

		public virtual bool CanSpawnInTeamChest => false;

		public virtual bool CanSpawnInColoseum => true;

		public virtual bool KeepOnDeath => false;

		public abstract string Name { get; }

		public virtual string[] SubNames => Array.Empty<string>();

		public abstract float Cooldown { get; }

		public abstract Color GlowColor { get; }

		public int Id { get; internal set; }

		public BaseUnityPlugin? Plugin { get; internal set; }

		internal Sprite? GetUiSprite()
		{
			if ((Object)(object)Plugin == (Object)null)
			{
				return null;
			}
			string path = Path.Combine(Path.GetDirectoryName(Plugin.Info.Location), "Sprites", Name.Replace(" ", "") + "_Ui.png");
			if (File.Exists(path))
			{
				return Utils.LoadSpriteFromDisk(path);
			}
			return Assembly.GetExecutingAssembly().LoadSpriteFromResources("BlackMagicAPI.Resources.Items.Item_Ui.png");
		}

		public virtual Texture2D? GetMainTexture()
		{
			if ((Object)(object)Plugin == (Object)null)
			{
				return null;
			}
			string path = Path.Combine(Path.GetDirectoryName(Plugin.Info.Location), "Sprites", Name.Replace(" ", "") + "_Main.png");
			if (File.Exists(path))
			{
				return Utils.LoadTextureFromDisk(path);
			}
			return Assembly.GetExecutingAssembly().LoadTextureFromResources("BlackMagicAPI.Resources.Items.Item_Main.png");
		}

		public virtual Texture2D? GetEmissionTexture()
		{
			if ((Object)(object)Plugin == (Object)null)
			{
				return null;
			}
			string path = Path.Combine(Path.GetDirectoryName(Plugin.Info.Location), "Sprites", Name.Replace(" ", "") + "_Emission.png");
			if (File.Exists(path))
			{
				return Utils.LoadTextureFromDisk(path);
			}
			return Assembly.GetExecutingAssembly().LoadTextureFromResources("BlackMagicAPI.Resources.Items.Item_Emission.png");
		}

		public virtual Task<SpellLogic?> GetLogicPrefab()
		{
			return Task.FromResult<SpellLogic>(null);
		}

		internal void SetUpPage(PageController page, SpellLogic logic)
		{
			page.ItemID = Id;
			page.CoolDown = Cooldown;
			page.PageCoolDownTimer = 0f - Cooldown;
			page.spellprefab = ((Component)logic).gameObject;
			SetMaterial(((Renderer)page.pagerender).material);
		}

		internal void SetMaterial(Material material)
		{
			Texture2D mainTexture = GetMainTexture();
			if ((Object)(object)mainTexture != (Object)null)
			{
				material.SetTexture("_bk", (Texture)(object)mainTexture);
			}
			Texture2D emissionTexture = GetEmissionTexture();
			if ((Object)(object)emissionTexture != (Object)null)
			{
				material.SetTexture("_emistexture", (Texture)(object)emissionTexture);
			}
		}

		internal void SetLight(Light? light)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)light == (Object)null))
			{
				light.color = GlowColor;
			}
		}
	}
	public abstract class SpellLogic : MonoBehaviour, ISpell
	{
		internal static Dictionary<string, List<SpellLogic>> Instances = new Dictionary<string, List<SpellLogic>>();

		[SerializeField]
		[Tooltip("Spelldata Fullname, (DO NOT SET)")]
		internal string? SpellDataTypeName;

		[SerializeField]
		[Tooltip("Keep item on death, (DO NOT SET)")]
		internal bool KeepOnDeath;

		public bool IsPrefab { get; internal set; } = true;


		protected virtual void Awake()
		{
			((MonoBehaviour)this).StartCoroutine(CoAwake());
		}

		protected virtual void OnDestroy()
		{
			if (SpellDataTypeName != null && Instances.TryGetValue(SpellDataTypeName, out List<SpellLogic> value))
			{
				value.Remove(this);
				if (value.Count <= 0)
				{
					Instances.Remove(SpellDataTypeName);
				}
			}
		}

		private IEnumerator CoAwake()
		{
			while (SpellDataTypeName == null)
			{
				yield return null;
			}
			float wait = 0f;
			while (IsPrefab)
			{
				wait += Time.deltaTime;
				if (wait > 5f)
				{
					yield break;
				}
				yield return null;
			}
			if (!Instances.ContainsKey(SpellDataTypeName))
			{
				Instances[SpellDataTypeName] = new List<SpellLogic>();
			}
			Instances[SpellDataTypeName].Add(this);
		}

		public void PlayerSetup(GameObject ownerobj, Vector3 fwdVector, int level)
		{
		}

		public abstract bool CastSpell(PlayerMovement caster, PageController page, Vector3 spawnPos, Vector3 viewDirectionVector, int castingLevel);

		public virtual void OnPageItemUse(PlayerMovement itemOwner, PageController page)
		{
		}

		public virtual void OnPrefabCreatedAutomatically(GameObject prefab)
		{
		}

		public virtual void WriteData(DataWriter dataWriter, PageController page, PlayerMovement caster, Vector3 spawnPos, Vector3 viewDirectionVector, int level)
		{
		}

		public virtual void SyncData(object[] values)
		{
		}

		public void DisposeSpell()
		{
			Object.Destroy((Object)(object)((Component)this).gameObject);
		}
	}
}
namespace BlackMagicAPI.Modules.Items
{
	[RequireComponent(typeof(AudioSource))]
	public abstract class ItemBehavior : NetworkBehaviour, IInteractable, IItemInteraction
	{
		[SerializeField]
		[Tooltip("The visual representation of the item in the game world, be sure that it's parenting to this object!")]
		public GameObject? ItemRender;

		[SerializeField]
		[Tooltip("Sound played when the item is picked up")]
		public AudioClip? EquipSound;

		[SerializeField]
		[Tooltip("Sound played when the item is dropped")]
		public AudioClip? DropSound;

		[SerializeField]
		[Tooltip("Display name of the item, (DO NOT SET)")]
		internal string Name = "???";

		[SerializeField]
		[Tooltip("Unique identifier for the item type, (DO NOT SET)")]
		internal int Id;

		[SerializeField]
		[Tooltip("Keep item on death, (DO NOT SET)")]
		internal bool KeepOnDeath;

		private bool waitingInitItem;

		private bool netInit;

		public PlayerMovement? LastOwner { get; private set; }

		protected virtual void Awake()
		{
			NetworkInitialize();
		}

		public int GetItemID()
		{
			return Id;
		}

		public string DisplayInteractUI(GameObject player)
		{
			return "Grasp " + Name;
		}

		public void ItemInit()
		{
			GameObject? itemRender = ItemRender;
			if (itemRender != null)
			{
				itemRender.SetActive(true);
			}
			PlayEquipSound();
			if (!waitingInitItem)
			{
				((MonoBehaviour)this).StartCoroutine(CoWaitInitItem());
			}
		}

		public void ItemInitObs()
		{
			ItemInit();
		}

		private IEnumerator CoWaitInitItem()
		{
			waitingInitItem = true;
			float wait = 0f;
			while (true)
			{
				Transform transform = ((Component)this).transform;
				object obj;
				if (transform == null)
				{
					obj = null;
				}
				else
				{
					Transform parent = transform.parent;
					obj = ((parent != null) ? ((Object)parent).name : null);
				}
				if (!((string?)obj != "pikupact"))
				{
					break;
				}
				wait += Time.deltaTime;
				if (wait >= 10f)
				{
					waitingInitItem = false;
					yield break;
				}
				yield return null;
			}
			LastOwner = ((Component)((Component)this).transform.parent.parent).GetComponent<PlayerMovement>();
			OnItemEquipped(LastOwner);
			waitingInitItem = false;
		}

		public void Interact(GameObject player)
		{
			player.GetComponent<PlayerInventory>().Pickup(((Component)this).gameObject);
		}

		public void Interaction(GameObject player)
		{
			OnItemUse(player.GetComponent<PlayerMovement>());
		}

		protected abstract void OnItemUse(PlayerMovement itemOwner);

		public virtual void OnItemEquipped(PlayerMovement itemOwner)
		{
		}

		public virtual void OnItemDropped(PlayerMovement itemOwner)
		{
		}

		public void Interaction2(GameObject subject)
		{
		}

		public void DropItem()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			LayerMask val = LayerMask.op_Implicit(192);
			RaycastHit val2 = default(RaycastHit);
			if (Physics.Raycast(((Component)this).transform.position, Vector3.down, ref val2, 100f, ~LayerMask.op_Implicit(val)))
			{
				SetDefaultTransforms();
				((Component)this).transform.position = ((RaycastHit)(ref val2)).point;
			}
			GameObject? itemRender = ItemRender;
			if (itemRender != null)
			{
				itemRender.SetActive(true);
			}
			PlayDropSound();
			if ((Object)(object)LastOwner != (Object)null)
			{
				OnItemDropped(LastOwner);
			}
		}

		public void HideItem()
		{
			GameObject? itemRender = ItemRender;
			if (itemRender != null)
			{
				itemRender.SetActive(false);
			}
		}

		public void PlayDropSound()
		{
			if (!((Object)(object)DropSound == (Object)null))
			{
				AudioSource component = ((Component)this).GetComponent<AudioSource>();
				if (component != null)
				{
					component.PlayOneShot(DropSound);
				}
			}
		}

		private void PlayEquipSound()
		{
			if (!((Object)(object)EquipSound == (Object)null))
			{
				AudioSource component = ((Component)this).GetComponent<AudioSource>();
				if (component != null)
				{
					component.PlayOneShot(EquipSound);
				}
			}
		}

		[Obsolete("Use SetDefaultTransforms instead.")]
		public virtual void SetScale()
		{
			SetDefaultTransforms();
		}

		public virtual void SetDefaultTransforms()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			((Component)this).transform.localScale = Vector3.one;
			((Component)this).transform.rotation = Quaternion.Euler(-90f, 0f, 0f);
		}

		public virtual void SetTransformOnCraftingForge()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			((Component)this).transform.localScale = Vector3.one;
			((Component)this).transform.rotation = Quaternion.Euler(-90f, 0f, 0f);
		}

		internal void SetAudioClips(AudioClip drop, AudioClip equip)
		{
			DropSound = drop;
			EquipSound = equip;
		}

		public virtual void OnPrefabCreatedAutomatically(GameObject prefab)
		{
		}

		public virtual void AddColliderToPrefab(GameObject prefab)
		{
			prefab.AddComponent<BoxCollider>();
		}

		private void NetworkInitialize()
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Expected O, but got Unknown
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Expected O, but got Unknown
			if (!netInit)
			{
				netInit = true;
				((NetworkBehaviour)this).RegisterServerRpc(0u, new ServerRpcDelegate(HandleSyncClientCmd));
				((NetworkBehaviour)this).RegisterObserversRpc(1u, new ClientRpcDelegate(HandleSyncClientRpc));
			}
		}

		protected void SendClientCmd(uint cmdId, params object[] args)
		{
			if (!((NetworkBehaviour)this).IsClientInitialized)
			{
				NetworkManagerExtensions.LogWarning(((NetworkBehaviour)this).NetworkManager, "Cannot complete action because client is not active. This may also occur if the object is not yet initialized, has deinitialized, or if it does not contain a NetworkObject component.");
				return;
			}
			PooledWriter val = WriterPool.Retrieve();
			((Writer)val).Write<uint>(cmdId);
			DataWriter dataWriter = new DataWriter();
			foreach (object value in args)
			{
				dataWriter.Write(value);
			}
			dataWriter.WriteFromBuffer(val);
			dataWriter.Dispose();
			((NetworkBehaviour)this).SendServerRpc(0u, val, (Channel)0, (DataOrderType)0);
			val.Store();
		}

		protected virtual void HandleSyncClient(uint cmdId, object[] args)
		{
		}

		private void HandleSyncClientCmd(PooledReader reader, Channel channel, NetworkConnection sender)
		{
			uint cmdId = ((Reader)reader).Read<uint>();
			DataWriter dataWriter = new DataWriter();
			dataWriter.ReadToBuffer(reader);
			HandleSyncClient(cmdId, dataWriter.GetObjectBuffer());
			dataWriter.Dispose();
		}

		protected void SendItemSync(uint syncId, params object[] args)
		{
			if (!((NetworkBehaviour)this).IsClientInitialized)
			{
				NetworkManagerExtensions.LogWarning(((NetworkBehaviour)this).NetworkManager, "Cannot complete action because client is not active. This may also occur if the object is not yet initialized, has deinitialized, or if it does not contain a NetworkObject component.");
				return;
			}
			PooledWriter val = WriterPool.Retrieve();
			((Writer)val).Write<uint>(syncId);
			DataWriter dataWriter = new DataWriter();
			foreach (object value in args)
			{
				dataWriter.Write(value);
			}
			dataWriter.WriteFromBuffer(val);
			dataWriter.Dispose();
			((NetworkBehaviour)this).SendObserversRpc(1u, val, (Channel)0, (DataOrderType)0, false, false, false);
			val.Store();
		}

		protected virtual void HandleItemSync(uint syncId, object[] args)
		{
		}

		private void HandleSyncClientRpc(PooledReader reader, Channel channel)
		{
			uint syncId = ((Reader)reader).Read<uint>();
			DataWriter dataWriter = new DataWriter();
			dataWriter.ReadToBuffer(reader);
			HandleItemSync(syncId, dataWriter.GetObjectBuffer());
			dataWriter.Dispose();
		}
	}
}
namespace BlackMagicAPI.Managers
{
	public class BlackMagicManager
	{
		public static T? SpawnItem<T>(Vector3? position = null, Quaternion? rotation = null) where T : IItemInteraction
		{
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			NetworkManager val = NetworkManager.Instances.FirstOrDefault() ?? throw new InvalidOperationException("Can not spawn iten when the NetworkManager is null!");
			if (!val.IsHostStarted)
			{
				BMAPlugin.Log.LogError((object)("Failed to spawn item " + typeof(T).Name + ": Items can only be spawned as host."));
				return default(T);
			}
			object obj = GetItemPrefab<T>();
			MonoBehaviour val2 = (MonoBehaviour)((obj is MonoBehaviour) ? obj : null);
			if (val2 != null)
			{
				MonoBehaviour val3 = Object.Instantiate<MonoBehaviour>(val2);
				if (position.HasValue)
				{
					((Component)val3).transform.position = position.Value;
				}
				if (rotation.HasValue)
				{
					((Component)val3).transform.rotation = rotation.Value;
				}
				val.ServerManager.Spawn(((Component)val3).gameObject, (NetworkConnection)null, default(Scene));
				BMAPlugin.Log.LogInfo((object)("Successfully spawned item " + typeof(T).Name + "."));
				return (T)(IItemInteraction)val3;
			}
			BMAPlugin.Log.LogError((object)("Failed to spawn item " + typeof(T).Name + ": Item prefab returned null."));
			return default(T);
		}

		public static PageController? SpawnSpell<T>(Vector3? position = null, Quaternion? rotation = null) where T : ISpell
		{
			//IL_0072: 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_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			NetworkManager val = NetworkManager.Instances.FirstOrDefault() ?? throw new InvalidOperationException("Can not spawn iten when the NetworkManager is null!");
			if (!val.IsHostStarted)
			{
				BMAPlugin.Log.LogError((object)("Failed to spawn spell page " + typeof(T).Name + ": Spells can only be spawned as host."));
				return null;
			}
			PageController spellPagePrefab = GetSpellPagePrefab<T>();
			if (spellPagePrefab != null)
			{
				PageController val2 = spellPagePrefab;
				PageController val3 = Object.Instantiate<PageController>(val2);
				if (position.HasValue)
				{
					((Component)val3).transform.position = position.Value;
				}
				if (rotation.HasValue)
				{
					((Component)val3).transform.rotation = rotation.Value;
				}
				val.ServerManager.Spawn(((Component)val3).gameObject, (NetworkConnection)null, default(Scene));
				BMAPlugin.Log.LogInfo((object)("Successfully spawned spell page " + typeof(T).Name + "."));
				return val3;
			}
			BMAPlugin.Log.LogError((object)("Failed to spawn spell page " + typeof(T).Name + ": Spells prefab returned null."));
			return null;
		}

		public static void RegisterCraftingRecipe(BaseUnityPlugin plugin, Type IItemInteraction_FirstType, Type IItemInteraction_SecondType, Type IItemInteraction_ResultType)
		{
			ItemManager.RegisterCraftingRecipe(plugin, IItemInteraction_FirstType, IItemInteraction_SecondType, IItemInteraction_ResultType);
		}

		public static T? GetItemPrefab<T>() where T : IItemInteraction
		{
			return ItemManager.GetItemPrefab<T>();
		}

		public static void RegisterItem(BaseUnityPlugin plugin, Type ItemDataType, Type? ItemBehaviorType = null)
		{
			ItemManager.RegisterItem(plugin, ItemDataType, ItemBehaviorType);
		}

		public static void RegisterSoup(BaseUnityPlugin plugin, Type IItemInteraction, Type SoupDataType, Type? SoupEffectType = null)
		{
			SoupManager.RegisterSoup(plugin, IItemInteraction, SoupDataType, SoupEffectType);
		}

		public static PageController GetSpellPagePrefab<T>() where T : ISpell
		{
			return SpellManager.GetSpellPagePrefab<T>();
		}

		public static T GetSpellLogicPrefab<T>() where T : ISpell
		{
			return SpellManager.GetSpellLogicPrefab<T>();
		}

		public static void RegisterSpell(BaseUnityPlugin plugin, Type SpellDataType, Type? SpellLogicType = null)
		{
			SpellManager.RegisterSpell(plugin, SpellDataType, SpellLogicType);
		}

		public static void RegisterDeathIcon(BaseUnityPlugin plugin, string deathReason, string spriteName)
		{
			string path = Path.Combine(Path.GetDirectoryName(plugin.Info.Location), "Sprites", spriteName.Replace(".png", "") + ".png");
			if (File.Exists(path))
			{
				Texture2D val = Utils.LoadTextureFromDisk(path);
				if (!((Object)(object)val == (Object)null) && PlayerRespawnManagerPatch.AddDeathIcon(plugin, deathReason, val))
				{
					BMAPlugin.Log.LogInfo((object)("Successfully registered " + deathReason + " Death Icon from " + plugin.Info.Metadata.GUID));
				}
			}
		}

		public static void RegisterDeathIcon(BaseUnityPlugin plugin, string deathReason, Texture2D icon)
		{
			if (!((Object)(object)icon == (Object)null) && PlayerRespawnManagerPatch.AddDeathIcon(plugin, deathReason, icon))
			{
				BMAPlugin.Log.LogInfo((object)("Successfully registered " + deathReason + " Death Icon from " + plugin.Info.Metadata.GUID));
			}
		}
	}
	internal enum CompatibilityResult
	{
		Successful,
		NotAssignable,
		NoProperty,
		OldVersion,
		Error
	}
	internal class CompatibilityManager
	{
		internal static Version COMPATIBILITY_VERSION { get; } = typeof(CompatibilityManager).Assembly.GetName().Version;


		internal static Version GetReferencedVersion(Type type)
		{
			return type?.Assembly?.GetReferencedAssemblies()?.FirstOrDefault((AssemblyName assembly) => assembly.Name == "BlackMagicAPI")?.Version ?? new Version("0.0.0.0");
		}

		private static bool CheckCompatibility(Version version)
		{
			if (version == COMPATIBILITY_VERSION)
			{
				return true;
			}
			return false;
		}

		private static bool CheckForProperty(Type type)
		{
			if (type.GetProperty("CompatibilityVersion", BindingFlags.Instance | BindingFlags.Public) == null)
			{
				return false;
			}
			return true;
		}

		internal static CompatibilityResult CheckSpellCompatibility(Type spellDataType)
		{
			if (!typeof(SpellData).IsAssignableFrom(spellDataType))
			{
				return CompatibilityResult.NotAssignable;
			}
			if (!CheckForProperty(spellDataType))
			{
				return CompatibilityResult.NoProperty;
			}
			try
			{
				if (Activator.CreateInstance(spellDataType) is SpellData spellData && CheckCompatibility(spellData.CompatibilityVersion))
				{
					return CompatibilityResult.Successful;
				}
				return CompatibilityResult.OldVersion;
			}
			catch
			{
				return CompatibilityResult.Error;
			}
		}

		internal static CompatibilityResult CheckItemCompatibility(Type itemDataType)
		{
			if (!typeof(ItemData).IsAssignableFrom(itemDataType))
			{
				return CompatibilityResult.NotAssignable;
			}
			if (!CheckForProperty(itemDataType))
			{
				return CompatibilityResult.NoProperty;
			}
			try
			{
				if (Activator.CreateInstance(itemDataType) is ItemData itemData && CheckCompatibility(itemData.CompatibilityVersion))
				{
					return CompatibilityResult.Successful;
				}
				return CompatibilityResult.OldVersion;
			}
			catch
			{
				return CompatibilityResult.Error;
			}
		}
	}
	internal static class ItemManager
	{
		private static readonly List<Type> registeredTypes = new List<Type>();

		internal static List<(ItemData data, ItemBehavior behavior)> Mapping = new List<(ItemData, ItemBehavior)>();

		internal static readonly Dictionary<Type, IItemInteraction> PrefabMapping = new Dictionary<Type, IItemInteraction>();

		internal static void RegisterCraftingRecipe(BaseUnityPlugin baseUnity, Type IItemInteraction_FirstType, Type IItemInteraction_SecondType, Type IItemInteraction_ResultType)
		{
			if (IItemInteraction_FirstType.IsInterface)
			{
				BMAPlugin.Log.LogError((object)("Failed to register item recipe from " + baseUnity.Info.Metadata.Name + ": IItemInteraction_FirstType can not be directly IItemInteraction interface!"));
				ModSyncManager.FailedRecipes.Add((baseUnity, IItemInteraction_FirstType, IItemInteraction_SecondType, IItemInteraction_ResultType));
				return;
			}
			if (IItemInteraction_SecondType.IsInterface)
			{
				BMAPlugin.Log.LogError((object)("Failed to register item recipe from " + baseUnity.Info.Metadata.Name + ": IItemInteraction_SecondType can not be directly IItemInteraction interface!"));
				ModSyncManager.FailedRecipes.Add((baseUnity, IItemInteraction_FirstType, IItemInteraction_SecondType, IItemInteraction_ResultType));
				return;
			}
			if (IItemInteraction_ResultType.IsInterface)
			{
				BMAPlugin.Log.LogError((object)("Failed to register item recipe from " + baseUnity.Info.Metadata.Name + ": IItemInteraction_ResultType can not be directly IItemInteraction interface!"));
				ModSyncManager.FailedRecipes.Add((baseUnity, IItemInteraction_FirstType, IItemInteraction_SecondType, IItemInteraction_ResultType));
				return;
			}
			if (!typeof(IItemInteraction).IsAssignableFrom(IItemInteraction_FirstType) && !typeof(ISpell).IsAssignableFrom(IItemInteraction_FirstType))
			{
				BMAPlugin.Log.LogError((object)("Failed to register item recipe from " + baseUnity.Info.Metadata.Name + ": IItemInteraction_FirstType must be inherited from IItemInteraction interface!"));
				ModSyncManager.FailedRecipes.Add((baseUnity, IItemInteraction_FirstType, IItemInteraction_SecondType, IItemInteraction_ResultType));
				return;
			}
			if (!typeof(IItemInteraction).IsAssignableFrom(IItemInteraction_SecondType) && !typeof(ISpell).IsAssignableFrom(IItemInteraction_SecondType))
			{
				BMAPlugin.Log.LogError((object)("Failed to register item recipe from " + baseUnity.Info.Metadata.Name + ": IItemInteraction_SecondType must be inherited from IItemInteraction interface!"));
				ModSyncManager.FailedRecipes.Add((baseUnity, IItemInteraction_FirstType, IItemInteraction_SecondType, IItemInteraction_ResultType));
				return;
			}
			if (!typeof(IItemInteraction).IsAssignableFrom(IItemInteraction_ResultType) && !typeof(ISpell).IsAssignableFrom(IItemInteraction_SecondType))
			{
				BMAPlugin.Log.LogError((object)("Failed to register item recipe from " + baseUnity.Info.Metadata.Name + ": IItemInteraction_ResultType must be inherited from IItemInteraction interface!"));
				ModSyncManager.FailedRecipes.Add((baseUnity, IItemInteraction_FirstType, IItemInteraction_SecondType, IItemInteraction_ResultType));
				return;
			}
			MonoBehaviour val = (MonoBehaviour)((!typeof(ISpell).IsAssignableFrom(IItemInteraction_FirstType)) ? ((object)/*isinst with value type is only supported in some contexts*/) : ((object)GetPageFromSpellType(IItemInteraction_FirstType)));
			if ((Object)(object)val != (Object)null)
			{
				MonoBehaviour val2 = (MonoBehaviour)((!typeof(ISpell).IsAssignableFrom(IItemInteraction_SecondType)) ? ((object)/*isinst with value type is only supported in some contexts*/) : ((object)GetPageFromSpellType(IItemInteraction_SecondType)));
				if ((Object)(object)val2 != (Object)null)
				{
					MonoBehaviour val3 = (MonoBehaviour)((!typeof(ISpell).IsAssignableFrom(IItemInteraction_SecondType)) ? ((object)/*isinst with value type is only supported in some contexts*/) : ((object)GetPageFromSpellType(IItemInteraction_ResultType)));
					if ((Object)(object)val3 != (Object)null)
					{
						if (CraftingForgePatch.RegisterRecipe(((Component)val).gameObject, ((Component)val2).gameObject, ((Component)val3).gameObject))
						{
							BMAPlugin.Log.LogInfo((object)$"Successfully registered ({IItemInteraction_FirstType}, {IItemInteraction_SecondType} => {IItemInteraction_ResultType} recipe from {baseUnity.Info.Metadata.GUID}");
						}
						else
						{
							BMAPlugin.Log.LogError((object)("Failed to register item recipe from " + baseUnity.Info.Metadata.Name + ": You cannot register a recipe that's already been registered!"));
							ModSyncManager.FailedRecipes.Add((baseUnity, IItemInteraction_FirstType, IItemInteraction_SecondType, IItemInteraction_ResultType));
						}
					}
					else
					{
						BMAPlugin.Log.LogError((object)("Failed to register item recipe from " + baseUnity.Info.Metadata.Name + ": Unable to find item prefab for " + IItemInteraction_ResultType.Name + "!"));
						ModSyncManager.FailedRecipes.Add((baseUnity, IItemInteraction_FirstType, IItemInteraction_SecondType, IItemInteraction_ResultType));
					}
				}
				else
				{
					BMAPlugin.Log.LogError((object)("Failed to register item recipe from " + baseUnity.Info.Metadata.Name + ": Unable to find item prefab for " + IItemInteraction_SecondType.Name + "!"));
					ModSyncManager.FailedRecipes.Add((baseUnity, IItemInteraction_FirstType, IItemInteraction_SecondType, IItemInteraction_ResultType));
				}
			}
			else
			{
				BMAPlugin.Log.LogError((object)("Failed to register item recipe from " + baseUnity.Info.Metadata.Name + ": Unable to find item prefab for " + IItemInteraction_FirstType.Name + "!"));
				ModSyncManager.FailedRecipes.Add((baseUnity, IItemInteraction_FirstType, IItemInteraction_SecondType, IItemInteraction_ResultType));
			}
		}

		private static MonoBehaviour? GetPageFromSpellType(Type spellType)
		{
			PageController[] array = Resources.FindObjectsOfTypeAll<PageController>();
			foreach (PageController val in array)
			{
				object obj;
				if (val == null)
				{
					obj = null;
				}
				else
				{
					GameObject spellprefab = val.spellprefab;
					obj = ((spellprefab == null) ? null : ((object)spellprefab.GetComponent<ISpell>())?.GetType());
				}
				if ((Type?)obj == spellType)
				{
					return (MonoBehaviour?)(object)val;
				}
			}
			return null;
		}

		internal static T? GetItemPrefab<T>() where T : IItemInteraction
		{
			return (T)(object)GetItemPrefab(typeof(T));
		}

		internal static IItemInteraction? GetItemPrefab(Type IItemInteraction_Type)
		{
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Expected O, but got Unknown
			Type IItemInteraction_Type2 = IItemInteraction_Type;
			if (PrefabMapping.TryGetValue(IItemInteraction_Type2, out IItemInteraction value))
			{
				return value;
			}
			IItemInteraction val = Mapping.Select<(ItemData, ItemBehavior), IItemInteraction>(((ItemData data, ItemBehavior behavior) map) => (IItemInteraction)(object)map.behavior)?.FirstOrDefault((Func<IItemInteraction, bool>)((IItemInteraction behavior) => ((object)behavior).GetType() == IItemInteraction_Type2));
			if (val != null)
			{
				PrefabMapping[IItemInteraction_Type2] = val;
				return val;
			}
			IItemInteraction val2 = (IItemInteraction)Resources.FindObjectsOfTypeAll(IItemInteraction_Type2).FirstOrDefault();
			if (val2 != null)
			{
				PrefabMapping[IItemInteraction_Type2] = val2;
				return val2;
			}
			throw new NullReferenceException("Item prefab could not be found!");
		}

		internal static void RegisterItem(BaseUnityPlugin baseUnity, Type ItemDataType, Type? ItemBehaviorType = null)
		{
			if (ItemDataType.IsAbstract)
			{
				BMAPlugin.Log.LogError((object)("Failed to register item from " + baseUnity.Info.Metadata.Name + ": ItemDataType can not be abstract!"));
				ModSyncManager.FailedItems.Add((baseUnity, ItemDataType));
				return;
			}
			if (!ItemDataType.IsSubclassOf(typeof(ItemData)))
			{
				BMAPlugin.Log.LogError((object)("Failed to register item from " + baseUnity.Info.Metadata.Name + ": ItemDataType must be inherited from SpellData!"));
				ModSyncManager.FailedItems.Add((baseUnity, ItemDataType));
				return;
			}
			if (ItemBehaviorType != null)
			{
				if (ItemBehaviorType.IsAbstract)
				{
					BMAPlugin.Log.LogError((object)("Failed to register item from " + baseUnity.Info.Metadata.Name + ": ItemBehaviorType can not be abstract!"));
					ModSyncManager.FailedItems.Add((baseUnity, ItemDataType));
					return;
				}
				if (!ItemBehaviorType.IsSubclassOf(typeof(ItemBehavior)))
				{
					BMAPlugin.Log.LogError((object)("Failed to register item from " + baseUnity.Info.Metadata.Name + ": ItemBehaviorType must be inherited from SpellLogic!"));
					ModSyncManager.FailedItems.Add((baseUnity, ItemDataType));
					return;
				}
			}
			if (registeredTypes.Contains(ItemDataType))
			{
				BMAPlugin.Log.LogError((object)("Failed to register item from " + baseUnity.Info.Metadata.Name + ": " + ItemDataType.Name + " has already been registered!"));
				ModSyncManager.FailedItems.Add((baseUnity, ItemDataType));
				return;
			}
			switch (CompatibilityManager.CheckItemCompatibility(ItemDataType))
			{
			case CompatibilityResult.NoProperty:
				BMAPlugin.Log.LogError((object)("Failed to register item from " + baseUnity.Info.Metadata.Name + ": Unable to find Compatibility property in " + ItemDataType.Name + ", this can be due to " + baseUnity.Info.Metadata.Name + " being outdated!"));
				ModSyncManager.FailedItems.Add((baseUnity, ItemDataType));
				break;
			case CompatibilityResult.OldVersion:
				BMAPlugin.Log.LogError((object)("Failed to register item from " + baseUnity.Info.Metadata.Name + ": " + ItemDataType.Name + " Is incompatible with BlackMagicAPI v3.0.1!"));
				ModSyncManager.FailedItems.Add((baseUnity, ItemDataType));
				break;
			case CompatibilityResult.Error:
				BMAPlugin.Log.LogError((object)("Failed to register item from " + baseUnity.Info.Metadata.Name + ": An error occurred when trying to get Compatibility Version from " + ItemDataType.Name + "!"));
				ModSyncManager.FailedItems.Add((baseUnity, ItemDataType));
				break;
			default:
				RegisterItemTask(baseUnity, ItemDataType, ItemBehaviorType);
				break;
			}
		}

		private static async Task RegisterItemTask(BaseUnityPlugin baseUnity, Type itemDataType, Type? itemBehaviorType)
		{
			object obj = Activator.CreateInstance(itemDataType);
			if (!(obj is ItemData data))
			{
				ModSyncManager.FailedItems.Add((baseUnity, itemDataType));
				throw new InvalidCastException($"Failed to create or cast {itemDataType} to SpellData");
			}
			data.Plugin = baseUnity;
			ItemBehavior itemBehavior = await data.GetItemPrefab();
			if ((Object)(object)itemBehavior == (Object)null)
			{
				if (itemBehaviorType == null)
				{
					BMAPlugin.Log.LogError((object)("Failed to register item from " + baseUnity.Info.Metadata.Name + ": spellLogicType cannot be null without a loadable prefab!"));
					ModSyncManager.FailedItems.Add((baseUnity, itemDataType));
					return;
				}
				itemBehavior = CreateItemBehavior(data, itemBehaviorType);
			}
			CreateItem(baseUnity, data, itemBehavior);
		}

		private static ItemBehavior CreateItemBehavior(ItemData itemData, Type itemBehaviorType)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Expected O, but got Unknown
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Expected O, but got Unknown
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(itemData.Name.Replace(" ", "") + "Item");
			Object.DontDestroyOnLoad((Object)(object)val);
			val.AddComponent<AudioSource>();
			GameObject val2 = new GameObject("ItemRender");
			val2.transform.SetParent(val.transform);
			val2.transform.rotation = Quaternion.Euler(-90f, 180f, 0f);
			ItemBehavior obj = (ItemBehavior)(object)val.AddComponent(itemBehaviorType);
			obj.Name = itemData.Name;
			obj.KeepOnDeath = itemData.KeepOnDeath;
			obj.ItemRender = val2;
			obj.EquipSound = itemData.GetPickupAudio();
			obj.DropSound = itemData.GetEquipAudio();
			obj.AddColliderToPrefab(val);
			obj.OnPrefabCreatedAutomatically(((Component)obj).gameObject);
			return obj;
		}

		private static void CreateItem(BaseUnityPlugin baseUnity, ItemData itemData, ItemBehavior itemBehavior)
		{
			ItemData itemData2 = itemData;
			ItemBehavior itemBehavior2 = itemBehavior;
			SynchronizeManager.SynchronizeItemId(baseUnity, itemData2.GetType(), itemData2.GetUiSprite, delegate(int id)
			{
				itemData2.Id = id;
				itemBehavior2.Id = id;
			});
			FishManager.RegisterNetworkObjectPrefab((BaseUnityPlugin)(object)BMAPlugin.Instance, (MonoBehaviour)(object)itemBehavior2, itemData2.GetType().FullName, true);
			Mapping.Add((itemData2, itemBehavior2));
			List<(ItemData, ItemBehavior)> list = new List<(ItemData, ItemBehavior)>();
			foreach (var item in Mapping.OrderBy<(ItemData, ItemBehavior), int>(((ItemData data, ItemBehavior behavior) map) => map.data.Id))
			{
				list.Add(item);
			}
			Mapping = list;
			registeredTypes.Add(itemData2.GetType());
			SynchronizeManager.UpdateSyncHash();
			BMAPlugin.Log.LogInfo((object)("Successfully registered " + itemData2.Name + " Item from " + baseUnity.Info.Metadata.GUID));
		}
	}
	internal class ModSyncManager
	{
		internal static List<(BaseUnityPlugin plugin, Type type)> FailedSpells = new List<(BaseUnityPlugin, Type)>();

		internal static List<(BaseUnityPlugin plugin, Type type)> FailedItems = new List<(BaseUnityPlugin, Type)>();

		internal static List<(BaseUnityPlugin plugin, Type type, Type type2, Type type3)> FailedRecipes = new List<(BaseUnityPlugin, Type, Type, Type)>();

		internal static List<(BaseUnityPlugin plugin, Type type)> FailedSoups = new List<(BaseUnityPlugin, Type)>();

		internal static void LogAll()
		{
			((MonoBehaviour)BMAPlugin.Instance).StartCoroutine(CoLogAll());
		}

		private static IEnumerator CoLogAll()
		{
			foreach (var failedSpell in FailedSpells)
			{
				BaseUnityPlugin item = failedSpell.plugin;
				Type item2 = failedSpell.type;
				float time4 = 0.1f;
				ModSyncUI.ShowMessage("BlackMagicAPI: " + item2.Name + " spell from " + item.Info.Metadata.Name + " failed to load!", (MessageType)3);
				while (time4 > 0f)
				{
					time4 -= Time.deltaTime;
					yield return null;
				}
			}
			foreach (var failedItem in FailedItems)
			{
				BaseUnityPlugin item3 = failedItem.plugin;
				Type item4 = failedItem.type;
				float time4 = 0.1f;
				ModSyncUI.ShowMessage("BlackMagicAPI: " + item4.Name + " item from " + item3.Info.Metadata.Name + " failed to load!", (MessageType)3);
				while (time4 > 0f)
				{
					time4 -= Time.deltaTime;
					yield return null;
				}
			}
			foreach (var failedRecipe in FailedRecipes)
			{
				BaseUnityPlugin item5 = failedRecipe.plugin;
				Type item6 = failedRecipe.type;
				Type item7 = failedRecipe.type2;
				Type item8 = failedRecipe.type3;
				float time4 = 0.1f;
				ModSyncUI.ShowMessage("BlackMagicAPI: Recipe (" + item6.Name + ", " + item7.Name + " -> " + item8.Name + ") from " + item5.Info.Metadata.Name + " failed to load!", (MessageType)3);
				while (time4 > 0f)
				{
					time4 -= Time.deltaTime;
					yield return null;
				}
			}
			foreach (var failedSoup in FailedSoups)
			{
				BaseUnityPlugin item9 = failedSoup.plugin;
				Type item10 = failedSoup.type;
				float time4 = 0.1f;
				ModSyncUI.ShowMessage("BlackMagicAPI: " + item10.Name + " soup from " + item9.Info.Metadata.Name + " failed to load!", (MessageType)3);
				while (time4 > 0f)
				{
					time4 -= Time.deltaTime;
					yield return null;
				}
			}
		}
	}
	internal class SoupManager
	{
		private static readonly List<Type> registeredTypes = new List<Type>();

		internal static List<(SoupData data, CrystalSoup itemPrefab, GameObject? render, SoupEffect effect)> Mapping = new List<(SoupData, CrystalSoup, GameObject, SoupEffect)>();

		internal static (SoupData data, CrystalSoup itemPrefab, GameObject? render, SoupEffect effect)? GetMapFromItemId(int id)
		{
			return Mapping.FirstOrDefault<(SoupData, CrystalSoup, GameObject, SoupEffect)>(((SoupData data, CrystalSoup itemPrefab, GameObject render, SoupEffect effect) map) => map.data.ItemId == id);
		}

		internal static void RegisterSoup(BaseUnityPlugin baseUnity, Type IItemInteraction, Type soupDataType, Type? soupEffectType = null)
		{
			if (IItemInteraction.IsInterface)
			{
				BMAPlugin.Log.LogError((object)("Failed to register soup from " + baseUnity.Info.Metadata.Name + ": IItemInteraction can not be directly IItemInteraction interface!"));
				ModSyncManager.FailedSoups.Add((baseUnity, soupDataType));
			}
			else if (!soupDataType.IsSubclassOf(typeof(SoupData)))
			{
				BMAPlugin.Log.LogError((object)("Failed to register soup from " + baseUnity.Info.Metadata.Name + ": soupDataType must be inherited from SoupData!"));
				ModSyncManager.FailedSoups.Add((baseUnity, soupDataType));
			}
			else if (soupEffectType != null && !soupEffectType.IsSubclassOf(typeof(SoupEffect)))
			{
				BMAPlugin.Log.LogError((object)("Failed to register soup from " + baseUnity.Info.Metadata.Name + ": soupEffectType must be inherited from SoupEffect!"));
				ModSyncManager.FailedSoups.Add((baseUnity, soupDataType));
			}
			else if (registeredTypes.Contains(soupDataType))
			{
				BMAPlugin.Log.LogError((object)("Failed to register soup from " + baseUnity.Info.Metadata.Name + ": " + soupDataType.Name + " has already been registered!"));
				ModSyncManager.FailedSoups.Add((baseUnity, soupDataType));
			}
			else
			{
				RegisterSoupTask(baseUnity, IItemInteraction, soupDataType, soupEffectType);
			}
		}

		private static async Task RegisterSoupTask(BaseUnityPlugin baseUnity, Type IItemInteraction, Type soupDataType, Type? soupEffectType)
		{
			object obj = Activator.CreateInstance(soupDataType);
			if (!(obj is SoupData data))
			{
				ModSyncManager.FailedSoups.Add((baseUnity, soupDataType));
				throw new InvalidCastException($"Failed to create or cast {soupDataType} to SoupData");
			}
			data.Plugin = baseUnity;
			IItemInteraction? itemPrefab = ItemManager.GetItemPrefab(IItemInteraction);
			data.RequiredItemId = ((itemPrefab != null) ? itemPrefab.GetItemID() : (-1));
			SoupEffect soupEffect = await data.GetEffectPrefab();
			if ((Object)(object)soupEffect == (Object)null)
			{
				if (soupEffectType == null)
				{
					BMAPlugin.Log.LogError((object)("Failed to register soup from " + baseUnity.Info.Metadata.Name + ": soupEffectType cannot be null without a loadable prefab!"));
					ModSyncManager.FailedSoups.Add((baseUnity, soupDataType));
					return;
				}
				soupEffect = CreateSoupEffect(data, soupEffectType);
			}
			((Component)soupEffect).gameObject.SetActive(false);
			CreateSoupItem(baseUnity, IItemInteraction, data, soupEffect);
		}

		private static SoupEffect CreateSoupEffect(SoupData soupData, Type SoupEffectType)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Expected O, but got Unknown
			GameObject val = new GameObject(soupData.Name.Replace(" ", "") + "Effect");
			Object.DontDestroyOnLoad((Object)val);
			SoupEffect obj = (SoupEffect)(object)val.AddComponent(SoupEffectType);
			obj.OnPrefabCreatedAutomatically(((Component)obj).gameObject);
			return obj;
		}

		private static void CreateSoupItem(BaseUnityPlugin baseUnity, Type IItemInteraction, SoupData soupData, SoupEffect soupEffect)
		{
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			SoupData soupData2 = soupData;
			SoupEffect soupEffect2 = soupEffect;
			CrystalSoup val = Resources.FindObjectsOfTypeAll<CrystalSoup>().First();
			CrystalSoup prefab = Object.Instantiate<CrystalSoup>(val);
			Object.DontDestroyOnLoad((Object)(object)prefab);
			((Object)prefab).name = soupData2.Name.Replace(" ", "") + "BowlItem";
			prefab.stewid = -1;
			((Renderer)prefab.mrend).materials[1].color = soupData2.SoupColor - Color.cyan;
			NetworkObject val2 = default(NetworkObject);
			if (((Component)prefab).TryGetComponent<NetworkObject>(ref val2) && (Object)(object)val2 != (Object)null)
			{
				Object.DestroyImmediate((Object)(object)val2);
			}
			Object.Destroy((Object)(object)((Component)((Component)prefab.mrend).transform.GetChild(0)).gameObject);
			IItemInteraction? itemPrefab = ItemManager.GetItemPrefab(IItemInteraction);
			IItemInteraction? obj = ((itemPrefab is MonoBehaviour) ? itemPrefab : null);
			GameObject val3 = Object.Instantiate<GameObject>((obj != null) ? ((Component)((Component)obj).transform.GetChild(0)).gameObject : null);
			if ((Object)(object)val3 != (Object)null)
			{
				soupData2.SetObjectVisualTransform(val3);
			}
			if (val3 != null)
			{
				val3.transform.SetParent(((Component)prefab.mrend).transform, false);
			}
			SynchronizeManager.SynchronizeItemId(baseUnity, soupData2.GetType(), soupData2.GetUiSprite, delegate(int id)
			{
				soupData2.ItemId = id;
				soupEffect2.Id = id;
				prefab.itemid = id;
			});
			FishManager.RegisterNetworkObjectPrefab((BaseUnityPlugin)(object)BMAPlugin.Instance, (MonoBehaviour)(object)prefab, soupData2.GetType().FullName ?? "", true);
			Mapping.Add((soupData2, prefab, val3, soupEffect2));
			List<(SoupData, CrystalSoup, GameObject, SoupEffect)> list = new List<(SoupData, CrystalSoup, GameObject, SoupEffect)>();
			foreach (var item in Mapping.OrderBy<(SoupData, CrystalSoup, GameObject, SoupEffect), int>(((SoupData data, CrystalSoup itemPrefab, GameObject render, SoupEffect effect) map) => map.data.ItemId))
			{
				list.Add(item);
			}
			Mapping = list;
			SynchronizeManager.UpdateSyncHash();
			BMAPlugin.Log.LogInfo((object)("Successfully registered " + soupData2.Name + " Soup from " + baseUnity.Info.Metadata.GUID));
			foreach (IGrouping<int, (SoupData, CrystalSoup, GameObject, SoupEffect)> item2 in from g in Mapping.ToLookup<(SoupData, CrystalSoup, GameObject, SoupEffect), int>(((SoupData data, CrystalSoup itemPrefab, GameObject render, SoupEffect effect) map) => map.data.RequiredItemId)
				where g.Count() > 1
				select g)
			{
				string text = item2.OrderBy<(SoupData, CrystalSoup, GameObject, SoupEffect), int>(((SoupData data, CrystalSoup itemPrefab, GameObject render, SoupEffect effect) map) => map.data.ItemId).FirstOrDefault().Item1.GetType().FullName ?? "";
				BMAPlugin.Log.LogWarning((object)("Warning multiple soups have been registered to the same item, " + text + " will override (" + string.Join(", ", from map in item2.OrderBy<(SoupData, CrystalSoup, GameObject, SoupEffect), int>(((SoupData data, CrystalSoup itemPrefab, GameObject render, SoupEffect effect) map) => map.data.ItemId).Skip(1)
					select map.data.GetType().FullName) + ") soups."));
			}
		}
	}
	internal static class SpellManager
	{
		private static readonly List<Type> registeredTypes = new List<Type>();

		internal static List<(SpellData data, PageController page)> Mapping = new List<(SpellData, PageController)>();

		internal static readonly Dictionary<Type, PageController> PrefabMapping = new Dictionary<Type, PageController>();

		internal static T GetSpellLogicPrefab<T>() where T : ISpell
		{
			T result = default(T);
			if (GetSpellPagePrefab<T>().spellprefab.TryGetComponent<T>(ref result))
			{
				return result;
			}
			throw new NullReferenceException("Logic prefab could not be found!");
		}

		internal static PageController GetSpellPagePrefab<T>() where T : ISpell
		{
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Expected O, but got Unknown
			if (PrefabMapping.TryGetValue(typeof(T), out PageController value))
			{
				return value;
			}
			PageController val = Mapping.Select<(SpellData, PageController), PageController>(((SpellData data, PageController page) map) => map.page)?.FirstOrDefault((Func<PageController, bool>)((PageController page) => ((object)page.spellprefab.GetComponent<ISpell>())?.GetType() == typeof(T)));
			if ((Object)(object)val != (Object)null)
			{
				PrefabMapping[typeof(T)] = val;
				return val;
			}
			PageController val2 = (PageController)((IEnumerable<Object>)Resources.FindObjectsOfTypeAll(typeof(PageController))).FirstOrDefault((Func<Object, bool>)delegate(Object page)
			{
				PageController val3 = (PageController)(object)((page is PageController) ? page : null);
				return val3 != null && ((object)val3.spellprefab.GetComponent<ISpell>())?.GetType() == typeof(T);
			});
			if ((Object)(object)val2 != (Object)null)
			{
				PrefabMapping[typeof(T)] = val2;
				return val2;
			}
			throw new NullReferenceException("Page prefab could not be found!");
		}

		internal static void RegisterSpell(BaseUnityPlugin baseUnity, Type SpellDataType, Type? SpellLogicType = null)
		{
			if (SpellDataType.IsAbstract)
			{
				BMAPlugin.Log.LogError((object)("Failed to register spell from " + baseUnity.Info.Metadata.Name + ": SpellDataType can not be abstract!"));
				ModSyncManager.FailedSpells.Add((baseUnity, SpellDataType));
				return;
			}
			if (!SpellDataType.IsSubclassOf(typeof(SpellData)))
			{
				BMAPlugin.Log.LogError((object)("Failed to register spell from " + baseUnity.Info.Metadata.Name + ": SpellDataType must be inherited from SpellData!"));
				ModSyncManager.FailedSpells.Add((baseUnity, SpellDataType));
				return;
			}
			if (SpellLogicType != null)
			{
				if (SpellLogicType.IsAbstract)
				{
					BMAPlugin.Log.LogError((object)("Failed to register spell from " + baseUnity.Info.Metadata.Name + ": SpellLogicType can not be abstract!"));
					ModSyncManager.FailedSpells.Add((baseUnity, SpellDataType));
					return;
				}
				if (!SpellLogicType.IsSubclassOf(typeof(SpellLogic)))
				{
					BMAPlugin.Log.LogError((object)("Failed to register spell from " + baseUnity.Info.Metadata.Name + ": SpellDataType must be inherited from SpellLogic!"));
					ModSyncManager.FailedSpells.Add((baseUnity, SpellDataType));
					return;
				}
			}
			if (registeredTypes.Contains(SpellDataType))
			{
				BMAPlugin.Log.LogError((object)("Failed to register spell from " + baseUnity.Info.Metadata.Name + ": " + SpellDataType.Name + " has already been registered!"));
				ModSyncManager.FailedSpells.Add((baseUnity, SpellDataType));
				return;
			}
			switch (CompatibilityManager.CheckSpellCompatibility(SpellDataType))
			{
			case CompatibilityResult.NoProperty:
				BMAPlugin.Log.LogError((object)("Failed to register spell from " + baseUnity.Info.Metadata.Name + ": Unable to find Compatibility property in " + SpellDataType.Name + ", this can be due to " + baseUnity.Info.Metadata.Name + " being outdated!"));
				ModSyncManager.FailedSpells.Add((baseUnity, SpellDataType));
				break;
			case CompatibilityResult.OldVersion:
				BMAPlugin.Log.LogError((object)("Failed to register spell from " + baseUnity.Info.Metadata.Name + ": " + SpellDataType.Name + " Is incompatible with BlackMagicAPI v3.0.1!"));
				ModSyncManager.FailedSpells.Add((baseUnity, SpellDataType));
				break;
			case CompatibilityResult.Error:
				BMAPlugin.Log.LogError((object)("Failed to register spell from " + baseUnity.Info.Metadata.Name + ": An error occurred when trying to get Compatibility Version from " + SpellDataType.Name + "!"));
				ModSyncManager.FailedSpells.Add((baseUnity, SpellDataType));
				break;
			default:
				RegisterSpellTask(baseUnity, SpellDataType, SpellLogicType);
				break;
			}
		}

		private static async Task RegisterSpellTask(BaseUnityPlugin baseUnity, Type spellDataType, Type? spellLogicType)
		{
			object obj = Activator.CreateInstance(spellDataType);
			if (!(obj is SpellData data))
			{
				ModSyncManager.FailedSpells.Add((baseUnity, spellDataType));
				throw new InvalidCastException($"Failed to create or cast {spellDataType} to SpellData");
			}
			data.Plugin = baseUnity;
			SpellLogic spellLogic = await data.GetLogicPrefab();
			if ((Object)(object)spellLogic == (Object)null)
			{
				if (spellLogicType == null)
				{
					ModSyncManager.FailedSpells.Add((baseUnity, spellDataType));
					BMAPlugin.Log.LogError((object)("Failed to register spell from " + baseUnity.Info.Metadata.Name + ": spellLogicType cannot be null without a loadable prefab!"));
					return;
				}
				spellLogic = CreateSpellLogic(data, spellLogicType);
			}
			((Component)spellLogic).gameObject.SetActive(false);
			spellLogic.SpellDataTypeName = spellDataType.FullName;
			spellLogic.KeepOnDeath = data.KeepOnDeath;
			CreateSpell(baseUnity, data, spellLogic);
		}

		private static SpellLogic CreateSpellLogic(SpellData spellData, Type spellLogicType)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Expected O, but got Unknown
			GameOb