Decompiled source of BetterArchery v2.0.0

BetterArchery/plugins/BetterArchery.dll

Decompiled a week ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using Auga;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using Common;
using HarmonyLib;
using JetBrains.Annotations;
using LitJson;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Networking;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("BetterArchery")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("BetterArchery")]
[assembly: AssemblyCopyright("Copyright ©  2021")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("04f6ef99-721d-41d7-86e2-59ced874c902")]
[assembly: AssemblyFileVersion("1.0.1.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8.1", FrameworkDisplayName = ".NET Framework 4.8.1")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.1.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[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 Common
{
	[Serializable]
	public class RecipeRequirementConfig
	{
		public string item = "";

		public int amount = 1;
	}
	[Serializable]
	public class RecipeConfig
	{
		public string name = "";

		public string item = "";

		public int amount = 1;

		public string craftingStation = "";

		public int minStationLevel = 1;

		public bool enabled = true;

		public string repairStation = "";

		public List<RecipeRequirementConfig> resources = new List<RecipeRequirementConfig>();
	}
	[Serializable]
	public class RecipesConfig
	{
		public List<RecipeConfig> recipes = new List<RecipeConfig>();
	}
	internal class CustomSlotItem : MonoBehaviour
	{
		public string m_slotName;
	}
	public static class CustomSlotCreator
	{
		public static readonly Dictionary<Humanoid, Dictionary<string, ItemData>> customSlotItemData = new Dictionary<Humanoid, Dictionary<string, ItemData>>();

		public static string GetCustomSlotName(ItemData item)
		{
			if (!IsCustomSlotItem(item))
			{
				return null;
			}
			return item.m_dropPrefab.GetComponent<CustomSlotItem>().m_slotName;
		}

		public static bool IsCustomSlotItem(ItemData item)
		{
			return item != null && Object.op_Implicit((Object)(object)item.m_dropPrefab) && Object.op_Implicit((Object)(object)item.m_dropPrefab.GetComponent<CustomSlotItem>());
		}

		private static bool TryGetSlots(Humanoid humanoid, out Dictionary<string, ItemData> slots)
		{
			slots = null;
			return (Object)(object)humanoid != (Object)null && customSlotItemData.TryGetValue(humanoid, out slots) && slots != null;
		}

		public static ItemData GetPrefabItemData(Humanoid humanoid, string slotName)
		{
			if (!TryGetSlots(humanoid, out var slots) || !slots.TryGetValue(slotName, out var value) || value == null || (Object)(object)value.m_dropPrefab == (Object)null)
			{
				return null;
			}
			return value.m_dropPrefab.GetComponent<ItemDrop>()?.m_itemData;
		}

		public static ItemData GetSlotItem(Humanoid humanoid, string slotName)
		{
			Dictionary<string, ItemData> slots;
			ItemData value;
			return (TryGetSlots(humanoid, out slots) && slots.TryGetValue(slotName, out value)) ? value : null;
		}

		public static void SetSlotItem(Humanoid humanoid, string slotName, ItemData item)
		{
			if (!((Object)(object)humanoid == (Object)null))
			{
				if (!TryGetSlots(humanoid, out var slots))
				{
					slots = new Dictionary<string, ItemData>();
					customSlotItemData[humanoid] = slots;
				}
				slots[slotName] = item;
			}
		}

		public static bool DoesSlotExist(Humanoid humanoid, string slotName)
		{
			Dictionary<string, ItemData> slots;
			return TryGetSlots(humanoid, out slots) && slots.ContainsKey(slotName);
		}

		public static bool IsSlotOccupied(Humanoid humanoid, string slotName)
		{
			Dictionary<string, ItemData> slots;
			ItemData value;
			return TryGetSlots(humanoid, out slots) && slots.TryGetValue(slotName, out value) && value != null;
		}

		public static void ApplyCustomSlotItem(GameObject prefab, string slotName)
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			if (Object.op_Implicit((Object)(object)prefab))
			{
				if (!Object.op_Implicit((Object)(object)prefab.GetComponent<CustomSlotItem>()))
				{
					prefab.AddComponent<CustomSlotItem>();
				}
				prefab.GetComponent<CustomSlotItem>().m_slotName = slotName;
				prefab.GetComponent<ItemDrop>().m_itemData.m_shared.m_itemType = (ItemType)0;
				Debug.Log((object)("[CustomSlotCreator] Created " + slotName + " slot for " + ((Object)prefab).name + "."));
			}
		}
	}
	public static class PrefabCreator
	{
		public static Dictionary<string, CraftingStation> CraftingStations;

		public static T RequireComponent<T>(GameObject go) where T : Component
		{
			T val = go.GetComponent<T>();
			if ((Object)(object)val == (Object)null)
			{
				val = go.AddComponent<T>();
			}
			return val;
		}

		public static void Reset()
		{
			CraftingStations = null;
		}

		private static void InitCraftingStations()
		{
			if (CraftingStations != null)
			{
				return;
			}
			CraftingStations = new Dictionary<string, CraftingStation>();
			foreach (Recipe recipe in ObjectDB.instance.m_recipes)
			{
				if ((Object)(object)recipe.m_craftingStation != (Object)null && !CraftingStations.ContainsKey(((Object)recipe.m_craftingStation).name))
				{
					CraftingStations.Add(((Object)recipe.m_craftingStation).name, recipe.m_craftingStation);
				}
			}
		}

		public static Recipe CreateRecipe(string name, string itemId, RecipeConfig recipeConfig)
		{
			//IL_0203: Unknown result type (might be due to invalid IL or missing references)
			//IL_0208: Unknown result type (might be due to invalid IL or missing references)
			//IL_0215: Unknown result type (might be due to invalid IL or missing references)
			//IL_0227: Expected O, but got Unknown
			InitCraftingStations();
			GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(itemId);
			if ((Object)(object)itemPrefab == (Object)null)
			{
				Debug.LogWarning((object)("[PrefabCreator] Could not find item prefab (" + itemId + ")"));
				return null;
			}
			Recipe val = ScriptableObject.CreateInstance<Recipe>();
			((Object)val).name = name;
			val.m_amount = recipeConfig.amount;
			val.m_minStationLevel = recipeConfig.minStationLevel;
			val.m_item = itemPrefab.GetComponent<ItemDrop>();
			val.m_enabled = recipeConfig.enabled;
			if (!string.IsNullOrEmpty(recipeConfig.craftingStation))
			{
				if (!CraftingStations.ContainsKey(recipeConfig.craftingStation))
				{
					Debug.LogWarning((object)("[PrefabCreator] Could not find crafting station (" + itemId + "): " + recipeConfig.craftingStation));
					string text = string.Join(", ", CraftingStations.Keys);
					Debug.Log((object)("[PrefabCreator] Available Stations: " + text));
				}
				else
				{
					val.m_craftingStation = CraftingStations[recipeConfig.craftingStation];
				}
			}
			if (!string.IsNullOrEmpty(recipeConfig.repairStation))
			{
				if (!CraftingStations.ContainsKey(recipeConfig.repairStation))
				{
					Debug.LogWarning((object)("[PrefabCreator] Could not find repair station (" + itemId + "): " + recipeConfig.repairStation));
					string text2 = string.Join(", ", CraftingStations.Keys);
					Debug.Log((object)("[PrefabCreator] Available Stations: " + text2));
				}
				else
				{
					val.m_repairStation = CraftingStations[recipeConfig.repairStation];
				}
			}
			List<Requirement> list = new List<Requirement>();
			foreach (RecipeRequirementConfig resource in recipeConfig.resources)
			{
				GameObject itemPrefab2 = ObjectDB.instance.GetItemPrefab(resource.item);
				if ((Object)(object)itemPrefab2 == (Object)null)
				{
					Debug.LogError((object)("[PrefabCreator] Could not find requirement item (" + itemId + "): " + resource.item));
					continue;
				}
				list.Add(new Requirement
				{
					m_amount = resource.amount,
					m_resItem = itemPrefab2.GetComponent<ItemDrop>()
				});
			}
			val.m_resources = list.ToArray();
			return val;
		}

		public static Recipe AddNewRecipe(string name, string itemId, RecipeConfig recipeConfig)
		{
			Recipe val = CreateRecipe(name, itemId, recipeConfig);
			if ((Object)(object)val == (Object)null)
			{
				Debug.LogError((object)("[PrefabCreator] Failed to create recipe (" + name + ")"));
				return null;
			}
			return AddNewRecipe(val);
		}

		public static Recipe AddNewRecipe(Recipe recipe)
		{
			int num = ObjectDB.instance.m_recipes.RemoveAll((Recipe x) => ((Object)x).name == ((Object)recipe).name);
			if (num > 0)
			{
				Debug.Log((object)$"[PrefabCreator] Removed recipe ({((Object)recipe).name}): {num}");
			}
			ObjectDB.instance.m_recipes.Add(recipe);
			Debug.Log((object)("[PrefabCreator] Added recipe: " + ((Object)recipe).name));
			return recipe;
		}
	}
	public static class Utils
	{
		private static MethodInfo _loadImageMethod;

		public static void PrintObject(object o)
		{
			if (o == null)
			{
				Debug.Log((object)"null");
			}
			else
			{
				Debug.Log((object)(o?.ToString() + ":\n" + GetObjectString(o, "  ")));
			}
		}

		public static string GetObjectString(object obj, string indent)
		{
			string text = "";
			Type type = obj.GetType();
			IEnumerable<FieldInfo> enumerable = from f in type.GetFields()
				where f.IsPublic
				select f;
			foreach (FieldInfo item in enumerable)
			{
				object value = item.GetValue(obj);
				string text2 = ((value == null) ? "null" : value.ToString());
				text = text + "\n" + indent + item.Name + ": " + text2;
			}
			return text;
		}

		private static bool LoadImageCompat(Texture2D tex, byte[] data)
		{
			try
			{
				if (_loadImageMethod == null)
				{
					Type type = Type.GetType("UnityEngine.ImageConversion, UnityEngine.ImageConversionModule");
					if (type == null)
					{
						Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
						foreach (Assembly assembly in assemblies)
						{
							if (assembly.GetName().Name == "UnityEngine.ImageConversionModule")
							{
								type = assembly.GetType("UnityEngine.ImageConversion");
								if (type != null)
								{
									break;
								}
							}
						}
					}
					if (type == null)
					{
						return false;
					}
					_loadImageMethod = type.GetMethod("LoadImage", new Type[2]
					{
						typeof(Texture2D),
						typeof(byte[])
					});
				}
				if (_loadImageMethod == null)
				{
					return false;
				}
				return (bool)_loadImageMethod.Invoke(null, new object[2] { tex, data });
			}
			catch
			{
				return false;
			}
		}

		public static Sprite LoadSpriteFromFile(string spritePath)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Expected O, but got Unknown
			//IL_004e: 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_005b: Unknown result type (might be due to invalid IL or missing references)
			spritePath = Path.Combine(Paths.PluginPath, spritePath);
			if (File.Exists(spritePath))
			{
				byte[] data = File.ReadAllBytes(spritePath);
				Texture2D val = new Texture2D(20, 20);
				if (LoadImageCompat(val, data))
				{
					return Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), default(Vector2), 100f);
				}
			}
			return null;
		}

		public static Sprite LoadSpriteFromFile(string modFolder, string iconName)
		{
			string spritePath = Path.Combine(modFolder, iconName);
			return LoadSpriteFromFile(spritePath);
		}

		public static bool IsServer()
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Invalid comparison between Unknown and I4
			return ZNet.instance.IsServer() || ZNet.instance.IsDedicated() || (int)SystemInfo.graphicsDeviceType == 4;
		}
	}
}
namespace BetterArchery
{
	public class Arrow
	{
		public string Name { get; set; }

		public float SpawnChance { get; set; }

		public string SpawnArrow { get; set; }
	}
	public enum QuiverHudOrientation
	{
		Horizontal,
		Vertical
	}
	[BepInPlugin("ishid4.mods.betterarchery", "Better Archery", "2.0.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class BetterArchery : BaseUnityPlugin
	{
		public enum ZoomState
		{
			Fixed,
			ZoomingIn,
			ZoomingOut
		}

		public const int QuiverUseSlotCount = 3;

		public static bool ZoomSfx;

		public static Dictionary<string, Dictionary<string, AudioClip>> CustomSfxDict = new Dictionary<string, Dictionary<string, AudioClip>>();

		private static readonly Dictionary<string, AudioClip[]> _customSfxClipCache = new Dictionary<string, AudioClip[]>();

		private static readonly Dictionary<string, AudioSource> _customSfxAudioSources = new Dictionary<string, AudioSource>();

		public static bool SpeedReduction;

		public static bool IsContainerOpen;

		public static float ZoomInTimer = 0.1f;

		public static float ZoomOutTimer;

		public static float ZoomOutDelayTimer = 0f;

		public static float __BaseFov;

		public static float __LastZoomFov;

		public static float __NewZoomFov = 0f;

		public static ZoomState __ZoomState;

		public static int QuiverRowIndex = 0;

		public static ConfigEntry<KeyboardShortcut> HoldingKeyCode;

		public static ConfigEntry<KeyboardShortcut>[] KeyCodes = new ConfigEntry<KeyboardShortcut>[3];

		public static ConfigEntry<string> ArrowRetrieveList;

		public static readonly Dictionary<string, Arrow> ArrowRetrieves = new Dictionary<string, Arrow>();

		public static ConfigEntry<float> ArrowDisappearTime;

		public static ConfigEntry<bool> ArrowDisappearOnHit;

		public static ConfigEntry<bool> ArrowRetrieveSolidCollider;

		public static ConfigEntry<Vector2> InventoryQuiverSlotLocation;

		public static ConfigEntry<Vector2> InventoryQuiverSlotLocationWithContainer;

		public static ConfigEntry<bool> QuiverHudEnabled;

		public static ConfigEntry<float> QuiverHudScale;

		public static ConfigEntry<Vector2> QuiverHudPositionOffset;

		public static ConfigEntry<QuiverHudOrientation> QuiverHudLayout;

		public static ConfigEntry<Vector3> QuiverModelRotation;

		public static ConfigEntry<Vector3> QuiverModelScale;

		public static ConfigEntry<Vector3> QuiverModelPosition;

		public static ConfigEntry<float> ArrowVelocity;

		public static ConfigEntry<float> ArrowGravity;

		public static ConfigEntry<float> ArrowAccuracy;

		public static ConfigEntry<Vector3> ArrowAimDir;

		public static ConfigEntry<bool> ConfigQuiverEnabled;

		public static ConfigEntry<bool> ConfigArrowImprovementsEnabled;

		public static ConfigEntry<bool> ConfigRetrievableArrowsEnabled;

		public static ConfigEntry<bool> ConfigBowZoomEnabled;

		public static ConfigEntry<KeyboardShortcut> BowDrawCancelKey;

		public static ConfigEntry<bool> BowDrawCancelEnabled;

		public static ConfigEntry<string> BowDrawCancelGamepadButton;

		public static ConfigEntry<float> BowZoomFactor;

		public static ConfigEntry<bool> AutomaticBowZoom;

		public static ConfigEntry<KeyboardShortcut> BowZoomKey;

		public static ConfigEntry<float> BowZoomConstantTime;

		public static ConfigEntry<bool> BowZoomSFXEnabled;

		public static ConfigEntry<float> StayInZoomTime;

		public static ConfigEntry<bool> IsCrosshairVisible;

		public static ConfigEntry<bool> IsBowCrosshairVisible;

		public static ConfigEntry<bool> ShowSneakDamage;

		public static ConfigEntry<bool> BowDrawMovementSpeedReductionEnabled;

		public static ConfigEntry<bool> ConfigCrouchBowDrawEnabled;

		public static ConfigEntry<bool> NockedArrowEnabled;

		public const string CrouchBowDrawClipName = "Bow Aim Idle 01";

		public const string CrouchBowDrawStateName = "staff_charge_loop";

		public static readonly Vector3 NockedArrowPosition = new Vector3(-0.01f, 0f, 0f);

		public static readonly Vector3 NockedArrowRotation = new Vector3(-1f, 0f, 0f);

		public const float NockedArrowScale = 1f;

		public const float NockedArrowYaw = 6f;

		public const string NockedArrowFlipped = "ArrowCarapace,BoltCarapace";

		public static ConfigEntry<int> DebugLevel;

		public static RecipesConfig Recipes;

		public static ConfigEntry<bool> WoodenArrowEverywhereEnabled;

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

		public static GameObject QuiverGO;

		public static ConfigEntry<int> NexusID;

		public static AudioSource PlayerAudioSource;

		public static BetterArchery _instance;

		private Harmony _harmony;

		public const string EquipmentAndQuickSlotsGuid = "randyknapp.mods.equipmentandquickslots";

		private static int eaqsPresent = -1;

		public const string ExtendedPlayerInventoryGuid = "aedenthorn.ExtendedPlayerInventory";

		private static int epiPresent = -1;

		public static bool hasAuga { get; private set; }

		public static bool isEquipmentAndQuickSlotsPresent
		{
			get
			{
				if (eaqsPresent < 0)
				{
					eaqsPresent = (Chainloader.PluginInfos.ContainsKey("randyknapp.mods.equipmentandquickslots") ? 1 : 0);
				}
				return eaqsPresent == 1;
			}
		}

		public static bool isExtendedPlayerInventoryPresent
		{
			get
			{
				if (epiPresent < 0)
				{
					epiPresent = (Chainloader.PluginInfos.ContainsKey("aedenthorn.ExtendedPlayerInventory") ? 1 : 0);
				}
				return epiPresent == 1;
			}
		}

		public static bool isInventoryExpansionModPresent => isEquipmentAndQuickSlotsPresent || isExtendedPlayerInventoryPresent;

		private void Awake()
		{
			//IL_0041: 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)
			//IL_00a2: 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_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_017a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0226: Unknown result type (might be due to invalid IL or missing references)
			//IL_0253: Unknown result type (might be due to invalid IL or missing references)
			//IL_030e: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_040f: Unknown result type (might be due to invalid IL or missing references)
			_instance = this;
			ConfigQuiverEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Quiver", "Enable Quiver", true, "Enable the quiver. Don't change this value while in the game. If you disable this while arrows are in the quiver, you will LOSE ALL OF THEM!");
			InventoryQuiverSlotLocation = ((BaseUnityPlugin)this).Config.Bind<Vector2>("Quiver", "Change location of inventory quiver slot", new Vector2(3f, -25f), "Change quiver slot inventory location. For 'More Slots' you can use this location, 'x:3.0, y:-167.0'.");
			InventoryQuiverSlotLocationWithContainer = ((BaseUnityPlugin)this).Config.Bind<Vector2>("Quiver", "Change location of inventory quiver slot when a chest opened", new Vector2(3f, -425f), "Change quiver slot inventory location when a chest opened.");
			QuiverModelRotation = ((BaseUnityPlugin)this).Config.Bind<Vector3>("Quiver", "Change Quiver Model Rotation", new Vector3(270f, 90f, -10f), "Change the quiver model rotation. Default is 'x:270.0, y:90.0, z:-10.0'");
			QuiverModelScale = ((BaseUnityPlugin)this).Config.Bind<Vector3>("Quiver", "Change Quiver Model Scale", new Vector3(2f, 2f, 2f), "Change the quiver model scale. Default is 'x:2.0, y:2.0, z:2.0'");
			QuiverModelPosition = ((BaseUnityPlugin)this).Config.Bind<Vector3>("Quiver", "Change Quiver Model Position", new Vector3(0.001f, 0f, 0.003f), "Change the quiver model position. Default is 'x:0.001, y:0.0, z:0.003'");
			QuiverHudEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Quiver", "Enable Quiver Hud", true, "Enable the quiver's hotbar on the screen/hud. This doesn't affect inventory.");
			QuiverHudScale = ((BaseUnityPlugin)this).Config.Bind<float>("Quiver", "Quiver Hud Scale", 0.7f, "Size of the quiver HUD slots.");
			QuiverHudPositionOffset = ((BaseUnityPlugin)this).Config.Bind<Vector2>("Quiver", "Quiver Hud Position Offset", new Vector2(-5f, 180f), "Change the quiver HUD position. Default is 'x:-5.0, y:180'");
			QuiverHudLayout = ((BaseUnityPlugin)this).Config.Bind<QuiverHudOrientation>("Quiver", "Quiver Hud Orientation", QuiverHudOrientation.Horizontal, "Layout of the quiver HUD slots: a horizontal row or a vertical column.");
			HoldingKeyCode = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Quiver", "Quiver slot hotkey holding key", new KeyboardShortcut((KeyCode)308, Array.Empty<KeyCode>()), "Change holding key. For the inputs: https://docs.unity3d.com/ScriptReference/KeyCode.html");
			KeyCodes[0] = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Quiver", "Quiver slot hotkey 1", new KeyboardShortcut((KeyCode)49, Array.Empty<KeyCode>()), "Hotkey for Quiver Slot 1. For the inputs: https://docs.unity3d.com/ScriptReference/KeyCode.html");
			KeyCodes[1] = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Quiver", "Quiver slot hotkey 2", new KeyboardShortcut((KeyCode)50, Array.Empty<KeyCode>()), "Hotkey for Quiver Slot 2. For the inputs: https://docs.unity3d.com/ScriptReference/KeyCode.html");
			KeyCodes[2] = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Quiver", "Quiver slot hotkey 3", new KeyboardShortcut((KeyCode)51, Array.Empty<KeyCode>()), "Hotkey for Quiver Slot 3. For the inputs: https://docs.unity3d.com/ScriptReference/KeyCode.html");
			ConfigArrowImprovementsEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Arrow Improvements", "Enable Arrow Improvements", true, "Arrow improvements including aim problems fixes, gravity changes.");
			ArrowVelocity = ((BaseUnityPlugin)this).Config.Bind<float>("Arrow Improvements", "Set Arrow Velocity", 70f, "Change the arrow's velocity. Vanilla is '60'.");
			ArrowGravity = ((BaseUnityPlugin)this).Config.Bind<float>("Arrow Improvements", "Set Arrow Gravity", 15f, "Change the arrow's gravity. Vanilla is '5'.");
			ArrowAccuracy = ((BaseUnityPlugin)this).Config.Bind<float>("Arrow Improvements", "Set Arrow Accuracy", 0f, "Change the arrow's accuracy. Vanilla is '-1'.");
			ArrowAimDir = ((BaseUnityPlugin)this).Config.Bind<Vector3>("Arrow Improvements", "Set Aim Direction", new Vector3(0f, 0.05f, 0f), "Change the aim direction. Vanilla is 'x:0.0, y:0.0, z: 0.0'.");
			ConfigBowZoomEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Bow Zoom", "Enable Bow Zoom", true, "Enable the zooming with bow.");
			AutomaticBowZoom = ((BaseUnityPlugin)this).Config.Bind<bool>("Bow Zoom", "Automatic Bow Zoom", false, "Zoom while drawing bow automatically.");
			BowZoomSFXEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Bow Zoom", "Enable Bow Zoom SFX", true, "Sound effects for zoom-in and zoom-out.");
			BowZoomFactor = ((BaseUnityPlugin)this).Config.Bind<float>("Bow Zoom", "Zoom Factor", 2f, "Max zoom.");
			BowZoomConstantTime = ((BaseUnityPlugin)this).Config.Bind<float>("Bow Zoom", "Bow Zoom Constant Time", -1f, "Change this value to '-1' if you don't want constant time while zooming. '1' is recommended.");
			BowZoomKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Bow Zoom", "Bow Zoom Hotkey", new KeyboardShortcut((KeyCode)324, Array.Empty<KeyCode>()), "Mouse0: Left Click, Mouse1: Right Click, Mouse2: Middle Click. For the other inputs: https://docs.unity3d.com/ScriptReference/KeyCode.html");
			BowDrawCancelKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Bow Zoom", "Bow Draw Cancel Hotkey", new KeyboardShortcut((KeyCode)101, Array.Empty<KeyCode>()), "Mouse0: Left Click, Mouse1: Right Click, Mouse2: Middle Click. For the other inputs: https://docs.unity3d.com/ScriptReference/KeyCode.html");
			BowDrawCancelEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Bow Zoom", "Enable Bow Draw Cancel", true, "When enabled, the Bow Draw Cancel Hotkey cancels bow drawing. Disable to restore vanilla cancel behavior.");
			BowDrawCancelGamepadButton = ((BaseUnityPlugin)this).Config.Bind<string>("Bow Zoom", "Bow Draw Cancel Gamepad Button", "JoyBlock", "Gamepad button that cancels bow drawing (ZInput button name). Empty to disable gamepad cancel. Requires 'Enable Bow Draw Cancel'.");
			StayInZoomTime = ((BaseUnityPlugin)this).Config.Bind<float>("Bow Zoom", "Stay In-Zoom Time", 2f, "Set the max time of staying on zoom while holding RMB after releasing an arrow.");
			IsCrosshairVisible = ((BaseUnityPlugin)this).Config.Bind<bool>("Other", "Enable Crosshair", true, "You can hide your crosshair.");
			IsBowCrosshairVisible = ((BaseUnityPlugin)this).Config.Bind<bool>("Other", "Enable Bow Crosshair", true, "You can hide your circle bow crosshair.");
			ShowSneakDamage = ((BaseUnityPlugin)this).Config.Bind<bool>("Other", "Enable Sneak Damage Showing", true, "Show sneak damage at top left.");
			BowDrawMovementSpeedReductionEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Other", "Enable Bow Draw Movement Speed Reduction", true, "Set walk speed while drawing bow.");
			ConfigCrouchBowDrawEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Other", "Enable Crouch Bow Draw", true, "Keep the character crouched while drawing a bow.");
			NockedArrowEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Other", "Enable Nocked Arrow", true, "Show the selected arrow model nocked on the bow string while drawing.");
			WoodenArrowEverywhereEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Other", "Enable Crafting Wooden Arrow Everywhere", true, "Enable to crafting wooden arrows without a crafting table.");
			ConfigRetrievableArrowsEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Retrievable Arrows", "Enable Retrievable Arrows", true, "Enable the retrievable arrows.");
			ArrowDisappearTime = ((BaseUnityPlugin)this).Config.Bind<float>("Retrievable Arrows", "Arrow Disappear Time", 60f, "Set arrow's disappear countdown time.");
			ArrowDisappearOnHit = ((BaseUnityPlugin)this).Config.Bind<bool>("Retrievable Arrows", "Arrow Disappear On Hit", false, "Make non-retrievable arrows disappear on hit.");
			ArrowRetrieveSolidCollider = ((BaseUnityPlugin)this).Config.Bind<bool>("Retrievable Arrows", "Retrievable Arrow Solid Collider", false, "Let players stand on retrievable arrows stuck in the ground.");
			ArrowRetrieveList = ((BaseUnityPlugin)this).Config.Bind<string>("Retrievable Arrows", "Arrow Retrieve List", "ArrowWood=0.2;ArrowFlint=0.3;ArrowBronze=0.5;ArrowIron=0.7;ArrowObsidian=0.7;ArrowNeedle=0.1;ArrowFire=0;ArrowPoison=0.7>ArrowObsidian;ArrowSilver=0.5;ArrowFrost=0.7>ArrowObsidian;ArrowCarapace=0.7;ArrowCharred=0.7;BoltBone=0.3;BoltIron=0.5;BoltBlackmetal=0.7;BoltCarapace=0.7;BoltCharred=0.7", "Retrievable ammo list. Format: AmmoPrefab=chance>SpawnPrefab, entries separated by ';'. The '>SpawnPrefab' part is optional and defaults to the same ammo. Example: ArrowWood=0.2;ArrowPoison=0.7>ArrowObsidian");
			ArrowRetrieveList.SettingChanged += delegate
			{
				RebuildArrowRetrieves();
			};
			NexusID = ((BaseUnityPlugin)this).Config.Bind<int>("Other", "NexusID", 348, "Nexus mod ID for updates.");
			DebugLevel = ((BaseUnityPlugin)this).Config.Bind<int>("Other", "Set Debug Log Level", 1, "0: Nothing, 1: Only Errors, 2: Errors and Warnings, 3: Everything");
			RebuildArrowRetrieves();
			Recipes = LoadJsonFile<RecipesConfig>("BetterArcheryRecipes.json");
			if (ConfigQuiverEnabled.Value)
			{
				AssetBundle val = LoadAssetBundle("quiverassets");
				if (Recipes != null && (Object)(object)val != (Object)null)
				{
					foreach (RecipeConfig recipe in Recipes.recipes)
					{
						if (val.Contains(recipe.item))
						{
							GameObject value = val.LoadAsset<GameObject>(recipe.item);
							Prefabs.Add(recipe.item, value);
						}
					}
				}
				if (val != null)
				{
					val.Unload(false);
				}
			}
			_harmony = Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), (string)null);
			hasAuga = API.IsLoaded();
		}

		public static void RebuildArrowRetrieves()
		{
			ArrowRetrieves.Clear();
			string text = ArrowRetrieveList?.Value;
			if (string.IsNullOrEmpty(text))
			{
				return;
			}
			string[] array = text.Split(new char[1] { ';' });
			foreach (string text2 in array)
			{
				string text3 = text2.Trim();
				if (text3.Length == 0)
				{
					continue;
				}
				string[] array2 = text3.Split(new char[1] { '=' });
				if (array2.Length != 2)
				{
					Log("Invalid arrow retrieve entry (expected Ammo=chance>Spawn): '" + text3 + "'", 1);
					continue;
				}
				string text4 = array2[0].Trim();
				string text5 = array2[1];
				string text6 = text5;
				string text7 = text4;
				int num = text5.IndexOf('>');
				if (num >= 0)
				{
					text6 = text5.Substring(0, num);
					text7 = text5.Substring(num + 1).Trim();
				}
				if (text4.Length == 0 || text7.Length == 0 || !float.TryParse(text6.Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out var result))
				{
					Log("Invalid arrow retrieve entry: '" + text3 + "'", 1);
					continue;
				}
				ArrowRetrieves[text4] = new Arrow
				{
					Name = text4,
					SpawnChance = Mathf.Clamp01(result),
					SpawnArrow = text7
				};
			}
			Log($"Loaded {ArrowRetrieves.Count} retrievable ammo entries.", 3);
		}

		public void Start()
		{
			hasAuga = API.IsLoaded();
			if (hasAuga)
			{
				Log("Auga Loaded.");
			}
			Dictionary<string, object> dictionary = LoadTranslationJsonFile<Dictionary<string, object>>("betterarchery_translations.json");
			if (dictionary.Count > 0)
			{
				LoadTranslations(dictionary);
			}
		}

		private void Update()
		{
			Player localPlayer = Player.m_localPlayer;
			CrouchBowDrawOverlay.Update(localPlayer);
			NockedArrow.Update(localPlayer);
			if (!((Object)(object)localPlayer == (Object)null) && ConfigQuiverEnabled.Value && ((Character)localPlayer).TakeInput())
			{
				for (int i = 0; i < 3; i++)
				{
					CheckQuiverUseInput(localPlayer, i);
				}
			}
		}

		private void OnDestroy()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			foreach (GameObject value in Prefabs.Values)
			{
				Object.Destroy((Object)(object)value);
			}
			Prefabs.Clear();
		}

		public static void Log(string str = "", int warningType = 2)
		{
			int num = ((DebugLevel == null) ? 1 : DebugLevel.Value);
			if (num == 0)
			{
				return;
			}
			if (warningType == 0)
			{
				Debug.LogError((object)("[" + typeof(BetterArchery).Namespace + "]: " + str));
			}
			if (num > 1)
			{
				if (warningType == 1)
				{
					Debug.LogWarning((object)("[" + typeof(BetterArchery).Namespace + "]: " + str));
				}
				if (num > 2 && warningType == 2)
				{
					Debug.Log((object)("[" + typeof(BetterArchery).Namespace + "]: " + str));
				}
			}
		}

		private static void LoadTranslations(Dictionary<string, object> translations)
		{
			if (translations == null)
			{
				Log("Could not parse betterarchery_translations.json!", 3);
				return;
			}
			List<KeyValuePair<string, string>> list = Localization.instance.m_translations.Where((KeyValuePair<string, string> instanceMTranslation) => instanceMTranslation.Key.StartsWith("mod_betterarchery_")).ToList();
			foreach (KeyValuePair<string, string> item in list)
			{
				Localization.instance.m_translations.Remove(item.Key);
			}
			foreach (KeyValuePair<string, object> translation in translations)
			{
				Localization.instance.AddWord(translation.Key, translation.Value.ToString());
			}
		}

		public unsafe static string GetBindingLabel(int index)
		{
			//IL_000c: 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)
			index = Mathf.Clamp(index, 0, 2);
			KeyCode bindingKeycode = GetBindingKeycode(index);
			if (((object)(*(KeyCode*)(&bindingKeycode))/*cast due to .constrained prefix*/).ToString().Contains("Alpha"))
			{
				return ((object)(*(KeyCode*)(&bindingKeycode))/*cast due to .constrained prefix*/).ToString().Replace("Alpha", "");
			}
			return ((object)(*(KeyCode*)(&bindingKeycode))/*cast due to .constrained prefix*/).ToString().ToUpperInvariant();
		}

		public static KeyCode GetBindingKeycode(int index)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: 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)
			index = Mathf.Clamp(index, 0, 2);
			KeyboardShortcut value = KeyCodes[index].Value;
			return ((KeyboardShortcut)(ref value)).MainKey;
		}

		public static bool IsBowZoomHeld()
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: 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)
			int result;
			if (BowZoomKey != null)
			{
				KeyboardShortcut value = BowZoomKey.Value;
				result = (Input.GetKey(((KeyboardShortcut)(ref value)).MainKey) ? 1 : 0);
			}
			else
			{
				result = 0;
			}
			return (byte)result != 0;
		}

		public static bool IsBowDrawCancelPressed()
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: 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)
			if (BowDrawCancelKey != null)
			{
				KeyboardShortcut value = BowDrawCancelKey.Value;
				if (Input.GetKey(((KeyboardShortcut)(ref value)).MainKey))
				{
					return true;
				}
			}
			string text = BowDrawCancelGamepadButton?.Value;
			if (!string.IsNullOrEmpty(text) && ZInput.IsGamepadActive())
			{
				try
				{
					if (ZInput.GetButton(text))
					{
						return true;
					}
				}
				catch
				{
				}
			}
			return false;
		}

		public static int GetBonusInventoryRowIndex()
		{
			if (Object.op_Implicit((Object)(object)Player.m_localPlayer) && QuiverRowIndex != 0)
			{
				return QuiverRowIndex;
			}
			return 0;
		}

		public static void CheckQuiverUseInput(Player player, int index)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: 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)
			KeyCode bindingKeycode = GetBindingKeycode(index);
			KeyboardShortcut value = HoldingKeyCode.Value;
			bool flag;
			if (!string.IsNullOrEmpty(((KeyboardShortcut)(ref value)).Serialize()))
			{
				value = HoldingKeyCode.Value;
				if (((KeyboardShortcut)(ref value)).Serialize() != "None")
				{
					value = HoldingKeyCode.Value;
					flag = Input.GetKey(((KeyboardShortcut)(ref value)).MainKey) && Input.GetKeyDown(bindingKeycode);
					goto IL_0070;
				}
			}
			flag = Input.GetKeyDown(bindingKeycode);
			goto IL_0070;
			IL_0070:
			if (flag)
			{
				int bonusInventoryRowIndex = GetBonusInventoryRowIndex();
				ItemData itemAt = ((Humanoid)player).GetInventory().GetItemAt(index, bonusInventoryRowIndex);
				if (itemAt != null)
				{
					((Humanoid)player).UseItem((Inventory)null, itemAt, false);
				}
			}
		}

		public static bool IsQuiverSlot(Vector2i pos)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			return IsQuiverSlot(pos.x, pos.y);
		}

		public static bool IsQuiverSlot(int x, int y)
		{
			int bonusInventoryRowIndex = GetBonusInventoryRowIndex();
			return y == bonusInventoryRowIndex && x >= 0 && x < 3;
		}

		public static Vector2i GetQuiverSlotPosition(int index)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: 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)
			int bonusInventoryRowIndex = GetBonusInventoryRowIndex();
			return new Vector2i(index, bonusInventoryRowIndex);
		}

		public static bool IsQuiverEquipped()
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return false;
			}
			if (CustomSlotCreator.IsSlotOccupied((Humanoid)(object)localPlayer, "quiver"))
			{
				return true;
			}
			Inventory inventory = ((Humanoid)localPlayer).GetInventory();
			return inventory != null && inventory.GetEquippedItems().Any((ItemData item) => CustomSlotCreator.IsCustomSlotItem(item) && CustomSlotCreator.GetCustomSlotName(item) == "quiver");
		}

		private static T LoadJsonFile<T>(string filename) where T : class
		{
			string assetPath = GetAssetPath(filename);
			if (!string.IsNullOrEmpty(assetPath))
			{
				string json = File.ReadAllText(assetPath);
				return JsonMapper.ToObject<T>(json);
			}
			return null;
		}

		private static Dictionary<string, object> LoadTranslationJsonFile<T>(string filename) where T : class
		{
			string assetPath = GetAssetPath(filename);
			if (!string.IsNullOrEmpty(assetPath))
			{
				string json = File.ReadAllText(assetPath);
				return JsonMapper.ToObject<Dictionary<string, object>>(json);
			}
			return null;
		}

		public static AssetBundle LoadAssetBundle(string filename)
		{
			Assembly callingAssembly = Assembly.GetCallingAssembly();
			AssetBundle result = AssetBundle.LoadFromStream(callingAssembly.GetManifestResourceStream(callingAssembly.GetName().Name + "." + filename));
			Log("Loaded AssetBundle (" + filename + ").", 3);
			Log(callingAssembly.GetName().Name);
			return result;
		}

		public static string GetAssetPath(string assetName, bool isDirectory = false)
		{
			string text = Path.Combine(Paths.PluginPath, "BetterArchery", assetName);
			if (isDirectory)
			{
				if (!Directory.Exists(text))
				{
					Assembly assembly = typeof(BetterArchery).Assembly;
					text = Path.Combine(Path.GetDirectoryName(assembly.Location), assetName);
					if (!Directory.Exists(text))
					{
						Log("Could not find directory (" + assetName + ").", 1);
						return null;
					}
				}
				return text;
			}
			if (!File.Exists(text))
			{
				Assembly assembly2 = typeof(BetterArchery).Assembly;
				text = Path.Combine(Path.GetDirectoryName(assembly2.Location), assetName);
				if (!File.Exists(text))
				{
					Log("Could not find asset (" + assetName + ").", 1);
					return null;
				}
			}
			return text;
		}

		public static void TryCreateCustomSlot(ZNetScene zNetScene)
		{
			if (!((Object)(object)zNetScene == (Object)null) && ConfigQuiverEnabled.Value)
			{
				GameObject prefab = zNetScene.GetPrefab("LeatherQuiver");
				CustomSlotCreator.ApplyCustomSlotItem(prefab, "quiver");
			}
		}

		public static void TryCreateCustomSFX()
		{
			if (!ConfigBowZoomEnabled.Value || !BowZoomSFXEnabled.Value)
			{
				return;
			}
			string assetPath = GetAssetPath("SFX", isDirectory: true);
			if (string.IsNullOrEmpty(assetPath))
			{
				Log("SFX folder not found.");
				return;
			}
			Log("path: " + assetPath);
			string[] directories = Directory.GetDirectories(assetPath);
			foreach (string path in directories)
			{
				Log("Checking folder " + Path.GetFileName(path));
				CustomSfxDict[Path.GetFileName(path)] = new Dictionary<string, AudioClip>();
				string[] files = Directory.GetFiles(path);
				foreach (string path2 in files)
				{
					if (Path.GetExtension(path2).ToLower().Equals(".wav"))
					{
						Log("Checking file " + Path.GetFileName(path2));
						((MonoBehaviour)_instance).StartCoroutine(LoadSFXCoroutine(path2, CustomSfxDict[Path.GetFileName(path)]));
					}
				}
			}
		}

		private static AudioSource CreateChildSfxSource(string name)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Expected O, but got Unknown
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("BA_SFX_" + name);
			val.transform.SetParent(((Component)PlayerAudioSource).transform, false);
			AudioSource val2 = val.AddComponent<AudioSource>();
			val2.outputAudioMixerGroup = PlayerAudioSource.outputAudioMixerGroup;
			val2.spatialBlend = PlayerAudioSource.spatialBlend;
			val2.rolloffMode = PlayerAudioSource.rolloffMode;
			val2.minDistance = PlayerAudioSource.minDistance;
			val2.maxDistance = PlayerAudioSource.maxDistance;
			val2.dopplerLevel = PlayerAudioSource.dopplerLevel;
			val2.playOnAwake = false;
			val2.loop = false;
			val2.volume = PlayerAudioSource.volume;
			return val2;
		}

		public static void PlayCustomSFX(string name, bool checkIfPlaying = true)
		{
			if ((Object)(object)PlayerAudioSource == (Object)null || !BowZoomSFXEnabled.Value)
			{
				return;
			}
			if (!CustomSfxDict.TryGetValue(name, out var value) || value.Count == 0)
			{
				Log("SFX not found.", 0);
				return;
			}
			try
			{
				if (!_customSfxAudioSources.TryGetValue(name, out var value2) || (Object)(object)value2 == (Object)null)
				{
					value2 = CreateChildSfxSource(name);
					_customSfxAudioSources[name] = value2;
				}
				if (checkIfPlaying && value2.isPlaying)
				{
					return;
				}
				if (!_customSfxClipCache.TryGetValue(name, out var value3) || value3 == null || value3.Length != value.Count)
				{
					value3 = value.Values.Where((AudioClip c) => (Object)(object)c != (Object)null).ToArray();
					_customSfxClipCache[name] = value3;
					if (value3.Length == 0)
					{
						return;
					}
				}
				AudioClip val = value3[Random.Range(0, value3.Length)];
				value2.pitch = 1f;
				value2.PlayOneShot(val);
			}
			catch (Exception ex)
			{
				Log("Error while playing custom SFX: " + ex.Message, 0);
			}
		}

		public static IEnumerator LoadSFXCoroutine(string path, Dictionary<string, AudioClip> dict)
		{
			path = "file:///" + path;
			UnityWebRequest www = UnityWebRequestMultimedia.GetAudioClip(path, (AudioType)20);
			try
			{
				yield return www.SendWebRequest();
				if (www == null)
				{
					Log("ww error.", 0);
					yield break;
				}
				DownloadHandlerAudioClip dh = (DownloadHandlerAudioClip)www.downloadHandler;
				if (dh != null)
				{
					AudioClip ac = dh.audioClip;
					if ((Object)(object)ac != (Object)null)
					{
						((Object)ac).name = Path.GetFileNameWithoutExtension(path);
						if (!dict.ContainsKey(((Object)ac).name))
						{
							dict[((Object)ac).name] = ac;
						}
						Log("Added " + ((Object)ac).name + " SFX.");
						yield break;
					}
				}
				Log("Error while adding custom SFX.", 0);
			}
			finally
			{
				((IDisposable)www)?.Dispose();
			}
		}

		public static void TryRegisterPrefabs(ZNetScene zNetScene)
		{
			if ((Object)(object)zNetScene == (Object)null)
			{
				return;
			}
			foreach (GameObject value in Prefabs.Values)
			{
				if (!ConfigQuiverEnabled.Value)
				{
					Log(((Object)value).name);
					if (((Object)value).name.Contains("Quiver"))
					{
						Debug.Log((object)("[PrefabCreator] " + ((Object)value).name + " prefab skipped."));
						continue;
					}
				}
				if (!zNetScene.m_prefabs.Contains(value))
				{
					zNetScene.m_prefabs.Add(value);
				}
			}
		}

		public static bool IsObjectDBReady()
		{
			return (Object)(object)ObjectDB.instance != (Object)null && ObjectDB.instance.m_items.Count != 0 && (Object)(object)ObjectDB.instance.GetItemPrefab("Amber") != (Object)null;
		}

		public static void TryRegisterItems()
		{
			if (!IsObjectDBReady())
			{
				return;
			}
			foreach (GameObject value in Prefabs.Values)
			{
				ItemDrop component = value.GetComponent<ItemDrop>();
				if (!((Object)(object)component == (Object)null))
				{
					if (!ConfigQuiverEnabled.Value && ((Object)component.m_itemData.m_dropPrefab).name.Contains("Quiver"))
					{
						Debug.Log((object)("[PrefabCreator] Skipped prefab: " + ((Object)component.m_itemData.m_dropPrefab).name));
					}
					else if ((Object)(object)ObjectDB.instance.GetItemPrefab(StringExtensionMethods.GetStableHashCode(((Object)value).name)) == (Object)null)
					{
						component.m_itemData.m_dropPrefab = value;
						ObjectDB.instance.m_items.Add(value);
					}
				}
			}
			ObjectDB.instance.UpdateRegisters();
		}

		public static void TryRegisterRecipes()
		{
			if (!IsObjectDBReady())
			{
				return;
			}
			PrefabCreator.Reset();
			foreach (RecipeConfig recipe in Recipes.recipes)
			{
				if (!ConfigQuiverEnabled.Value && recipe.item.Contains("Quiver"))
				{
					Debug.Log((object)("[PrefabCreator] Skipped recipe: " + recipe.name));
				}
				else if (!WoodenArrowEverywhereEnabled.Value && recipe.name == "Recipe_ArrowWoodAnywhere")
				{
					Debug.Log((object)("[PrefabCreator] Skipped recipe: " + recipe.name));
				}
				else
				{
					PrefabCreator.AddNewRecipe(recipe.name, recipe.item, recipe);
				}
			}
		}
	}
	[HarmonyPatch(typeof(Terminal), "InitTerminal")]
	public static class TerminalAwake_Patch
	{
		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static ConsoleEvent <>9__0_0;

			internal void <Postfix>b__0_0(ConsoleEventArgs args)
			{
				//IL_020c: Unknown result type (might be due to invalid IL or missing references)
				if (args.Length < 2)
				{
					args.Context.AddString("Syntax: ba [action]");
					return;
				}
				switch (args.FullLine.Substring(args[0].Length + 1))
				{
				case "reload":
					((BaseUnityPlugin)BetterArchery._instance).Config.Reload();
					BetterArchery.RebuildArrowRetrieves();
					args.Context.AddString("Better Archery Reloaded.");
					args.Context.AddString(Localization.instance.Localize("$mod_betterarchery_test"));
					break;
				case "drop":
				{
					Inventory inventory = ((Humanoid)Player.m_localPlayer).m_inventory;
					for (int num = inventory.m_inventory.Count - 1; num >= 0; num--)
					{
						ItemData val = inventory.m_inventory[num];
						if (val.m_gridPos.y >= 5 && !BetterArchery.IsQuiverSlot(val.m_gridPos))
						{
							BetterArchery.Log($"Found {((Object)val.m_dropPrefab).name} x {val.m_stack} in invisible slots; attempting to drop.");
							((Humanoid)Player.m_localPlayer).DropItem(inventory, val, val.m_stack);
						}
					}
					break;
				}
				case "god":
					Player.m_localPlayer.SetGodMode(!Player.m_localPlayer.m_godMode);
					Player.m_localPlayer.SetNoPlacementCost(!Player.m_localPlayer.m_noPlacementCost);
					Player.m_localPlayer.m_staminaRegenDelay = 0.05f;
					Player.m_localPlayer.m_staminaRegen = 999f;
					Player.m_localPlayer.m_runStaminaDrain = 0f;
					Player.m_localPlayer.SetMaxStamina(9999f, true);
					((Character)Player.m_localPlayer).AddStamina(999f);
					break;
				case "clear":
					((Humanoid)Player.m_localPlayer).GetInventory().RemoveAll();
					break;
				case "sfx":
					BetterArchery.PlayCustomSFX("exhale");
					break;
				case "kill":
					((Character)Player.m_localPlayer).SetHealth(0f);
					break;
				case "removequivermodel":
					ZNetScene.instance.Destroy(BetterArchery.QuiverGO);
					break;
				case "fill":
				{
					for (int i = 0; i < 32; i++)
					{
						((Humanoid)Player.m_localPlayer).m_inventory.AddItem(ObjectDB.instance.GetItemPrefab("Wood"), 100);
					}
					break;
				}
				default:
					args.Context.AddString("Syntax: ba [action]");
					break;
				}
			}
		}

		public static void Postfix()
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Expected O, but got Unknown
			//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
			object obj = <>c.<>9__0_0;
			if (obj == null)
			{
				ConsoleEvent val = delegate(ConsoleEventArgs args)
				{
					//IL_020c: Unknown result type (might be due to invalid IL or missing references)
					if (args.Length < 2)
					{
						args.Context.AddString("Syntax: ba [action]");
					}
					else
					{
						switch (args.FullLine.Substring(args[0].Length + 1))
						{
						case "reload":
							((BaseUnityPlugin)BetterArchery._instance).Config.Reload();
							BetterArchery.RebuildArrowRetrieves();
							args.Context.AddString("Better Archery Reloaded.");
							args.Context.AddString(Localization.instance.Localize("$mod_betterarchery_test"));
							break;
						case "drop":
						{
							Inventory inventory = ((Humanoid)Player.m_localPlayer).m_inventory;
							for (int num = inventory.m_inventory.Count - 1; num >= 0; num--)
							{
								ItemData val3 = inventory.m_inventory[num];
								if (val3.m_gridPos.y >= 5 && !BetterArchery.IsQuiverSlot(val3.m_gridPos))
								{
									BetterArchery.Log($"Found {((Object)val3.m_dropPrefab).name} x {val3.m_stack} in invisible slots; attempting to drop.");
									((Humanoid)Player.m_localPlayer).DropItem(inventory, val3, val3.m_stack);
								}
							}
							break;
						}
						case "god":
							Player.m_localPlayer.SetGodMode(!Player.m_localPlayer.m_godMode);
							Player.m_localPlayer.SetNoPlacementCost(!Player.m_localPlayer.m_noPlacementCost);
							Player.m_localPlayer.m_staminaRegenDelay = 0.05f;
							Player.m_localPlayer.m_staminaRegen = 999f;
							Player.m_localPlayer.m_runStaminaDrain = 0f;
							Player.m_localPlayer.SetMaxStamina(9999f, true);
							((Character)Player.m_localPlayer).AddStamina(999f);
							break;
						case "clear":
							((Humanoid)Player.m_localPlayer).GetInventory().RemoveAll();
							break;
						case "sfx":
							BetterArchery.PlayCustomSFX("exhale");
							break;
						case "kill":
							((Character)Player.m_localPlayer).SetHealth(0f);
							break;
						case "removequivermodel":
							ZNetScene.instance.Destroy(BetterArchery.QuiverGO);
							break;
						case "fill":
						{
							for (int i = 0; i < 32; i++)
							{
								((Humanoid)Player.m_localPlayer).m_inventory.AddItem(ObjectDB.instance.GetItemPrefab("Wood"), 100);
							}
							break;
						}
						default:
							args.Context.AddString("Syntax: ba [action]");
							break;
						}
					}
				};
				<>c.<>9__0_0 = val;
				obj = (object)val;
			}
			ConsoleCommand val2 = new ConsoleCommand("ba", "[action]", (ConsoleEvent)obj, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false)
			{
				IsCheat = false
			};
		}
	}
	public static class CrouchBowDrawOverlay
	{
		private enum Phase
		{
			Off,
			Drawing,
			Releasing
		}

		private const string SourceClipName = "Charge Staff Loop";

		private const string RecoilClipName = "Bow Aim Recoil";

		private const string FireTriggerName = "bow_fire";

		private const int LayerIndex = 1;

		private const float ReleaseDuration = 0.6f;

		private const float MinReleaseHold = 0.2f;

		private static Player _installedPlayer;

		private static AnimatorOverrideController _overrideController;

		private static AnimationClip _sourceClip;

		private static AnimationClip _aimClip;

		private static AnimationClip _recoilClip;

		private static Phase _phase;

		private static float _releaseStartTime;

		private static bool _pendingRestore;

		private static bool _warned;

		private static int _crouchStateHash;

		private static int _overlayStateHash;

		private static int _noneStateHash;

		private static bool _hashesReady;

		public static bool IsActiveFor(Player player)
		{
			return _phase != Phase.Off && (Object)(object)_installedPlayer != (Object)null && (Object)(object)_installedPlayer == (Object)(object)player;
		}

		public static void CancelBowDraw(Player player)
		{
			ItemData currentWeapon = ((Humanoid)player).GetCurrentWeapon();
			if (currentWeapon != null && currentWeapon.m_shared.m_attack.m_bowDraw)
			{
				((Humanoid)player).m_attackDrawTime = -1f;
				if (!string.IsNullOrEmpty(currentWeapon.m_shared.m_attack.m_drawAnimationState))
				{
					((Character)player).m_zanim.SetBool(currentWeapon.m_shared.m_attack.m_drawAnimationState, false);
				}
			}
		}

		public static bool OnFireTrigger(ZSyncAnimation zanim, string name)
		{
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Invalid comparison between Unknown and I4
			if (name != "bow_fire")
			{
				return false;
			}
			if (!BetterArchery.ConfigCrouchBowDrawEnabled.Value)
			{
				return false;
			}
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || (Object)(object)((Character)localPlayer).m_zanim != (Object)(object)zanim)
			{
				return false;
			}
			if (!localPlayer.m_crouchToggled)
			{
				return false;
			}
			ItemData currentWeapon = ((Humanoid)localPlayer).GetCurrentWeapon();
			if (currentWeapon == null || (int)currentWeapon.m_shared.m_itemType != 4)
			{
				return false;
			}
			if ((Object)(object)_overrideController == (Object)null)
			{
				return false;
			}
			_phase = Phase.Releasing;
			_releaseStartTime = Time.time;
			PlayClip(localPlayer, _recoilClip);
			return true;
		}

		public static void Update(Player player)
		{
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Invalid comparison between Unknown and I4
			if (!BetterArchery.ConfigCrouchBowDrawEnabled.Value || (Object)(object)player == (Object)null || (Object)(object)((Character)player).m_animator == (Object)null)
			{
				Stop();
				return;
			}
			if ((Object)(object)_installedPlayer != (Object)(object)player)
			{
				Stop();
				Reset();
				_installedPlayer = player;
			}
			EnsureController(player);
			if (_pendingRestore)
			{
				TryRestoreClip(player);
			}
			int num;
			if (player.m_crouchToggled && ((Character)player).IsDrawingBow())
			{
				ItemData currentWeapon = ((Humanoid)player).GetCurrentWeapon();
				num = ((currentWeapon != null && (int)currentWeapon.m_shared.m_itemType == 4) ? 1 : 0);
			}
			else
			{
				num = 0;
			}
			bool flag = (byte)num != 0;
			if (_phase == Phase.Releasing)
			{
				float num2 = Time.time - _releaseStartTime;
				if (num2 < 0.6f)
				{
					if (flag && num2 >= 0.2f)
					{
						StartAim(player);
					}
					else
					{
						KeepCrouch(player);
					}
				}
				else if (flag)
				{
					StartAim(player);
				}
				else
				{
					Stop();
				}
			}
			else if (!flag)
			{
				Stop();
			}
			else if (!((Object)(object)_overrideController == (Object)null))
			{
				StartAim(player);
			}
		}

		private static void StartAim(Player player)
		{
			if (_phase != Phase.Drawing)
			{
				_phase = Phase.Drawing;
				PlayClip(player, _aimClip);
			}
			KeepCrouch(player);
			((Character)player).m_animator.SetLayerWeight(OverlayLayer(((Character)player).m_animator), Mathf.Clamp01(((Humanoid)player).GetAttackDrawPercentage() * 1.5f));
		}

		private static void KeepCrouch(Player player)
		{
			if (((Character)player).GetNextOrCurrentAnimHash() != Player.s_animatorTagCrouch)
			{
				((Character)player).m_animator.CrossFadeInFixedTime(_crouchStateHash, 0.15f, 0);
			}
		}

		private static void PlayClip(Player player, AnimationClip clip)
		{
			_pendingRestore = false;
			_overrideController[((Object)_sourceClip).name] = clip;
			Animator animator = ((Character)player).m_animator;
			int num = OverlayLayer(animator);
			animator.Play(_overlayStateHash, num, 0f);
			animator.SetLayerWeight(num, 1f);
		}

		private static bool TryRestoreClip(Player player)
		{
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_overrideController == (Object)null || (Object)(object)_sourceClip == (Object)null)
			{
				_pendingRestore = false;
				return false;
			}
			Animator animator = ((Character)player).m_animator;
			if ((Object)(object)animator == (Object)null)
			{
				_pendingRestore = false;
				return false;
			}
			int num = OverlayLayer(animator);
			if (!animator.IsInTransition(num))
			{
				AnimatorStateInfo currentAnimatorStateInfo = animator.GetCurrentAnimatorStateInfo(num);
				if (((AnimatorStateInfo)(ref currentAnimatorStateInfo)).shortNameHash != _overlayStateHash)
				{
					_overrideController[((Object)_sourceClip).name] = _sourceClip;
					_pendingRestore = false;
					return true;
				}
			}
			return false;
		}

		private static int OverlayLayer(Animator animator)
		{
			return Mathf.Clamp(1, 0, animator.layerCount - 1);
		}

		private static void Stop()
		{
			if (_phase != Phase.Off)
			{
				_phase = Phase.Off;
				_pendingRestore = true;
				Animator val = (((Object)(object)_installedPlayer != (Object)null) ? ((Character)_installedPlayer).m_animator : null);
				if ((Object)(object)val != (Object)null && (Object)(object)val.runtimeAnimatorController == (Object)(object)_overrideController)
				{
					int num = OverlayLayer(val);
					val.CrossFadeInFixedTime(_noneStateHash, 0.1f, num);
					val.SetLayerWeight(num, 1f);
				}
			}
		}

		private static void Reset()
		{
			_installedPlayer = null;
			_overrideController = null;
			_sourceClip = null;
			_aimClip = null;
			_recoilClip = null;
			_phase = Phase.Off;
			_pendingRestore = false;
			_warned = false;
		}

		private static void EnsureController(Player player)
		{
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: Expected O, but got Unknown
			if ((Object)(object)_overrideController != (Object)null)
			{
				if ((Object)(object)((Character)player).m_animator.runtimeAnimatorController != (Object)(object)_overrideController)
				{
					((Character)player).m_animator.runtimeAnimatorController = (RuntimeAnimatorController)(object)_overrideController;
				}
				return;
			}
			RuntimeAnimatorController runtimeAnimatorController = ((Character)player).m_animator.runtimeAnimatorController;
			if ((Object)(object)runtimeAnimatorController == (Object)null)
			{
				return;
			}
			if (!_hashesReady)
			{
				_crouchStateHash = Animator.StringToHash("Crouch");
				_overlayStateHash = Animator.StringToHash("staff_charge_loop");
				_noneStateHash = Animator.StringToHash("None");
				_hashesReady = true;
			}
			AnimationClip val = FindClip(runtimeAnimatorController, "Charge Staff Loop");
			AnimationClip val2 = FindClip(runtimeAnimatorController, "Bow Aim Idle 01");
			AnimationClip val3 = FindClip(runtimeAnimatorController, "Bow Aim Recoil");
			if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null || (Object)(object)val3 == (Object)null)
			{
				if (!_warned)
				{
					BetterArchery.Log("Crouch bow draw overlay disabled: clip 'Bow Aim Idle 01', 'Bow Aim Recoil' or 'Charge Staff Loop' not found.", 1);
					_warned = true;
				}
				return;
			}
			try
			{
				_sourceClip = val;
				_aimClip = val2;
				_recoilClip = val3;
				_overrideController = new AnimatorOverrideController(runtimeAnimatorController);
				((Character)player).m_animator.runtimeAnimatorController = (RuntimeAnimatorController)(object)_overrideController;
			}
			catch (Exception ex)
			{
				if (!_warned)
				{
					BetterArchery.Log("Crouch bow draw overlay failed: " + ex.Message, 0);
					_warned = true;
				}
			}
		}

		private static AnimationClip FindClip(RuntimeAnimatorController controller, string clipName)
		{
			if ((Object)(object)controller == (Object)null || string.IsNullOrEmpty(clipName))
			{
				return null;
			}
			AnimationClip[] animationClips = controller.animationClips;
			foreach (AnimationClip val in animationClips)
			{
				if ((Object)(object)val != (Object)null && ((Object)val).name == clipName)
				{
					return val;
				}
			}
			return null;
		}
	}
	[HarmonyPatch]
	public class Patches
	{
		private class QuiverSyncComponent : MonoBehaviour
		{
			internal Humanoid h;

			private int _nextFrame;

			private void Update()
			{
				if (Object.op_Implicit((Object)(object)h) && Object.op_Implicit((Object)(object)((Character)h).m_nview) && ((Character)h).m_nview.IsValid())
				{
					int frameCount = Time.frameCount;
					if (frameCount >= _nextFrame)
					{
						_nextFrame = frameCount + 60;
						SyncQuiverFromZdo(h);
					}
				}
			}
		}

		private const string QuiverSlotName = "quiver";

		private const string ZdoKeyQuiver = "BetterArchery.QuiverPrefab";

		private static readonly Dictionary<Humanoid, GameObject> QuiverInstances = new Dictionary<Humanoid, GameObject>();

		[HarmonyPatch(typeof(ItemData), "IsEquipable")]
		[HarmonyPostfix]
		private static void IsEquipablePostfix(ref bool __result, ref ItemData __instance)
		{
			__result = __result || CustomSlotCreator.IsCustomSlotItem(__instance);
		}

		[HarmonyPatch(typeof(Humanoid), "Awake")]
		[HarmonyPostfix]
		private static void HumanoidEntryPostfix(ref Humanoid __instance)
		{
			CustomSlotCreator.customSlotItemData[__instance] = new Dictionary<string, ItemData>();
			if (!Object.op_Implicit((Object)(object)((Component)__instance).gameObject.GetComponent<QuiverSyncComponent>()))
			{
				QuiverSyncComponent quiverSyncComponent = ((Component)__instance).gameObject.AddComponent<QuiverSyncComponent>();
				quiverSyncComponent.h = __instance;
			}
		}

		[HarmonyPatch(typeof(Player), "Load")]
		[HarmonyPostfix]
		private static void InventoryLoadPostfix(ref Player __instance)
		{
			foreach (ItemData equippedItem in ((Humanoid)__instance).m_inventory.GetEquippedItems())
			{
				if (CustomSlotCreator.IsCustomSlotItem(equippedItem))
				{
					string customSlotName = CustomSlotCreator.GetCustomSlotName(equippedItem);
					CustomSlotCreator.SetSlotItem((Humanoid)(object)__instance, customSlotName, equippedItem);
				}
			}
		}

		[HarmonyPatch(typeof(Humanoid), "EquipItem")]
		[HarmonyPostfix]
		private static void EquipItemPostfix(ref bool __result, ref Humanoid __instance, ItemData item, bool triggerEquipEffects = true)
		{
			if (CustomSlotCreator.IsCustomSlotItem(item))
			{
				string customSlotName = CustomSlotCreator.GetCustomSlotName(item);
				if (CustomSlotCreator.IsSlotOccupied(__instance, customSlotName))
				{
					__instance.UnequipItem(CustomSlotCreator.GetSlotItem(__instance, customSlotName), triggerEquipEffects);
				}
				CustomSlotCreator.SetSlotItem(__instance, customSlotName, item);
				if (__instance.IsItemEquiped(item))
				{
					item.m_equipped = true;
				}
				__instance.SetupEquipment();
				if (triggerEquipEffects)
				{
					__instance.TriggerEquipEffect(item);
				}
				if (customSlotName == "quiver" && Object.op_Implicit((Object)(object)item.m_dropPrefab))
				{
					string name = ((Object)item.m_dropPrefab).name;
					SetQuiverZdo(__instance, name);
					CreateOrUpdateQuiverVisual(__instance, name);
				}
				__result = true;
			}
		}

		[HarmonyPatch(typeof(Humanoid), "UnequipItem")]
		[HarmonyPostfix]
		private static void UnequipItemPostfix(ref Humanoid __instance, ItemData item, bool triggerEquipEffects = true)
		{
			if (CustomSlotCreator.IsCustomSlotItem(item))
			{
				string customSlotName = CustomSlotCreator.GetCustomSlotName(item);
				if (item == CustomSlotCreator.GetSlotItem(__instance, customSlotName))
				{
					CustomSlotCreator.SetSlotItem(__instance, customSlotName, null);
				}
				if (!BetterArchery.IsQuiverEquipped())
				{
					SetQuiverZdo(__instance, "");
					RemoveQuiverVisual(__instance);
				}
				__instance.UpdateEquipmentStatusEffects();
			}
		}

		[HarmonyPatch(typeof(Humanoid), "SetupEquipment")]
		[HarmonyPostfix]
		private static void SetupEquipmentPostfix(Humanoid __instance)
		{
			SyncQuiverFromZdo(__instance);
		}

		[HarmonyPatch(typeof(Humanoid), "OnDestroy")]
		[HarmonyPrefix]
		private static void HumanoidOnDestroyPrefix(Humanoid __instance)
		{
			RemoveQuiverVisual(__instance);
		}

		private static void SetQuiverZdo(Humanoid h, string prefabName)
		{
			if (Object.op_Implicit((Object)(object)h) && !((Object)(object)((Character)h).m_nview == (Object)null) && ((Character)h).m_nview.IsValid() && ((Character)h).m_nview.IsOwner())
			{
				ZDO zDO = ((Character)h).m_nview.GetZDO();
				string text = zDO.GetString("BetterArchery.QuiverPrefab", "");
				if (!(text == prefabName))
				{
					zDO.Set("BetterArchery.QuiverPrefab", prefabName);
				}
			}
		}

		private static void SyncQuiverFromZdo(Humanoid h)
		{
			if (!Object.op_Implicit((Object)(object)h) || (Object)(object)((Character)h).m_nview == (Object)null || !((Character)h).m_nview.IsValid())
			{
				return;
			}
			ZDO zDO = ((Character)h).m_nview.GetZDO();
			string text = zDO.GetString("BetterArchery.QuiverPrefab", "");
			if (string.IsNullOrEmpty(text))
			{
				RemoveQuiverVisual(h);
				return;
			}
			if (QuiverInstances.TryGetValue(h, out var value) && (Object)(object)value != (Object)null)
			{
				if (((Object)value).name.StartsWith(text))
				{
					return;
				}
				RemoveQuiverVisual(h);
			}
			CreateOrUpdateQuiverVisual(h, text);
		}

		private static void CreateOrUpdateQuiverVisual(Humanoid h, string prefabName)
		{
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_0149: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0169: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			if (string.IsNullOrEmpty(prefabName) || (Object)(object)h == (Object)null || (Object)(object)ZNetScene.instance == (Object)null)
			{
				return;
			}
			try
			{
				GameObject prefab = ZNetScene.instance.GetPrefab(prefabName);
				if ((Object)(object)prefab == (Object)null)
				{
					BetterArchery.Log("Quiver prefab '" + prefabName + "' not found.");
					return;
				}
				Transform val = Utils.FindChild(prefab.transform, "attach", (IterativeSearchType)0);
				if ((Object)(object)val == (Object)null)
				{
					BetterArchery.Log("Quiver prefab '" + prefabName + "' missing child 'attach'.");
					return;
				}
				Transform val2 = Utils.FindChild(((Component)h).transform, "BackBow_attach", (IterativeSearchType)0);
				if ((Object)(object)val2 == (Object)null)
				{
					BetterArchery.Log("BackBow_attach not found on humanoid.");
					return;
				}
				GameObject val3 = Object.Instantiate<GameObject>(((Component)val).gameObject, val2.position, val2.rotation, ((Component)val2).transform);
				((Object)val3).name = prefabName + "_QuiverInstance";
				val3.transform.localPosition = BetterArchery.QuiverModelPosition.Value;
				val3.transform.localScale = new Vector3(0.01f * BetterArchery.QuiverModelScale.Value.x, 0.01f * BetterArchery.QuiverModelScale.Value.y, 0.01f * BetterArchery.QuiverModelScale.Value.z);
				val3.transform.localEulerAngles = BetterArchery.QuiverModelRotation.Value;
				BoxCollider component = val3.GetComponent<BoxCollider>();
				if (Object.op_Implicit((Object)(object)component))
				{
					Object.DestroyImmediate((Object)(object)component);
				}
				QuiverInstances[h] = val3;
			}
			catch (Exception arg)
			{
				BetterArchery.Log($"Failed to create quiver visual: {arg}", 0);
			}
		}

		private static void RemoveQuiverVisual(Humanoid h)
		{
			if (!QuiverInstances.TryGetValue(h, out var value) || (Object)(object)value == (Object)null)
			{
				return;
			}
			try
			{
				if (Object.op_Implicit((Object)(object)ZNetScene.instance))
				{
					ZNetScene.instance.Destroy(value);
				}
				else
				{
					Object.DestroyImmediate((Object)(object)value);
				}
			}
			catch
			{
				Object.DestroyImmediate((Object)(object)value);
			}
			QuiverInstances.Remove(h);
		}

		[HarmonyPatch(typeof(Humanoid), "IsItemEquiped")]
		[HarmonyPostfix]
		private static void IsItemEquipedPostfix(ref bool __result, ref Humanoid __instance, ItemData item)
		{
			if (CustomSlotCreator.IsCustomSlotItem(item))
			{
				string customSlotName = CustomSlotCreator.GetCustomSlotName(item);
				bool flag = CustomSlotCreator.DoesSlotExist(__instance, customSlotName) && CustomSlotCreator.GetSlotItem(__instance, customSlotName) == item;
				__result |= flag;
			}
		}

		[HarmonyPatch(typeof(Humanoid), "GetEquipmentWeight")]
		[HarmonyPostfix]
		private static void GetEquipmentWeightPostfix(ref float __result, ref Humanoid __instance)
		{
			foreach (string key in CustomSlotCreator.customSlotItemData[__instance].Keys)
			{
				if (CustomSlotCreator.IsSlotOccupied(__instance, key))
				{
					__result += CustomSlotCreator.GetSlotItem(__instance, key).m_shared.m_weight;
				}
			}
		}

		[HarmonyPatch(typeof(Humanoid), "UnequipAllItems")]
		[HarmonyPostfix]
		private static void UnequipAllItemsPostfix(ref Humanoid __instance)
		{
			foreach (string item in CustomSlotCreator.customSlotItemData[__instance].Keys.ToList())
			{
				if (CustomSlotCreator.IsSlotOccupied(__instance, item))
				{
					__instance.UnequipItem(CustomSlotCreator.GetSlotItem(__instance, item), false);
				}
			}
		}

		[HarmonyPatch(typeof(Humanoid), "GetSetCount")]
		[HarmonyPostfix]
		private static void GetSetCountPostfix(ref int __result, ref Humanoid __instance, string setName)
		{
			foreach (string item in CustomSlotCreator.customSlotItemData[__instance].Keys.ToList())
			{
				if (CustomSlotCreator.IsSlotOccupied(__instance, item) && CustomSlotCreator.GetSlotItem(__instance, item).m_shared.m_setName == setName)
				{
					__result++;
				}
			}
		}

		public static HashSet<StatusEffect> GetStatusEffectsFromCustomSlotItems(Humanoid __instance)
		{
			HashSet<StatusEffect> hashSet = new HashSet<StatusEffect>();
			foreach (string key in CustomSlotCreator.customSlotItemData[__instance].Keys)
			{
				if (CustomSlotCreator.IsSlotOccupied(__instance, key))
				{
					if (Object.op_Implicit((Object)(object)CustomSlotCreator.GetSlotItem(__instance, key).m_shared.m_equipStatusEffect))
					{
						StatusEffect equipStatusEffect = CustomSlotCreator.GetSlotItem(__instance, key).m_shared.m_equipStatusEffect;
						hashSet.Add(equipStatusEffect);
					}
					if (__instance.HaveSetEffect(CustomSlotCreator.GetSlotItem(__instance, key)))
					{
						StatusEffect setStatusEffect = CustomSlotCreator.GetSlotItem(__instance, key).m_shared.m_setStatusEffect;
						hashSet.Add(setStatusEffect);
					}
				}
			}
			return hashSet;
		}
	}
	[HarmonyPatch]
	public static class QuiverHudInstaller
	{
		[HarmonyPatch(typeof(Hud), "Awake")]
		[HarmonyPostfix]
		private static void Install(Hud __instance)
		{
			if (BetterArchery.ConfigQuiverEnabled.Value && BetterArchery.QuiverHudEnabled.Value)
			{
				QuiverHud.TryCreate(__instance);
			}
		}

		[HarmonyPatch(typeof(Hud), "OnDestroy")]
		[HarmonyPostfix]
		private static void Uninstall()
		{
			QuiverHud.Destroy();
		}
	}
	public class QuiverHud : MonoBehaviour
	{
		private class CachedSlot
		{
			public GameObject Go;

			public Image Icon;

			public TMP_Text Amount;

			public TMP_Text Binding;

			public GameObject Equipped;

			public int StackText = -1;
		}

		private static QuiverHud _instance;

		private RectTransform _anchorFood;

		private float _appliedScale = -1f;

		private Vector2 _appliedOffset = new Vector2(float.NaN, float.NaN);

		private QuiverHudOrientation _appliedOrientation;

		private bool _hasAppliedOrientation;

		private float _elementSpace = 70f;

		private readonly CachedSlot[] _slots = new CachedSlot[3];

		private GameObject _slotsRoot;

		private bool _built;

		private bool _lastGamepad;

		private static void HideChild(GameObject go, string childName)
		{
			Transform val = go.transform.Find(childName);
			if ((Object)(object)val != (Object)null)
			{
				((Component)val).gameObject.SetActive(false);
			}
		}

		public static void TryCreate(Hud hud)
		{
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Expected O, but got Unknown
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: 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_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_015a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0169: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_018f: Unknown result type (might be due to invalid IL or missing references)
			//IL_019e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f6: Unknown result type (might be due to invalid IL or missing references)
			Destroy();
			if ((Object)(object)hud == (Object)null)
			{
				BetterArchery.Log("[BA-HUD] TryCreate: hud is null.", 0);
				return;
			}
			HotkeyBar componentInChildren = ((Component)hud).GetComponentInChildren<HotkeyBar>();
			if ((Object)(object)componentInChildren == (Object)null || (Object)(object)componentInChildren.m_elementPrefab == (Object)null || (Object)(object)((Component)componentInChildren).transform.parent == (Object)null)
			{
				BetterArchery.Log("[BA-HUD] TryCreate: no vanilla hotbar found, cannot install.", 0);
				return;
			}
			GameObject val = new GameObject("QuiverHotkeyBar");
			float num = HudScale();
			Vector2 value = BetterArchery.QuiverHudPositionOffset.Value;
			RectTransform val2 = val.AddComponent<RectTransform>();
			RectTransform foodBarRoot = hud.m_foodBarRoot;
			if ((Object)(object)foodBarRoot != (Object)null && (Object)(object)((Transform)foodBarRoot).parent != (Object)null)
			{
				val.transform.SetParent(((Transform)foodBarRoot).parent, false);
				val2.anchorMin = foodBarRoot.anchorMin;
				val2.anchorMax = foodBarRoot.anchorMax;
				val2.pivot = new Vector2(0f, 0f);
				val2.anchoredPosition = HudBasePosition(foodBarRoot) + value;
			}
			else
			{
				val.transform.SetParent(((Component)componentInChildren).transform.parent, false);
				Transform transform = ((Component)componentInChildren).transform;
				RectTransform val3 = (RectTransform)(object)((transform is RectTransform) ? transform : null);
				if ((Object)(object)val3 != (Object)null)
				{
					val2.anchorMin = val3.anchorMin;
					val2.anchorMax = val3.anchorMax;
					val2.pivot = new Vector2(0f, 0f);
					val2.anchoredPosition = val3.anchoredPosition + new Vector2(0f, 95f) + value;
				}
			}
			val.transform.localScale = new Vector3(num, num, 1f);
			_instance = val.AddComponent<QuiverHud>();
			_instance._anchorFood = foodBarRoot;
			_instance._appliedScale = num;
			_instance._appliedOffset = value;
		}

		private static float HudScale()
		{
			float num = ((BetterArchery.QuiverHudScale != null) ? BetterArchery.QuiverHudScale.Value : 0.8f);
			return Mathf.Clamp(num, 0.3f, 2f);
		}

		private static Vector2 HudBasePosition(RectTransform food)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: 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_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: 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_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			float x = food.anchoredPosition.x;
			Rect rect = food.rect;
			float num = x - ((Rect)(ref rect)).width * food.pivot.x;
			float y = food.anchoredPosition.y;
			rect = food.rect;
			float num2 = y + ((Rect)(ref rect)).height * (1f - food.pivot.y);
			return new Vector2(num, num2 + 8f);
		}

		public static void Destroy()
		{
			if ((Object)(object)_instance != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)_instance).gameObject);
				_instance = null;
			}
		}

		private void Update()
		{
			try
			{
				Refresh();
			}
			catch (Exception arg)
			{
				BetterArchery.Log($"Quiver HUD refresh failed: {arg}", 0);
				((Behaviour)this).enabled = false;
			}
		}

		private void Refresh()
		{
			Player localPlayer = Player.m_localPlayer;
			if (!BetterArchery.ConfigQuiverEnabled.Value || !BetterArchery.QuiverHudEnabled.Value || !((Object)(object)localPlayer != (Object)null) || ((Character)localPlayer).IsDead() || !BetterArchery.IsQuiverEquipped() || (!_built && !BuildSlots(localPlayer)))
			{
				SetSlotsVisible(visible: false);
				return;
			}
			SetSlotsVisible(visible: true);
			ApplyLayout();
			bool flag = ZInput.IsGamepadActive();
			if (flag != _lastGamepad)
			{
				_lastGamepad = flag;
				UpdateBindingLabels(flag);
			}
			int bonusInventoryRowIndex = BetterArchery.GetBonusInventoryRowIndex();
			Inventory inventory = ((Humanoid)localPlayer).GetInventory();
			ItemData ammoItem = ((Humanoid)localPlayer).GetAmmoItem();
			for (int i = 0; i < _slots.Length; i++)
			{
				CachedSlot cachedSlot = _slots[i];
				if (cachedSlot == null || (Object)(object)cachedSlot.Go == (Object)null || (Object)(object)cachedSlot.Icon == (Object)null)
				{
					continue;
				}
				ItemData itemAt = inventory.GetItemAt(i, bonusInventoryRowIndex);
				bool flag2 = itemAt != null;
				((Component)cachedSlot.Icon).gameObject.SetActive(flag2);
				if ((Object)(object)cachedSlot.Equipped != (Object)null)
				{
					cachedSlot.Equipped.SetActive(flag2 && (itemAt.m_equipped || itemAt == ammoItem));
				}
				if ((Object)(object)cachedSlot.Amount != (Object)null)
				{
					bool flag3 = flag2 && itemAt.m_shared.m_maxStackSize > 1;
					((Component)cachedSlot.Amount).gameObject.SetActive(flag3);
					if (flag3 && cachedSlot.StackText != itemAt.m_stack)
					{
						cachedSlot.Amount.text = $"{itemAt.m_stack} / {itemAt.m_shared.m_maxStackSize}";
						cachedSlot.StackText = itemAt.m_stack;
					}
				}
				if (flag2)
				{
					cachedSlot.Icon.sprite = itemAt.GetIcon();
				}
			}
		}

		private Vector3 SlotLocalPosition(int index)
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			if (BetterArchery.QuiverHudLayout.Value == QuiverHudOrientation.Vertical)
			{
				return new Vector3(0f, (float)(-index) * _elementSpace, 0f);
			}
			return new Vector3((float)index * _elementSpace, 0f, 0f);
		}

		private void ApplyLayout()
		{
			//IL_000c: 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_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: 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_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			float num = HudScale();
			Vector2 value = BetterArchery.QuiverHudPositionOffset.Value;
			QuiverHudOrientation value2 = BetterArchery.QuiverHudLayout.Value;
			if (Mathf.Approximately(num, _appliedScale) && value == _appliedOffset && _hasAppliedOrientation && value2 == _appliedOrientation)
			{
				return;
			}
			_appliedScale = num;
			_appliedOffset = value;
			_appliedOrientation = value2;
			_hasAppliedOrientation = true;
			Transform transform = ((Component)this).transform;
			RectTransform val = (RectTransform)(object)((transform is RectTransform) ? transform : null);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			((Transform)val).localScale = new Vector3(num, num, 1f);
			if ((Object)(object)_anchorFood != (Object)null)
			{
				val.anchoredPosition = HudBasePosition(_anchorFood) + value;
			}
			for (int i = 0; i < _slots.Length; i++)
			{
				CachedSlot cachedSlot = _slots[i];
				if ((Object)(object)cachedSlot?.Go != (Object)null)
				{
					cachedSlot.Go.transform.localPosition = SlotLocalPosition(i);
				}
			}
		}

		private void SetSlotsVisible(bool visible)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Expected O, but got Unknown
			if ((Object)(object)_slotsRoot == (Object)null)
			{
				_slotsRoot = new GameObject("Slots");
				_slotsRoot.transform.SetParent(((Component)this).transform, false);
			}
			if (_slotsRoot.activeSelf != visible)
			{
				_slotsRoot.SetActive(visible);
			}
		}

		private bool BuildSlots(Player player)
		{
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Expected O, but got Unknown
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0265: Unknown result type (might be due to invalid IL or missing references)
			//IL_026f: Expected O, but got Unknown
			Hud componentInParent = ((Component)this).GetComponentInParent<Hud>();
			HotkeyBar val = ((componentInParent != null) ? ((Component)componentInParent).GetComponentInChildren<HotkeyBar>() : null);
			if ((Object)(object)val == (Object)null || (Object)(object)val.m_elementPrefab == (Object)null)
			{
				return false;
			}
			if ((Object)(object)_slotsRoot == (Object)null)
			{
				_slotsRoot = new GameObject("Slots");
				_slotsRoot.transform.SetParent(((Component)this).transform, false);
			}
			for (int i = 0; i < _slots.Length; i++)
			{
				if ((Object)(object)_slots[i]?.Go != (Object)null)
				{
					Object.Destroy((Object)(object)_slots[i].Go);
				}
				_slots[i] = null;
			}
			_elementSpace = val.m_elementSpace;
			for (int j = 0; j < _slots.Length; j++)
			{
				GameObject val2 = Object.Instantiate<GameObject>(val.m_elementPrefab, _slotsRoot.transform);
				val2.transform.localPosition = SlotLocalPosition(j);
				Transform obj = val2.transform.Find("icon");
				Image val3 = ((obj != null) ? ((Component)obj).GetComponent<Image>() : null);
				if ((Object)(object)val3 == (Object)null)
				{
					Object.Destroy((Object)(object)val2);
					return false;
				}
				Transform obj2 = val2.transform.Find("binding");
				TMP_Text val4 = ((obj2 != null) ? ((Component)obj2).GetComponent<TMP_Text>() : null);
				if ((Object)(object)val4 != (Object)null)
				{
					((Behaviour)val4).enabled = true;
					val4.overflowMode = (TextOverflowModes)0;
					val4.horizontalAlignment = (HorizontalAlignmentOptions)2;
					val4.fontSize = 11f;
					val4.autoSizeTextContainer = true;
					val4.rectTransform.anchoredPosition = new Vector2(28f, -7f);
				}
				Transform obj3 = val2.transform.Find("amount");
				TMP_Text amount = ((obj3 != null) ? ((Component)obj3).GetComponent<TMP_Text>() : null);
				Transform obj4 = val2.transform.Find("equiped");
				GameObject equipped = ((obj4 != null) ? ((Component)obj4).gameObject : null);
				HideChild(val2, "queued");
				HideChild(val2, "selected");
				HideChild(val2, "durability");
				int slotIndex = j;
				Button component = val2.GetComponent<Button>();
				if ((Object)(object)component != (Object)null)
				{
					((UnityEvent)component.onClick).AddListener((UnityAction)delegate
					{
						UseQuiverSlot(slotIndex);
					});
				}
				_slots[j] = new CachedSlot
				{
					Go = val2,
					Icon = val3,
					Amount = amount,
					Binding = val4,
					Equipped = equipped
				};
			}
			_appliedOrientation = BetterArchery.QuiverHudLayout.Value;
			_hasAppliedOrientation = true;
			_lastGamepad = ZInput.IsGamepadActive();
			UpdateBindingLabels(_lastGamepad);
			_built = true;
			return true;
		}

		private void UpdateBindingLabels(bool gamepad)
		{
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: 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_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: 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)
			for (int i = 0; i < _slots.Length; i++)
			{
				CachedSlot cachedSlot = _slots[i];
				if ((Object)(object)cachedSlot?.Binding == (Object)null)
				{
					continue;
				}
				if (gamepad)
				{
					cachedSlot.Binding.text = string.Empty;
					continue;
				}
				KeyboardShortcut value = BetterArchery.HoldingKeyCode.Value;
				if (!string.IsNullOrEmpty(((KeyboardShortcut)(ref value)).Serialize()))
				{
					value = BetterArchery.HoldingKeyCode.Value;
					if (!(((KeyboardShortcut)(ref value)).Serialize() == "None"))
					{
						TMP_Text binding = cachedSlot.Binding;
						value = BetterArchery.HoldingKeyCode.Value;
						binding.text = ((object)((KeyboardShortcut)(ref value)).MainKey/*cast due to .constrained prefix*/).ToString() + " + " + BetterArchery.GetBindingLabel(i);
						continue;
					}
				}
				cachedSlot.Binding.text = BetterArchery.GetBindingLabel(i);
			}
		}

		private static void UseQuiverSlot(int index)
		{
			Player localPlayer = Player.m_localPlayer;
			if (!((Object)(object)localPlayer == (Object)null))
			{
				ItemData itemAt = ((Humanoid)localPlayer).GetInventory().GetItemAt(index, BetterArchery.GetBonusInventoryRowIndex());
				if (itemAt != null)
				{
					((Humanoid)localPlayer).UseItem((Inventory)null, itemAt, false);
				}
			}
		}
	}
	[HarmonyPatch(typeof(InventoryGrid), "OnLeftClick")]
	public static class InventoryGrid_OnLeftClick_Patch
	{
		public static bool Prefix(InventoryGrid __instance, UIInputHandler clickHandler)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			if (!BetterArchery.ConfigQuiverEnabled.Value)
			{
				return true;
			}
			GameObject gameObject = ((Component)clickHandler).gameObject;
			Vector2i buttonPos = __instance.GetButtonPos(gameObject);
			ItemData itemAt = __instance.m_inventory.GetItemAt(buttonPos.x, buttonPos.y);
			if ((Input.GetKey((KeyCode)306) || Input.GetKey((KeyCode)305)) && itemAt != null && itemAt.m_equipped && ((Object)itemAt.m_dropPrefab).name.Contains("Quiver"))
			{
				MessageHud.instance.ShowMessage((MessageType)2, "$mod_betterarchery_quiver_equipped_error", 0, (Sprite)null, false, true);
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(InventoryGrid), "UpdateGui", new Type[]
	{
		typeof(Player),
		typeof(ItemData)
	})]
	public static class InventoryGrid_UpdateGui_Patch
	{
		public static Vector2 customLocation;

		private static void Postfix(InventoryGrid __instance, Player player, ItemData dragItem, List<InventoryElement> ___m_elements)
		{
			if (((Object)__instance).name != "PlayerGrid" || !BetterArchery.ConfigQuiverEnabled.Value || BetterArchery.isInventoryExpansionModPresent)
			{
				return;
			}
			try
			{
				EnsureQuiverRows(__instance);
			}
			catch (Exception arg)
			{
				BetterArchery.Log($"EnsureQuiverRows failed: {arg}", 0);
			}
			try
			{
				HideModRows(__instance, ___m_elements);
			}
			catch (Exception arg2)
			{
				BetterArchery.Log($"HideModRows failed: {arg2}", 0);
			}
			try
			{
				if (BetterArchery.IsQuiverEquipped())
				{
					CreateQuiverSlots(__instance, ___m_elements);
				}
				else
				{
					RemoveQuiverSlots(__instance, ___m_elements);
				}
			}
			catch (Exception arg3)
			{
				BetterArchery.Log($"Quiver slot handling failed: {arg3}", 0);
			}
		}

		private static void EnsureQuiverRows(InventoryGrid __instance)
		{
			Inventory inventory = __instance.GetInventory();
			if (inventory != null)
			{
				int quiverRowIndex = BetterArchery.QuiverRowIndex;
				if (quiverRowIndex > 0 && inventory.GetHeight() <= quiverRowIndex)
				{
					inventory.SetHeight(quiverRowIndex + 1);
					BetterArchery.Log($"Restored quiver rows: inventory is now {inventory.GetWidth()}x{inventory.GetHeight()} (quiver row {quiverRowIndex}).", 0);
				}
			}
		}

		private static void HideModRows(InventoryGrid __instance, List<InventoryElement> ___m_elements)
		{
			if (BetterArchery.QuiverRowIndex >= __instance.GetInventory().GetHeight())
			{
				BetterArchery.Log($"refusing to hide rows: quiver row {BetterArchery.QuiverRowIndex} outside {__instance.GetInventory().GetWidth()}x{__instance.GetInventory().GetHeight()}.", 0);
				return;
			}
			if (__instance.GetInventory().GetHeight() > 5)
			{
				InventoryElement element = GetElement(___m_elements, 7, __instance.GetInventory().GetHeight() - 1);
				if (element == null || !((Component)element).gameObject.activeSelf)
				{
					return;
				}
				for (int i = __instance.GetInventory().GetHeight() - 2; i < __instance.GetInventory().GetHeight(); i++)
				{
					for (int j = 0; j < 8; j++)
					{
						InventoryElement element2 = GetElement(___m_elements, j, i);
						if (element2 != null)
						{
							((Component)element2).gameObject.SetActive(false);
						}
					}
				}
				return;
			}
			InventoryElement element3 = GetElement(___m_elements, 7, __instance.GetInventory().GetHeight() - 1);
			if (element3 == null || !((Component)element3).gameObject.activeSelf)
			{
				return;
			}
			for (int k = __instance.GetInventory().GetHeight() - 1; k < __instance.GetInventory().GetHeight(); k++)
			{
				for (int l = 0; l < 8; l++)
				{
					InventoryElement element4 = GetElement(___m_elements, l, k);
					if (element4 != null)
					{
						((Component)element4).gameObject.SetActive(false);
					}
				}
			}
		}

		public static void CreateQuiverSlots(InventoryGrid __instance, List<InventoryElement> ___m_elements)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: 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_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0506: Unknown result type (might be due to invalid IL or missing references)
			//IL_053e: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_0150: Unknown result type (might be due to invalid IL or missing references)
			//IL_03df: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_044d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0452: Unknown result type (might be due to invalid IL or missing references)
			//IL_047e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0480: Unknown result type (might be due to invalid IL or missing references)
			//IL_0482: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0200: Unknown result type (might be due to invalid IL or missing references)
			//IL_0232: Unknown result type (might be due to invalid IL or missing references)
			//IL_0234: Unknown result type (might be due to invalid IL or missing references)
			//IL_0236: Unknown result type (might be due to invalid IL or missing references)
			//IL_0173: Unknown result type (might be due to invalid IL or missing references)
			//IL_0178: Unknown result type (might be due to invalid IL or missing references)
			//IL_0418: Unknown result type (might be due to invalid IL or missing references)
			//IL_041d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0421: Unknown result type (might be due to invalid IL or missing references)
			//IL_0426: Unknown result type (might be due to invalid IL or missing references)
			//IL_018d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0192: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d4: Unknown result type (might be due to invalid IL or missing references)
			Vector2 val = (BetterArchery.IsContainerOpen ? BetterArchery.InventoryQuiverSlotLocationWithContainer.Value : BetterArchery.InventoryQuiverSlotLocation.Value);
			int bonusInventoryRowIndex = BetterArchery.GetBonusInventoryRowIndex();
			Transform val2 = ((Component)__instance).transform.parent.Find("QuiverSlotBkg");
			if (Object.op_Implicit((Object)(object)val2) && customLocation == val && QuiverSlotsInPlace(__instance, ___m_elements, bonusInventoryRowIndex, val))
			{
				return;
			}
			customLocation = (BetterArchery.IsContainerOpen ? BetterArchery.InventoryQuiverSlotLocationWithContainer.Value : BetterArchery.InventoryQuiverSlotLocation.Value);
			KeyboardShortcut value;
			if (BetterArchery.hasAuga)
			{
				Vector2 val6 = default(Vector2);
				for (int i = 0; i < 3; i++)
				{
					int num = i;
					InventoryElement element = GetElement(___m_elements, num, bonusInventoryRowIndex);
					if ((Object)(object)element == (Object)null)
					{
						continue;
					}
					((Component)element).gameObject.SetActive(true);
					Transform val3 = ((Component)element).transform.Find("binding");
					TMP_Text val4 = (((Object)(object)val3 != (Object)null) ? ((Component)val3).GetComponent<TMP_Text>() : null);
					if ((Object)(object)val4 == (Object)null)
					{
						BetterArchery.Log("quiver slot has no 'binding' text child, skipping label styling.", 0);
					}
					else
					{
						((Behaviour)val4).enabled = true;
						val4.overflowMode = (TextOverflowModes)0;
						val4.fontSize = 11f;
						val4.autoSizeTextContainer = true;
						val4.rectTransform.anchoredPosition = new Vector2(1f, 14f);
					}
					if ((Object)(object)val4 != (Object)null)
					{
						value = BetterArchery.HoldingKeyCode.Value;
						if (!string.IsNullOrEmpty(((KeyboardShortcut)(ref value)).Serialize()))
						{
							value = BetterArchery.HoldingKeyCode.Value;
							if (!(((KeyboardShortcut)(ref value)).Serialize() == "None"))
							{
								value = BetterArchery.HoldingKeyCode.Value;
								val4.text = ((object)((KeyboardShortcut)(ref value)).MainKey/*cast due to .constrained prefix*/).ToString() + " + " + BetterArchery.GetBindingLabel(i);
								goto IL_01fb;
							}
						}
						val4.text = BetterArchery.GetBindingLabel(i);
					}
					goto IL_01fb;
					IL_01fb:
					Vector2 val5 = customLocation;
					((Vector2)(ref val6))..ctor((float)num * __instance.m_elementSpace, 4f * (0f - __instance.m_elementSpace) + 30f);
					Transform transform = ((Component)element).transform;
					((RectTransform)((transform is RectTransform) ? transform : null)).anchoredPosition = val5 + val6;
				}
				RectTransform orCreateBackground = GetOrCreateBackground(__instance, "QuiverSlotBkg");
				if ((Object)(object)orCreateBackground == (Object)null)
				{
					BetterArchery.Log("quiver background unavailable, slots work without backdrop.", 0);
					return;
				}
				orCreateBackground.anchoredPosition = new Vector2(-174f + customLocation.x, -235f + customLocation.y);
				orCreateBackground.SetSizeWithCurrentAnchors((Axis)0, 235f);
				orCreateBackground.SetSizeWithCurrentAnchors((Axis)1, 90f);
				((Transform)orCreateBackground).localScale = new Vector3(1f, 1f, 1f);
				return;
			}
			Vector2 val10 = default(Vector2);
			for (int j = 0; j < 3; j++)
			{
				int num2 = j;
				InventoryElement element2 = GetElement(___m_elements, num2, bonusInventoryRowIndex);
				if ((Object)(object)element2 == (Object)null)
				{
					continue;
				}
				((Component)element2).gameObject.SetActive(true);
				Transform val7 = ((Component)element2).transform.Find("binding");
				TMP_Text val8 = (((Object)(object)val7 != (Object)null) ? ((Component)val7).GetComponent<TMP_Text>() : null);
				if ((Object)(object)val8 == (Object)null)
				{
					BetterArchery.Log("quiver slot has no 'binding' text child, skipping label styling.", 0);
				}
				else
				{
					((Behaviour)val8).enabled = true;
					val8.overflowMode = (TextOverflowModes)0;
					val8.horizontalAlignment = (HorizontalAlignmentOptions)2;
					val8.fontSize = 11f;
					val8.autoSizeTextContainer = true;
					val8.rectTransform.anchoredPosition = new Vector2(28f, -7f);
					value = BetterArchery.HoldingKeyCode.Value;
					if (!string.IsNullOrEmpty(((KeyboardShortcut)(ref value)).Serialize()))
					{
						value = BetterArchery.HoldingKeyCode.Value;
						if (!(((KeyboardShortcut)(ref value)).Serialize() == "None"))
						{
							value = BetterArchery.HoldingKeyCode.Value;
							val8.text = ((object)((KeyboardShortcut)(r