Decompiled source of ValheimBB v0.2.3

BepInEx\plugins\ValheimBB.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Splatform;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Networking;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("ValheimBB")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ValheimBB")]
[assembly: AssemblyCopyright("Copyright ©  2025")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("1699c6b0-5753-49cf-903b-e6b635fbcab9")]
[assembly: AssemblyFileVersion("0.2.3.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("0.2.3.0")]
namespace ValheimBB
{
	[BepInPlugin("com.valheimbb", "ValheimBB", "0.2.3")]
	public class ValheimBBPlugin : BaseUnityPlugin
	{
		internal enum WisplightOutsideMistlandsMode
		{
			VanillaOrbit,
			Off,
			LockedInPlace
		}

		[HarmonyPatch(typeof(BaseAI), "DoIdleSound")]
		public static class BaseAI_DoIdleSound_AttachedOriginSound_Patch
		{
			private static void Prefix(BaseAI __instance)
			{
				SetDeerAlertedIdleSoundState(__instance, (Object)(object)__instance != (Object)null && __instance.IsAlerted());
				ForceAttachSoundEffects(__instance?.m_idleSound);
			}

			private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
			{
				return ReplaceEffectListCreateNullParentWithSelfTransform(instructions);
			}
		}

		[HarmonyPatch(typeof(BaseAI), "SetAlerted")]
		public static class BaseAI_SetAlerted_AttachedOriginSound_Patch
		{
			private static void Prefix(BaseAI __instance)
			{
				ForceAttachSoundEffects(__instance?.m_alertedEffects);
			}

			private static void Postfix(BaseAI __instance, bool __0)
			{
				SetDeerAlertedIdleSoundState(__instance, __0);
			}

			private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
			{
				return ReplaceEffectListCreateNullParentWithSelfTransform(instructions);
			}
		}

		[HarmonyPatch(typeof(BaseAI), "OnDestroy")]
		public static class BaseAI_OnDestroy_DeerAlertedScaredSfx_Patch
		{
			private static void Postfix(BaseAI __instance)
			{
				ClearDeerAlertedIdleSoundState(__instance);
			}
		}

		[HarmonyPatch(typeof(Attack), "Update")]
		public static class Attack_Update_AttachedOriginSound_Patch
		{
			private static void Prefix(Attack __instance)
			{
				NormalizeAttackStartSoundEffects(__instance);
			}
		}

		[HarmonyPatch(typeof(Attack), "DoMeleeAttack")]
		public static class Attack_DoMeleeAttack_AttachedOriginSound_Patch
		{
			private static void Prefix(Attack __instance)
			{
				NormalizeAttackTriggerSoundEffects(__instance);
			}
		}

		[HarmonyPatch(typeof(Attack), "DoAreaAttack")]
		public static class Attack_DoAreaAttack_AttachedOriginSound_Patch
		{
			private static void Prefix(Attack __instance)
			{
				NormalizeAttackTriggerSoundEffects(__instance);
			}
		}

		[HarmonyPatch(typeof(Attack), "ProjectileAttackTriggered")]
		public static class Attack_ProjectileAttackTriggered_AttachedOriginSound_Patch
		{
			private static void Prefix(Attack __instance)
			{
				NormalizeAttackTriggerSoundEffects(__instance);
			}
		}

		[HarmonyPatch(typeof(Attack), "OnTrailStart")]
		public static class Attack_OnTrailStart_AttachedOriginSound_Patch
		{
			private static void Prefix(Attack __instance)
			{
				NormalizeAttackTrailSoundEffects(__instance);
			}
		}

		[HarmonyPatch(typeof(Character), "ApplyDamage")]
		public static class Character_ApplyDamage_FallDamageGrunt_Patch
		{
			private static void Prefix(Character __instance, HitData hit, ref float __state)
			{
				__state = 0f;
				if (ShouldPlayFallDamageGrunt(__instance, hit))
				{
					__state = __instance.GetHealth();
				}
			}

			private static void Postfix(Character __instance, HitData hit, float __state)
			{
				if (!(__state <= 0f) && ShouldPlayFallDamageGrunt(__instance, hit))
				{
					float health = __instance.GetHealth();
					if (!(health <= 0f) && !(__state - health <= 0.1f))
					{
						TryBroadcastPlayerDamageGrunt((Player)(object)((__instance is Player) ? __instance : null));
					}
				}
			}

			private static bool ShouldPlayFallDamageGrunt(Character character, HitData hit)
			{
				//IL_0021: Unknown result type (might be due to invalid IL or missing references)
				//IL_0027: Invalid comparison between Unknown and I4
				Player val = (Player)(object)((character is Player) ? character : null);
				if ((Object)(object)val != (Object)null && (Object)(object)val == (Object)(object)Player.m_localPlayer && hit != null)
				{
					return (int)hit.m_hitType == 3;
				}
				return false;
			}
		}

		[HarmonyPatch(typeof(Character), "AddFireDamage")]
		public static class Character_AddFireDamage_FireDamageGrunt_Patch
		{
			private static void Postfix(Character __instance, float damage)
			{
				Player val = (Player)(object)((__instance is Player) ? __instance : null);
				if (!((Object)(object)val == (Object)null) && !((Object)(object)val != (Object)(object)Player.m_localPlayer) && !(damage <= 0f))
				{
					TryBroadcastPlayerDamageGrunt(val);
				}
			}
		}

		[HarmonyPatch(typeof(Player), "Awake")]
		public static class Player_Awake_PlayerSfxRpc_Patch
		{
			private static void Postfix(Player __instance)
			{
				RegisterPlayerSfxRpc(__instance);
				RegisterPickaxeBedrockAudioRpc(__instance);
			}
		}

		[HarmonyPatch(typeof(Player), "OnDeath")]
		public static class Player_OnDeath_DeathSplat_Patch
		{
			private static void Postfix(Player __instance)
			{
				if (!((Object)(object)__instance == (Object)null) && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer))
				{
					TryBroadcastPlayerDeathSplat(__instance);
				}
			}
		}

		[HarmonyPatch(typeof(Attack), "SpawnOnHitTerrain")]
		public static class Attack_SpawnOnHitTerrain_PickaxeBedrockTracking_Patch
		{
			private static void Prefix(Vector3 hitPoint, GameObject prefab, Character character, ItemData weapon)
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				RegisterLocalPickaxeTerrainHit(hitPoint, prefab, character, weapon);
			}
		}

		[HarmonyPatch(typeof(TerrainOp), "OnPlaced")]
		public static class TerrainOp_OnPlaced_PickaxeBedrockAudio_Patch
		{
			private static void Prefix(TerrainOp __instance)
			{
				TryHandlePickaxeBedrockHit(__instance);
			}
		}

		[HarmonyPatch(typeof(Attack), "DoMeleeAttack")]
		private static class Attack_DoMeleeAttack_PickaxeVegetationAudioContext
		{
			private static void Prefix(Attack __instance, out bool __state)
			{
				__state = BeginLocalPickaxeVegetationAudio(__instance);
			}

			private static Exception Finalizer(bool __state, Exception __exception)
			{
				EndLocalPickaxeVegetationAudio(__state);
				return __exception;
			}
		}

		[HarmonyPatch(typeof(Destructible), "Damage")]
		private static class Destructible_Damage_PickaxeVegetationAudio_Patch
		{
			private static void Prefix(Destructible __instance, HitData hit)
			{
				try
				{
					TryReplayPickaxeVegetationHitEffect((Component)(object)__instance, __instance?.m_hitEffect, hit);
				}
				catch (Exception arg)
				{
					ManualLogSource log = Log;
					if (log != null)
					{
						log.LogError((object)$"[ValheimBB] Error replaying pickaxe destructible vegetation hit effect: {arg}");
					}
				}
			}
		}

		[HarmonyPatch(typeof(WearNTear), "Damage")]
		private static class WearNTear_Damage_PickaxeVegetationAudio_Patch
		{
			private static void Prefix(WearNTear __instance, HitData hit)
			{
				try
				{
					TryReplayPickaxeVegetationHitEffect((Component)(object)__instance, __instance?.m_hitEffect, hit);
				}
				catch (Exception arg)
				{
					ManualLogSource log = Log;
					if (log != null)
					{
						log.LogError((object)$"[ValheimBB] Error replaying pickaxe wear-and-tear vegetation hit effect: {arg}");
					}
				}
			}
		}

		[HarmonyPatch(typeof(Chat), "InputText")]
		public static class Chat_InputText_Patch
		{
			private const float DefaultRemovePinRadius = 10f;

			private static bool Prefix(ref Chat __instance)
			{
				string text = ((TMP_InputField)((Terminal)__instance).m_input).text;
				if (string.IsNullOrWhiteSpace(text))
				{
					return true;
				}
				if (!text.StartsWith("/", StringComparison.Ordinal))
				{
					return true;
				}
				if (text.StartsWith("/addpin", StringComparison.OrdinalIgnoreCase))
				{
					HandleAddPin(__instance, text);
					return false;
				}
				if (text.StartsWith("/removepin", StringComparison.OrdinalIgnoreCase))
				{
					HandleRemoveNearestPin(__instance, text);
					return false;
				}
				if (text.StartsWith("/cleardeaths", StringComparison.OrdinalIgnoreCase))
				{
					HandleClearDeathPins(__instance);
					return false;
				}
				return true;
			}

			private static void HandleAddPin(Chat chat, string text)
			{
				//IL_005b: Unknown result type (might be due to invalid IL or missing references)
				//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
				//IL_00c6: 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_00cd: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
				//IL_00df: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
				//IL_00fd: 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_00b3: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)Player.m_localPlayer == (Object)null || (Object)(object)Minimap.instance == (Object)null)
				{
					return;
				}
				string[] array = text.Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
				if (array.Length >= 2 && array[1].Equals("help", StringComparison.OrdinalIgnoreCase))
				{
					ShowHelp();
					((TMP_InputField)((Terminal)chat).m_input).text = string.Empty;
					return;
				}
				PinType val = (PinType)3;
				int num = 3;
				if (array.Length >= 2)
				{
					string text2 = array[1];
					if (text2.StartsWith("icon", StringComparison.OrdinalIgnoreCase))
					{
						text2 = text2.Substring(4);
					}
					if (int.TryParse(text2, out var result) && result >= 0 && result <= 4 && Enum.TryParse<PinType>("Icon" + result, out PinType result2))
					{
						val = result2;
						num = result;
					}
				}
				Vector3 position = ((Component)Player.m_localPlayer).transform.position;
				Minimap.instance.AddPin(position, val, "", true, false, 0L, default(PlatformUserID));
				ManualLogSource log = Log;
				if (log != null)
				{
					log.LogInfo((object)$"[ValheimBB] /addpin -> {val} at {position}");
				}
				if ((Object)(object)Chat.instance != (Object)null)
				{
					((Terminal)Chat.instance).AddString("ValheimBB", $"Pin {num} added.\n" + "Options: Pin 0 = Campfire, Pin 1 = House, Pin 2 = Anchor, Pin 3 = Dot, Pin 4 = Portal", (Type)1, false);
				}
				((TMP_InputField)((Terminal)chat).m_input).text = string.Empty;
			}

			private static void HandleRemoveNearestPin(Chat chat, string text)
			{
				//IL_005a: Unknown result type (might be due to invalid IL or missing references)
				//IL_005f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0065: Unknown result type (might be due to invalid IL or missing references)
				if (!((Object)(object)Player.m_localPlayer == (Object)null) && !((Object)(object)Minimap.instance == (Object)null))
				{
					float num = 10f;
					string[] array = text.Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
					if (array.Length >= 2 && float.TryParse(array[1], out var result) && result > 0f)
					{
						num = result;
					}
					Vector3 position = ((Component)Player.m_localPlayer).transform.position;
					bool flag = Minimap.instance.RemovePin(position, num);
					if ((Object)(object)Chat.instance != (Object)null)
					{
						string text2 = (flag ? $"Removed nearest pin within {num:0.#}m." : $"No pin found within {num:0.#}m.");
						((Terminal)Chat.instance).AddString("ValheimBB", text2, (Type)1, false);
					}
					((TMP_InputField)((Terminal)chat).m_input).text = string.Empty;
				}
			}

			private static void HandleClearDeathPins(Chat chat)
			{
				//IL_0096: Unknown result type (might be due to invalid IL or missing references)
				//IL_009c: Invalid comparison between Unknown and I4
				if ((Object)(object)Minimap.instance == (Object)null)
				{
					return;
				}
				int num = 0;
				try
				{
					Minimap instance = Minimap.instance;
					FieldInfo field = typeof(Minimap).GetField("m_pins", BindingFlags.Instance | BindingFlags.NonPublic);
					if (field == null)
					{
						ManualLogSource log = Log;
						if (log != null)
						{
							log.LogWarning((object)"[ValheimBB] Could not find Minimap.m_pins via reflection.");
						}
						return;
					}
					if (!(field.GetValue(instance) is List<PinData> list))
					{
						ManualLogSource log2 = Log;
						if (log2 != null)
						{
							log2.LogWarning((object)"[ValheimBB] Minimap.m_pins is null or of unexpected type.");
						}
						return;
					}
					List<PinData> list2 = new List<PinData>();
					foreach (PinData item in list)
					{
						if ((int)item.m_type == 4)
						{
							list2.Add(item);
						}
					}
					num = list2.Count;
					foreach (PinData item2 in list2)
					{
						instance.RemovePin(item2);
					}
					if ((Object)(object)Chat.instance != (Object)null)
					{
						string text = ((num > 0) ? $"Removed {num} death marker(s)." : "No death markers found.");
						((Terminal)Chat.instance).AddString("ValheimBB", text, (Type)1, false);
					}
				}
				catch (Exception arg)
				{
					ManualLogSource log3 = Log;
					if (log3 != null)
					{
						log3.LogError((object)$"[ValheimBB] Error clearing death pins: {arg}");
					}
				}
				finally
				{
					((TMP_InputField)((Terminal)chat).m_input).text = string.Empty;
				}
			}

			public static void ShowHelp()
			{
				if (!((Object)(object)Chat.instance == (Object)null))
				{
					string text = "ValheimBB command help:\n/addpin [index] - Add a map pin at your current position.\n    index: 0 = Campfire, 1 = House, 2 = Anchor, 3 = Dot, 4 = Portal (default: 3)\n/removepin [radius] - Remove the nearest pin within the given radius (meters).\n    radius: optional, default is 10.\n/cleardeaths - Remove all death markers from the map.";
					((Terminal)Chat.instance).AddString("ValheimBB", text, (Type)1, false);
				}
			}
		}

		private sealed class ValheimBBCompendiumEntry
		{
			private readonly Func<string> _textFactory;

			private string _text;

			public string Label { get; }

			public string Name { get; }

			public string Topic { get; }

			public string Text
			{
				get
				{
					if (_text == null)
					{
						_text = _textFactory() ?? string.Empty;
					}
					return _text;
				}
			}

			public ValheimBBCompendiumEntry(string name, string topic, string label, string text)
				: this(name, topic, label, () => text)
			{
			}

			public ValheimBBCompendiumEntry(string name, string topic, string label, Func<string> textFactory)
			{
				if (textFactory == null)
				{
					throw new ArgumentNullException("textFactory");
				}
				Name = name;
				Topic = topic;
				Label = label;
				_textFactory = textFactory;
			}
		}

		[HarmonyPatch]
		private static class Tutorial_Awake_ValheimBBCompendium_Patch
		{
			private static MethodBase TargetMethod()
			{
				Type type = AccessTools.TypeByName("Tutorial");
				if (!(type == null))
				{
					return AccessTools.Method(type, "Awake", (Type[])null, (Type[])null);
				}
				return null;
			}

			private static void Postfix(object __instance)
			{
				EnsureValheimBBCompendiumEntries(__instance);
			}
		}

		[HarmonyPatch(typeof(Player), "GetKnownTexts")]
		private static class Player_GetKnownTexts_ValheimBBCompendium_Patch
		{
			private static void Postfix(ref List<KeyValuePair<string, string>> __result)
			{
				EnsureValheimBBKnownTexts(__result);
			}
		}

		private sealed class AmmoRecipeBatchTweakDefinition
		{
			public string RecipeName;

			public string OutputPrefabName;

			public HashSet<string> StaticRequirementPrefabNames;

			public Dictionary<string, int> VanillaRequirementAmounts;

			public bool TryGetTargetRequirementAmount(string requirementPrefabName, out int amount)
			{
				amount = 0;
				if (string.IsNullOrWhiteSpace(requirementPrefabName) || VanillaRequirementAmounts == null || !VanillaRequirementAmounts.TryGetValue(requirementPrefabName, out var value))
				{
					return false;
				}
				amount = ((StaticRequirementPrefabNames != null && StaticRequirementPrefabNames.Contains(requirementPrefabName)) ? value : (value * 5));
				return true;
			}
		}

		private struct AmmoRequirementBaseline
		{
			public string PrefabName;

			public int Amount;

			public AmmoRequirementBaseline(string prefabName, int amount)
			{
				PrefabName = prefabName;
				Amount = amount;
			}
		}

		[HarmonyPatch(typeof(ObjectDB), "Awake")]
		private static class ObjectDB_Awake_AmmoRecipeBatchTweaks_Patch
		{
			private static void Postfix(ObjectDB __instance)
			{
				ApplyAmmoRecipeBatchTweaks(__instance);
			}
		}

		[HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")]
		private static class ObjectDB_CopyOtherDB_AmmoRecipeBatchTweaks_Patch
		{
			private static void Postfix(ObjectDB __instance)
			{
				ApplyAmmoRecipeBatchTweaks(__instance);
			}
		}

		[HarmonyPatch(typeof(ObjectDB), "Awake")]
		private static class ObjectDB_Awake_BearHeaddressRecipe_Patch
		{
			private static void Postfix(ObjectDB __instance)
			{
				UpdateBearHeaddressRecipe(__instance);
			}
		}

		[HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")]
		private static class ObjectDB_CopyOtherDB_BearHeaddressRecipe_Patch
		{
			private static void Postfix(ObjectDB __instance)
			{
				UpdateBearHeaddressRecipe(__instance);
			}
		}

		[HarmonyPatch(typeof(Character), "ApplyPushback", new Type[]
		{
			typeof(Vector3),
			typeof(float)
		})]
		private static class Character_ApplyPushback_CreatureMassScaling_Patch
		{
			private static void Prefix(Character __instance, ref float pushForce)
			{
				if (IsFeatureEnabled(EnableCreaturePushbackScaling) && !((Object)(object)__instance == (Object)null) && !__instance.IsPlayer() && pushForce != 0f)
				{
					Rigidbody component = ((Component)__instance).GetComponent<Rigidbody>();
					if (!((Object)(object)component == (Object)null) && !(component.mass <= 10f))
					{
						float num = component.mass / 10f;
						float num2 = 1f + Mathf.Log(num, 2f) * 0.25f;
						pushForce *= Mathf.Min(num2, 2f);
					}
				}
			}
		}

		private struct PreviousLoadedWeaponState
		{
			public ItemData Weapon;
		}

		[HarmonyPatch]
		private static class Player_UpdateWeaponLoading_PersistentCrossbowLoad_Patch
		{
			private static MethodBase TargetMethod()
			{
				return AccessTools.Method(typeof(Player), "UpdateWeaponLoading", (Type[])null, (Type[])null);
			}

			private static bool Prefix(Player __instance, ItemData weapon, float dt)
			{
				if (!IsFeatureEnabled(EnableCrossbowLoadedPersistence))
				{
					return true;
				}
				ClearInvalidLoadedWeapon(__instance);
				ItemData loadedWeapon = GetLoadedWeapon(__instance);
				if (!RequiresReload(weapon))
				{
					return false;
				}
				if (HasPersistentLoadedFlag(weapon))
				{
					if (loadedWeapon != weapon)
					{
						SetLoadedWeapon(__instance, weapon);
					}
					return false;
				}
				if (!IsReloadActionQueued(__instance) && ((Character)__instance).TryUseEitr(weapon.m_shared.m_attack.m_reloadEitrDrain))
				{
					QueueReloadAction(__instance);
				}
				return false;
			}
		}

		[HarmonyPatch]
		private static class Player_SetWeaponLoaded_PersistentCrossbowLoad_Patch
		{
			private static MethodBase TargetMethod()
			{
				return AccessTools.Method(typeof(Player), "SetWeaponLoaded", (Type[])null, (Type[])null);
			}

			private static void Prefix(Player __instance, out PreviousLoadedWeaponState __state)
			{
				__state = new PreviousLoadedWeaponState
				{
					Weapon = (IsFeatureEnabled(EnableCrossbowLoadedPersistence) ? GetLoadedWeapon(__instance) : null)
				};
			}

			private static void Postfix(Player __instance, ItemData weapon, PreviousLoadedWeaponState __state)
			{
				if (IsFeatureEnabled(EnableCrossbowLoadedPersistence))
				{
					if (weapon == null && __state.Weapon != null)
					{
						SetPersistentLoadedFlag(__state.Weapon, isLoaded: false);
					}
					if (RequiresReload(weapon))
					{
						SetPersistentLoadedFlag(weapon, isLoaded: true);
					}
				}
			}
		}

		[HarmonyPatch]
		private static class Player_IsWeaponLoaded_PersistentCrossbowLoad_Patch
		{
			private static MethodBase TargetMethod()
			{
				return AccessTools.Method(typeof(Player), "IsWeaponLoaded", (Type[])null, (Type[])null);
			}

			private static void Postfix(Player __instance, ref bool __result)
			{
				if (!IsFeatureEnabled(EnableCrossbowLoadedPersistence) || (Object)(object)__instance == (Object)null || (Object)(object)__instance != (Object)(object)Player.m_localPlayer)
				{
					return;
				}
				ItemData currentWeapon = ((Humanoid)__instance).GetCurrentWeapon();
				if (!RequiresReload(currentWeapon))
				{
					__result = false;
				}
				else if (HasPersistentLoadedFlag(currentWeapon))
				{
					if (GetLoadedWeapon(__instance) != currentWeapon)
					{
						SetLoadedWeapon(__instance, currentWeapon);
					}
					__result = true;
				}
				else
				{
					if (GetLoadedWeapon(__instance) == currentWeapon)
					{
						ClearLoadedWeapon(__instance);
					}
					__result = false;
				}
			}
		}

		[HarmonyPatch(typeof(Humanoid), "UnequipItem")]
		private static class Humanoid_UnequipItem_PersistentCrossbowLoad_Patch
		{
			private static void Prefix(Humanoid __instance, ItemData item)
			{
				s_loadedWeaponPreservePlayer = null;
				s_loadedWeaponPreserveItem = null;
				if (!IsFeatureEnabled(EnableCrossbowLoadedPersistence))
				{
					return;
				}
				Player val = (Player)(object)((__instance is Player) ? __instance : null);
				if (!((Object)(object)val == (Object)null) && item != null)
				{
					ItemData loadedWeapon = GetLoadedWeapon(val);
					if (CanPersistLoadedWeapon(val, loadedWeapon))
					{
						s_loadedWeaponPreservePlayer = val;
						s_loadedWeaponPreserveItem = loadedWeapon;
					}
				}
			}

			private static void Finalizer()
			{
				s_loadedWeaponPreservePlayer = null;
				s_loadedWeaponPreserveItem = null;
			}
		}

		[HarmonyPatch(typeof(Player), "ResetLoadedWeapon")]
		private static class Player_ResetLoadedWeapon_PersistentCrossbowLoad_Patch
		{
			private static bool Prefix(Player __instance)
			{
				if (!IsFeatureEnabled(EnableCrossbowLoadedPersistence))
				{
					return true;
				}
				if ((Object)(object)s_loadedWeaponPreservePlayer != (Object)(object)__instance || s_loadedWeaponPreserveItem == null)
				{
					return true;
				}
				if (!CanPersistLoadedWeapon(__instance, s_loadedWeaponPreserveItem))
				{
					return true;
				}
				CancelReloadAction(__instance);
				return false;
			}
		}

		[HarmonyPatch(typeof(Attack), "Start", new Type[]
		{
			typeof(Humanoid),
			typeof(Rigidbody),
			typeof(ZSyncAnimation),
			typeof(CharacterAnimEvent),
			typeof(VisEquipment),
			typeof(ItemData),
			typeof(Attack),
			typeof(float),
			typeof(float)
		})]
		private static class Attack_Start_PersistentCrossbowLoad_Patch
		{
			private static bool Prefix(Humanoid character, ItemData weapon, ref bool __result)
			{
				if (!IsFeatureEnabled(EnableCrossbowLoadedPersistence))
				{
					return true;
				}
				Player val = (Player)(object)((character is Player) ? character : null);
				if ((Object)(object)val == (Object)null || (Object)(object)val != (Object)(object)Player.m_localPlayer || !RequiresReload(weapon))
				{
					return true;
				}
				if (HasPersistentLoadedFlag(weapon))
				{
					if (GetLoadedWeapon(val) != weapon)
					{
						SetLoadedWeapon(val, weapon);
					}
					return true;
				}
				__result = false;
				return false;
			}
		}

		[HarmonyPatch(typeof(Fireplace), "Interact")]
		public static class Fireplace_Interact_AltFuel_Patch
		{
			private static void Prefix(Fireplace __instance, Humanoid user, bool hold, bool alt, ref ItemDrop __state)
			{
				__state = null;
				try
				{
					if (hold || alt || (Object)(object)user == (Object)null)
					{
						return;
					}
					Inventory inventory = user.GetInventory();
					if (inventory == null || inventory.GetItem("Wood", -1, true) != null)
					{
						return;
					}
					ItemData val = inventory.GetItem("RoundLog", -1, true) ?? inventory.GetItem("ElderBark", -1, true);
					if (val != null && !((Object)(object)val.m_dropPrefab == (Object)null))
					{
						ItemDrop component = val.m_dropPrefab.GetComponent<ItemDrop>();
						if (!((Object)(object)component == (Object)null))
						{
							__state = __instance.m_fuelItem;
							__instance.m_fuelItem = component;
						}
					}
				}
				catch (Exception arg)
				{
					ManualLogSource log = Log;
					if (log != null)
					{
						log.LogError((object)$"[ValheimBB] Error in Fireplace.Interact alt-fuel Prefix: {arg}");
					}
				}
			}

			private static void Postfix(Fireplace __instance, ItemDrop __state)
			{
				try
				{
					if ((Object)(object)__state != (Object)null)
					{
						__instance.m_fuelItem = __state;
					}
				}
				catch (Exception arg)
				{
					ManualLogSource log = Log;
					if (log != null)
					{
						log.LogError((object)$"[ValheimBB] Error restoring fireplace fuel item: {arg}");
					}
				}
			}
		}

		[HarmonyPatch(typeof(Player), "ActivateGuardianPower")]
		public static class Player_ActivateGuardianPower_ModerDuration_Patch
		{
			private static void Prefix(StatusEffect ___m_guardianSE)
			{
				try
				{
					if (!((Object)(object)___m_guardianSE == (Object)null) && !(((Object)___m_guardianSE).name != "GP_Moder"))
					{
						float ttl = ___m_guardianSE.m_ttl;
						___m_guardianSE.m_ttl = 600f;
						ManualLogSource log = Log;
						if (log != null)
						{
							log.LogInfo((object)$"[ValheimBB] Moder buff duration changed from {ttl} to {___m_guardianSE.m_ttl} seconds.");
						}
					}
				}
				catch (Exception arg)
				{
					ManualLogSource log2 = Log;
					if (log2 != null)
					{
						log2.LogError((object)$"[ValheimBB] Error while extending Moder power duration: {arg}");
					}
				}
			}
		}

		[HarmonyPatch(typeof(EnvMan), "GetWindDir")]
		public static class EnvMan_GetWindDir_ModerSideWind_Patch
		{
			private static void Postfix(ref Vector3 __result)
			{
				//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
				//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
				try
				{
					if ((Object)(object)Player.m_localPlayer == (Object)null)
					{
						return;
					}
					SEMan sEMan = ((Character)Player.m_localPlayer).GetSEMan();
					if (sEMan == null)
					{
						return;
					}
					bool flag = false;
					List<StatusEffect> statusEffects = sEMan.GetStatusEffects();
					if (statusEffects == null)
					{
						return;
					}
					foreach (StatusEffect item in statusEffects)
					{
						if ((Object)(object)item != (Object)null && ((Object)item).name == "GP_Moder")
						{
							flag = true;
							break;
						}
					}
					if (!flag)
					{
						return;
					}
					Ship localShip = Ship.GetLocalShip();
					if ((Object)(object)localShip == (Object)null)
					{
						return;
					}
					Vector3 forward = ((Component)localShip).transform.forward;
					forward.y = 0f;
					if (!(((Vector3)(ref forward)).sqrMagnitude < 0.0001f))
					{
						((Vector3)(ref forward)).Normalize();
						Vector3 val = Vector3.Cross(Vector3.up, forward);
						if (!(((Vector3)(ref val)).sqrMagnitude < 0.0001f))
						{
							((Vector3)(ref val)).Normalize();
							__result = val;
						}
					}
				}
				catch (Exception arg)
				{
					ManualLogSource log = Log;
					if (log != null)
					{
						log.LogError((object)$"[ValheimBB] Error in Moder side-wind GetWindDir patch: {arg}");
					}
				}
			}
		}

		[HarmonyPatch(typeof(ObjectDB), "Awake")]
		private static class ObjectDB_Awake_MuckshakeFoodTweaks_Patch
		{
			private static void Postfix(ObjectDB __instance)
			{
				ApplyMuckshakeFoodTweaks(__instance);
			}
		}

		[HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")]
		private static class ObjectDB_CopyOtherDB_MuckshakeFoodTweaks_Patch
		{
			private static void Postfix(ObjectDB __instance)
			{
				ApplyMuckshakeFoodTweaks(__instance);
			}
		}

		[HarmonyPatch(typeof(Player), "OnSpawned")]
		private static class Player_OnSpawned_MuckshakeFoodRepair_Patch
		{
			private static void Postfix(Player __instance)
			{
				if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer)
				{
					return;
				}
				try
				{
					RepairMuckshakeInventory(((Humanoid)__instance).GetInventory());
				}
				catch (Exception arg)
				{
					ManualLogSource log = Log;
					if (log != null)
					{
						log.LogError((object)$"[ValheimBB] Error while repairing Muckshake items on player spawn: {arg}");
					}
				}
			}
		}

		[HarmonyPatch(typeof(Inventory), "AddItem", new Type[] { typeof(ItemData) })]
		private static class Inventory_AddItem_MuckshakeFoodRepair_Patch
		{
			private static void Prefix(ItemData item)
			{
				NormalizeMuckshakeItem(item);
			}
		}

		[HarmonyPatch(typeof(Inventory), "AddItem", new Type[]
		{
			typeof(ItemData),
			typeof(Vector2i)
		})]
		private static class Inventory_AddItemAtPos_MuckshakeFoodRepair_Patch
		{
			private static void Prefix(ItemData item)
			{
				NormalizeMuckshakeItem(item);
			}
		}

		[HarmonyPatch]
		private static class Inventory_AddItemToGrid_MuckshakeFoodRepair_Patch
		{
			private static MethodBase TargetMethod()
			{
				return AccessTools.Method(typeof(Inventory), "AddItem", new Type[4]
				{
					typeof(ItemData),
					typeof(int),
					typeof(int),
					typeof(int)
				}, (Type[])null);
			}

			private static void Prefix(ItemData item)
			{
				NormalizeMuckshakeItem(item);
			}
		}

		private sealed class CraftRecipeSeenClickHandler : MonoBehaviour
		{
			public InventoryGui InventoryGui;

			public GameObject Element;

			public void HandleClick()
			{
				if (IsFeatureEnabled(EnableBuildAndRecipeUnlockMarkers))
				{
					MarkCraftRecipeSeenByElement(InventoryGui, Element);
				}
			}
		}

		[HarmonyPatch(typeof(Hud), "UpdatePieceList")]
		private static class Hud_UpdatePieceList_NewBuildPieceMarkers_Patch
		{
			private static void Postfix(Hud __instance, Player player)
			{
				RefreshNewBuildPieceMarkers(__instance, player);
			}
		}

		[HarmonyPatch(typeof(Hud), "OnHoverPiece")]
		private static class Hud_OnHoverPiece_NewBuildPieceMarkers_Patch
		{
			private static void Postfix(Hud __instance, UIInputHandler ih)
			{
				if (!IsFeatureEnabled(EnableBuildAndRecipeUnlockMarkers))
				{
					return;
				}
				Player localPlayer = Player.m_localPlayer;
				if (!((Object)(object)localPlayer == (Object)null) && !((Object)(object)ih == (Object)null))
				{
					Piece buildPieceForIcon = GetBuildPieceForIcon(__instance, localPlayer, ((Component)ih).gameObject);
					if (!((Object)(object)buildPieceForIcon == (Object)null) && MarkBuildPieceSeen(localPlayer, buildPieceForIcon))
					{
						RefreshNewBuildPieceMarkers(__instance, localPlayer);
					}
				}
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "UpdateRecipeList")]
		private static class InventoryGui_UpdateRecipeList_NewRecipeMarkers_Patch
		{
			private static void Postfix(InventoryGui __instance)
			{
				Player localPlayer = Player.m_localPlayer;
				if (!((Object)(object)localPlayer == (Object)null) && __instance.InCraftTab())
				{
					if (IsFeatureEnabled(EnableBuildAndRecipeUnlockMarkers))
					{
						WireCraftRecipeHoverHandlers(__instance);
					}
					RefreshCraftRecipeMarkers(__instance, localPlayer);
				}
			}
		}

		[HarmonyPatch(typeof(Minimap), "Update")]
		private static class Minimap_Update_NoMapBiomeLabel_Patch
		{
			private static void Postfix(Minimap __instance)
			{
				UpdateNoMapBiomeLabel(__instance);
			}
		}

		[HarmonyPatch(typeof(Minimap), "OnDestroy")]
		private static class Minimap_OnDestroy_NoMapBiomeLabel_Patch
		{
			private static void Prefix()
			{
				s_noMapBiomeLabel = null;
			}
		}

		[HarmonyPatch(typeof(Attack), "DoMeleeAttack")]
		private static class Attack_DoMeleeAttack_BedrockEffectContext
		{
			private static void Prefix(Attack __instance, ref bool __state)
			{
				__state = false;
				if (IsPickaxeAttack(__instance))
				{
					if (s_activePickaxeAttackDepth == 0)
					{
						s_activePickaxeAttack = __instance;
					}
					s_activePickaxeAttackDepth++;
					__state = true;
				}
			}

			private static Exception Finalizer(bool __state, Exception __exception)
			{
				if (__state && s_activePickaxeAttackDepth > 0)
				{
					s_activePickaxeAttackDepth--;
					if (s_activePickaxeAttackDepth == 0)
					{
						s_activePickaxeAttack = null;
					}
				}
				return __exception;
			}
		}

		[HarmonyPatch(typeof(TerrainModifier), "OnPlaced")]
		private static class TerrainModifier_OnPlaced_BedrockEffectContext
		{
			private static void Prefix(TerrainModifier __instance, ref bool __state)
			{
				//IL_0013: Unknown result type (might be due to invalid IL or missing references)
				//IL_0018: 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_002e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0033: Unknown result type (might be due to invalid IL or missing references)
				//IL_0041: Unknown result type (might be due to invalid IL or missing references)
				__state = false;
				if (!((Object)(object)__instance == (Object)null))
				{
					Vector3 checkPosition = ((Component)__instance).transform.position + Vector3.up * s_terrainModifierLevelOffsetRef.Invoke(__instance);
					__state = TryBeginSuppressedPlacementEffect(s_terrainModifierOnPlacedEffectRef.Invoke(__instance), checkPosition);
				}
			}

			private static Exception Finalizer(bool __state, Exception __exception)
			{
				EndSuppressedPlacementEffect(__state);
				return __exception;
			}
		}

		[HarmonyPatch(typeof(TerrainOp), "OnPlaced")]
		private static class TerrainOp_OnPlaced_BedrockEffectContext
		{
			private static void Prefix(TerrainOp __instance, ref bool __state)
			{
				//IL_0020: Unknown result type (might be due to invalid IL or missing references)
				//IL_0025: Unknown result type (might be due to invalid IL or missing references)
				//IL_0030: 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)
				//IL_003a: 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)
				__state = false;
				if (!((Object)(object)__instance == (Object)null))
				{
					Settings val = s_terrainOpSettingsRef.Invoke(__instance);
					Vector3 checkPosition = ((Component)__instance).transform.position + Vector3.up * val.m_levelOffset;
					__state = TryBeginSuppressedPlacementEffect(s_terrainOpOnPlacedEffectRef.Invoke(__instance), checkPosition);
				}
			}

			private static Exception Finalizer(bool __state, Exception __exception)
			{
				EndSuppressedPlacementEffect(__state);
				return __exception;
			}
		}

		[HarmonyPatch(typeof(EffectList), "Create", new Type[]
		{
			typeof(Vector3),
			typeof(Quaternion),
			typeof(Transform),
			typeof(float),
			typeof(int)
		})]
		private static class EffectList_Create_BedrockParticleSuppress
		{
			private static bool Prefix(EffectList __instance, Vector3 __0, ref GameObject[] __result)
			{
				//IL_0009: Unknown result type (might be due to invalid IL or missing references)
				if (!IsSuppressedPlacementEffect(__instance) && !ShouldSuppressPickaxeTerrainEffect(__instance, __0))
				{
					return true;
				}
				__result = Array.Empty<GameObject>();
				return false;
			}
		}

		private struct ActivePickaxeSwingState
		{
			public bool Active;

			public Player Player;

			public float PaidStaminaCost;

			public bool HitDirt;

			public bool HitNonDirt;
		}

		[HarmonyPatch(typeof(Attack), "GetAttackStamina")]
		public static class Attack_GetAttackStamina_PickaxeCost_Patch
		{
			[HarmonyPostfix]
			private static void Postfix(Attack __instance, ref float __result)
			{
				try
				{
					if (IsFeatureEnabled(EnablePickaxeStaminaTweaks) && TryGetLocalPickaxeSwingPlayer(__instance, out var _) && TryGetOverridePickaxeStaminaCost(__instance, out var staminaCost))
					{
						__result = staminaCost;
					}
				}
				catch (Exception arg)
				{
					ManualLogSource log = Log;
					if (log != null)
					{
						log.LogError((object)$"[ValheimBB] Error overriding pickaxe stamina: {arg}");
					}
				}
			}
		}

		[HarmonyPatch(typeof(Attack), "DoMeleeAttack")]
		public static class Attack_DoMeleeAttack_PickaxeRefund_Patch
		{
			[HarmonyPrefix]
			private static void Prefix(Attack __instance, out bool __state)
			{
				__state = false;
				try
				{
					if (IsFeatureEnabled(EnablePickaxeDirtOnlyRefund) && TryGetLocalPickaxeSwingPlayer(__instance, out var player))
					{
						float paidStaminaCost = Mathf.Max(0f, GetCurrentAttackStaminaCost(__instance));
						BeginLocalPickaxeSwing(player, paidStaminaCost);
						__state = true;
					}
				}
				catch (Exception arg)
				{
					s_activePickaxeSwing = default(ActivePickaxeSwingState);
					ManualLogSource log = Log;
					if (log != null)
					{
						log.LogError((object)$"[ValheimBB] Error starting pickaxe refund tracking: {arg}");
					}
				}
			}

			[HarmonyPostfix]
			private static void Postfix(bool __state)
			{
				if (!__state)
				{
					return;
				}
				try
				{
					FinishLocalPickaxeSwing();
				}
				catch (Exception arg)
				{
					s_activePickaxeSwing = default(ActivePickaxeSwingState);
					ManualLogSource log = Log;
					if (log != null)
					{
						log.LogError((object)$"[ValheimBB] Error finishing pickaxe refund tracking: {arg}");
					}
				}
			}

			[HarmonyFinalizer]
			private static Exception Finalizer(bool __state, Exception __exception)
			{
				if (__state)
				{
					s_activePickaxeSwing = default(ActivePickaxeSwingState);
				}
				return __exception;
			}
		}

		[HarmonyPatch(typeof(Attack), "SpawnOnHit")]
		public static class Attack_SpawnOnHit_PickaxeRefund_Patch
		{
			[HarmonyPrefix]
			private static void Prefix(GameObject target)
			{
				try
				{
					if (IsFeatureEnabled(EnablePickaxeDirtOnlyRefund) && (Object)(object)target != (Object)null)
					{
						RegisterLocalPickaxeNonDirtHit();
					}
				}
				catch (Exception arg)
				{
					ManualLogSource log = Log;
					if (log != null)
					{
						log.LogError((object)$"[ValheimBB] Error registering pickaxe non-dirt hit: {arg}");
					}
				}
			}
		}

		[HarmonyPatch(typeof(Attack), "SpawnOnHitTerrain")]
		public static class Attack_SpawnOnHitTerrain_PickaxeRefund_Patch
		{
			[HarmonyPrefix]
			private static void Prefix(Vector3 hitPoint)
			{
				//IL_000f: Unknown result type (might be due to invalid IL or missing references)
				try
				{
					if (IsFeatureEnabled(EnablePickaxeDirtOnlyRefund))
					{
						if (Heightmap.AtMaxLevelDepth(hitPoint))
						{
							RegisterLocalPickaxeNonDirtHit();
						}
						else
						{
							RegisterLocalPickaxeDirtHit();
						}
					}
				}
				catch (Exception arg)
				{
					ManualLogSource log = Log;
					if (log != null)
					{
						log.LogError((object)$"[ValheimBB] Error registering pickaxe terrain hit: {arg}");
					}
				}
			}
		}

		private enum ResourceTrackerEventKind
		{
			Collected,
			Used,
			InBuilds
		}

		private enum ResourceTrackerSortColumn
		{
			Item,
			Collected,
			Used,
			InBuilds,
			Net,
			Inventory
		}

		private sealed class ResourceTrackerTotals
		{
			public long Collected;

			public long Used;

			public long InBuilds;
		}

		private sealed class ResourceTrackerRow
		{
			public string PrefabName;

			public string DisplayName;

			public long Collected;

			public long Used;

			public long InBuilds;

			public long Net;

			public int Inventory;
		}

		private sealed class ResourceDropContext
		{
			public DropTable DropTable;

			public long PlayerId;
		}

		private struct ResourceTrackerInventoryRemoveState
		{
			public bool Active;

			public string PrefabName;

			public int BeforeStack;

			public int BeforeCount;
		}

		[HarmonyPatch(typeof(InventoryGui), "Show")]
		private static class InventoryGui_Show_ResourceTracker_Patch
		{
			private static void Postfix(InventoryGui __instance)
			{
				EnsureResourceTrackerButton(__instance);
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "Hide")]
		private static class InventoryGui_Hide_ResourceTracker_Patch
		{
			private static void Postfix()
			{
				CloseResourceTrackerPanel();
			}
		}

		[HarmonyPatch(typeof(DropTable), "GetDropList", new Type[] { })]
		private static class DropTable_GetDropList_ResourceTracker_Patch
		{
			private static void Postfix(DropTable __instance, List<GameObject> __result)
			{
				ResourceDropContext resourceDropContext = FindResourceDropContext(__instance);
				if (resourceDropContext != null)
				{
					RecordDropListForContext(resourceDropContext, __result);
				}
			}
		}

		[HarmonyPatch(typeof(TreeBase), "RPC_Damage")]
		private static class TreeBase_RPCDamage_ResourceTracker_Patch
		{
			private static void Prefix(TreeBase __instance, HitData hit, out ResourceDropContext __state)
			{
				PushResourceDropContext(__instance?.m_dropWhenDestroyed, hit, out __state);
			}

			private static void Finalizer(ResourceDropContext __state)
			{
				PopResourceDropContext(__state);
			}
		}

		[HarmonyPatch(typeof(TreeLog), "Destroy")]
		private static class TreeLog_Destroy_ResourceTracker_Patch
		{
			private static void Prefix(TreeLog __instance, HitData hitData, out ResourceDropContext __state)
			{
				PushResourceDropContext(__instance?.m_dropWhenDestroyed, hitData, out __state);
			}

			private static void Finalizer(ResourceDropContext __state)
			{
				PopResourceDropContext(__state);
			}
		}

		[HarmonyPatch(typeof(MineRock), "RPC_Hit")]
		private static class MineRock_RPCHit_ResourceTracker_Patch
		{
			private static void Prefix(MineRock __instance, HitData hit, out ResourceDropContext __state)
			{
				PushResourceDropContext(__instance?.m_dropItems, hit, out __state);
			}

			private static void Finalizer(ResourceDropContext __state)
			{
				PopResourceDropContext(__state);
			}
		}

		[HarmonyPatch(typeof(MineRock5), "DamageArea")]
		private static class MineRock5_DamageArea_ResourceTracker_Patch
		{
			private static void Prefix(MineRock5 __instance, HitData hit, out ResourceDropContext __state)
			{
				PushResourceDropContext(__instance?.m_dropItems, hit, out __state);
			}

			private static void Finalizer(ResourceDropContext __state)
			{
				PopResourceDropContext(__state);
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "DoCrafting")]
		private static class InventoryGui_DoCrafting_ResourceTracker_Patch
		{
			private static void Prefix(Player player, out bool __state)
			{
				PushResourceTrackerUsageContext((Humanoid)(object)player, out __state);
			}

			private static void Finalizer(bool __state)
			{
				PopResourceTrackerUsageContext(__state);
			}
		}

		[HarmonyPatch(typeof(Fireplace), "Interact")]
		private static class Fireplace_Interact_ResourceTracker_Patch
		{
			private static void Prefix(Humanoid user, out bool __state)
			{
				PushResourceTrackerUsageContext(user, out __state);
			}

			private static void Finalizer(bool __state)
			{
				PopResourceTrackerUsageContext(__state);
			}
		}

		[HarmonyPatch(typeof(Fireplace), "UseItem")]
		private static class Fireplace_UseItem_ResourceTracker_Patch
		{
			private static void Prefix(Humanoid user, out bool __state)
			{
				PushResourceTrackerUsageContext(user, out __state);
			}

			private static void Finalizer(bool __state)
			{
				PopResourceTrackerUsageContext(__state);
			}
		}

		[HarmonyPatch(typeof(Smelter), "OnAddOre")]
		private static class Smelter_OnAddOre_ResourceTracker_Patch
		{
			private static void Prefix(Humanoid user, out bool __state)
			{
				PushResourceTrackerUsageContext(user, out __state);
			}

			private static void Finalizer(bool __state)
			{
				PopResourceTrackerUsageContext(__state);
			}
		}

		[HarmonyPatch(typeof(Smelter), "OnAddFuel")]
		private static class Smelter_OnAddFuel_ResourceTracker_Patch
		{
			private static void Prefix(Humanoid user, out bool __state)
			{
				PushResourceTrackerUsageContext(user, out __state);
			}

			private static void Finalizer(bool __state)
			{
				PopResourceTrackerUsageContext(__state);
			}
		}

		[HarmonyPatch(typeof(CookingStation), "OnUseItem")]
		private static class CookingStation_OnUseItem_ResourceTracker_Patch
		{
			private static void Prefix(Humanoid user, out bool __state)
			{
				PushResourceTrackerUsageContext(user, out __state);
			}

			private static void Finalizer(bool __state)
			{
				PopResourceTrackerUsageContext(__state);
			}
		}

		[HarmonyPatch(typeof(CookingStation), "OnAddFuelSwitch")]
		private static class CookingStation_OnAddFuelSwitch_ResourceTracker_Patch
		{
			private static void Prefix(Humanoid user, out bool __state)
			{
				PushResourceTrackerUsageContext(user, out __state);
			}

			private static void Finalizer(bool __state)
			{
				PopResourceTrackerUsageContext(__state);
			}
		}

		[HarmonyPatch(typeof(Player), "ConsumeItem", new Type[]
		{
			typeof(Inventory),
			typeof(ItemData),
			typeof(bool)
		})]
		private static class Player_ConsumeItem_ResourceTracker_Patch
		{
			private static void Postfix(Player __instance, ItemData item, bool __result)
			{
				if (__result && (Object)(object)__instance == (Object)(object)Player.m_localPlayer)
				{
					RecordUsedItem(item, 1);
				}
			}
		}

		[HarmonyPatch(typeof(Attack), "UseAmmo")]
		private static class Attack_UseAmmo_ResourceTracker_Patch
		{
			private static void Postfix(Attack __instance, ref ItemData ammoItem, bool __result)
			{
				//IL_0015: Unknown result type (might be due to invalid IL or missing references)
				//IL_001b: Invalid comparison between Unknown and I4
				if (__result && ammoItem != null)
				{
					SharedData shared = ammoItem.m_shared;
					if ((shared == null || (int)shared.m_itemType != 2) && (Object)(object)s_resourceTrackerAttackCharacterRef.Invoke(__instance) == (Object)(object)Player.m_localPlayer)
					{
						RecordUsedItem(ammoItem, 1);
					}
				}
			}
		}

		[HarmonyPatch(typeof(Inventory), "RemoveItem", new Type[]
		{
			typeof(string),
			typeof(int),
			typeof(int),
			typeof(bool)
		})]
		private static class Inventory_RemoveItemByName_ResourceTracker_Patch
		{
			private static void Prefix(Inventory __instance, string name, int itemQuality, out ResourceTrackerInventoryRemoveState __state)
			{
				__state = default(ResourceTrackerInventoryRemoveState);
				if (ShouldBeginInventoryRemoveTracking(__instance) && TryGetPrefabNameFromSharedName(name, out var prefabName))
				{
					__state.Active = true;
					__state.PrefabName = prefabName;
					__state.BeforeCount = __instance.CountItems(name, itemQuality, false);
					BeginInventoryRemoveTracking(ref __state);
				}
			}

			private static void Postfix(Inventory __instance, string name, int itemQuality, ResourceTrackerInventoryRemoveState __state)
			{
				if (__state.Active)
				{
					int num = __instance.CountItems(name, itemQuality, false);
					EndInventoryRemoveTracking(__state, Mathf.Max(0, __state.BeforeCount - num));
				}
			}
		}

		[HarmonyPatch(typeof(Inventory), "RemoveItem", new Type[]
		{
			typeof(ItemData),
			typeof(int)
		})]
		private static class Inventory_RemoveItemAmount_ResourceTracker_Patch
		{
			private static void Prefix(Inventory __instance, ItemData item, out ResourceTrackerInventoryRemoveState __state)
			{
				__state = default(ResourceTrackerInventoryRemoveState);
				if (ShouldBeginInventoryRemoveTracking(__instance) && ShouldTrackUsedItem(item))
				{
					__state.Active = true;
					__state.PrefabName = GetItemPrefabName(item);
					__state.BeforeStack = item?.m_stack ?? 0;
					BeginInventoryRemoveTracking(ref __state);
				}
			}

			private static void Postfix(Inventory __instance, ItemData item, bool __result, ResourceTrackerInventoryRemoveState __state)
			{
				if (__state.Active)
				{
					int num = ((item != null && __instance.ContainsItem(item)) ? item.m_stack : 0);
					EndInventoryRemoveTracking(__state, __result ? Mathf.Max(0, __state.BeforeStack - num) : 0);
				}
			}
		}

		[HarmonyPatch(typeof(Inventory), "RemoveItem", new Type[] { typeof(ItemData) })]
		private static class Inventory_RemoveWholeItem_ResourceTracker_Patch
		{
			private static void Prefix(Inventory __instance, ItemData item, out ResourceTrackerInventoryRemoveState __state)
			{
				__state = default(ResourceTrackerInventoryRemoveState);
				if (ShouldBeginInventoryRemoveTracking(__instance) && ShouldTrackUsedItem(item))
				{
					__state.Active = true;
					__state.PrefabName = GetItemPrefabName(item);
					__state.BeforeStack = item?.m_stack ?? 0;
					BeginInventoryRemoveTracking(ref __state);
				}
			}

			private static void Postfix(bool __result, ResourceTrackerInventoryRemoveState __state)
			{
				EndInventoryRemoveTracking(__state, __result ? Mathf.Max(0, __state.BeforeStack) : 0);
			}
		}

		[HarmonyPatch(typeof(Inventory), "RemoveOneItem")]
		private static class Inventory_RemoveOneItem_ResourceTracker_Patch
		{
			private static void Prefix(Inventory __instance, ItemData item, out ResourceTrackerInventoryRemoveState __state)
			{
				__state = default(ResourceTrackerInventoryRemoveState);
				if (ShouldBeginInventoryRemoveTracking(__instance) && ShouldTrackUsedItem(item))
				{
					__state.Active = true;
					__state.PrefabName = GetItemPrefabName(item);
					__state.BeforeStack = item?.m_stack ?? 0;
					BeginInventoryRemoveTracking(ref __state);
				}
			}

			private static void Postfix(bool __result, ResourceTrackerInventoryRemoveState __state)
			{
				EndInventoryRemoveTracking(__state, __result ? 1 : 0);
			}
		}

		[HarmonyPatch(typeof(Player), "TryPlacePiece")]
		private static class Player_TryPlacePiece_ResourceTracker_Patch
		{
			private static void Prefix(Player __instance)
			{
				if (IsFeatureEnabled(EnableResourceTracker) && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer))
				{
					ResourceTrackerBuildContext s_resourceTrackerBuildContext = default(ResourceTrackerBuildContext);
					s_resourceTrackerBuildContext.Active = true;
					s_resourceTrackerBuildContext.PlayerId = __instance.GetPlayerID();
					ValheimBBPlugin.s_resourceTrackerBuildContext = s_resourceTrackerBuildContext;
				}
			}

			private static void Finalizer()
			{
				s_resourceTrackerBuildContext = default(ResourceTrackerBuildContext);
			}
		}

		[HarmonyPatch(typeof(Piece), "SetCreator")]
		private static class Piece_SetCreator_ResourceTracker_Patch
		{
			private static void Postfix(Piece __instance, long uid)
			{
				//IL_0041: Unknown result type (might be due to invalid IL or missing references)
				if (s_resourceTrackerBuildContext.Active && uid != 0L && uid == s_resourceTrackerBuildContext.PlayerId && !((Object)(object)__instance == (Object)null) && __instance.GetCreator() == uid && (!((Object)(object)ZoneSystem.instance != (Object)null) || (!ZoneSystem.instance.GetGlobalKey(__instance.FreeBuildKey()) && !ZoneSystem.instance.GetGlobalKey((GlobalKeys)19))) && (!((Object)(object)Player.m_localPlayer != (Object)null) || !Player.m_localPlayer.NoCostCheat()))
				{
					MarkPieceResourceTracking(__instance);
					AddBuildResourceTotals(__instance, 1);
				}
			}
		}

		[HarmonyPatch(typeof(Piece), "DropResources")]
		private static class Piece_DropResources_ResourceTracker_Patch
		{
			private static void Prefix(Piece __instance)
			{
				if (IsTrackedLocalPiece(__instance))
				{
					AddBuildResourceTotals(__instance, -1);
					ClearPieceResourceTracking(__instance);
				}
			}
		}

		[HarmonyPatch(typeof(WearNTear), "Destroy", new Type[]
		{
			typeof(HitData),
			typeof(bool)
		})]
		private static class WearNTear_Destroy_ResourceTracker_Patch
		{
			private static void Prefix(WearNTear __instance, bool blockDrop)
			{
				if (blockDrop)
				{
					Piece piece = (((Object)(object)__instance != (Object)null) ? ((Component)__instance).GetComponent<Piece>() : null);
					if (IsTrackedLocalPiece(piece))
					{
						MoveBuildResourcesToUsed(piece);
						ClearPieceResourceTracking(piece);
					}
				}
			}
		}

		[HarmonyPatch(typeof(ObjectDB), "Awake")]
		public static class ObjectDB_Awake_RestingDelay_Patch
		{
			private static void Postfix(ObjectDB __instance)
			{
				ApplyRestingDelayToTemplates(__instance);
			}
		}

		[HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")]
		public static class ObjectDB_CopyOtherDB_RestingDelay_Patch
		{
			private static void Postfix(ObjectDB __instance)
			{
				ApplyRestingDelayToTemplates(__instance);
			}
		}

		[HarmonyPatch(typeof(SE_Cozy), "Setup")]
		public static class SE_Cozy_Setup_RestingDelay_Patch
		{
			private static void Postfix(SE_Cozy __instance)
			{
				ApplyRestingDelay(__instance);
			}
		}

		[HarmonyPatch(typeof(SE_Cozy), "UpdateStatusEffect")]
		public static class SE_Cozy_UpdateStatusEffect_RestingDelay_Patch
		{
			private static void Prefix(SE_Cozy __instance)
			{
				ApplyRestingDelay(__instance);
			}
		}

		[HarmonyPatch(typeof(Hud), "UpdateStatusEffects")]
		public static class Hud_UpdateStatusEffects_RestingCountdown_Patch
		{
			private static void Postfix(Hud __instance, List<StatusEffect> statusEffects)
			{
				if (!((Object)(object)__instance == (Object)null) && statusEffects != null && HudStatusEffectsField?.GetValue(__instance) is List<RectTransform> list)
				{
					int num = Mathf.Min(statusEffects.Count, list.Count);
					for (int i = 0; i < num; i++)
					{
						RectTransform statusEffectRoot = list[i];
						StatusEffect obj = statusEffects[i];
						UpdateRestingCountdown(statusEffectRoot, (SE_Cozy)(object)((obj is SE_Cozy) ? obj : null));
					}
				}
			}

			private static void UpdateRestingCountdown(RectTransform statusEffectRoot, SE_Cozy cozyEffect)
			{
				if ((Object)(object)statusEffectRoot == (Object)null)
				{
					return;
				}
				if (!IsRestingEffect(cozyEffect))
				{
					HideRestingCountdown(statusEffectRoot);
					return;
				}
				if (!IsFeatureEnabled(EnableRestingTweaks))
				{
					ApplyRestingDelay(cozyEffect);
					HideRestingCountdown(statusEffectRoot);
					return;
				}
				ApplyRestingDelay(cozyEffect);
				TextMeshProUGUI val = EnsureRestingCountdownLabel(statusEffectRoot);
				if (!((Object)(object)val == (Object)null))
				{
					PositionRestingCountdownLabel(statusEffectRoot, ((TMP_Text)val).rectTransform);
					int num = Mathf.CeilToInt(15f - ((StatusEffect)cozyEffect).GetDuration());
					if (num > 0)
					{
						((TMP_Text)val).text = num.ToString();
						((Component)val).gameObject.SetActive(true);
					}
					else
					{
						((Component)val).gameObject.SetActive(false);
					}
				}
			}

			private static void HideRestingCountdown(RectTransform statusEffectRoot)
			{
				Transform val = ((Transform)statusEffectRoot).Find("BB_RestingCountdown");
				if ((Object)(object)val != (Object)null)
				{
					((Component)val).gameObject.SetActive(false);
				}
			}

			private static TextMeshProUGUI EnsureRestingCountdownLabel(RectTransform statusEffectRoot)
			{
				//IL_007c: 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_0092: 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_00c7: Unknown result type (might be due to invalid IL or missing references)
				//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
				//IL_0121: Unknown result type (might be due to invalid IL or missing references)
				//IL_0181: Unknown result type (might be due to invalid IL or missing references)
				Transform val = ((Transform)statusEffectRoot).Find("BB_RestingCountdown");
				if ((Object)(object)val != (Object)null)
				{
					return ((Component)val).GetComponent<TextMeshProUGUI>();
				}
				Transform obj = ((Transform)statusEffectRoot).Find("Icon");
				Transform obj2 = ((obj is RectTransform) ? obj : null);
				Transform obj3 = ((Transform)statusEffectRoot).Find("TimeText");
				TMP_Text val2 = ((obj3 != null) ? ((Component)obj3).GetComponent<TMP_Text>() : null);
				if ((Object)(object)obj2 == (Object)null || (Object)(object)val2 == (Object)null)
				{
					return null;
				}
				GameObject val3 = new GameObject("BB_RestingCountdown", new Type[2]
				{
					typeof(RectTransform),
					typeof(TextMeshProUGUI)
				})
				{
					layer = ((Component)statusEffectRoot).gameObject.layer
				};
				RectTransform component = val3.GetComponent<RectTransform>();
				((Transform)component).SetParent((Transform)(object)statusEffectRoot, false);
				((Transform)component).SetAsLastSibling();
				component.pivot = new Vector2(1f, 0f);
				component.anchorMin = new Vector2(0.5f, 0.5f);
				component.anchorMax = new Vector2(0.5f, 0.5f);
				component.sizeDelta = new Vector2(26f, 16f);
				PositionRestingCountdownLabel(statusEffectRoot, component);
				TextMeshProUGUI component2 = val3.GetComponent<TextMeshProUGUI>();
				((TMP_Text)component2).font = val2.font;
				((TMP_Text)component2).fontSharedMaterial = val2.fontSharedMaterial;
				((TMP_Text)component2).fontStyle = val2.fontStyle;
				((TMP_Text)component2).fontSize = val2.fontSize;
				((TMP_Text)component2).characterSpacing = val2.characterSpacing;
				((TMP_Text)component2).wordSpacing = val2.wordSpacing;
				((TMP_Text)component2).lineSpacing = val2.lineSpacing;
				((TMP_Text)component2).enableAutoSizing = val2.enableAutoSizing;
				((TMP_Text)component2).fontSizeMin = val2.fontSizeMin;
				((TMP_Text)component2).fontSizeMax = val2.fontSizeMax;
				((Graphic)component2).color = ((Graphic)val2).color;
				((TMP_Text)component2).alignment = (TextAlignmentOptions)1028;
				((TMP_Text)component2).textWrappingMode = (TextWrappingModes)0;
				((TMP_Text)component2).overflowMode = (TextOverflowModes)0;
				((Graphic)component2).raycastTarget = false;
				((Component)component2).gameObject.SetActive(false);
				return component2;
			}

			private static void PositionRestingCountdownLabel(RectTransform statusEffectRoot, RectTransform countdownRect)
			{
				//IL_0025: 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_0030: Unknown result type (might be due to invalid IL or missing references)
				//IL_003e: Unknown result type (might be due to invalid IL or missing references)
				//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_005a: 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)
				//IL_006a: 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_0071: Unknown result type (might be due to invalid IL or missing references)
				//IL_007c: 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)
				Transform obj = ((Transform)statusEffectRoot).Find("Icon");
				RectTransform val = (RectTransform)(object)((obj is RectTransform) ? obj : null);
				if (!((Object)(object)val == (Object)null) && !((Object)(object)countdownRect == (Object)null))
				{
					Vector2 anchoredPosition = val.anchoredPosition;
					Rect rect = val.rect;
					float num = ((Rect)(ref rect)).width * (1f - val.pivot.x);
					rect = val.rect;
					Vector2 val2 = anchoredPosition + new Vector2(num, (0f - ((Rect)(ref rect)).height) * val.pivot.y);
					countdownRect.anchoredPosition = val2 + new Vector2(-2f, 4f);
				}
			}
		}

		private struct PendingThrownSpearContext
		{
			public bool Active;

			public string ThrowerIdentity;

			public string ExpectedItemName;
		}

		[HarmonyPatch(typeof(Projectile), "OnHit")]
		private static class Projectile_OnHit_ThrownSpearPickupRules_Patch
		{
			private static void Prefix(Projectile __instance, out PendingThrownSpearContext __state)
			{
				__state = s_pendingThrownSpearContext;
				if (TryCreatePendingThrownSpearContext(__instance, out var context))
				{
					s_pendingThrownSpearContext = context;
				}
			}

			private static void Finalizer(PendingThrownSpearContext __state)
			{
				s_pendingThrownSpearContext = __state;
			}
		}

		[HarmonyPatch(typeof(ItemDrop), "DropItem", new Type[]
		{
			typeof(ItemData),
			typeof(int),
			typeof(Vector3),
			typeof(Quaternion)
		})]
		private static class ItemDrop_DropItem_ThrownSpearPickupRules_Patch
		{
			private static void Prefix(ItemData item)
			{
				TryTagPendingThrownSpearItem(item);
			}
		}

		[HarmonyPatch(typeof(Player), "AutoPickup")]
		private static class Player_AutoPickup_ThrownSpearPickupRules_Patch
		{
			private static void Prefix(out int __state)
			{
				__state = s_autoPickupContextDepth;
				s_autoPickupContextDepth = __state + 1;
			}

			private static void Finalizer(int __state)
			{
				s_autoPickupContextDepth = __state;
			}
		}

		[HarmonyPatch(typeof(ItemDrop), "CanPickup", new Type[] { typeof(bool) })]
		private static class ItemDrop_CanPickup_ThrownSpearPickupRules_Patch
		{
			private static void Postfix(ItemDrop __instance, ref bool __result)
			{
				if (IsFeatureEnabled(EnableThrownSpearPickupProtection) && __result && IsInAutoPickupContext() && __instance?.m_itemData != null && TryGetThrownSpearThrowerIdentity(__instance.m_itemData, out var throwerIdentity) && TryGetPlayerIdentity(Player.m_localPlayer, out var playerIdentity) && !string.Equals(playerIdentity, throwerIdentity, StringComparison.Ordinal))
				{
					__result = false;
				}
			}
		}

		[HarmonyPatch(typeof(ItemDrop), "RequestOwn")]
		private static class ItemDrop_RequestOwn_ThrownSpearPickupRules_Patch
		{
			private static bool Prefix(ItemDrop __instance)
			{
				if (!IsFeatureEnabled(EnableThrownSpearPickupProtection))
				{
					return true;
				}
				if (!IsInAutoPickupContext() || __instance?.m_itemData == null)
				{
					return true;
				}
				if (!TryGetThrownSpearThrowerIdentity(__instance.m_itemData, out var throwerIdentity))
				{
					return true;
				}
				if (!TryGetPlayerIdentity(Player.m_localPlayer, out var playerIdentity))
				{
					return true;
				}
				return string.Equals(playerIdentity, throwerIdentity, StringComparison.Ordinal);
			}
		}

		[HarmonyPatch(typeof(Humanoid), "Pickup", new Type[]
		{
			typeof(GameObject),
			typeof(bool),
			typeof(bool)
		})]
		private static class Humanoid_Pickup_ThrownSpearPickupRules_Patch
		{
			private static void Postfix(GameObject go, bool __result)
			{
				if (__result && !((Object)(object)go == (Object)null))
				{
					ItemDrop component = go.GetComponent<ItemDrop>();
					if (component?.m_itemData != null)
					{
						ClearThrownSpearThrowerIdentity(component.m_itemData);
					}
				}
			}
		}

		[HarmonyPatch(typeof(ProximityState), "OnTriggerEnter")]
		private static class ProximityState_OnTriggerEnter_StoneOvenDoorDelay_Patch
		{
			private static void Postfix(ProximityState __instance, Collider other)
			{
				if (ShouldDelayStoneOvenDoor(__instance) && IsAcceptedProximityCollider(__instance, other))
				{
					CancelStoneOvenDoorClose(__instance);
				}
			}
		}

		[HarmonyPatch(typeof(ProximityState), "Start")]
		private static class ProximityState_Start_StoneOvenDoorRadius_Patch
		{
			private static void Postfix(ProximityState __instance)
			{
				if (ShouldDelayStoneOvenDoor(__instance))
				{
					TryApplyStoneOvenDoorTriggerRadius(__instance, out var _, out var _);
				}
			}
		}

		[HarmonyPatch(typeof(ProximityState), "OnTriggerExit")]
		private static class ProximityState_OnTriggerExit_StoneOvenDoorDelay_Patch
		{
			private static bool Prefix(ProximityState __instance, Collider other)
			{
				if (!ShouldDelayStoneOvenDoor(__instance))
				{
					return true;
				}
				List<Collider> list = s_proximityStateNearRef.Invoke(__instance);
				list?.Remove(other);
				if ((list == null || list.Count == 0) && (Object)(object)__instance.m_animator != (Object)null && __instance.m_animator.GetBool("near"))
				{
					ScheduleStoneOvenDoorClose(__instance);
				}
				return false;
			}
		}

		[HarmonyPatch]
		private static class Player_UpdateTeleport_TransitionFailsafe_Patch
		{
			private static MethodBase TargetMethod()
			{
				return AccessTools.Method(typeof(Player), "UpdateTeleport", (Type[])null, (Type[])null);
			}

			private static void Postfix(Player __instance)
			{
				TrackLocalTeleportState(__instance);
			}
		}

		[HarmonyPatch(typeof(ObjectDB), "Awake")]
		private static class ObjectDB_Awake_WeaponKnockbackTweaks_Patch
		{
			private static void Postfix(ObjectDB __instance)
			{
				ApplyWeaponKnockbackTweaks(__instance);
			}
		}

		[HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")]
		private static class ObjectDB_CopyOtherDB_WeaponKnockbackTweaks_Patch
		{
			private static void Postfix(ObjectDB __instance)
			{
				ApplyWeaponKnockbackTweaks(__instance);
			}
		}

		[HarmonyPatch(typeof(SE_Demister), "Setup")]
		private static class SE_Demister_Setup_WisplightAutoRetract_Patch
		{
			private static void Prefix(SE_Demister __instance)
			{
				if (GetWisplightOutsideMistlandsBehavior() != 0 && (Object)(object)__instance != (Object)null)
				{
					((StatusEffect)__instance).m_startMessage = string.Empty;
				}
			}
		}

		[HarmonyPatch(typeof(SE_Demister), "UpdateStatusEffect")]
		private static class SE_Demister_UpdateStatusEffect_WisplightAutoRetract_Patch
		{
			private static bool Prefix(SE_Demister __instance)
			{
				if (!ShouldOverrideWisplightBall(__instance))
				{
					return true;
				}
				if (GetWisplightOutsideMistlandsBehavior() == WisplightOutsideMistlandsMode.Off)
				{
					HideWisplightBall(__instance);
				}
				else
				{
					PinWisplightBallToChest(__instance);
				}
				return false;
			}
		}

		[HarmonyPatch(typeof(ObjectDB), "Awake")]
		public static class ObjectDB_Awake_Patch
		{
			private static readonly MethodInfo s_updateRegistersMethod = AccessTools.Method(typeof(ObjectDB), "UpdateRegisters", (Type[])null, (Type[])null);

			private static void Postfix(ObjectDB __instance)
			{
				if (!IsFeatureEnabled(EnableCustomHoes))
				{
					return;
				}
				try
				{
					EnsureCustomHoeRegistrations(__instance);
				}
				catch (Exception arg)
				{
					ManualLogSource log = Log;
					if (log != null)
					{
						log.LogError((object)$"[ValheimBB] Error while registering custom hoe recipes: {arg}");
					}
				}
			}

			private static void EnsureFlintHoeRegistered(ObjectDB objectDB)
			{
				EnsureCustomHoeRegistered(objectDB, FlintHoePrefab, "HoeFlint", "Recipe_HoeFlint", "Flint", "Flint Hoe");
			}

			private static void EnsureBronzeHoeRegistered(ObjectDB objectDB)
			{
				EnsureCustomHoeRegistered(objectDB, BronzeHoePrefab, "HoeBronze", "Recipe_HoeBronze", "Bronze", "Bronze Hoe");
			}

			internal static void EnsureCustomHoeRegistrations(ObjectDB objectDB)
			{
				if (IsFeatureEnabled(EnableCustomHoes))
				{
					EnsureCustomHoePrefabsAvailable(objectDB);
					EnsureFlintHoeRegistered(objectDB);
					EnsureBronzeHoeRegistered(objectDB);
				}
			}

			internal static void EnsureCustomHoePrefabsAvailable(ObjectDB objectDB)
			{
				EnsureCustomHoePrefabAvailable(objectDB, ref FlintHoePrefab, "HoeFlint", "Flint Hoe", "A flint-edged hoe for wider roadwork and brush clearing.", ref FlintHoeBaseStaminaCost, ref FlintHoeExtraClearStaminaCost);
				EnsureCustomHoePrefabAvailable(objectDB, ref BronzeHoePrefab, "HoeBronze", "Bronze Hoe", "A bronze hoe that clears more brush with each swing. Can also clear dead tree logs and stumps.", ref BronzeHoeBaseStaminaCost, ref BronzeHoeExtraClearStaminaCost);
			}

			private static void EnsureCustomHoePrefabAvailable(ObjectDB objectDB, ref GameObject customHoePrefab, string customHoePrefabName, string displayName, string description, ref float baseStaminaCost, ref float extraClearStaminaCost)
			{
				if ((Object)(object)objectDB == (Object)null)
				{
					return;
				}
				GameObject itemPrefab = objectDB.GetItemPrefab("Hoe");
				ItemDrop val = ((itemPrefab != null) ? itemPrefab.GetComponent<ItemDrop>() : null);
				if ((Object)(object)itemPrefab == (Object)null || (Object)(object)val == (Object)null)
				{
					return;
				}
				val.m_itemData.m_shared.m_name = "Stone Hoe";
				if ((Object)(object)customHoePrefab == (Object)null)
				{
					customHoePrefab = CreateDetachedCustomHoePrefab(itemPrefab, customHoePrefabName);
				}
				ItemDrop component = customHoePrefab.GetComponent<ItemDrop>();
				if ((Object)(object)component == (Object)null)
				{
					ManualLogSource log = Log;
					if (log != null)
					{
						log.LogWarning((object)("[ValheimBB] ItemDrop missing on " + displayName + " prefab."));
					}
					return;
				}
				component.m_itemData.m_dropPrefab = customHoePrefab;
				component.m_itemData.m_shared.m_name = displayName;
				component.m_itemData.m_shared.m_description = description;
				float num = val.m_itemData.m_shared.m_attack?.m_attackStamina ?? 5f;
				baseStaminaCost = num * 0.2f;
				extraClearStaminaCost = Mathf.Max(0f, num * 0.5f - baseStaminaCost);
				if (component.m_itemData.m_shared.m_attack != null)
				{
					component.m_itemData.m_shared.m_attack.m_attackStamina = baseStaminaCost;
				}
				EnsureDetachedClonedPieceTable(val, component, customHoePrefabName + "_PieceTable");
			}

			private static GameObject CreateDetachedCustomHoePrefab(GameObject originalHoePrefab, string prefabName)
			{
				bool activeSelf = originalHoePrefab.activeSelf;
				originalHoePrefab.SetActive(false);
				GameObject obj = Object.Instantiate<GameObject>(originalHoePrefab);
				originalHoePrefab.SetActive(activeSelf);
				((Object)obj).name = prefabName;
				obj.SetActive(false);
				Object.DontDestroyOnLoad((Object)(object)obj);
				return obj;
			}

			private static PieceTable EnsureDetachedClonedPieceTable(ItemDrop originalHoeItem, ItemDrop customHoeItem, string pieceTableName)
			{
				PieceTable val = customHoeItem.m_itemData?.m_shared?.m_buildPieces;
				if ((Object)(object)val != (Object)null && (Object)(object)((Component)val).gameObject != (Object)null && ((Object)((Component)val).gameObject).name == pieceTableName)
				{
					return val;
				}
				PieceTable val2 = originalHoeItem.m_itemData?.m_shared?.m_buildPieces;
				if ((Object)(object)val2 == (Object)null || (Object)(object)((Component)val2).gameObject == (Object)null)
				{
					return null;
				}
				GameObject obj = Object.Instantiate<GameObject>(((Component)val2).gameObject);
				((Object)obj).name = pieceTableName;
				Object.DontDestroyOnLoad((Object)(object)obj);
				PieceTable component = obj.GetComponent<PieceTable>();
				customHoeItem.m_itemData.m_shared.m_buildPieces = component;
				return component;
			}

			private static void EnsureCustomHoeRegistered(ObjectDB objectDB, GameObject customHoePrefab, string customHoePrefabName, string recipeName, string replacementRequirementPrefab, string displayName)
			{
				if ((Object)(object)objectDB == (Object)null || objectDB.m_items == null || objectDB.m_recipes == null || (Object)(object)customHoePrefab == (Object)null)
				{
					return;
				}
				GameObject itemPrefab = objectDB.GetItemPrefab("Hoe");
				if ((Object)(object)itemPrefab != (Object)null)
				{
					ItemDrop component = itemPrefab.GetComponent<ItemDrop>();
					if ((Object)(object)component != (Object)null)
					{
						component.m_itemData.m_shared.m_name = "Stone Hoe";
					}
				}
				if (!objectDB.m_items.Contains(customHoePrefab))
				{
					objectDB.m_items.Add(customHoePrefab);
				}
				ItemDrop component2 = customHoePrefab.GetComponent<ItemDrop>();
				if ((Object)(object)component2 == (Object)null)
				{
					return;
				}
				Recipe val = null;
				Recipe val2 = null;
				foreach (Recipe recipe in objectDB.m_recipes)
				{
					if (!((Object)(object)recipe == (Object)null) && !((Object)(object)recipe.m_item == (Object)null))
					{
						string text = CleanPrefabName(((Object)recipe.m_item).name);
						if (text == "Hoe")
						{
							val = recipe;
						}
						if (text == customHoePrefabName || string.Equals(((Object)recipe).name, recipeName, StringComparison.OrdinalIgnoreCase))
						{
							val2 = recipe;
						}
					}
				}
				if ((Object)(object)val == (Object)null)
				{
					ManualLogSource log = Log;
					if (log != null)
					{
						log.LogWarning((object)("[ValheimBB] Could not find the vanilla Hoe recipe to clone for " + displayName + "."));
					}
					RefreshObjectDB(objectDB);
					return;
				}
				if ((Object)(object)val2 == (Object)null)
				{
					val2 = Object.Instantiate<Recipe>(val);
					objectDB.m_recipes.Add(val2);
				}
				((Object)val2).name = recipeName;
				val2.m_item = component2;
				val2.m_enabled = true;
				val2.m_resources = BuildCustomHoeRequirements(objectDB, val.m_resources, replacementRequirementPrefab);
				RefreshObjectDB(objectDB);
			}

			private static Requirement[] BuildCustomHoeRequirements(ObjectDB objectDB, Requirement[] sourceRequirements, string replacementRequirementPrefab)
			{
				//IL_003a: 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_004b: 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_0063: Unknown result type (might be due to invalid IL or missing references)
				//IL_0071: Expected O, but got Unknown
				if (sourceRequirements == null || sourceRequirements.Length == 0)
				{
					return Array.Empty<Requirement>();
				}
				List<Requirement> list = new List<Requirement>(sourceRequirements.Length);
				foreach (Requirement val in sourceRequirements)
				{
					if (val == null || (Object)(object)val.m_resItem == (Object)null)
					{
						continue;
					}
					Requirement val2 = new Requirement
					{
						m_resItem = val.m_resItem,
						m_amount = val.m_amount,
						m_amountPerLevel = val.m_amountPerLevel,
						m_recover = val.m_recover
					};
					if (string.Equals(CleanPrefabName(((Object)val.m_resItem).name), "Stone", StringComparison.OrdinalIgnoreCase))
					{
						GameObject itemPrefab = objectDB.GetItemPrefab(replacementRequirementPrefab);
						ItemDrop val3 = ((itemPrefab != null) ? itemPrefab.GetComponent<ItemDrop>() : null);
						if ((Object)(object)val3 != (Object)null)
						{
							val2.m_resItem = val3;
						}
					}
					list.Add(val2);
				}
				return list.ToArray();
			}

			private static void RefreshObjectDB(ObjectDB objectDB)
			{
				s_updateRegistersMethod?.Invoke(objectDB, null);
			}
		}

		[HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")]
		public static class ObjectDB_CopyOtherDB_CustomHoeRegistration_Patch
		{
			private static void Postfix(ObjectDB __instance)
			{
				if (!IsFeatureEnabled(EnableCustomHoes))
				{
					return;
				}
				try
				{
					ObjectDB_Awake_Patch.EnsureCustomHoeRegistrations(__instance);
				}
				catch (Exception arg)
				{
					ManualLogSource log = Log;
					if (log != null)
					{
						log.LogError((object)$"[ValheimBB] Error while re-registering custom hoes after ObjectDB copy: {arg}");
					}
				}
			}
		}

		[HarmonyPatch(typeof(Player), "OnSpawned")]
		public static class Player_OnSpawned_CustomHoeRepair_Patch
		{
			private static void Postfix(Player __instance)
			{
				if (!IsFeatureEnabled(EnableCustomHoes) || (Object)(object)__instance != (Object)(object)Player.m_localPlayer)
				{
					return;
				}
				try
				{
					RepairCustomItemInventory(((Humanoid)__instance).GetInventory());
				}
				catch (Exception arg)
				{
					ManualLogSource log = Log;
					if (log != null)
					{
						log.LogError((object)$"[ValheimBB] Error while repairing custom hoe inventory items: {arg}");
					}
				}
			}
		}

		[HarmonyPatch(typeof(Inventory), "Save")]
		public static class Inventory_Save_CustomHoeRepair_Patch
		{
			private static void Prefix(Inventory __instance, out List<SavedCustomItemDropPrefabState> __state)
			{
				__state = null;
				if (!IsFeatureEnabled(EnableCustomHoes))
				{
					return;
				}
				try
				{
					__state = PrepareCustomItemInventoryForSave(__instance);
				}
				catch (Exception arg)
				{
					ManualLogSource log = Log;
					if (log != null)
					{
						log.LogError((object)$"[ValheimBB] Error while repairing custom hoes before inventory save: {arg}");
					}
				}
			}

			private static void Postfix(List<SavedCustomItemDropPrefabState> __state)
			{
				RestoreCustomItemInventoryAfterSave(__state);
			}
		}

		[HarmonyPatch(typeof(Inventory), "AddItem", new Type[] { typeof(ItemData) })]
		public static class Inventory_AddItem_CustomHoeRepair_Patch
		{
			private static void Prefix(ItemData item)
			{
				if (IsFeatureEnabled(EnableCustomHoes))
				{
					NormalizeCustomItem(item);
				}
			}
		}

		[HarmonyPatch(typeof(Inventory), "AddItem", new Type[]
		{
			typeof(ItemData),
			typeof(Vector2i)
		})]
		public static class Inventory_AddItemAtPos_CustomHoeRepair_Patch
		{
			private static void Prefix(ItemData item)
			{
				if (IsFeatureEnabled(EnableCustomHoes))
				{
					NormalizeCustomItem(item);
				}
			}
		}

		[HarmonyPatch]
		public static class Inventory_AddItemToGrid_CustomHoeRepair_Patch
		{
			private static MethodBase TargetMethod()
			{
				return AccessTools.Method(typeof(Inventory), "AddItem", new Type[4]
				{
					typeof(ItemData),
					typeof(int),
					typeof(int),
					typeof(int)
				}, (Type[])null);
			}

			private static void Prefix(ItemData item)
			{
				if (IsFeatureEnabled(EnableCustomHoes))
				{
					NormalizeCustomItem(item);
				}
			}
		}

		[HarmonyPatch]
		public static class Inventory_AddSerializedItem_CustomHoeAlias_Patch
		{
			private static MethodBase TargetMethod()
			{
				return AccessTools.Method(typeof(Inventory), "AddItem", new Type[12]
				{
					typeof(string),
					typeof(int),
					typeof(float),
					typeof(Vector2i),
					typeof(bool),
					typeof(int),
					typeof(int),
					typeof(long),
					typeof(string),
					typeof(Dictionary<string, string>),
					typeof(int),
					typeof(bool)
				}, (Type[])null);
			}

			private static void Prefix(ref string name, Dictionary<string, string> customData)
			{
				if (!IsFeatureEnabled(EnableCustomHoes))
				{
					return;
				}
				string text = name;
				if (!TryResolveSerializedCustomItemRuntimePrefab(name, customData, out var resolvedName))
				{
					return;
				}
				name = resolvedName;
				if (!string.Equals(CleanPrefabName(text), resolvedName, StringComparison.OrdinalIgnoreCase))
				{
					ManualLogSource log = Log;
					if (log != null)
					{
						log.LogInfo((object)("[ValheimBB] Rewrote serialized custom item save name '" + text + "' to '" + resolvedName + "'."));
					}
				}
			}
		}

		[HarmonyPatch(typeof(Humanoid), "EquipItem")]
		public static class Humanoid_EquipItem_CustomHoeRepair_Patch
		{
			private static void Prefix(ItemData item)
			{
				if (IsFeatureEnabled(EnableCustomHoes) && IsCustomHoeItem(item))
				{
					NormalizeCustomItem(item);
				}
			}
		}

		[HarmonyPatch(typeof(ObjectDB), "GetItemPrefab", new Type[] { typeof(string) })]
		public static class ObjectDB_GetItemPrefab_CustomHoeAlias_Patch
		{
			private static bool Prefix(ObjectDB __instance, string name, ref GameObject __result)
			{
				if (!IsFeatureEnabled(EnableCustomHoes))
				{
					return true;
				}
				if (!TryResolveCustomItemPrefab(__instance, null, name, out var prefab))
				{
					return true;
				}
				__result = prefab;
				return false;
			}
		}

		[HarmonyPatch]
		public static class ObjectDB_TryGetItemPrefab_CustomHoeAlias_Patch
		{
			private static MethodBase TargetMethod()
			{
				return AccessTools.Method(typeof(ObjectDB), "TryGetItemPrefab", new Type[2]
				{
					typeof(string),
					typeof(GameObject).MakeByRefType()
				}, (Type[])null);
			}

			private static bool Prefix(string name, ref bool __result, ref GameObject prefab)
			{
				if (!IsFeatureEnabled(EnableCustomHoes))
				{
					return true;
				}
				if (!TryResolveCustomItemPrefab(ObjectDB.instance, null, name, out var prefab2))
				{
					return true;
				}
				prefab = prefab2;
				__result = (Object)(object)prefab2 != (Object)null;
				return false;
			}
		}

		private struct TreeBaseDropSuppressState
		{
			public bool Active;

			public DropTable DropWhenDestroyed;
		}

		private struct TreeLogDropSuppressState
		{
			public bool Active;

			public DropTable DropWhenDestroyed;

			public GameObject SubLogPrefab;
		}

		private struct DestructibleDropSuppressState
		{
			public bool Active;

			public GameObject SpawnWhenDestroyed;
		}

		private struct HoeClearDropSuppressState
		{
			public bool Active;
		}

		[HarmonyPatch]
		private static class DamageText_ShowText_HoeClearSuppress_Patch
		{
			[CompilerGenerated]
			private sealed class <TargetMethods>d__0 : IEnumerable<MethodBase>, IEnumerable, IEnumerator<MethodBase>, IDisposable, IEnumerator
			{
				private int <>1__state;

				private MethodBase <>2__current;

				private int <>l__initialThreadId;

				private MethodInfo[] <>7__wrap1;

				private int <>7__wrap2;

				MethodBase IEnumerator<MethodBase>.Current
				{
					[DebuggerHidden]
					get
					{
						return <>2__current;
					}
				}

				object IEnumerator.Current
				{
					[DebuggerHidden]
					get
					{
						return <>2__current;
					}
				}

				[DebuggerHidden]
				public <TargetMethods>d__0(int <>1__state)
				{
					this.<>1__state = <>1__state;
					<>l__initialThreadId = Environment.CurrentManagedThreadId;
				}

				[DebuggerHidden]
				void IDisposable.Dispose()
				{
					<>7__wrap1 = null;
					<>1__state = -2;
				}

				private bool MoveNext()
				{
					int num = <>1__state;
					if (num != 0)
					{
						if (num != 1)
						{
							return false;
						}
						<>1__state = -1;
						goto IL_006e;
					}
					<>1__state = -1;
					<>7__wrap1 = typeof(DamageText).GetMethods(BindingFlags.Instance | BindingFlags.Public);
					<>7__wrap2 = 0;
					goto IL_007c;
					IL_006e:
					<>7__wrap2++;
					goto IL_007c;
					IL_007c:
					if (<>7__wrap2 < <>7__wrap1.Length)
					{
						MethodInfo methodInfo = <>7__wrap1[<>7__wrap2];
						if (methodInfo.Name == "ShowText")
						{
							<>2__current = methodInfo;
							<>1__state = 1;
							return true;
						}
						goto IL_006e;
					}
					<>7__wrap1 = null;
					return false;
				}

				bool IEnumerator.MoveNext()
				{
					//ILSpy generated this explicit interface implementation from .override directive in MoveNext
					return this.MoveNext();
				}

				[DebuggerHidden]
				void IEnumerator.Reset()
				{
					throw new NotSupportedException();
				}

				[DebuggerHidden]
				IEnumerator<MethodBase> IEnumerable<MethodBase>.GetEnumerator()
				{
					if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId)
					{
						<>1__state = 0;
						return this;
					}
					return new <TargetMethods>d__0(0);
				}

				[DebuggerHidden]
				IEnumerator IEnumerable.GetEnumerator()
				{
					return ((IEnumerable<MethodBase>)this).GetEnumerator();
				}
			}

			[IteratorStateMachine(typeof(<TargetMethods>d__0))]
			private static IEnumerable<MethodBase> TargetMethods()
			{
				//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
				return new <TargetMethods>d__0(-2);
			}

			private static bool Prefix()
			{
				if (s_hoeClearDamageTextSuppressDepth <= 0)
				{
					return Time.realtimeSinceStartup >= s_hoeClearDamageTextSuppressUntil;
				}
				return false;
			}
		}

		[HarmonyPatch(typeof(TreeBase), "RPC_Damage")]
		private static class TreeBase_RPCDamage_HoeClearNoDrops_Patch
		{
			private static void Prefix(TreeBase __instance, HitData hit, out TreeBaseDropSuppressState __state)
			{
				//IL_0043: Unknown result type (might be due to invalid IL or missing references)
				//IL_004d: Expected O, but got Unknown
				__state = default(TreeBaseDropSuppressState);
				if (!((Object)(object)__instance == (Object)null) && IsHoeClearNoDropsHit(hit))
				{
					__state = new TreeBaseDropSuppressState
					{
						Active = true,
						DropWhenDestroyed = __instance.m_dropWhenDestroyed
					};
					BeginHoeClearDropSuppress();
					__instance.m_dropWhenDestroyed = new DropTable();
				}
			}

			private static void Finalizer(TreeBase __instance, TreeBaseDropSuppressState __state)
			{
				if (__state.Active)
				{
					if ((Object)(object)__instance != (Object)null)
					{
						__instance.m_dropWhenDestroyed = __state.DropWhenDestroyed;
					}
					EndHoeClearDropSuppress();
				}
			}
		}

		[HarmonyPatch(typeof(TreeBase), "SpawnLog")]
		private static class TreeBase_SpawnLog_HoeClearNoDrops_Patch
		{
			private static bool Prefix()
			{
				return !ShouldSuppressHoeClearDrops();
			}
		}

		[HarmonyPatch(typeof(TreeLog), "Destroy")]
		private static class TreeLog_Destroy_HoeClearNoDrops_Patch
		{
			private static void Prefix(TreeLog __instance, HitData hitData, out TreeLogDropSuppressState __state)
			{
				//IL_0050: Unknown result type (might be due to invalid IL or missing references)
				//IL_005a: Expected O, but got Unknown
				__state = default(TreeLogDropSuppressState);
				if (!((Object)(object)__instance == (Object)null) && IsHoeClearNoDropsHit(hitData))
				{
					__state = new TreeLogDropSuppressState
					{
						Active = true,
						DropWhenDestroyed = __instance.m_dropWhenDestroyed,
						SubLogPrefab = __instance.m_subLogPrefab
					};
					BeginHoeClearDropSuppress();
					__instance.m_dropWhenDestroyed = new DropTable();
					__instance.m_subLogPrefab = null;
				}
			}

			private static void Finalizer(TreeLog __instance, TreeLogDropSuppressState __state)
			{
				if (__state.Active)
				{
					if ((Object)(object)__instance != (Object)null)
					{
						__instance.m_dropWhenDestroyed = __state.DropWhenDestroyed;
						__instance.m_subLogPrefab = __state.SubLogPrefab;
					}
					EndHoeClearDropSuppress();
				}
			}
		}

		[HarmonyPatch(typeof(Destructible), "Destroy", new Type[] { typeof(HitData) })]
		private static class Destructible_Destroy_HoeClearNoDrops_Patch
		{
			private static void Prefix(Destructible __instance, HitData hit, out DestructibleDropSuppressState __state)
			{
				__state = default(DestructibleDropSuppressState);
				if (!((Object)(object)__instance == (Object)null) && IsHoeClearNoDropsHit(hit))
				{
					__state = new DestructibleDropSuppressState
					{
						Active = true,
						SpawnWhenDestroyed = __instance.m_spawnWhenDestroyed
					};
					BeginHoeClearDropSuppress();
					__instance.m_spawnWhenDestroyed = null;
				}
			}

			private static void Finalizer(Destructible __instance, DestructibleDropSuppressState __state)
			{
				if (__state.Active)
				{
					if ((Object)(object)__instance != (Object)null)
					{
						__instance.m_spawnWhenDestroyed = __state.SpawnWhenDestroyed;
					}
					EndHoeClearDropSuppress();
				}
			}
		}

		[HarmonyPatch(typeof(WearNTear), "Destroy", new Type[]
		{
			typeof(HitData),
			typeof(bool)
		})]
		private static class WearNTear_Destroy_HoeClearNoDrops_Patch
		{
			private static void Prefix(HitData hitData, ref bool blockDrop, out HoeClearDropSuppressState __state)
			{
				__state = default(HoeClearDropSuppressState);
				if (IsHoeClearNoDropsHit(hitData))
				{
					__state = new HoeClearDropSuppressState
					{
						Active = true
					};
					BeginHoeClearDropSuppress();
					blockDrop = true;
				}
			}

			private static void Finalizer(HoeClearDropSuppressState __state)
			{
				if (__state.Active)
				{
					EndHoeClearDropSuppress();
				}
			}
		}

		[HarmonyPatch(typeof(DropOnDestroyed), "OnDestroyed")]
		private static class DropOnDestroyed_OnDestroyed_HoeClearNoDrops_Patch
		{
			private static bool Prefix()
			{
				return !ShouldSuppressHoeClearDrops();
			}
		}

		[HarmonyPatch(typeof(Player), "PlacePiece")]
		internal static class PathenShrubClearPatch
		{
			private static readonly FieldInfo s_placementGhostField = AccessTools.Field(typeof(Player), "m_placementGhost");

			private static readonly int s_shrubMask = LayerMask.GetMask(new string[5] { "Default", "Default_small", "piece", "piece_nonsolid", "static_solid" });

			[HarmonyPostfix]
			private static void Postfix(Player __instance, Piece piece)
			{
				//IL_0073: Unknown result type (might be due to invalid IL or missing references)
				//IL_0078: 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_00c6: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
				//IL_00b4: 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_0189: 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_01c4: Unknown result type (might be due to invalid IL or missing references)
				//IL_01e2: Unknown result type (might be due to invalid IL or missing references)
				//IL_023c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0279: Unknown result type (might be due to invalid IL or missing references)
				if (!IsFeatureEnabled(EnableCustomHoes))
				{
					ClearPendingClearState();
				}
				else
				{
					if ((Object)(object)piece == (Object)null)
					{
						return;
					}
					if (!IsPathPiece(piece))
					{
						ClearPendingClearState();
						return;
					}
					object? value = s_placementGhostField.GetValue(__instance);
					GameObject val = (GameObject)((value is GameObject) ? value : null);
					if ((Object)(object)val == (Object)null)
					{
						return;
					}
					ItemData equippedHoeItem = GetEquippedHoeItem(__instance);
					string customHoePrefabName = GetCustomHoePrefabName(equippedHoeItem);
					int customHoeClearTargetCap = GetCustomHoeClearTargetCap(equippedHoeItem);
					if (string.IsNullOrEmpty(customHoePrefabName) || customHoeClearTargetCap <= 0)
					{
						ClearPendingClearState();
						return;
					}
					Vector3 position = val.transform.position;
					float terrainRadius = GetTerrainRadius(((Component)piece).gameObject);
					List<ClearCandidate> list = CollectClearCandidates(position, terrainRadius, s_shrubMask);
					if (list.Count == 0)
					{
						ClearPendingClearState();
						ManualLogSource log = Log;
						if (log != null)
						{
							log.LogInfo((object)$"[ValheimBB] Clear preview at {position}: no candidate roots found.");
						}
						return;
					}
					LogClearCatalog(position, terrainRadius, equippedHoeItem, list);
					List<ClearCandidate> allowedCandidatesOrdered = GetAllowedCandidatesOrdered(list, position, equippedHoeItem);
					int count = allowedCandidatesOrdered.Count;
					ClearCandidate clearCandidate = null;
					ClearCandidate clearCandidate2 = null;
					ClearCandidate clearCandidate3 = null;
					foreach (ClearCandidate item in allowedCandidatesOrdered)
					{
						if (clearCandidate3 == null)
						{
							clearCandidate3 = item;
						}
						if (clearCandidate == null && HasEffects(item.HitEffect))
						{
							clearCandidate = item;
						}
						if (clearCandidate2 == null && HasEffects(item.DestroyEffect))
						{
							clearCandidate2 = item;
						}
					}
					if (clearCandidate == null)
					{
						clearCandidate = clearCandidate2;
					}
					if (clearCandidate == null)
					{
						clearCandidate = clearCandidate3;
					}
					if (count == 0)
					{
						ClearPendingClearState();
						return;
					}
					string pieceName = CleanPrefabName(((Object)piece).name);
					if (!IsConfirmedClearClick(pieceName, customHoePrefabName, position, terrainRadius))
					{
						StorePendingClearState(pieceName, customHoePrefabName, position, terrainRadius);
						if (clearCandidate != null)
						{
							PlayCandidateEffect(clearCandidate, preferDestroyEffect: false, position);
						}
						return;
					}
					float customHoeExtraClearStaminaCost = GetCustomHoeExtraClearStaminaCost(equippedHoeItem);
					if (customHoeExtraClearStaminaCost > 0f && !((Character)__instance).HaveStamina(customHoeExtraClearStaminaCost))
					{
						StorePendingClearState(pieceName, customHoePrefabName, position, terrainRadius);
						((Character)__instance).Message((MessageType)2, "Not enough stamina to clear brush.", 0, (Sprite)null);
						if (clearCandidate != null)
						{
							PlayCandidateEffect(clearCandidate, preferDestroyEffect: false, position);
						}
						return;
					}
					int num = 0;
					int num2 = Mathf.Min(customHoeClearTargetCap, allowedCandidatesOrdered.Count);
					for (int i = 0; i < num2; i++)
					{
						ClearCandidate candidate = allowedCandidatesOrdered[i];
						if (DestroyCandidate(__instance, equippedHoeItem, candidate))
						{
							num++;
						}
					}
					if (allowedCandidatesOrdered.Count > num)
					{
						StorePendingClearState(pieceName, customHoePrefabName, position, terrainRadius);
					}
					else
					{
						ClearPendingClearState();
					}
					if (num > 0)
					{
						ApplyExtraClearStamina(__instance, equippedHoeItem);
						ManualLogSource log2 = Log;
						if (log2 != null)
						{
							log2.LogInfo((object)$"[ValheimBB] Cleared {num} brush object(s) at {position} (radius {terrainRadius:F1}) using {customHoePrefabName}.");
						}
					}
				}
			}

			private static bool IsPathPiece(Piece piece)
			{
				if ((Object)(object)piece == (Object)null)
				{
					return false;
				}
				string text = CleanPrefabName(((Object)piece).name);
				if (!text.EndsWith("_clear", StringComparison.OrdinalIgnoreCase))
				{
					return false;
				}
				if (!text.StartsWith("path", StringComparison.OrdinalIgnoreCase))
				{
					return text.StartsWith("mud_road", StringComparison.OrdinalIgnoreCase);
				}
				return true;
			}
		}

		private sealed class CustomItemDefinition
		{
			public string ItemId;

			public int PersistenceVersion;

			public string RuntimePrefabName;

			public string SurrogatePrefabName;

			public string DisplayName;

			public string LegacyPrefabMarkerValue;

			public string LegacyPieceTableName;

			public string[] SpawnAliases;

			public Func<GameObject> GetRuntimePrefab;

			public Action<ObjectDB, ZNetScene> EnsureRuntimePrefabAvailable;
		}

		private sealed class SavedCustomItemDropPrefabState
		{
			public ItemData Item;

			public GameObject OriginalDropPrefab;
		}

		[HarmonyPatch(typeof(ZNetScene), "GetPrefab", new Type[] { typeof(string) })]
		public static class ZNetScene_GetPrefab_CustomItemAlias_Patch
		{
			private static bool Prefix(ZNetScene __instance, string name, ref GameObject __result)
			{
				if (!TryResolveCustomItemPrefab(null, __instance, name, out var prefab))
				{
					return true;
				}
				__result = prefab;
				return false;
			}
		}

		[HarmonyPatch(typeof(ZNetScene), "GetPrefabNames")]
		public static class ZNetScene_GetPrefabNames_CustomItemAlias_Patch
		{
			private static void Postfix(List<string> __result)
			{
				if (!IsFeatureEnabled(EnableCustomHoes) || __result == null)
				{
					return;
				}
				CustomItemDefinition[] s_customItemDefinitions = ValheimBBPlugin.s_customItemDefinitions;
				foreach (CustomItemDefinition customItemDefinition in s_customItemDefinitions)
				{
					if (customItemDefinition == null)
					{
						continue;
					}
					if (!__result.Contains(customItemDefinition.RuntimePrefabName))
					{
						__result.Add(customItemDefinition.RuntimePrefabName);
					}
					if (customItemDefinition.SpawnAliases == null)
					{
						continue;
					}
					string[] spawnAliases = customItemDefinition.SpawnAliases;
					foreach (string item in spawnAliases)
					{
						if (!__result.Contains(item))
						{
							__result.Add(item);
						}
					}
				}
			}
		}

		[HarmonyPatch(typeof(ItemDrop), "DropItem", new Type[]
		{
			typeof(ItemData),
			typeof(int),
			typeof(Vector3),
			typeof(Quaternion)
		})]
		public static class ItemDrop_DropItem_CustomItemSurrogate_Patch
		{
			private static void Prefix(ref ItemData item)
			{
				ItemData val = CreateSurrogateWorldDropItem(item);
				if (val != null)
				{
					item = val;
				}
			}
		}

		[HarmonyPatch]
		public static class ItemDrop_LoadFromZDO_CustomItemRepair_Patch
		{
			private static MethodBase TargetMethod()
			{
				return AccessTools.Method(typeof(ItemDrop), "LoadFromZDO", new Type[2]
				{
					typeof(ItemData),
					typeof(ZDO)
				}, (Type[])null);
			}

			private static void Postfix(ItemData itemData)
			{
				NormalizeCustomItem(itemData);
			}
		}

		[HarmonyPatch]
		public static class ItemDrop_LoadIndexedFromZDO_CustomItemRepair_Patch
		{
			private static MethodBase TargetMethod()
			{
				return AccessTools.Method(typeof(ItemDrop), "LoadFromZDO", new Type[3]
				{
					typeof(int),
					typeof(ItemData),
					typeof(ZDO)
				}, (Type[])null);
			}

			private static void Postfix(ItemData itemData)
			{
				NormalizeCustomItem(itemData);
			}
		}

		[HarmonyPatch(typeof(Plant), "GetHoverText")]
		public static class ValheimBB_PlantHoverTimerPatch
		{
			[HarmonyPostfix]
			private static void AddGrowthTimer(Plant __instance, ref string __result)
			{
				if (!EnablePlantGrowthTimer.Value)
				{
					return;
				}
				try
				{
					if (!((Object)(object)__instance == (Object)null))
					{
						string plantGrowthLabel = GetPlantGrowthLabel(__instance);
						if (!string.IsNullOrEmpty(plantGrowthLabel))
						{
							string text = "<color=orange>(" + plantGrowthLabel + ")</color>";
							__result = (string.IsNullOrEmpty(__result) ? text : (__result + "\n" + text));
						}
					}
				}
				catch (Exception arg)
				{
					ManualLogSource log = Log;
					if (log != null)
					{
						log.LogError((object)$"[ValheimBB] Error adding plant growth timer: {arg}");
					}
				}
			}
		}

		[HarmonyPatch(typeof(Pickable), "GetHoverText")]
		public static class ValheimBB_PickableBerryBushHoverPatch
		{
			[HarmonyPostfix]
			private static void ShowBerryBushRegrowthState(Pickable __instance, ref string __result)
			{
				if (!EnablePlantGrowthTimer.Value || !string.IsNullOrEmpty(__result))
				{
					return;
				}
				try
				{
					if (!((Object)(object)__instance == (Object)null) && IsRegrowingPickable(__instance) && !(s_pickablePickedField == null) && (bool)s_pickablePickedField.GetValue(__instance))
					{
						string hoverName = __instance.GetHoverName();
						if (!string.IsNullOrEmpty(hoverName))
						{
							string text = hoverName + " <color=orange>(" + GetPickableRegrowthLabel(__instance) + ")</color>";
							__result = LocalizeHoverText(text);
						}
					}
				}
				catch (Exception arg)
				{
					ManualLogSource log = Log;
					if (log != null)
					{
						log.LogError((object)$"[ValheimBB] Error adding berry bush hover text: {arg}");
					}
				}
			}
		}

		[HarmonyPatch(typeof(ZNetScene), "RemoveObjects")]
		private static class ZNetScene_RemoveObjects_InvalidInstanceGuard_Patch
		{
			private static void Prefix(ZNetScene __instance)
			{
				SanitizeTrackedSceneInstances(__instance);
			}
		}

		[HarmonyPatch(typeof(ZNetScene), "Awake")]
		public static class ZNetScene_Awake_Patch
		{
			private const string LegacyPathPrefabName = "path";

			private const string LegacyLevelGroundPrefabName = "mud_road";

			private const string PathPrefabName = "path_v2";

			private const string LevelGroundPrefabName = "mud_road_v2";

			private const string LegacyPathClearPrefabName = "path_clear";

			private const string LegacyLevelGroundClearPrefabName = "mud_road_clear";

			private const string PathClearPrefabName = "path_v2_clear";

			private const string LevelGroundClearPrefabName = "mud_road_v2_clear";

			private sta