Decompiled source of ValheimBB v0.2.2

BepInEx\plugins\ValheimBB.dll

Decompiled a day 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.2.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("0.2.2.0")]
namespace ValheimBB
{
	[BepInPlugin("com.valheimbb", "ValheimBB", "0.2.2")]
	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 && !Mathf.Approximately(0.5f, 1f))
				{
					pushForce /= 0.5f;
				}
			}
		}

		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}");
					}
				}
			}
		}

		[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 static readonly FieldInfo s_prefabsField = AccessTools.Field(typeof(ZNetScene), "m_prefabs");

			private static readonly FieldInfo s_namedPrefabsField = AccessTools.Field(typeof(ZNetScene), "m_namedPrefabs");

			private static readonly Dictionary<string, string> s_hoeIconFiles = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
			{
				{ "path", "clear_path.png" },
				{ "path_v2", "clear_path.png" },
				{ "mud_road", "clear_ground.png" },
				{ "mud_road_v2", "clear_ground.png" }
			};

			private const string HiddenPrefabContainerName = "_ValheimBB_HiddenPrefabs";

			private static readonly Dictionary<string, Sprite> s_hoeIconCache = new Dictionary<string, Sprite>(StringComparer.OrdinalIgnoreCase);

			private static readonly Dictionary<string, GameObject> s_clearPieceVariantPrefabs = new Dictionary<string, GameObject>(StringComparer.OrdinalIgnoreCase);

			private static readonly Dictionary<string, GameObject> s_hoeTablePiecePrefabs = new Dictionary<string, GameObject>(StringComparer.OrdinalIgnoreCase);

			private static readonly Dictionary<string, float> s_baseTorchSecPerFuel = new Dictionary<string, float>(StringComparer.OrdinalIgnoreCase);

			private static GameObject s_hiddenPrefabContainer;

			private static void Postfix(ZNetScene __instance)
			{
				try
				{
					ConfigureTorchFuelSettings(__instance);
				}
				catch (Exception arg)
				{
					ManualLogSource log = Log;
					if (log != null)
					{
						log.LogError((object)$"[ValheimBB] Error while tweaking torch fuel settings: {arg}");
					}
				}
				try
				{
					ConfigureStoneOvenDoorPrefab(__instance);
				}
				catch (Exception arg2)
				{
					ManualLogSource log2 = Log;
					if (log2 != null)
					{
						log2.LogError((object)$"[ValheimBB] Error while tweaking stone oven door behavior: {arg2}");
					}
				}
				if (IsFeatureEnabled(EnableStandingTorchAndKilnTweaks))
				{
					try
					{
						GameObject prefab = __instance.GetPrefab("piece_groundtorch_wood");
						if ((Object)(object)prefab == (Object)null)
						{
							ManualLogSource log3 = Log;
							if (log3 != null)
							{
								log3.LogWarning((object)"[ValheimBB] Could not find 'piece_groundtorch_wood' in ZNetScene.");
							}
						}
						else
						{
							Piece component = prefab.GetComponent<Piece>();
							if ((Object)(object)component == (Object)null)
							{
								ManualLogSource log4 = Log;
								if (log4 != null)
								{
									log4.LogWarning((object)"[ValheimBB] Prefab 'piece_groundtorch_wood' has no Piece component.");
								}
							}
							else
							{
								if ((Object)(object)component.m_craftingStation != (Object)null)
								{
									ManualLogSource log5 = Log;
									if (log5 != null)
									{
										log5.LogInfo((object)("[ValheimBB] Standing Wood Torch originally required crafting station: " + component.m_craftingStation.m_name + ". Removing requirement."));
									}
								}
								else
								{
									ManualLogSource log6 = Log;
									if (log6 != null)
									{
										log6.LogInfo((object)"[ValheimBB] Standing Wood Torch already had no crafting station set.");
									}
								}
								component.m_craftingStation = null;
							}
						}
					}
					catch (Exception arg3)
					{
						ManualLogSource log7 = Log;
						if (log7 != null)
						{
							log7.LogError((object)$"[ValheimBB] Error while tweaking torch build requirements: {arg3}");
						}
					}
				}
				if (IsFeatureEnabled(EnableCustomHoes))
				{
					try
					{
						if (!TryMatchTerrainRadius(__instance, "mud_road_v2", "path_v2"))
						{
							TryMatchTerrainRadius(__instance, "mud_road", "path");
						}
					}
					catch (Exception arg4)
					{
						ManualLogSource log8 = Log;
						if (log8 != null)
						{
							log8.LogError((object)$"[ValheimBB] Error while widening path radius: {arg4}");
						}
					}
					try
					{
						EnsureFlintHoePrefab(__instance);
						EnsureBronzeHoePrefab(__instance);
						ConfigureFlintHoePreviewEffect(__instance);
						ObjectDB_Awake_Patch.EnsureCustomHoeRegistrations(ObjectDB.instance);
					}
					catch (Exception arg5)
					{
						ManualLogSource log9 = Log;
						if (log9 != null)
						{
							log9.LogError((object)$"[ValheimBB] Error while creating custom hoe prefabs: {arg5}");
						}
					}
				}
				if (!IsFeatureEnabled(EnableStandingTorchAndKilnTweaks))
				{
					return;
				}
				try
				{
					GameObject prefab2 = __instance.GetPrefab("charcoal_kiln");
					if ((Object)(object)prefab2 == (Object)null)
					{
						ManualLogSource log10 = Log;
						if (log10 != null)
						{
							log10.LogWarning((object)"[ValheimBB] charcoal_kiln prefab not found.");
						}
						return;
					}
					Smelter component2 = prefab2.GetComponent<Smelter>();
					if ((Object)(object)component2 == (Object)null)
					{
						ManualLogSource log11 = Log;
						if (log11 != null)
						{
							log11.LogWarning((object)"[ValheimBB] Smelter component missing on charcoal_kiln prefab.");
						}
						return;
					}
					if (component2.m_conversion == null)
					{
						ManualLogSource log12 = Log;
						if (log12 != null)
						{
							log12.LogWarning((object)"[ValheimBB] charcoal_kiln Smelter has no conversion list.");
						}
						return;
					}
					int count = component2.m_conversion.Count;
					component2.m_conversion.RemoveAll(delegate(ItemConversion conv)
					{
						if (conv == null || (Object)(object)conv.m_from == (Object)null)
						{
							return false;
						}
						GameObject gameObject = ((Component)conv.m_from).gameObject;
						string obj = (((Object)(object)gameObject != (Object)null) ? ((Object)gameObject).name : string.Empty);
						string text = conv.m_from.m_itemData?.m_shared?.m_name ?? string.Empty;
						bool num2 = obj.Equals("FineWood", StringComparison.OrdinalIgnoreCase);
						bool flag = text.Equals("$item_finewood", StringComparison.OrdinalIgnoreCase);
						return num2 || flag;
					});
					int count2 = component2.m_conversion.Count;
					int num = count - count2;
					ManualLogSource log13 = Log;
					if (log13 != null)
					{
						log13.LogInfo((object)$"[ValheimBB] charcoal_kiln conversion entries: {count} -> {count2} (removed {num} FineWood entries).");
					}
				}
				catch (Exception arg6)
				{
					ManualLogSource log14 = Log;
					if (log14 != null)
					{
						log14.LogError((object)$"[ValheimBB] Error while tweaking charcoal_kiln conversions: {arg6}");
					}
				}
			}

			private static void ConfigureTorchFuelSettings(ZNetScene scene)
			{
				if ((Object)(object)scene == (Object)null)
				{
					return;
				}
				if (!(s_prefabsField?.GetValue(scene) is List<GameObject> list) || list.Count == 0)
				{
					ManualLogSource log = Log;
					if (log != null)
					{
						log.LogWarning((object)"[ValheimBB] Could not read ZNetScene prefab list while syncing torch and brazier fuel settings.");
					}
					return;
				}
				int num = 0;
				foreach (GameObject item in list)
				{
					if (!TryGetTorchOrBrazierFireplace(item, out var fireplace))
					{
						continue;
					}
					string text = CleanPrefabName(((Object)item).name);
					if (!s_baseTorchSecPerFuel.TryGetValue(text, out var value))
					{
						value = fireplace.m_secPerFuel;
						s_baseTorchSecPerFuel[text] = value;
					}
					float secPerFuel = value * 2f;
					float secPerFuel2 = fireplace.m_secPerFuel;
					float maxFuel = fireplace.m_maxFuel;
					fireplace.m_secPerFuel = secPerFuel;
					if (string.Equals(text, "piece_groundtorch_wood", StringComparison.OrdinalIgnoreCase) && IsFeatureEnabled(EnableStandingTorchAndKilnTweaks))
					{
						fireplace.m_maxFuel = 5f;
					}
					if (!Mathf.Approximately(secPerFuel2, fireplace.m_secPerFuel) || !Mathf.Approximately(maxFuel, fireplace.m_maxFuel))
					{
						num++;
						ManualLogSource log2 = Log;
						if (log2 != null)
						{
							log2.LogInfo((object)$"[ValheimBB] Fuel updated for '{text}': max fuel {maxFuel:0.#} -> {fireplace.m_maxFuel:0.#}, sec/fuel {secPerFuel2:0.#} -> {fireplace.m_secPerFuel:0.#}.");
						}
					}
				}
				ManualLogSource log3 = Log;
				if (log3 != null)
				{
					log3.LogInfo((object)$"[ValheimBB] Updated burn time for {num} torch/brazier prefabs.");
				}
			}

			private static bool TryGetTorchOrBrazierFireplace(GameObject prefab, out Fireplace fireplace)
			{
				fireplace = ((prefab != null) ? prefab.GetComponent<Fireplace>() : null);
				if ((Object)(object)fireplace == (Object)null || (Object)(object)prefab.GetComponent<Piece>() == (Object)null)
				{
					return false;
				}
				string text = CleanPrefabName(((Object)prefab).name);
				if (string.IsNullOrWhiteSpace(text))
				{
					return false;
				}
				if (text.IndexOf("torch", StringComparison.OrdinalIgnoreCase) < 0 && text.IndexOf("brazier", StringComparison.OrdinalIgnoreCase) < 0)
				{
					return text.IndexOf("sconce", StringComparison.OrdinalIgnoreCase) >= 0;
				}
				return true;
			}

			internal static void EnsureFlintHoePrefab(ZNetScene scene)
			{
				GameObject prefab = scene.GetPrefab("Hoe");
				if ((Object)(object)prefab == (Object)null)
				{
					ManualLogSource log = Log;
					if (log != null)
					{
						log.LogWarning((object)"[ValheimBB] Hoe prefab not found.");
					}
					return;
				}
				ItemDrop component = prefab.GetComponent<ItemDrop>();
				if ((Object)(object)component == (Object)null)
				{
					ManualLogSource log2 = Log;
					if (log2 != null)
					{
						log2.LogWarning((object)"[ValheimBB] ItemDrop missing on Hoe prefab.");
					}
					return;
				}
				component.m_itemData.m_shared.m_name = "Stone Hoe";
				if ((Object)(object)FlintHoePrefab == (Object)null)
				{
					FlintHoePrefab = CreateCustomHoePrefab(prefab, "HoeFlint");
				}
				ParkCloneAsHiddenPrefab(FlintHoePrefab);
				RegisterPrefabWithScene(scene, FlintHoePrefab);
				ConfigureFlintHoePrefab(component, FlintHoePrefab, scene);
			}

			internal static void EnsureBronzeHoePrefab(ZNetScene scene)
			{
				GameObject prefab = scene.GetPrefab("Hoe");
				if ((Object)(object)prefab == (Object)null)
				{
					ManualLogSource log = Log;
					if (log != null)
					{
						log.LogWarning((object)"[ValheimBB] Hoe prefab not found.");
					}
					return;
				}
				ItemDrop component = prefab.GetComponent<ItemDrop>();
				if ((Object)(object)component == (Object)null)
				{
					ManualLogSource log2 = Log;
					if (log2 != null)
					{
						log2.LogWarning((object)"[ValheimBB] ItemDrop missing on Hoe prefab.");
					}
					return;
				}
				component.m_itemData.m_shared.m_name = "Stone Hoe";
				if ((Object)(object)BronzeHoePrefab == (Object)null)
				{
					BronzeHoePrefab = CreateCustomHoePrefab(prefab, "HoeBronze");
				}
				ParkCloneAsHiddenPrefab(BronzeHoePrefab);
				RegisterPrefabWithScene(scene, BronzeHoePrefab);
				ConfigureBronzeHoePrefab(component, BronzeHoePrefab, scene);
			}

			private static GameObject CreateCustomHoePrefab(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 void ConfigureFlintHoePreviewEffect(ZNetScene scene)
			{
				if (!((Object)(object)scene == (Object)null) && !TrySetFlintHoePreviewEffect(scene, "Beech1") && !TrySetFlintHoePreviewEffect(scene, "FirTree_oldLog") && !TrySetFlintHoePreviewEffect(scene, "Beech_small1") && !TrySetFlintHoePreviewEffect(scene, "Beech_small2"))
				{
					FlintHoePreviewEffect = null;
					FlintHoePreviewEffectSource = null;
					ManualLogSource log = Log;
					if (log != null)
					{
						log.LogWarning((object)"[ValheimBB] Could not resolve a fixed Flint Hoe preview effect.");
					}
				}
			}

			private static bool TrySetFlintHoePreviewEffect(ZNetScene scene, string prefabName)
			{
				GameObject prefab = scene.GetPrefab(prefabName);
				if ((Object)(object)prefab == (Object)null)
				{
					return false;
				}
				EffectList val = null;
				TreeBase component = prefab.GetComponent<TreeBase>();
				if ((Object)(object)component != (Object)null && HasEffects(component.m_hitEffect))
				{
					val = component.m_hitEffect;
				}
				if (!HasEffects(val))
				{
					TreeLog component2 = prefab.GetComponent<TreeLog>();
					if ((Object)(object)component2 != (Object)null && HasEffects(component2.m_hitEffect))
					{
						val = component2.m_hitEffect;
					}
				}
				if (!HasEffects(val))
				{
					Destructible component3 = prefab.GetComponent<Destructible>();
					if ((Object)(object)component3 != (Object)null && HasEffects(component3.m_hitEffect))
					{
						val = component3.m_hitEffect;
					}
				}
				if (!HasEffects(val))
				{
					WearNTear component4 = prefab.GetComponent<WearNTear>();
					if ((Object)(object)component4 != (Object)null && HasEffects(component4.m_hitEffect))
					{
						val = component4.m_hitEffect;
					}
				}
				if (!HasEffects(val))
				{
					return false;
				}
				FlintHoePreviewEffect = val;
				FlintHoePreviewEffectSource = prefabName;
				ManualLogSource log = Log;
				if (log != null)