Decompiled source of BlackMagicAPI v2.4.0

BepInEx/plugins/BlackMagicAPI/BlackMagicAPI.dll

Decompiled 5 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
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.Logging;
using BlackMagicAPI.Enums;
using BlackMagicAPI.Helpers;
using BlackMagicAPI.Managers;
using BlackMagicAPI.Modules.Items;
using BlackMagicAPI.Modules.Spells;
using BlackMagicAPI.Network;
using BlackMagicAPI.Patches.Items;
using BlackMagicAPI.Patches.Managers;
using BlackMagicAPI.Patches.Voice;
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 Microsoft.CodeAnalysis;
using Recognissimo;
using Recognissimo.Components;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

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

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

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

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

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

		internal const string PluginName = "BlackMagicAPI";

		private const string VersionString = "2.4.0";

		private static Harmony? Harmony;

		private ManualLogSource? _log;

		public static string modsync = "all";

		internal static BMAPlugin Instance { get; private set; }

		internal static ManualLogSource Log => Instance._log;

		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)"BlackMagicAPI v2.4.0 loaded!");
			BlackMagicManager.UpdateSyncHash();
		}
	}
}
namespace BlackMagicAPI.Patches.Voice
{
	[HarmonyPatch(typeof(PlayerInventory))]
	internal class PlayerInventoryPatch
	{
		[HarmonyPatch]
		private static class PlaceOnCraftingTablePatch
		{
			private static MethodBase TargetMethod()
			{
				return Utils.PatchRpcMethod<PlayerInventory>("RpcLogic___PlaceOnCraftingTableObserver");
			}

			[HarmonyPostfix]
			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]
		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]
		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;
		}
	}
}
namespace BlackMagicAPI.Patches.Managers
{
	[HarmonyPatch(typeof(ColoseumManager))]
	internal class ColoseumManagerPatch
	{
		[HarmonyPatch("OnStartClient")]
		[HarmonyPrefix]
		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]
			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]
		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]
		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]
		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]
		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, 78f, 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]
		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.Generation
{
	[HarmonyPatch(typeof(DungeonGenerator))]
	internal class DungeonGeneratorPatch
	{
		[HarmonyPatch("Start")]
		[HarmonyPrefix]
		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;
		}
	}
}
namespace BlackMagicAPI.Patches.Items
{
	[HarmonyPatch(typeof(ChestNetController))]
	internal class ChestNetControllerPatch
	{
		[HarmonyPatch]
		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]
		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(ChestNetController1))]
	internal class ChestNetController1Patch
	{
		[HarmonyPatch]
		private static class ServerPlaceItemPatch
		{
			private static MethodBase TargetMethod()
			{
				return Utils.PatchRpcMethod<ChestNetController1>("RpcLogic___ServerPlaceItem");
			}

			[HarmonyPrefix]
			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]
		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]
			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>();
			resultPrefap.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]
		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(Generator2D))]
	internal class Generator2DPatch
	{
		[HarmonyPatch]
		private static class ServerPlaceItemPatch
		{
			private static MethodBase TargetMethod()
			{
				return Utils.PatchRpcMethod<Generator2D>("RpcLogic___ServerPlaceItem");
			}

			[HarmonyPrefix]
			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]
		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]
			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()
			{
				List<MethodInfo> list = (from m in typeof(PageController).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
					where m.Name.StartsWith("RpcReader___Observers_CastSpellObs")
					select m).ToList();
				if (list.Count == 0)
				{
					throw new Exception("Could not find RpcReader___Observers_CastSpellObs method");
				}
				return list[0];
			}

			[HarmonyPrefix]
			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]
		private static void Interaction_Prefix(PageController __instance, GameObject player)
		{
			if (IsCustomSpell(__instance))
			{
				__instance.spellprefab.GetComponent<SpellLogic>()?.OnPageItemUse(player, __instance);
			}
		}

		[HarmonyPatch("CastSpellServer")]
		[HarmonyPrefix]
		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_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: 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, 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_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)ownerobj != (Object)null)
			{
				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();
					spellLogic.CastSpell(ownerobj, __instance, spawnpos, fwdVector, level);
				}
			}
		}
	}
}
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.Spells
{
	public abstract class ItemData
	{
		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; }

		internal BaseUnityPlugin? Plugin { get; 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);
		}
	}
	internal class CustomSpellCommand : MonoBehaviour, ISpellCommand
	{
		internal string SpellName { get; set; } = "[]";


		internal SpellData SpellData { get; 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 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
	{
		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; }

		internal BaseUnityPlugin? Plugin { get; 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 void CastSpell(GameObject playerObj, PageController page, Vector3 spawnPos, Vector3 viewDirectionVector, int castingLevel);

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

		public virtual void OnPrefabCreatedAutomatically(GameObject prefab)
		{
		}

		public virtual void WriteData(DataWriter dataWriter, PageController page, GameObject playerObj, 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 virtual void OnItemUse(PlayerMovement itemOwner)
		{
			OnItemUse(((Component)itemOwner).gameObject);
		}

		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
			if (!netInit)
			{
				netInit = true;
				((NetworkBehaviour)this).RegisterObserversRpc(0u, new ClientRpcDelegate(HandleSyncClientRpc));
			}
		}

		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(0u, 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();
		}

		[Obsolete("This method is deprecated. Please override OnItemUse(PlayerMovement) instead.")]
		protected virtual void OnItemUse(GameObject itemOwner)
		{
		}
	}
}
namespace BlackMagicAPI.Managers
{
	public class BlackMagicManager
	{
		internal static void UpdateSyncHash()
		{
			StringBuilder stringBuilder = new StringBuilder();
			foreach (var item3 in from map in SpellManager.Mapping
				orderby map.data.Plugin?.GetUniqueHash(), map.data.GetType().FullName
				select map)
			{
				SpellData item = item3.Item1;
				AppendMappingData(stringBuilder, item?.Plugin?.GetUniqueHash(), item?.Id.ToString(), item?.GetType().FullName);
			}
			foreach (var item4 in from map in ItemManager.Mapping
				orderby map.data.Plugin?.GetUniqueHash(), map.data.GetType().FullName
				select map)
			{
				ItemData item2 = item4.Item1;
				AppendMappingData(stringBuilder, item2?.Plugin?.GetUniqueHash(), item2?.Id.ToString(), item2?.GetType().FullName);
			}
			string text = stringBuilder.ToString();
			string text2 = ((text.Length > 0) ? Utils.Generate9DigitHash(text) : "000 | 000 | 000");
			MainMenuManagerPatch.UpdateHash("(Black Magic Sync)\n" + text2);
		}

		private static void AppendMappingData(StringBuilder builder, params string?[] values)
		{
			builder.Append('[');
			foreach (string text in values)
			{
				builder.Append(text ?? "");
			}
			builder.Append(']');
		}

		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 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 static class ItemManager
	{
		private static readonly List<Type> registeredTypes = new List<Type>();

		internal static readonly 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!"));
				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!"));
				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!"));
				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!"));
				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!"));
				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!"));
				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_FirstType)));
				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_FirstType)));
					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!"));
						}
					}
					else
					{
						BMAPlugin.Log.LogError((object)("Failed to register item recipe from " + baseUnity.Info.Metadata.Name + ": Unable to find item prefab for " + IItemInteraction_ResultType.Name + "!"));
					}
				}
				else
				{
					BMAPlugin.Log.LogError((object)("Failed to register item recipe from " + baseUnity.Info.Metadata.Name + ": Unable to find item prefab for " + IItemInteraction_SecondType.Name + "!"));
				}
			}
			else
			{
				BMAPlugin.Log.LogError((object)("Failed to register item recipe from " + baseUnity.Info.Metadata.Name + ": Unable to find item prefab for " + IItemInteraction_FirstType.Name + "!"));
			}
		}

		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
		{
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			if (PrefabMapping.TryGetValue(typeof(T), out IItemInteraction value))
			{
				return (T)(object)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() == typeof(T)));
			if (val != null)
			{
				PrefabMapping[typeof(T)] = val;
				return (T)(object)val;
			}
			T val2 = (T)(IItemInteraction)Resources.FindObjectsOfTypeAll(typeof(T)).FirstOrDefault();
			if (val2 != null)
			{
				PrefabMapping[typeof(T)] = (IItemInteraction)(object)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!"));
				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!"));
				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!"));
					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!"));
					return;
				}
			}
			if (registeredTypes.Contains(ItemDataType))
			{
				BMAPlugin.Log.LogError((object)("Failed to register item from " + baseUnity.Info.Metadata.Name + ": " + ItemDataType.Name + " has already been registered!"));
			}
			else
			{
				RegisterItemTask(baseUnity, ItemDataType, ItemBehaviorType);
			}
		}

		private static async Task RegisterItemTask(BaseUnityPlugin baseUnity, Type spellItemType, Type? itemBehaviorType)
		{
			object obj = Activator.CreateInstance(spellItemType);
			if (!(obj is ItemData data))
			{
				throw new InvalidCastException($"Failed to create or cast {spellItemType} 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!"));
					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_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Expected O, but got Unknown
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Expected O, but got Unknown
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(itemData.Name.Replace(" ", "") + "Item")
			{
				hideFlags = (HideFlags)61
			};
			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;
			NetworkObjectManager.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));
			registeredTypes.Add(itemData2.GetType());
			BlackMagicManager.UpdateSyncHash();
			BMAPlugin.Log.LogInfo((object)("Successfully registered " + itemData2.Name + " Item from " + baseUnity.Info.Metadata.GUID));
		}
	}
	internal class NetworkObjectManager
	{
		private static readonly List<(BaseUnityPlugin plugin, Type type, Func<Sprite?> getSpriteCallback, Action<int> setIdCallback)> Mapping = new List<(BaseUnityPlugin, Type, Func<Sprite>, Action<int>)>();

		internal static void SynchronizeItemId(BaseUnityPlugin baseUnity, Type type, Func<Sprite?> sprite, Action<int> SetIdCallback)
		{
			Mapping.Add((baseUnity, type, sprite, SetIdCallback));
			int num = Resources.FindObjectsOfTypeAll<PlayerInventory>().First().ItemIcons.Length + 1;
			foreach (var item in from m in Mapping
				orderby m.plugin.GetUniqueHash(), m.type.FullName
				select m)
			{
				PlayerInventoryPatch.SetUiSprite(item.Item3(), num);
				item.Item4(num);
				num++;
			}
		}
	}
	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!"));
				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!"));
				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!"));
					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!"));
					return;
				}
			}
			if (registeredTypes.Contains(SpellDataType))
			{
				BMAPlugin.Log.LogError((object)("Failed to register spell from " + baseUnity.Info.Metadata.Name + ": " + SpellDataType.Name + " has already been registered!"));
			}
			else
			{
				RegisterSpellTask(baseUnity, SpellDataType, SpellLogicType);
			}
		}

		private static async Task RegisterSpellTask(BaseUnityPlugin baseUnity, Type spellDataType, Type? spellLogicType)
		{
			object obj = Activator.CreateInstance(spellDataType);
			if (!(obj is SpellData data))
			{
				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)
				{
					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_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Expected O, but got Unknown
			GameObject val = new GameObject(spellData.Name.Replace(" ", "") + "Spell")
			{
				hideFlags = (HideFlags)61
			};
			Object.DontDestroyOnLoad((Object)val);
			SpellLogic obj = (SpellLogic)(object)val.AddComponent(spellLogicType);
			obj.OnPrefabCreatedAutomatically(((Component)obj).gameObject);
			return obj;
		}

		private static void CreateSpell(BaseUnityPlugin baseUnity, SpellData spellData, SpellLogic spellLogic)
		{
			SpellData spellData2 = spellData;
			if (spellData2.SpellType == SpellType.Page)
			{
				PageController val = Resources.FindObjectsOfTypeAll<PageController>().First();
				if ((Object)(object)val != (Object)null)
				{
					PageController prefab = Object.Instantiate<PageController>(val);
					((Object)prefab).hideFlags = (HideFlags)61;
					Object.DontDestroyOnLoad((Object)(object)prefab);
					((Object)prefab).name = "Page" + spellData2.Name.Replace(" ", "");
					NetworkObjectManager.SynchronizeItemId(baseUnity, spellData2.GetType(), spellData2.GetUiSprite, delegate(int id)
					{
						spellData2.Id = id;
						prefab.ItemID = id;
					});
					FishManager.RegisterNetworkObjectPrefab((BaseUnityPlugin)(object)BMAPlugin.Instance, (MonoBehaviour)(object)prefab, spellData2.GetType().FullName, true);
					spellData2.SetUpPage(((Component)prefab).GetComponent<PageController>(), spellLogic);
					spellData2.SetLight(((Component)prefab).GetComponentInChildren<Light>(true));
					Mapping.Add((spellData2, prefab));
					registeredTypes.Add(spellData2.GetType());
					BlackMagicManager.UpdateSyncHash();
				}
			}
			BMAPlugin.Log.LogInfo((object)("Successfully registered " + spellData2.Name + " Spell from " + baseUnity.Info.Metadata.GUID));
		}
	}
}
namespace BlackMagicAPI.Helpers
{
	public static class Utils
	{
		internal static Dictionary<string, Sprite> CachedSprites = new Dictionary<string, Sprite>();

		public static Sprite? LoadSpriteFromDisk(string path, float pixelsPerUnit = 1f)
		{
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (CachedSprites.TryGetValue(path + pixelsPerUnit, out Sprite value))
				{
					return value;
				}
				Texture2D val = LoadTextureFromDisk(path);
				if ((Object)(object)val == (Object)null)
				{
					return null;
				}
				value = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), pixelsPerUnit);
				Sprite obj = value;
				((Object)obj).hideFlags = (HideFlags)(((Object)obj).hideFlags | 0x3D);
				return CachedSprites[path + pixelsPerUnit] = value;
			}
			catch (Exception ex)
			{
				BMAPlugin.Log.LogError((object)ex);
				return null;
			}
		}

		public static Texture2D? LoadTextureFromDisk(string path)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Expected O, but got Unknown
			try
			{
				if (File.Exists(path))
				{
					Texture2D val = new Texture2D(2, 2, (TextureFormat)5, false);
					byte[] array = File.ReadAllBytes(path);
					if (ImageConversion.LoadImage(val, array, false))
					{
						return val;
					}
					BMAPlugin.Log.LogError((object)"Failed to load image data into texture.");
				}
				else
				{
					BMAPlugin.Log.LogError((object)("File does not exist: " + path));
				}
			}
			catch (Exception ex)
			{
				BMAPlugin.Log.LogError((object)("Exception while loading texture: " + ex));
			}
			return null;
		}

		public static Sprite? LoadSpriteFromResources(this Assembly assembly, string path, float pixelsPerUnit = 1f)
		{
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: 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)
			try
			{
				if (CachedSprites.TryGetValue(path + pixelsPerUnit, out Sprite value))
				{
					return value;
				}
				Texture2D val = assembly.LoadTextureFromResources(path);
				if ((Object)(object)val == (Object)null)
				{
					return null;
				}
				value = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), pixelsPerUnit);
				Sprite obj = value;
				((Object)obj).hideFlags = (HideFlags)(((Object)obj).hideFlags | 0x3D);
				return CachedSprites[path + pixelsPerUnit] = value;
			}
			catch (Exception ex)
			{
				BMAPlugin.Log.LogError((object)ex);
				return null;
			}
		}

		public static Texture2D? LoadTextureFromResources(this Assembly assembly, string path)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Expected O, but got Unknown
			try
			{
				Stream manifestResourceStream = assembly.GetManifestResourceStream(path);
				if (manifestResourceStream == null)
				{
					return null;
				}
				Texture2D val = new Texture2D(1, 1, (TextureFormat)5, false);
				using (MemoryStream memoryStream = new MemoryStream())
				{
					manifestResourceStream.CopyTo(memoryStream);
					if (!ImageConversion.LoadImage(val, memoryStream.ToArray(), false))
					{
						return null;
					}
				}
				return val;
			}
			catch (Exception ex)
			{
				BMAPlugin.Log.LogError((object)ex);
				return null;
			}
		}

		public static AudioClip? LoadWavFromDisk(string filePath)
		{
			if (!File.Exists(filePath))
			{
				Debug.LogError((object)("File not found: " + filePath));
				return null;
			}
			if (Path.GetExtension(filePath).ToLower() != ".wav")
			{
				Debug.LogError((object)"Only .wav files are supported.");
				return null;
			}
			try
			{
				return WavUtility.ToAudioClip(File.ReadAllBytes(filePath));
			}
			catch (Exception arg)
			{
				Debug.LogError((object)$"Failed to load WAV: {arg}");
				return null;
			}
		}

		public static AudioClip? LoadWavFromResources(this Assembly assembly, string resourcePath)
		{
			try
			{
				using Stream stream = assembly.GetManifestResourceStream(resourcePath);
				if (stream == null)
				{
					Debug.LogError((object)("Resource not found: " + resourcePath));
					return null;
				}
				using MemoryStream memoryStream = new MemoryStream();
				stream.CopyTo(memoryStream);
				return WavUtility.ToAudioClip(memoryStream.ToArray());
			}
			catch (Exception arg)
			{
				Debug.LogError((object)$"Failed to load WAV from resources: {arg}");
				return null;
			}
		}

		public static AssetBundle? LoadAssetBundleFromDisk(string path)
		{
			try
			{
				if (!File.Exists(path))
				{
					Debug.LogError((object)("AssetBundle file not found at: " + path));
					return null;
				}
				AssetBundle obj = AssetBundle.LoadFromFile(path);
				if ((Object)(object)obj == (Object)null)
				{
					Debug.LogError((object)("Failed to load AssetBundle from: " + path));
				}
				return obj;
			}
			catch (Exception ex)
			{
				Debug.LogError((object)("Exception loading AssetBundle: " + ex.Message));
				return null;
			}
		}

		public static AssetBundle? LoadAssetBundleFromResources(this Assembly assembly, string resourcePath)
		{
			try
			{
				using Stream stream = assembly.GetManifestResourceStream(resourcePath);
				if (stream == null)
				{
					Debug.LogError((object)("Resource not found: " + resourcePath));
					return null;
				}
				using MemoryStream memoryStream = new MemoryStream();
				stream.CopyTo(memoryStream);
				AssetBundle obj = AssetBundle.LoadFromMemory(memoryStream.ToArray());
				if ((Object)(object)obj == (Object)null)
				{
					Debug.LogError((object)("Failed to load AssetBundle from embedded resource: " + resourcePath));
				}
				return obj;
			}
			catch (Exception ex)
			{
				Debug.LogError((object)("Exception loading AssetBundle from resources: " + ex.Message));
				return null;
			}
		}

		internal static string Generate9DigitHash(string input)
		{
			using SHA256 sHA = SHA256.Create();
			return ((long)BitConverter.ToUInt32(sHA.ComputeHash(Encoding.UTF8.GetBytes(input)), 0) % 1000000000L).ToString("000 | 000 | 000");
		}

		internal static string GenerateHash(string input)
		{
			using SHA256 sHA = SHA256.Create();
			return BitConverter.ToString(sHA.ComputeHash(Encoding.UTF8.GetBytes(input))).Trim();
		}

		internal static string GetUniqueHash(this BaseUnityPlugin baseUnity)
		{
			return GenerateHash(baseUnity.Info.Metadata.GUID + "|" + baseUnity.Info.Metadata.Name);
		}

		internal static MethodBase PatchRpcMethod<T>(string rpcNamePrefix)
		{
			string rpcNamePrefix2 = rpcNamePrefix;
			List<MethodInfo> list = (from m in typeof(T).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
				where m.Name.StartsWith(rpcNamePrefix2)
				select m).ToList();
			if (list.Count == 0)
			{
				throw new Exception($"Could not find method that starts with {rpcNamePrefix2} in {typeof(T)}");
			}
			return list[0];
		}

		internal static GameObject? FindInactive(string path, string sceneName = null)
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			if (string.IsNullOrEmpty(path))
			{
				Debug.LogError((object)"[FindInactive] Path is null or empty");
				return null;
			}
			string[] array = path.Split('/');
			if (array.Length == 0)
			{
				Debug.LogError((object)"[FindInactive] Path has no valid segments");
				return null;
			}
			bool flag = string.IsNullOrEmpty(sceneName);
			Transform val = null;
			for (int i = 0; i < SceneManager.sceneCount; i++)
			{
				Scene sceneAt = SceneManager.GetSceneAt(i);
				if (!flag && !((Scene)(ref sceneAt)).name.Equals(sceneName))
				{
					continue;
				}
				GameObject[] rootGameObjects = ((Scene)(ref sceneAt)).GetRootGameObjects();
				foreach (GameObject val2 in rootGameObjects)
				{
					if (((Object)val2).name.Equals(array[0]))
					{
						val = val2.transform;
						Debug.Log((object)("[FindInactive] Found root '" + array[0] + "' in scene '" + ((Scene)(ref sceneAt)).name + "'"));
						break;
					}
				}
				if ((Object)(object)val != (Object)null)
				{
					break;
				}
			}
			if ((Object)(object)val == (Object)null)
			{
				Debug.LogError((object)("[FindInactive] Root object '" + array[0] + "' not found " + (flag ? "in any scene" : ("in scene '" + sceneName + "'"))));
				return null;
			}
			for (int k = 1; k < array.Length; k++)
			{
				val = val.Find(array[k]);
				if ((Object)(object)val == (Object)null)
				{
					Debug.LogError((object)("[FindInactive] Child '" + array[k] + "' not found under '" + array[k - 1] + "'"));
					return null;
				}
			}
			Debug.Log((object)("[FindInactive] Successfully found '" + path + "' " + (flag ? "" : ("in scene '" + sceneName + "'"))));
			return ((Component)val).gameObject;
		}
	}
	internal class WavUtility
	{
		public static AudioClip? ToAudioClip(byte[] wavBytes)
		{
			//IL_0190: Unknown result type (might be due to invalid IL or missing references)
			//IL_0197: Expected O, but got Unknown
			if (wavBytes.Length < 44)
			{
				BMAPlugin.Log.LogError((object)"Invalid WAV file (too short)");
				return null;
			}
			if (wavBytes[0] != 82 || wavBytes[1] != 73 || wavBytes[2] != 70 || wavBytes[3] != 70)
			{
				BMAPlugin.Log.LogError((object)"Invalid WAV file (missing RIFF header)");
				return null;
			}
			int num = BitConverter.ToInt32(wavBytes, 24);
			int num2 = BitConverter.ToInt16(wavBytes, 22);
			int num3 = BitConverter.ToInt32(wavBytes, 40) / 2;
			int i;
			for (i = 36; i < wavBytes.Length - 8; i++)
			{
				if (wavBytes[i] == 100 && wavBytes[i + 1] == 97 && wavBytes[i + 2] == 116 && wavBytes[i + 3] == 97)
				{
					i += 4;
					BitConverter.ToInt32(wavBytes, i);
					i += 4;
					break;
				}
			}
			float[] array = new float[num3];
			for (int j = 0; j < num3; j++)
			{
				short num4 = BitConverter.ToInt16(wavBytes, i + j * 2);
				array[j] = (float)num4 / 32768f;
			}
			Type typeFromHandle = typeof(AudioClip);
			Type[] types = new Type[5]
			{
				typeof(string),
				typeof(int),
				typeof(int),
				typeof(int),
				typeof(bool)
			};
			MethodInfo? method = typeFromHandle.GetMethod("Create", BindingFlags.Static | BindingFlags.Public, null, types, null);
			if (method == null)
			{
				throw new MissingMethodException("AudioClip.Create method not found!");
			}
			AudioClip val = (AudioClip)method.Invoke(null, new object[5]
			{
				"LoadedWav",
				num3 / num2,
				num2,
				num,
				false
			});
			MethodInfo? method2 = typeFromHandle.GetMethod("SetData", BindingFlags.Instance | BindingFlags.Public, null, new Type[2]
			{
				typeof(float[]),
				typeof(int)
			}, null);
			if (method2 == null)
			{
				throw new MissingMethodException("AudioClip.SetData method not found!");
			}
			method2.Invoke(val, new object[2] { array, 0 });
			return val;
		}
	}
}
namespace BlackMagicAPI.Enums
{
	public enum SpellType
	{
		Page
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}