Decompiled source of CiCisPioneersClimbingAxes v1.0.0

plugins/ClimbingAxesMod/ClimbingAxesMod.dll

Decompiled 6 months ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("ClimbingAxesMod")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("ClimbingAxesMod")]
[assembly: AssemblyTitle("ClimbingAxesMod")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace ClimbingAxesMod
{
	[BepInPlugin("com.cicismods.climbingaxes", "Climbing Axes Mod", "0.1.0")]
	public class Plugin : BaseUnityPlugin
	{
		public const string ItemTag = "climbingaxe";

		public const int StartingDurability = 30;

		public const float RegenIntervalSeconds = 60f;

		public const float HandholdLifetimeSeconds = 0f;

		public const string DurabilityDataKey = "axe_durability";

		public const float AxeRange = 4f;

		public const float LodgeDelaySeconds = 0f;

		public const float AxeMinChargeTime = 0.05f;

		public const float AxeChargeDamage = 1f;

		public const float AxeAutoReleaseDelay = 0.5f;

		public const float AxeHitShakeAmount = 0.025f;

		public static readonly Vector3 LodgedAxeEulerOffset = new Vector3(-90f, 180f, -90f);

		public const float LodgedAxeHandleTiltDegrees = 15f;

		public static Item_Object AxeTemplate;

		public static ManualLogSource Log;

		public static GameObject AxePrefab;

		public static Sprite AxeHandSprite;

		public static Texture2D AxeTexture;

		public static readonly List<AudioClip> AxeHitClips = new List<AudioClip>();

		public static AudioClip AxeBreakClip;

		private Harmony _harmony;

		private void Awake()
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Expected O, but got Unknown
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			WK_Leaderboard_Core.disableLeaderboards = true;
			LoadAssetBundle();
			LoadCustomAudio();
			_harmony = new Harmony("com.cicismods.climbingaxes");
			_harmony.PatchAll();
			GameObject val = new GameObject("ClimbingAxesMod_Handler");
			((Object)val).hideFlags = (HideFlags)61;
			Object.DontDestroyOnLoad((Object)(object)val);
			val.AddComponent<AxeModHandler>();
		}

		private void LoadAssetBundle()
		{
			//IL_0171: 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)
			string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
			string text = Path.Combine(directoryName, "climbingaxemod");
			if (!File.Exists(text))
			{
				Log.LogError((object)("Asset bundle not found at: " + text));
				return;
			}
			AssetBundle val = AssetBundle.LoadFromFile(text);
			if ((Object)(object)val == (Object)null)
			{
				Log.LogError((object)"AssetBundle.LoadFromFile returned null");
				return;
			}
			GameObject[] array = val.LoadAllAssets<GameObject>();
			if (array == null || array.Length == 0)
			{
				Log.LogError((object)"Bundle loaded but contains no GameObject assets");
			}
			else
			{
				AxePrefab = array[0];
			}
			Sprite[] array2 = val.LoadAllAssets<Sprite>();
			if (array2 != null && array2.Length != 0)
			{
				AxeHandSprite = array2[0];
				if ((Object)(object)AxeHandSprite.texture != (Object)null)
				{
					((Texture)AxeHandSprite.texture).filterMode = (FilterMode)0;
					AxeTexture = AxeHandSprite.texture;
				}
			}
			if ((Object)(object)AxeHandSprite == (Object)null)
			{
				Texture2D[] array3 = val.LoadAllAssets<Texture2D>();
				if (array3 != null && array3.Length != 0)
				{
					AxeTexture = array3[0];
					((Texture)AxeTexture).filterMode = (FilterMode)0;
					AxeHandSprite = Sprite.Create(AxeTexture, new Rect(0f, 0f, (float)((Texture)AxeTexture).width, (float)((Texture)AxeTexture).height), new Vector2(0.5f, 0.5f), 100f, 0u, (SpriteMeshType)0);
					((Object)AxeHandSprite).name = "ClimbingAxe_HandSprite";
				}
			}
			if ((Object)(object)AxeHandSprite == (Object)null)
			{
				Log.LogWarning((object)"No axe sprite/texture found in bundle");
			}
		}

		private void LoadCustomAudio()
		{
			string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
			string[] array = new string[2] { "climbingaxe_hit_1.wav", "climbingaxe_hit_2.wav" };
			string[] array2 = array;
			foreach (string filename in array2)
			{
				AudioClip val = TryLoadWav(directoryName, filename);
				if ((Object)(object)val != (Object)null)
				{
					AxeHitClips.Add(val);
				}
			}
			AxeBreakClip = TryLoadWav(directoryName, "climbingaxe_break.wav");
		}

		private AudioClip TryLoadWav(string dir, string filename)
		{
			string text = Path.Combine(dir, filename);
			if (!File.Exists(text))
			{
				Log.LogWarning((object)("Audio not found: " + filename + " (at " + text + ")"));
				return null;
			}
			try
			{
				AudioClip val = WavLoader.LoadFromFile(text);
				if ((Object)(object)val != (Object)null)
				{
					((Object)val).name = filename;
				}
				return val;
			}
			catch (Exception ex)
			{
				Log.LogError((object)("WAV load failed for " + filename + ": " + ex.Message));
				return null;
			}
		}

		public static void EnsureAxeTemplate()
		{
			if ((Object)(object)AxeTemplate != (Object)null)
			{
				return;
			}
			GameObject val = AxePrefab;
			if ((Object)(object)val == (Object)null)
			{
				val = CL_AssetManager.GetAssetGameObject("Item_Hammer", "");
				if ((Object)(object)val == (Object)null)
				{
					ManualLogSource log = Log;
					if (log != null)
					{
						log.LogWarning((object)"Neither AxePrefab (bundle) nor Item_Hammer available");
					}
					return;
				}
				ManualLogSource log2 = Log;
				if (log2 != null)
				{
					log2.LogWarning((object)"AxePrefab bundle missing — falling back to Item_Hammer clone");
				}
			}
			GameObject val2 = Object.Instantiate<GameObject>(val);
			val2.SetActive(false);
			((Object)val2).name = "ClimbingAxe_Template";
			((Object)val2).hideFlags = (HideFlags)61;
			Object.DontDestroyOnLoad((Object)(object)val2);
			ApplyGameShader(val2);
			ConfigureAsPickup(val2);
			Item_Object val3 = val2.GetComponent<Item_Object>();
			if ((Object)(object)val3 == (Object)null)
			{
				val3 = val2.AddComponent<Item_Object>();
			}
			AxeTemplate = val3;
		}

		internal static void ApplyGameShader(GameObject target)
		{
			Shader val = Shader.Find("Dark Machine/SHDR_Base") ?? Shader.Find("Unlit/Texture");
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			Renderer[] componentsInChildren = target.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val2 in componentsInChildren)
			{
				Material[] materials = val2.materials;
				for (int j = 0; j < materials.Length; j++)
				{
					if (!((Object)(object)materials[j] == (Object)null))
					{
						Texture val3 = (materials[j].HasProperty("_MainTex") ? materials[j].GetTexture("_MainTex") : null);
						materials[j].shader = val;
						if ((Object)(object)val3 != (Object)null && materials[j].HasProperty("_MainTex"))
						{
							materials[j].SetTexture("_MainTex", val3);
						}
					}
				}
				val2.materials = materials;
			}
		}

		private static void ConfigureAsPickup(GameObject go)
		{
			//IL_017e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			go.layer = 10;
			Transform[] componentsInChildren = go.GetComponentsInChildren<Transform>(true);
			foreach (Transform val in componentsInChildren)
			{
				((Component)val).gameObject.layer = 10;
			}
			try
			{
				go.tag = "Pickupable";
			}
			catch
			{
			}
			ObjectTagger val2 = go.GetComponent<ObjectTagger>() ?? go.AddComponent<ObjectTagger>();
			if (val2.tags == null)
			{
				val2.tags = new List<string>();
			}
			if (!val2.tags.Contains("Pickupable"))
			{
				val2.tags.Add("Pickupable");
			}
			if (!val2.tags.Contains("Item"))
			{
				val2.tags.Add("Item");
			}
			if ((Object)(object)go.GetComponentInChildren<Collider>() == (Object)null)
			{
				Renderer[] componentsInChildren2 = go.GetComponentsInChildren<Renderer>();
				if (componentsInChildren2.Length != 0)
				{
					Bounds bounds = componentsInChildren2[0].bounds;
					for (int j = 1; j < componentsInChildren2.Length; j++)
					{
						((Bounds)(ref bounds)).Encapsulate(componentsInChildren2[j].bounds);
					}
					BoxCollider val3 = go.AddComponent<BoxCollider>();
					val3.center = go.transform.InverseTransformPoint(((Bounds)(ref bounds)).center);
					val3.size = ((Bounds)(ref bounds)).size;
				}
				else
				{
					BoxCollider val4 = go.AddComponent<BoxCollider>();
					val4.size = new Vector3(0.6f, 0.3f, 0.3f);
				}
			}
			Rigidbody val5 = go.GetComponent<Rigidbody>() ?? go.AddComponent<Rigidbody>();
			val5.mass = 0.4f;
			CL_Prop val6 = go.GetComponent<CL_Prop>();
			if ((Object)(object)val6 == (Object)null)
			{
				val6 = go.AddComponent<CL_Prop>();
			}
			if (val6.hitSounds == null)
			{
				val6.hitSounds = new List<PropAudioEffect>();
			}
			if (val6.dragSounds == null)
			{
				val6.dragSounds = new List<PropAudioEffect>();
			}
			if (val6.breakSounds == null)
			{
				val6.breakSounds = new List<PropAudioEffect>();
			}
			if (val6.unstickSounds == null)
			{
				val6.unstickSounds = new List<PropAudioEffect>();
			}
			if (val6.damageSounds == null)
			{
				val6.damageSounds = new List<PropAudioEffect>();
			}
		}

		public static Item CreateAxeItem()
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: 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_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Expected O, but got Unknown
			Item val = new Item
			{
				itemName = "Climbing Axe",
				itemTag = "climbingaxe",
				itemTags = new List<string> { "tool", "climbingaxe" },
				prefabName = "Item_Hammer",
				upDirection = Vector3.up,
				pocketable = true,
				pouchable = true,
				worth = 2,
				inventoryScale = 1f,
				itemWeight = 1f,
				allowCosmetics = false,
				data = new List<string> { string.Format("{0}={1}", "axe_durability", 30) },
				dataModules = new List<Item_Data>(),
				dataModuleSaves = new List<DataModuleSave>(),
				pickupSounds = new List<AudioClip>(),
				executionModules = new List<ItemExecutionModule>()
			};
			try
			{
				EnsureAxeTemplate();
			}
			catch (Exception ex)
			{
				ManualLogSource log = Log;
				if (log != null)
				{
					log.LogWarning((object)("Template build deferred: " + ex.Message));
				}
			}
			if ((Object)(object)AxeTemplate != (Object)null)
			{
				val.itemAsset = AxeTemplate;
			}
			AxeModHandler.MarkAxeUsedNow(val);
			try
			{
				GameObject assetGameObject = CL_AssetManager.GetAssetGameObject("Item_Hammer", "");
				if ((Object)(object)assetGameObject != (Object)null)
				{
					Item_Object component = assetGameObject.GetComponent<Item_Object>();
					if ((Object)(object)component != (Object)null && component.itemData != null)
					{
						val.handItemAsset = component.itemData.handItemAsset;
						val.itemWeight = component.itemData.itemWeight / 3f;
					}
				}
			}
			catch (Exception ex2)
			{
				ManualLogSource log2 = Log;
				if (log2 != null)
				{
					log2.LogWarning((object)("Hammer hand lookup failed: " + ex2.Message));
				}
			}
			return val;
		}

		public static int GetDurability(Item item)
		{
			if (item?.data == null)
			{
				return 0;
			}
			foreach (string datum in item.data)
			{
				if (datum != null && datum.StartsWith("axe_durability=") && int.TryParse(datum.Substring("axe_durability".Length + 1), out var result))
				{
					return result;
				}
			}
			return 0;
		}

		public static void SetDurability(Item item, int value)
		{
			if (item == null)
			{
				return;
			}
			if (item.data == null)
			{
				item.data = new List<string>();
			}
			string text = string.Format("{0}={1}", "axe_durability", value);
			for (int i = 0; i < item.data.Count; i++)
			{
				if (item.data[i] != null && item.data[i].StartsWith("axe_durability="))
				{
					item.data[i] = text;
					return;
				}
			}
			item.data.Add(text);
		}
	}
	[HarmonyPatch(typeof(Inventory), "Initialize")]
	public static class InventoryInitPatch
	{
		public static bool needsStartingItems;

		public static Inventory pendingInventory;

		[HarmonyPostfix]
		public static void Postfix(Inventory __instance)
		{
			needsStartingItems = true;
			pendingInventory = __instance;
		}
	}
	[HarmonyPatch(typeof(HandItem), "Initialize")]
	public static class AxeRangePatch
	{
		[HarmonyPostfix]
		public static void Postfix(HandItem __instance, Item i)
		{
			if (!(i?.itemTag != "climbingaxe"))
			{
				HandItem_Melee val = (HandItem_Melee)(object)((__instance is HandItem_Melee) ? __instance : null);
				if (val != null)
				{
					val.range = 4f;
					val.canCharge = true;
					val.minimumChargeAttackTime = 0.05f;
					val.chargeAttackDamage = 1f;
				}
			}
		}
	}
	[HarmonyPatch(typeof(HandItem_Melee), "Use")]
	public static class AxeAutoReleasePatch
	{
		[HarmonyPostfix]
		public static void Postfix(HandItem_Melee __instance)
		{
			if (!(((HandItem)(__instance?)).item?.itemTag != "climbingaxe") && !((HandItem)__instance).used && !AxeModHandler.HasPendingAutoRelease(__instance))
			{
				AxeModHandler.ScheduleAutoRelease(__instance, 0.5f);
			}
		}
	}
	[HarmonyPatch(typeof(HandItem_Melee), "Hit")]
	public static class AxeHitPatch
	{
		private static readonly FieldInfo _hitField = AccessTools.Field(typeof(HandItem_Melee), "hit");

		private static readonly FieldInfo _hasHitField = AccessTools.Field(typeof(HandItem_Melee), "hasHit");

		private static readonly FieldInfo _hitTaggerField = AccessTools.Field(typeof(HandItem_Melee), "hitTagger");

		internal static readonly FieldInfo _grabAnywhereHitField = AccessTools.Field(typeof(ENT_Player), "grabAnywhereHit");

		internal static readonly FieldInfo _grabAnywherePositionField = AccessTools.Field(typeof(ENT_Player), "grabAnywherePosition");

		public static bool OurAxeIsHitting;

		[HarmonyPrefix]
		public static void Prefix(HandItem_Melee __instance)
		{
			if (((HandItem)(__instance?)).item?.itemTag == "climbingaxe")
			{
				OurAxeIsHitting = true;
				AxeModHandler.MarkAxeUsedNow(((HandItem)__instance).item);
			}
		}

		[HarmonyPostfix]
		public static void Postfix(HandItem_Melee __instance)
		{
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: 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)
			bool flag = ((HandItem)(__instance?)).item?.itemTag == "climbingaxe";
			if (flag)
			{
				OurAxeIsHitting = false;
			}
			if (!flag)
			{
				return;
			}
			bool flag2 = (bool)(_hasHitField?.GetValue(__instance) ?? ((object)false));
			RaycastHit hit = (RaycastHit)_hitField.GetValue(__instance);
			object? value = _hitTaggerField.GetValue(__instance);
			ObjectTagger val = (ObjectTagger)((value is ObjectTagger) ? value : null);
			if (flag2 && Plugin.AxeHitClips.Count > 0)
			{
				AudioClip val2 = Plugin.AxeHitClips[Random.Range(0, Plugin.AxeHitClips.Count)];
				if ((Object)(object)val2 != (Object)null)
				{
					AudioSource.PlayClipAtPoint(val2, ((RaycastHit)(ref hit)).point);
				}
			}
			if (flag2)
			{
				try
				{
					CL_CameraControl.Shake(0.025f);
				}
				catch (Exception ex)
				{
					Plugin.Log.LogWarning((object)("Shake failed: " + ex.Message));
				}
			}
			bool flag3 = flag2;
			if (flag3 && (Object)(object)((RaycastHit)(ref hit)).collider != (Object)null && (Object)(object)((Component)((RaycastHit)(ref hit)).collider).GetComponentInParent<CL_Handhold>() != (Object)null)
			{
				flag3 = false;
			}
			if (flag3 && (Object)(object)val != (Object)null && val.HasTag("Damageable"))
			{
				flag3 = false;
			}
			if (flag3 && AxeModHandler.HasActiveLodge(__instance))
			{
				flag3 = false;
			}
			if (flag3 && !OtherHandAllowsLodge(__instance))
			{
				flag3 = false;
			}
			if (flag3)
			{
				AxeModHandler.QueuePendingLodge(__instance, hit, 0f);
			}
			else
			{
				AxeModHandler.DislodgeAxe(__instance);
			}
		}

		internal static void DoLodgeNow(HandItem_Melee axe, RaycastHit hit)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			SpawnTempHandhold(axe, hit);
		}

		private static bool OtherHandAllowsLodge(HandItem_Melee axe)
		{
			if (((Hand_Base)(axe?)).hand == null)
			{
				return true;
			}
			Hand otherHand = ((Hand_Base)axe).hand.GetOtherHand();
			if (otherHand == null)
			{
				return true;
			}
			if ((Object)(object)otherHand.handhold != (Object)null)
			{
				return true;
			}
			try
			{
				if (otherHand.GetHandItem()?.item?.itemTag == "climbingaxe")
				{
					return true;
				}
			}
			catch
			{
			}
			return false;
		}

		private static void SpawnTempHandhold(HandItem_Melee axe, RaycastHit hit)
		{
			//IL_0536: Unknown result type (might be due to invalid IL or missing references)
			//IL_053b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0540: Unknown result type (might be due to invalid IL or missing references)
			//IL_0545: Unknown result type (might be due to invalid IL or missing references)
			//IL_0549: Unknown result type (might be due to invalid IL or missing references)
			//IL_054e: Unknown result type (might be due to invalid IL or missing references)
			//IL_05c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_05dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0584: Unknown result type (might be due to invalid IL or missing references)
			//IL_0589: Unknown result type (might be due to invalid IL or missing references)
			//IL_058e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0593: Unknown result type (might be due to invalid IL or missing references)
			//IL_0597: Unknown result type (might be due to invalid IL or missing references)
			//IL_059c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0576: Unknown result type (might be due to invalid IL or missing references)
			//IL_05a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_05b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_05b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_05ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_0172: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c6: Expected O, but got Unknown
			//IL_03f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0402: Unknown result type (might be due to invalid IL or missing references)
			//IL_0407: Unknown result type (might be due to invalid IL or missing references)
			//IL_0433: Unknown result type (might be due to invalid IL or missing references)
			//IL_043f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0444: Unknown result type (might be due to invalid IL or missing references)
			//IL_0449: 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_0425: Unknown result type (might be due to invalid IL or missing references)
			//IL_042a: 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_0476: Unknown result type (might be due to invalid IL or missing references)
			//IL_0478: Unknown result type (might be due to invalid IL or missing references)
			//IL_047d: 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_0486: Unknown result type (might be due to invalid IL or missing references)
			//IL_048b: Unknown result type (might be due to invalid IL or missing references)
			//IL_046a: Unknown result type (might be due to invalid IL or missing references)
			//IL_046f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0474: Unknown result type (might be due to invalid IL or missing references)
			//IL_04a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_04aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_04af: Unknown result type (might be due to invalid IL or missing references)
			//IL_04b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_04b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_04be: Unknown result type (might be due to invalid IL or missing references)
			//IL_04c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_04c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_04cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_04d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_04d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_04d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_04a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_04a6: Unknown result type (might be due to invalid IL or missing references)
			if (AxeModHandler.HasActiveLodge(axe) && AxeModHandler.DislodgeAndReportBreak(axe))
			{
				if ((Object)(object)axe != (Object)null)
				{
					try
					{
						((HandItem)axe).RemoveItem();
						return;
					}
					catch (Exception ex)
					{
						Plugin.Log.LogWarning((object)("RemoveItem on replace-break failed: " + ex.Message));
						return;
					}
				}
				return;
			}
			ENT_Player playerObject = ENT_Player.playerObject;
			if ((Object)(object)playerObject == (Object)null || ((Hand_Base)axe).hand == null)
			{
				Plugin.Log.LogWarning((object)"SpawnTempHandhold: player or axe.hand is null");
				return;
			}
			int id = ((Hand_Base)axe).hand.id;
			CL_Handhold[] grabAnywhereFakeHandholds = playerObject.grabAnywhereFakeHandholds;
			if (grabAnywhereFakeHandholds == null || grabAnywhereFakeHandholds.Length <= id || (Object)(object)grabAnywhereFakeHandholds[id] == (Object)null)
			{
				Plugin.Log.LogWarning((object)"grabAnywhereFakeHandholds not set up on player");
				return;
			}
			CL_Handhold val = grabAnywhereFakeHandholds[id];
			try
			{
				Transform[] array = _grabAnywhereHitField?.GetValue(playerObject) as Transform[];
				Vector3[] array2 = _grabAnywherePositionField?.GetValue(playerObject) as Vector3[];
				if (array != null)
				{
					array[id] = ((Component)((RaycastHit)(ref hit)).collider).transform;
				}
				if (array2 != null)
				{
					array2[id] = ((Component)((RaycastHit)(ref hit)).collider).transform.InverseTransformPoint(((RaycastHit)(ref hit)).point);
				}
				((Component)val).transform.position = ((RaycastHit)(ref hit)).point;
				((Component)val).transform.rotation = Quaternion.identity;
				((Component)val).gameObject.SetActive(true);
				GameObject val2 = null;
				Vector3 val13;
				try
				{
					GameObject val3 = Plugin.AxePrefab ?? CL_AssetManager.GetAssetGameObject("Item_Hammer", "");
					if ((Object)(object)val3 != (Object)null)
					{
						GameObject val4 = new GameObject("AxeStuckTemp");
						val4.SetActive(false);
						val2 = Object.Instantiate<GameObject>(val3, val4.transform);
						((Object)val2).name = "ClimbingAxe_LodgedVisual";
						Collider[] componentsInChildren = val2.GetComponentsInChildren<Collider>(true);
						foreach (Collider val5 in componentsInChildren)
						{
							Object.DestroyImmediate((Object)(object)val5);
						}
						Rigidbody[] componentsInChildren2 = val2.GetComponentsInChildren<Rigidbody>(true);
						foreach (Rigidbody val6 in componentsInChildren2)
						{
							Object.DestroyImmediate((Object)(object)val6);
						}
						Item_Object[] componentsInChildren3 = val2.GetComponentsInChildren<Item_Object>(true);
						foreach (Item_Object val7 in componentsInChildren3)
						{
							Object.DestroyImmediate((Object)(object)val7);
						}
						CL_Prop[] componentsInChildren4 = val2.GetComponentsInChildren<CL_Prop>(true);
						foreach (CL_Prop val8 in componentsInChildren4)
						{
							Object.DestroyImmediate((Object)(object)val8);
						}
						CL_Handhold[] componentsInChildren5 = val2.GetComponentsInChildren<CL_Handhold>(true);
						foreach (CL_Handhold val9 in componentsInChildren5)
						{
							Object.DestroyImmediate((Object)(object)val9);
						}
						List<Transform> list = new List<Transform>();
						Transform[] componentsInChildren6 = val2.GetComponentsInChildren<Transform>(true);
						foreach (Transform val10 in componentsInChildren6)
						{
							if (!((Object)(object)val10 == (Object)null) && ((Object)((Component)val10).gameObject).name.StartsWith("Scan_Target"))
							{
								list.Add(val10);
							}
						}
						foreach (Transform item in list)
						{
							if ((Object)(object)item != (Object)null)
							{
								Object.DestroyImmediate((Object)(object)((Component)item).gameObject);
							}
						}
						int layer = LayerMask.NameToLayer("Ignore Raycast");
						Transform[] componentsInChildren7 = val2.GetComponentsInChildren<Transform>(true);
						foreach (Transform val11 in componentsInChildren7)
						{
							((Component)val11).gameObject.layer = layer;
						}
						Plugin.ApplyGameShader(val2);
						Transform currentLevelParentRoot = WorldLoader.GetCurrentLevelParentRoot();
						if ((Object)(object)currentLevelParentRoot != (Object)null)
						{
							val2.transform.SetParent(currentLevelParentRoot, false);
						}
						val2.transform.position = ((RaycastHit)(ref hit)).point + ((RaycastHit)(ref hit)).normal * 0.05f;
						Camera main = Camera.main;
						Vector3 val12;
						if (!((Object)(object)main != (Object)null))
						{
							val12 = -((RaycastHit)(ref hit)).normal;
						}
						else
						{
							val13 = ((RaycastHit)(ref hit)).point - ((Component)main).transform.position;
							val12 = ((Vector3)(ref val13)).normalized;
						}
						Vector3 val14 = val12;
						if (((Vector3)(ref val14)).sqrMagnitude < 0.001f)
						{
							val14 = -((RaycastHit)(ref hit)).normal;
						}
						val13 = Vector3.Cross(val14, Vector3.up);
						Vector3 val15 = ((Vector3)(ref val13)).normalized;
						if (((Vector3)(ref val15)).sqrMagnitude < 0.001f)
						{
							val15 = Vector3.right;
						}
						Quaternion val16 = Quaternion.LookRotation(val14) * Quaternion.Euler(Plugin.LodgedAxeEulerOffset);
						Quaternion val17 = Quaternion.AngleAxis(15f, val15);
						val2.transform.rotation = val17 * val16;
						val2.AddComponent<UT_SoftParent>().Initialize(((Component)((RaycastHit)(ref hit)).collider).transform);
						val2.SetActive(true);
						Object.Destroy((Object)(object)val4);
					}
				}
				catch (Exception ex2)
				{
					Plugin.Log.LogWarning((object)("Stuck-axe visual spawn failed: " + ex2.Message));
				}
				val13 = Vector3.ProjectOnPlane(((RaycastHit)(ref hit)).normal, Vector3.up);
				Vector3 wallNormal = ((Vector3)(ref val13)).normalized;
				if (((Vector3)(ref wallNormal)).sqrMagnitude < 0.001f)
				{
					Camera main2 = Camera.main;
					Vector3 val18;
					if (!((Object)(object)main2 != (Object)null))
					{
						val18 = Vector3.forward;
					}
					else
					{
						val13 = Vector3.ProjectOnPlane(((Component)main2).transform.forward, Vector3.up);
						val18 = -((Vector3)(ref val13)).normalized;
					}
					Vector3 val19 = val18;
					wallNormal = ((((Vector3)(ref val19)).sqrMagnitude > 0.001f) ? val19 : Vector3.forward);
				}
				AxeModHandler.RegisterHandhold(axe, ((Component)val).gameObject, val2, wallNormal);
				try
				{
					((Hand_Base)axe).hand.GrabHold(((Component)val).transform, ((RaycastHit)(ref hit)).point, (InteractionInfo)null);
					((Hand_Base)axe).hand.lockHand = true;
				}
				catch (Exception ex3)
				{
					Plugin.Log.LogWarning((object)("GrabHold failed: " + ex3.Message));
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"SpawnTempHandhold failed: {arg}");
			}
		}
	}
	public class AxeModHandler : MonoBehaviour
	{
		private struct ActiveLodge
		{
			public GameObject handhold;

			public GameObject stuckVisual;

			public bool firstPersonHidden;

			public Hand hand;

			public Item axeItem;

			public Vector3 wallNormal;
		}

		private struct PendingLodge
		{
			public float fireAt;

			public RaycastHit hit;
		}

		private float _startingItemsAddAt = -1f;

		private bool _jumpHookInstalled;

		private static readonly Dictionary<HandItem_Melee, ActiveLodge> _activeLodges = new Dictionary<HandItem_Melee, ActiveLodge>();

		private static readonly Dictionary<HandItem_Melee, PendingLodge> _pendingLodges = new Dictionary<HandItem_Melee, PendingLodge>();

		private static readonly Dictionary<Item, float> _lastUseTime = new Dictionary<Item, float>();

		private float _nextRegenCheck;

		private static readonly MaterialPropertyBlock _mpb = new MaterialPropertyBlock();

		private static readonly int _colorId = Shader.PropertyToID("_Color");

		private static readonly Dictionary<HandItem_Melee, float> _pendingAutoReleases = new Dictionary<HandItem_Melee, float>();

		private static bool _debugLoggingEnabled;

		private float _nextDebugLogAt;

		private static readonly string _debugLogPath = "H:\\WhiteKnuckleMOD\\axe_debug.log";

		private static FieldInfo _hasHitField = AccessTools.Field(typeof(ENT_Player), "hasHit");

		private static FieldInfo _hitNormalField = AccessTools.Field(typeof(ENT_Player), "hitNormal");

		private static Mesh _cachedAxeMesh;

		private static Material[] _cachedAxeMaterials;

		private void OnEnable()
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Expected O, but got Unknown
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			Camera.onPreCull = (CameraCallback)Delegate.Combine((Delegate?)(object)Camera.onPreCull, (Delegate?)new CameraCallback(OnCameraPreCull));
		}

		private void OnDisable()
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Expected O, but got Unknown
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			Camera.onPreCull = (CameraCallback)Delegate.Remove((Delegate?)(object)Camera.onPreCull, (Delegate?)new CameraCallback(OnCameraPreCull));
		}

		private void OnCameraPreCull(Camera cam)
		{
			if (!((Object)(object)cam != (Object)(object)Camera.main))
			{
				UpdateTintAndSlide();
			}
		}

		private void UpdateTintAndSlide()
		{
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			ENT_Player playerObject = ENT_Player.playerObject;
			if ((Object)(object)playerObject == (Object)null || playerObject.hands == null)
			{
				return;
			}
			Hand[] hands = playerObject.hands;
			foreach (Hand val in hands)
			{
				if (val == null)
				{
					continue;
				}
				HandItem handItem = val.GetHandItem();
				if (!(handItem?.item?.itemTag != "climbingaxe"))
				{
					int durability = Plugin.GetDurability(handItem.item);
					float num = 1f - Mathf.Clamp01((float)durability / 30f);
					Color tint = Color.Lerp(Color.white, Color.black, num);
					ApplyTintToHierarchy(((Component)handItem).gameObject, tint);
					SwapHandItemMeshIfNeeded(handItem);
					SwapHandItemWeaponSpriteIfNeeded(handItem);
					HandItem_Melee val2 = (HandItem_Melee)(object)((handItem is HandItem_Melee) ? handItem : null);
					if (val2 != null && _activeLodges.TryGetValue(val2, out var value) && (Object)(object)value.handhold != (Object)null)
					{
						ApplyTintToHierarchy(value.stuckVisual, tint);
					}
				}
			}
		}

		public static Vector3 GetWallNormalForHand(Hand hand)
		{
			//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_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: 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)
			if (hand == null)
			{
				return Vector3.zero;
			}
			foreach (KeyValuePair<HandItem_Melee, ActiveLodge> activeLodge in _activeLodges)
			{
				ActiveLodge value = activeLodge.Value;
				if (!((Object)(object)value.handhold == (Object)null))
				{
					CL_Handhold component = value.handhold.GetComponent<CL_Handhold>();
					if ((Object)(object)hand.handhold == (Object)(object)component)
					{
						return value.wallNormal;
					}
				}
			}
			return Vector3.zero;
		}

		public static void QueuePendingLodge(HandItem_Melee axe, RaycastHit hit, float delay)
		{
			//IL_002c: 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)
			if (!((Object)(object)axe == (Object)null))
			{
				_pendingLodges[axe] = new PendingLodge
				{
					fireAt = Time.time + delay,
					hit = hit
				};
			}
		}

		public static void CancelPendingLodge(HandItem_Melee axe)
		{
			if (!((Object)(object)axe == (Object)null))
			{
				_pendingLodges.Remove(axe);
			}
		}

		public static bool HasActiveLodge(HandItem_Melee axe)
		{
			return (Object)(object)axe != (Object)null && _activeLodges.ContainsKey(axe);
		}

		public static void MarkAxeUsedNow(Item axeItem)
		{
			if (axeItem != null)
			{
				_lastUseTime[axeItem] = Time.time;
			}
		}

		public static bool HasPendingAutoRelease(HandItem_Melee axe)
		{
			return (Object)(object)axe != (Object)null && _pendingAutoReleases.ContainsKey(axe);
		}

		public static void ScheduleAutoRelease(HandItem_Melee axe, float delay)
		{
			if (!((Object)(object)axe == (Object)null))
			{
				_pendingAutoReleases[axe] = Time.time + delay;
			}
		}

		public static bool DislodgeAndReportBreak(HandItem_Melee axe)
		{
			if ((Object)(object)axe == (Object)null)
			{
				return false;
			}
			_pendingLodges.Remove(axe);
			return EndLodgeAndTick(axe);
		}

		public static void RegisterHandhold(HandItem_Melee axe, GameObject handhold, GameObject stuckVisual, Vector3 wallNormal)
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			SetFirstPersonAxeVisible(axe, visible: false);
			_activeLodges[axe] = new ActiveLodge
			{
				handhold = handhold,
				stuckVisual = stuckVisual,
				firstPersonHidden = true,
				hand = ((Hand_Base)axe).hand,
				axeItem = ((HandItem)axe).item,
				wallNormal = wallNormal
			};
			AutoDislodgeOtherHand(axe);
		}

		private static void AutoDislodgeOtherHand(HandItem_Melee currentAxe)
		{
			if ((Object)(object)currentAxe == (Object)null || ((Hand_Base)currentAxe).hand == null)
			{
				return;
			}
			List<HandItem_Melee> list = null;
			foreach (KeyValuePair<HandItem_Melee, ActiveLodge> activeLodge in _activeLodges)
			{
				if (!((Object)(object)activeLodge.Key == (Object)(object)currentAxe) && activeLodge.Value.hand != null && activeLodge.Value.hand != ((Hand_Base)currentAxe).hand)
				{
					(list ?? (list = new List<HandItem_Melee>())).Add(activeLodge.Key);
				}
			}
			if (list == null)
			{
				return;
			}
			foreach (HandItem_Melee item in list)
			{
				DislodgeAxe(item);
			}
		}

		public static void DislodgeAxe(HandItem_Melee axe)
		{
			if ((Object)(object)axe != (Object)null)
			{
				_pendingLodges.Remove(axe);
			}
			if (EndLodgeAndTick(axe) && (Object)(object)axe != (Object)null)
			{
				try
				{
					((HandItem)axe).RemoveItem();
				}
				catch (Exception ex)
				{
					Plugin.Log.LogWarning((object)("RemoveItem on break failed: " + ex.Message));
				}
			}
		}

		private static bool EndLodgeAndTick(HandItem_Melee axe)
		{
			//IL_020a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_020f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0216: Unknown result type (might be due to invalid IL or missing references)
			if (!_activeLodges.TryGetValue(axe, out var value))
			{
				return false;
			}
			bool flag = (Object)(object)value.handhold != (Object)null;
			if (value.hand != null)
			{
				value.hand.lockHand = false;
				try
				{
					value.hand.DropHand(false);
				}
				catch (Exception ex)
				{
					Plugin.Log.LogWarning((object)("DropHand failed during cleanup: " + ex.Message));
				}
			}
			ENT_Player playerObject = ENT_Player.playerObject;
			if ((Object)(object)playerObject != (Object)null && value.hand != null)
			{
				try
				{
					int id = value.hand.id;
					if (AxeHitPatch._grabAnywhereHitField?.GetValue(playerObject) is Transform[] array && id < array.Length)
					{
						array[id] = null;
					}
					if (playerObject.grabAnywhereFakeHandholds != null && id < playerObject.grabAnywhereFakeHandholds.Length && (Object)(object)playerObject.grabAnywhereFakeHandholds[id] != (Object)null)
					{
						((Component)playerObject.grabAnywhereFakeHandholds[id]).gameObject.SetActive(false);
					}
				}
				catch (Exception ex2)
				{
					Plugin.Log.LogWarning((object)("grabAnywhere cleanup failed: " + ex2.Message));
				}
			}
			if ((Object)(object)value.stuckVisual != (Object)null)
			{
				Object.Destroy((Object)(object)value.stuckVisual);
			}
			if ((Object)(object)axe != (Object)null)
			{
				SetFirstPersonAxeVisible(axe, visible: true);
			}
			_activeLodges.Remove(axe);
			if (value.axeItem != null)
			{
				MarkAxeUsedNow(value.axeItem);
				int num = Plugin.GetDurability(value.axeItem) - 1;
				if (num <= 0)
				{
					Plugin.SetDurability(value.axeItem, 0);
					if (flag && (Object)(object)Plugin.AxeBreakClip != (Object)null)
					{
						Camera main = Camera.main;
						Vector3 val = (((Object)(object)main != (Object)null) ? ((Component)main).transform.position : Vector3.zero);
						AudioSource.PlayClipAtPoint(Plugin.AxeBreakClip, val);
					}
					return true;
				}
				Plugin.SetDurability(value.axeItem, num);
			}
			return false;
		}

		private static void FinalizeBreak(HandItem_Melee axe)
		{
			if ((Object)(object)axe == (Object)null)
			{
				return;
			}
			_pendingLodges.Remove(axe);
			try
			{
				((HandItem)axe).RemoveItem();
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("FinalizeBreak RemoveItem failed: " + ex.Message));
			}
		}

		private void Update()
		{
			if (InventoryInitPatch.needsStartingItems && _startingItemsAddAt < 0f)
			{
				_startingItemsAddAt = Time.time + 1f;
			}
			if (_startingItemsAddAt > 0f && Time.time >= _startingItemsAddAt)
			{
				TryAddStartingItems();
				InventoryInitPatch.needsStartingItems = false;
				InventoryInitPatch.pendingInventory = null;
				_startingItemsAddAt = -1f;
			}
			ProcessPendingLodges();
			ProcessPendingAutoReleases();
			HookPlayerJumpIfNeeded();
			ProcessDurabilityRegen();
			ProcessDebugLogging();
			if (Input.GetKeyDown((KeyCode)291))
			{
				SpawnTestAxe();
			}
			if (Input.GetKeyDown((KeyCode)289))
			{
				_debugLoggingEnabled = !_debugLoggingEnabled;
				if (_debugLoggingEnabled)
				{
					DbgReset($"[AxeDbg] session start {DateTime.Now:HH:mm:ss}");
				}
				DbgLine("[AxeDbg] logging " + (_debugLoggingEnabled ? "ON" : "OFF"));
			}
		}

		private static void DbgLine(string line)
		{
			Plugin.Log.LogWarning((object)line);
			try
			{
				File.AppendAllText(_debugLogPath, line + Environment.NewLine);
			}
			catch
			{
			}
		}

		private static void DbgReset(string banner)
		{
			try
			{
				File.WriteAllText(_debugLogPath, banner + Environment.NewLine);
			}
			catch
			{
			}
		}

		private void ProcessDebugLogging()
		{
			//IL_021e: Unknown result type (might be due to invalid IL or missing references)
			//IL_022f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0240: Unknown result type (might be due to invalid IL or missing references)
			//IL_0256: Unknown result type (might be due to invalid IL or missing references)
			//IL_025d: Unknown result type (might be due to invalid IL or missing references)
			//IL_028a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_017b: 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_016b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			//IL_0187: Unknown result type (might be due to invalid IL or missing references)
			//IL_0189: Unknown result type (might be due to invalid IL or missing references)
			//IL_018a: 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_0194: Unknown result type (might be due to invalid IL or missing references)
			//IL_0199: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01df: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d5: Unknown result type (might be due to invalid IL or missing references)
			if (!_debugLoggingEnabled || Time.time < _nextDebugLogAt)
			{
				return;
			}
			_nextDebugLogAt = Time.time + 0.25f;
			ENT_Player playerObject = ENT_Player.playerObject;
			if ((Object)(object)playerObject == (Object)null || playerObject.hands == null)
			{
				return;
			}
			Vector3 v = (((Object)(object)Camera.main != (Object)null) ? ((Component)Camera.main).transform.forward : Vector3.zero);
			Vector3 position = ((Component)playerObject).transform.position;
			Vector3 v2 = Vector3.zero;
			try
			{
				CharacterController component = ((Component)playerObject).GetComponent<CharacterController>();
				v2 = ((component != null) ? component.velocity : Vector3.zero);
			}
			catch
			{
			}
			for (int i = 0; i < playerObject.hands.Length; i++)
			{
				Hand val = playerObject.hands[i];
				if (val == null)
				{
					continue;
				}
				string arg = "free";
				bool flag = false;
				if ((Object)(object)val.handhold != (Object)null)
				{
					string name = ((Object)((Component)val.handhold).gameObject).name;
					arg = ((name == "ClimbingAxe_Handhold") ? "AXE " : "VANILLA");
					arg = arg + "(" + name + ")";
				}
				if (!((Object)(object)val.handhold == (Object)null))
				{
					Vector3 val2 = (((Object)(object)val.holdTarget != (Object)null) ? val.holdTarget.TransformPoint(val.holdPosition) : Vector3.zero);
					Vector3 val3 = val2 - position;
					bool flag2 = false;
					Vector3 v3 = Vector3.zero;
					try
					{
						flag2 = (bool)(_hasHitField?.GetValue(playerObject) ?? ((object)false));
						v3 = (Vector3)(_hitNormalField?.GetValue(playerObject) ?? ((object)Vector3.zero));
					}
					catch
					{
					}
					CL_Handhold handhold = val.handhold;
					DbgLine($"[AxeDbg] h{i} {arg} | " + "player=" + F(position) + " vel=" + F(v2) + " camFwd=" + F(v) + " | " + $"holdWorld={F(val2)} Δy={val3.y:F2} Δmag={((Vector3)(ref val3)).magnitude:F2} | " + $"hasHit={flag2} hitN={F(v3)} | " + $"climbMult={handhold.climbMult:F2} active={handhold.active} " + $"layer={((Component)handhold).gameObject.layer}");
				}
			}
		}

		private static string F(Vector3 v)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: 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)
			return $"({v.x:F2},{v.y:F2},{v.z:F2})";
		}

		private static string TagSummary(ObjectTagger t)
		{
			if ((Object)(object)t == (Object)null || t.tags == null)
			{
				return "-";
			}
			return string.Join(",", t.tags);
		}

		private void ProcessDurabilityRegen()
		{
			if (Time.time < _nextRegenCheck)
			{
				return;
			}
			_nextRegenCheck = Time.time + 1f;
			if (_lastUseTime.Count == 0)
			{
				return;
			}
			HashSet<Item> hashSet = null;
			if (_activeLodges.Count > 0)
			{
				hashSet = new HashSet<Item>();
				foreach (ActiveLodge value in _activeLodges.Values)
				{
					if (value.axeItem != null)
					{
						hashSet.Add(value.axeItem);
					}
				}
			}
			List<Item> list = null;
			List<Item> list2 = new List<Item>(_lastUseTime.Keys);
			foreach (Item item in list2)
			{
				if (item == null)
				{
					(list ?? (list = new List<Item>())).Add(item);
				}
				else
				{
					if (hashSet != null && hashSet.Contains(item))
					{
						continue;
					}
					float num = Time.time - _lastUseTime[item];
					if (!(num < 60f))
					{
						int durability = Plugin.GetDurability(item);
						if (durability < 30)
						{
							Plugin.SetDurability(item, durability + 1);
							_lastUseTime[item] = Time.time;
						}
					}
				}
			}
			if (list == null)
			{
				return;
			}
			foreach (Item item2 in list)
			{
				_lastUseTime.Remove(item2);
			}
		}

		private void HookPlayerJumpIfNeeded()
		{
			if (!_jumpHookInstalled)
			{
				ENT_Player playerObject = ENT_Player.playerObject;
				if (!((Object)(object)playerObject == (Object)null))
				{
					playerObject._OnJump = (Action)Delegate.Combine(playerObject._OnJump, new Action(OnPlayerJumped));
					_jumpHookInstalled = true;
				}
			}
		}

		private void OnPlayerJumped()
		{
			if (_activeLodges.Count == 0)
			{
				return;
			}
			List<HandItem_Melee> list = new List<HandItem_Melee>(_activeLodges.Keys);
			foreach (HandItem_Melee item in list)
			{
				DislodgeAxe(item);
			}
		}

		private void ProcessPendingAutoReleases()
		{
			if (_pendingAutoReleases.Count == 0)
			{
				return;
			}
			List<HandItem_Melee> list = null;
			List<HandItem_Melee> list2 = null;
			foreach (KeyValuePair<HandItem_Melee, float> pendingAutoRelease in _pendingAutoReleases)
			{
				HandItem_Melee key = pendingAutoRelease.Key;
				if ((Object)(object)key == (Object)null || !((Component)key).gameObject.activeInHierarchy)
				{
					(list2 ?? (list2 = new List<HandItem_Melee>())).Add(key);
				}
				else if (Time.time >= pendingAutoRelease.Value)
				{
					(list ?? (list = new List<HandItem_Melee>())).Add(key);
				}
			}
			if (list2 != null)
			{
				foreach (HandItem_Melee item in list2)
				{
					_pendingAutoReleases.Remove(item);
				}
			}
			if (list == null)
			{
				return;
			}
			foreach (HandItem_Melee item2 in list)
			{
				_pendingAutoReleases.Remove(item2);
				try
				{
					((HandItem)item2).StopUse();
				}
				catch (Exception ex)
				{
					Plugin.Log.LogWarning((object)("Auto-release StopUse failed: " + ex.Message));
				}
			}
		}

		private void ProcessPendingLodges()
		{
			//IL_0159: Unknown result type (might be due to invalid IL or missing references)
			if (_pendingLodges.Count == 0)
			{
				return;
			}
			List<HandItem_Melee> list = null;
			List<HandItem_Melee> list2 = null;
			foreach (KeyValuePair<HandItem_Melee, PendingLodge> pendingLodge in _pendingLodges)
			{
				HandItem_Melee key = pendingLodge.Key;
				PendingLodge value = pendingLodge.Value;
				if ((Object)(object)key == (Object)null || !((Component)key).gameObject.activeInHierarchy)
				{
					(list2 ?? (list2 = new List<HandItem_Melee>())).Add(key);
				}
				else if (Time.time >= value.fireAt)
				{
					(list ?? (list = new List<HandItem_Melee>())).Add(key);
				}
			}
			if (list2 != null)
			{
				foreach (HandItem_Melee item in list2)
				{
					_pendingLodges.Remove(item);
				}
			}
			if (list == null)
			{
				return;
			}
			foreach (HandItem_Melee item2 in list)
			{
				if (_pendingLodges.TryGetValue(item2, out var value2))
				{
					_pendingLodges.Remove(item2);
					AxeHitPatch.DoLodgeNow(item2, value2.hit);
				}
			}
		}

		private void LateUpdate()
		{
			if (_activeLodges.Count == 0)
			{
				return;
			}
			List<HandItem_Melee> list = null;
			foreach (KeyValuePair<HandItem_Melee, ActiveLodge> activeLodge in _activeLodges)
			{
				HandItem_Melee key = activeLodge.Key;
				ActiveLodge value = activeLodge.Value;
				if ((Object)(object)key == (Object)null || (Object)(object)value.handhold == (Object)null)
				{
					(list ?? (list = new List<HandItem_Melee>())).Add(key);
				}
				else if (!((Component)key).gameObject.activeInHierarchy)
				{
					(list ?? (list = new List<HandItem_Melee>())).Add(key);
				}
				else if (((Hand_Base)key).hand != null)
				{
					CL_Handhold component = value.handhold.GetComponent<CL_Handhold>();
					if (!((Object)(object)((Hand_Base)key).hand.handhold == (Object)(object)component) && !((HandItem)key).used)
					{
						(list ?? (list = new List<HandItem_Melee>())).Add(key);
					}
				}
			}
			if (list == null)
			{
				return;
			}
			foreach (HandItem_Melee item in list)
			{
				_pendingLodges.Remove(item);
				if (EndLodgeAndTick(item))
				{
					FinalizeBreak(item);
				}
			}
		}

		private static void SwapHandItemMeshIfNeeded(HandItem hi)
		{
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Expected O, but got Unknown
			if ((Object)(object)hi == (Object)null || (Object)(object)Plugin.AxePrefab == (Object)null)
			{
				return;
			}
			if ((Object)(object)_cachedAxeMesh == (Object)null)
			{
				MeshFilter componentInChildren = Plugin.AxePrefab.GetComponentInChildren<MeshFilter>(true);
				MeshRenderer val = (((Object)(object)componentInChildren != (Object)null) ? ((Component)componentInChildren).GetComponent<MeshRenderer>() : null);
				if ((Object)(object)componentInChildren == (Object)null || (Object)(object)componentInChildren.sharedMesh == (Object)null)
				{
					return;
				}
				_cachedAxeMesh = componentInChildren.sharedMesh;
				if ((Object)(object)val != (Object)null)
				{
					Material[] sharedMaterials = ((Renderer)val).sharedMaterials;
					_cachedAxeMaterials = (Material[])(object)new Material[sharedMaterials.Length];
					Shader val2 = Shader.Find("Dark Machine/SHDR_Base") ?? Shader.Find("Unlit/Texture");
					for (int i = 0; i < sharedMaterials.Length; i++)
					{
						if ((Object)(object)sharedMaterials[i] == (Object)null)
						{
							continue;
						}
						Material val3 = new Material(sharedMaterials[i]);
						if ((Object)(object)val2 != (Object)null)
						{
							Texture val4 = (val3.HasProperty("_MainTex") ? val3.GetTexture("_MainTex") : null);
							val3.shader = val2;
							if ((Object)(object)val4 != (Object)null && val3.HasProperty("_MainTex"))
							{
								val3.SetTexture("_MainTex", val4);
							}
						}
						_cachedAxeMaterials[i] = val3;
					}
				}
			}
			MeshFilter[] componentsInChildren = ((Component)hi).GetComponentsInChildren<MeshFilter>(true);
			foreach (MeshFilter val5 in componentsInChildren)
			{
				if ((Object)(object)val5 == (Object)null)
				{
					continue;
				}
				if ((Object)(object)val5.sharedMesh != (Object)(object)_cachedAxeMesh)
				{
					val5.sharedMesh = _cachedAxeMesh;
				}
				MeshRenderer component = ((Component)val5).GetComponent<MeshRenderer>();
				if ((Object)(object)component == (Object)null)
				{
					continue;
				}
				if (_cachedAxeMaterials != null && _cachedAxeMaterials.Length != 0)
				{
					((Renderer)component).sharedMaterials = _cachedAxeMaterials;
				}
				if (!((Object)(object)Plugin.AxeTexture != (Object)null))
				{
					continue;
				}
				Material[] sharedMaterials2 = ((Renderer)component).sharedMaterials;
				for (int k = 0; k < sharedMaterials2.Length; k++)
				{
					if (!((Object)(object)sharedMaterials2[k] == (Object)null) && sharedMaterials2[k].HasProperty("_MainTex"))
					{
						sharedMaterials2[k].SetTexture("_MainTex", (Texture)(object)Plugin.AxeTexture);
					}
				}
			}
		}

		private static void SwapHandItemWeaponSpriteIfNeeded(HandItem hi)
		{
			if ((Object)(object)hi == (Object)null || (Object)(object)Plugin.AxeHandSprite == (Object)null)
			{
				return;
			}
			SpriteRenderer[] componentsInChildren = ((Component)hi).GetComponentsInChildren<SpriteRenderer>(true);
			foreach (SpriteRenderer val in componentsInChildren)
			{
				if (!((Object)(object)val == (Object)null))
				{
					string name = ((Object)((Component)val).gameObject).name;
					if ((!(name != "Sprite") || !(name != "ChargeSprite")) && !((Object)(object)val.sprite == (Object)(object)Plugin.AxeHandSprite))
					{
						val.sprite = Plugin.AxeHandSprite;
					}
				}
			}
		}

		private static void ApplyTintToHierarchy(GameObject root, Color tint)
		{
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)root == (Object)null)
			{
				return;
			}
			Renderer[] componentsInChildren = root.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val in componentsInChildren)
			{
				Material[] materials = val.materials;
				for (int j = 0; j < materials.Length; j++)
				{
					if (!((Object)(object)materials[j] == (Object)null) && materials[j].HasProperty(_colorId))
					{
						materials[j].SetColor(_colorId, tint);
					}
				}
			}
		}

		private static void SetFirstPersonAxeVisible(HandItem_Melee axe, bool visible)
		{
			if (!((Object)(object)axe == (Object)null))
			{
				Renderer[] componentsInChildren = ((Component)axe).GetComponentsInChildren<Renderer>(true);
				foreach (Renderer val in componentsInChildren)
				{
					val.enabled = visible;
				}
			}
		}

		private void TryAddStartingItems()
		{
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			Inventory pendingInventory = InventoryInitPatch.pendingInventory;
			if ((Object)(object)pendingInventory == (Object)null)
			{
				return;
			}
			int num = 0;
			foreach (Item bagItem in pendingInventory.bagItems)
			{
				if (bagItem != null && bagItem.itemTag == "climbingaxe")
				{
					num++;
				}
			}
			int num2 = Math.Max(0, 2 - num);
			for (int i = 0; i < num2; i++)
			{
				try
				{
					Item val = Plugin.CreateAxeItem();
					pendingInventory.AddItemToInventoryScreen(new Vector3(0.15f * ((float)i - 0.5f), 0.1f, 1f), val, true, false);
				}
				catch (Exception arg)
				{
					Plugin.Log.LogError((object)$"Failed to add starting axe {i}: {arg}");
				}
			}
		}

		private void SpawnTestAxe()
		{
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: 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_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			Plugin.EnsureAxeTemplate();
			if ((Object)(object)Plugin.AxeTemplate == (Object)null)
			{
				Plugin.Log.LogError((object)"Test spawn: axe template unavailable");
				return;
			}
			Camera main = Camera.main;
			if (!((Object)(object)main == (Object)null))
			{
				Vector3 val = ((Component)main).transform.position + ((Component)main).transform.forward * 2f;
				GameObject val2 = Object.Instantiate<GameObject>(((Component)Plugin.AxeTemplate).gameObject, val, Quaternion.identity);
				val2.SetActive(true);
				Item_Object component = val2.GetComponent<Item_Object>();
				if ((Object)(object)component != (Object)null)
				{
					component.itemData = Plugin.CreateAxeItem();
				}
				Plugin.Log.LogInfo((object)$"Test axe spawned at {val}");
			}
		}
	}
	public static class WavLoader
	{
		public static AudioClip LoadFromFile(string path)
		{
			byte[] array = File.ReadAllBytes(path);
			if (array.Length < 44 || array[0] != 82 || array[1] != 73 || array[2] != 70 || array[3] != 70)
			{
				throw new Exception("Not a RIFF file");
			}
			if (array[8] != 87 || array[9] != 65 || array[10] != 86 || array[11] != 69)
			{
				throw new Exception("Not a WAVE file");
			}
			int i = 12;
			int num = 0;
			int num2 = 0;
			int num3 = 0;
			int num4 = -1;
			int num5 = -1;
			int num6;
			for (; i < array.Length - 8; i += 8 + num6)
			{
				string @string = Encoding.ASCII.GetString(array, i, 4);
				num6 = BitConverter.ToInt32(array, i + 4);
				if (@string == "fmt ")
				{
					num = BitConverter.ToInt16(array, i + 10);
					num2 = BitConverter.ToInt32(array, i + 12);
					num3 = BitConverter.ToInt16(array, i + 22);
				}
				else if (@string == "data")
				{
					num4 = i + 8;
					num5 = num6;
					break;
				}
			}
			if (num4 < 0)
			{
				throw new Exception("No data chunk found");
			}
			int num7 = num3 / 8;
			int num8 = num5 / num7;
			float[] array2 = new float[num8];
			switch (num3)
			{
			case 16:
			{
				for (int m = 0; m < num8; m++)
				{
					short num13 = BitConverter.ToInt16(array, num4 + m * 2);
					array2[m] = (float)num13 / 32768f;
				}
				break;
			}
			case 24:
			{
				for (int k = 0; k < num8; k++)
				{
					int num9 = array[num4 + k * 3];
					int num10 = array[num4 + k * 3 + 1];
					int num11 = (sbyte)array[num4 + k * 3 + 2];
					int num12 = (num11 << 16) | (num10 << 8) | num9;
					array2[k] = (float)num12 / 8388608f;
				}
				break;
			}
			case 32:
			{
				for (int l = 0; l < num8; l++)
				{
					array2[l] = BitConverter.ToSingle(array, num4 + l * 4);
				}
				break;
			}
			case 8:
			{
				for (int j = 0; j < num8; j++)
				{
					array2[j] = (float)(array[num4 + j] - 128) / 128f;
				}
				break;
			}
			default:
				throw new Exception($"Unsupported bit depth: {num3}");
			}
			AudioClip val = AudioClip.Create("climbingaxe_hit_custom", num8 / num, num, num2, false);
			val.SetData(array2, 0);
			return val;
		}
	}
	[HarmonyPatch(typeof(AudioGroup), "PlayAudioSet")]
	public static class SuppressHammerHitAudioPatch
	{
		[HarmonyPrefix]
		public static bool Prefix()
		{
			return !AxeHitPatch.OurAxeIsHitting;
		}
	}
	[HarmonyPatch(typeof(UT_AudioClipHandler), "PlaySound", new Type[] { typeof(string) })]
	public static class SuppressHammerPlaySoundPatch
	{
		[HarmonyPrefix]
		public static bool Prefix()
		{
			return !AxeHitPatch.OurAxeIsHitting;
		}
	}
	[HarmonyPatch(typeof(CL_Handhold), "HammerIn")]
	public static class SuppressAxeHammerPatch
	{
		[HarmonyPrefix]
		public static bool Prefix()
		{
			return !AxeHitPatch.OurAxeIsHitting;
		}
	}
	[HarmonyPatch]
	public static class HangWallNormalPatch
	{
		private static readonly FieldInfo _hasHitField = AccessTools.Field(typeof(ENT_Player), "hasHit");

		private static readonly FieldInfo _hitNormalField = AccessTools.Field(typeof(ENT_Player), "hitNormal");

		public static MethodBase TargetMethod()
		{
			return AccessTools.Method(typeof(ENT_Player), "Hang", (Type[])null, (Type[])null);
		}

		[HarmonyPrefix]
		public static void Prefix(ENT_Player __instance)
		{
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)__instance == (Object)null || __instance.hands == null)
			{
				return;
			}
			for (int i = 0; i < __instance.hands.Length; i++)
			{
				Hand val = __instance.hands[i];
				if (val == null || (Object)(object)val.handhold == (Object)null)
				{
					continue;
				}
				Vector3 wallNormalForHand = AxeModHandler.GetWallNormalForHand(val);
				if (!(wallNormalForHand == Vector3.zero))
				{
					try
					{
						_hasHitField?.SetValue(__instance, true);
						_hitNormalField?.SetValue(__instance, wallNormalForHand);
						break;
					}
					catch
					{
						break;
					}
				}
			}
		}
	}
}