Decompiled source of Hearthstone v1.4.1

Hearthstone.dll

Decompiled 9 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("assembly_guiutils")]
[assembly: IgnoresAccessChecksTo("assembly_valheim")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("Valheim Overhaul")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Consumable Hearthstone that channels you back to your bound bed. Comfort tool, not a portal replacement.")]
[assembly: AssemblyFileVersion("1.2.0.0")]
[assembly: AssemblyInformationalVersion("1.2.0")]
[assembly: AssemblyProduct("Hearthstone")]
[assembly: AssemblyTitle("Hearthstone")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.2.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace Hearthstone
{
	internal static class HearthstoneCaster
	{
		internal const string ProgressToken = "$hud_hearthstone_casting";

		private static ItemData _activeItem;

		private static float _vfxTimer;

		private static float _startedAt;

		private static GameObject _vfxPrefab;

		internal static bool IsCasting => _activeItem != null;

		internal static bool TryBegin(Player player, ItemData item)
		{
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Expected O, but got Unknown
			if (!HearthstoneConfig.EnableMod.Value || (Object)(object)player == (Object)null || item == null)
			{
				return false;
			}
			if ((Object)(object)player != (Object)(object)Player.m_localPlayer)
			{
				return false;
			}
			if (IsCasting)
			{
				return false;
			}
			if (((Character)player).IsDead() || ((Character)player).InCutscene() || ((Character)player).IsTeleporting())
			{
				return false;
			}
			if (!HearthstoneItem.IsHearthstone(item))
			{
				return false;
			}
			if (!HearthstoneItem.IsOwnedBy(item, player))
			{
				((Character)player).Message((MessageType)2, "$msg_hearthstone_notowner", 0, (Sprite)null);
				return false;
			}
			if (HearthstoneCooldown.IsOnCooldown(player, out var remainingSeconds))
			{
				((Character)player).Message((MessageType)2, Localization.instance.Localize("$msg_hearthstone_cooldown", new string[1] { HearthstoneCooldown.FormatRemaining(remainingSeconds) }), 0, (Sprite)null);
				return false;
			}
			if (!HearthstoneTeleport.TryGetDestination(player, out var _, out var failToken))
			{
				((Character)player).Message((MessageType)2, failToken ?? "$msg_hearthstone_nobed", 0, (Sprite)null);
				return false;
			}
			if (!HearthstoneTeleport.CanTeleportInventory(player, out var failToken2))
			{
				((Character)player).Message((MessageType)2, failToken2 ?? "$msg_noteleport", 0, (Sprite)null);
				return false;
			}
			HearthstoneItem.ClaimOwnership(item, player);
			((Humanoid)player).ClearActionQueue();
			StopActionAnimation(player);
			if ((Object)(object)InventoryGui.instance != (Object)null && InventoryGui.IsVisible())
			{
				InventoryGui.instance.Hide();
			}
			float duration = Mathf.Max(0.51f, HearthstoneConfig.CastTime.Value);
			MinorActionData item2 = new MinorActionData
			{
				m_item = item,
				m_type = (ActionType)2,
				m_duration = duration,
				m_time = 0f,
				m_progressText = "$hud_hearthstone_casting",
				m_animation = string.Empty
			};
			player.m_actionQueue.Add(item2);
			_activeItem = item;
			_vfxTimer = 0f;
			_startedAt = Time.time;
			PlayWishbonePulse(player);
			return true;
		}

		internal static void Cancel(Player player, bool showMessage)
		{
			if (!IsCasting && ((Object)(object)player == (Object)null || !HasQueuedCast(player)))
			{
				return;
			}
			ItemData activeItem = _activeItem;
			_activeItem = null;
			_vfxTimer = 0f;
			if ((Object)(object)player != (Object)null)
			{
				if (activeItem != null)
				{
					((Humanoid)player).RemoveEquipAction(activeItem);
				}
				else
				{
					RemoveQueuedCast(player);
				}
				StopActionAnimation(player);
				if (showMessage)
				{
					((Character)player).Message((MessageType)2, "$msg_hearthstone_cancelled", 0, (Sprite)null);
				}
			}
		}

		internal static bool IsOurAction(MinorActionData action)
		{
			if (action != null && action.m_progressText == "$hud_hearthstone_casting")
			{
				return HearthstoneItem.IsHearthstone(action.m_item);
			}
			return false;
		}

		internal static bool HasQueuedCast(Player player)
		{
			if (player?.m_actionQueue == null)
			{
				return false;
			}
			foreach (MinorActionData item in player.m_actionQueue)
			{
				if (IsOurAction(item))
				{
					return true;
				}
			}
			return false;
		}

		internal static bool TryUpdateActionQueue(Player player, float dt)
		{
			if ((Object)(object)player == (Object)null || player.m_actionQueue == null || player.m_actionQueue.Count == 0)
			{
				return false;
			}
			MinorActionData val = player.m_actionQueue[0];
			if (!IsOurAction(val))
			{
				return false;
			}
			if (player.m_actionQueuePause > 0f)
			{
				player.m_actionQueuePause -= dt;
				return true;
			}
			if (((Character)player).InAttack())
			{
				return true;
			}
			val.m_time += dt;
			if (val.m_time <= val.m_duration)
			{
				return true;
			}
			ItemData item = val.m_item;
			player.m_actionQueue.RemoveAt(0);
			player.m_actionQueuePause = 0.05f;
			CompleteFromActionQueue(player, item);
			return true;
		}

		internal static void Update(Player player, float dt)
		{
			if ((Object)(object)player == (Object)null || (Object)(object)player != (Object)(object)Player.m_localPlayer || (!IsCasting && !HasQueuedCast(player)))
			{
				return;
			}
			if (!HearthstoneConfig.EnableMod.Value || ((Character)player).IsDead() || ((Character)player).IsTeleporting() || _activeItem == null || !((Humanoid)player).GetInventory().ContainsItem(_activeItem))
			{
				Cancel(player, showMessage: false);
				return;
			}
			if (!HasQueuedCast(player))
			{
				_activeItem = null;
				StopActionAnimation(player);
				return;
			}
			if (Time.time - _startedAt > 0.35f && ShouldCancel(player))
			{
				Cancel(player, showMessage: true);
				return;
			}
			_vfxTimer += dt;
			if (_vfxTimer >= 1.25f)
			{
				_vfxTimer = 0f;
				PlayWishbonePulse(player);
			}
		}

		internal static void CompleteFromActionQueue(Player player, ItemData item)
		{
			_activeItem = null;
			_vfxTimer = 0f;
			StopActionAnimation(player);
			if (!((Object)(object)player == (Object)null) && item != null && ((Humanoid)player).GetInventory().ContainsItem(item) && HearthstoneTeleport.TryTeleport(player))
			{
				HearthstoneItem.ConsumeOneUse(player, item);
				HearthstoneCooldown.Start(player);
				PlayWishbonePulse(player);
			}
		}

		internal static void EnsureActionBarVisible(Player player)
		{
			if (!IsCasting || (Object)(object)player == (Object)null || (Object)(object)Hud.instance == (Object)null)
			{
				return;
			}
			string text = default(string);
			float value = default(float);
			MinorActionData val = default(MinorActionData);
			player.GetActionProgress(ref text, ref value, ref val);
			if (val == null || !IsOurAction(val))
			{
				text = "$hud_hearthstone_casting";
				if (_activeItem != null && player.m_actionQueue != null)
				{
					foreach (MinorActionData item in player.m_actionQueue)
					{
						if (IsOurAction(item))
						{
							value = ((item.m_duration > 0f) ? Mathf.Clamp01(item.m_time / item.m_duration) : 0f);
							val = item;
							break;
						}
					}
				}
			}
			if (val != null && !(val.m_duration <= 0.5f))
			{
				Hud.instance.m_actionBarRoot.SetActive(true);
				Hud.instance.m_actionProgress.SetValue(value);
				Hud.instance.m_actionName.text = Localization.instance.Localize(string.IsNullOrEmpty(text) ? "$hud_hearthstone_casting" : text);
			}
		}

		private static void RemoveQueuedCast(Player player)
		{
			if (player?.m_actionQueue == null)
			{
				return;
			}
			for (int num = player.m_actionQueue.Count - 1; num >= 0; num--)
			{
				if (IsOurAction(player.m_actionQueue[num]))
				{
					player.m_actionQueue.RemoveAt(num);
				}
			}
		}

		private static void StopActionAnimation(Player player)
		{
			if ((Object)(object)((Character)(player?)).m_zanim == (Object)null)
			{
				return;
			}
			if (!string.IsNullOrEmpty(player.m_actionAnimation))
			{
				((Character)player).m_zanim.SetBool(player.m_actionAnimation, false);
				player.m_actionAnimation = null;
			}
			try
			{
				((Character)player).m_zanim.SetBool("equipping", false);
			}
			catch
			{
			}
		}

		private static bool ShouldCancel(Player player)
		{
			if (HearthstoneConfig.CancelOnDodge.Value && ((Character)player).InDodge())
			{
				return true;
			}
			if (HearthstoneConfig.CancelOnJump.Value && IsJumping(player))
			{
				return true;
			}
			if (HearthstoneConfig.CancelOnMove.Value && IsMoving(player))
			{
				return true;
			}
			return false;
		}

		private static bool IsMoving(Player player)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			Vector3 moveDir = ((Character)player).GetMoveDir();
			if (((Vector3)(ref moveDir)).sqrMagnitude > 0.01f)
			{
				return true;
			}
			try
			{
				if (ZInput.GetButton("Forward") || ZInput.GetButton("Backward") || ZInput.GetButton("Left") || ZInput.GetButton("Right") || ZInput.GetButton("JoyForward") || ZInput.GetButton("JoyBackward") || ZInput.GetButton("JoyLeft") || ZInput.GetButton("JoyRight"))
				{
					return true;
				}
			}
			catch
			{
			}
			return ((Character)player).IsRunning();
		}

		private static bool IsJumping(Player player)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			if (!((Character)player).IsOnGround() && ((Character)player).GetVelocity().y > 0.5f)
			{
				return true;
			}
			try
			{
				if (ZInput.GetButtonDown("Jump") || ZInput.GetButtonDown("JoyJump"))
				{
					return true;
				}
			}
			catch
			{
			}
			return false;
		}

		private static void PlayWishbonePulse(Player player)
		{
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)player == (Object)null))
			{
				if ((Object)(object)_vfxPrefab == (Object)null && (Object)(object)ZNetScene.instance != (Object)null)
				{
					_vfxPrefab = ZNetScene.instance.GetPrefab("vfx_WishbonePing");
				}
				if ((Object)(object)_vfxPrefab != (Object)null)
				{
					Object.Instantiate<GameObject>(_vfxPrefab, ((Component)player).transform.position + Vector3.up * 0.5f, Quaternion.identity);
				}
			}
		}
	}
	internal static class HearthstoneConfig
	{
		internal static ConfigEntry<bool> EnableMod;

		internal static ConfigEntry<int> Uses;

		internal static ConfigEntry<float> CastTime;

		internal static ConfigEntry<float> CooldownMinutes;

		internal static ConfigEntry<float> Weight;

		internal static ConfigEntry<bool> RequireBoundBed;

		internal static ConfigEntry<bool> CancelOnDamage;

		internal static ConfigEntry<bool> CancelOnDodge;

		internal static ConfigEntry<bool> CancelOnJump;

		internal static ConfigEntry<bool> CancelOnMove;

		internal static ConfigEntry<bool> AllowTeleportWithRestrictedItems;

		internal static void Bind(ConfigFile config)
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Expected O, but got Unknown
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Expected O, but got Unknown
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Expected O, but got Unknown
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Expected O, but got Unknown
			EnableMod = config.Bind<bool>("General", "Enable Mod", true, "Enable or disable the Hearthstone mod.");
			Uses = config.Bind<int>("Hearthstone", "Uses", 10, new ConfigDescription("Number of successful teleports before the Hearthstone is destroyed.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 100), Array.Empty<object>()));
			CastTime = config.Bind<float>("Hearthstone", "Cast Time", 10f, new ConfigDescription("Channel duration in seconds before teleporting.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 60f), Array.Empty<object>()));
			CooldownMinutes = config.Bind<float>("Hearthstone", "Cooldown Minutes", 7f, new ConfigDescription("Cooldown after a successful teleport, in minutes. Persists across logout.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 120f), Array.Empty<object>()));
			Weight = config.Bind<float>("Hearthstone", "Weight", 0.2f, new ConfigDescription("Item weight.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.01f, 20f), Array.Empty<object>()));
			RequireBoundBed = config.Bind<bool>("Hearthstone", "Require Bound Bed", true, "If true, casting requires a currently bound bed (same spawn used on death).");
			CancelOnDamage = config.Bind<bool>("Hearthstone", "Cancel On Damage", true, "Cancel channeling when taking damage. Does not consume a use or start cooldown.");
			CancelOnDodge = config.Bind<bool>("Hearthstone", "Cancel On Dodge", true, "Cancel channeling when dodging / rolling.");
			CancelOnJump = config.Bind<bool>("Hearthstone", "Cancel On Jump", true, "Cancel channeling when jumping.");
			CancelOnMove = config.Bind<bool>("Hearthstone", "Cancel On Move", true, "Cancel channeling when walking, running, or otherwise moving.");
			AllowTeleportWithRestrictedItems = config.Bind<bool>("Hearthstone", "Allow Teleport With Restricted Items", false, "If false (default), uses Inventory.IsTeleportable() exactly like portals — including Adventure Backpacks. If true, bypasses that check.");
		}
	}
	internal static class HearthstoneCooldown
	{
		internal static bool IsOnCooldown(Player player, out float remainingSeconds)
		{
			remainingSeconds = 0f;
			if (player?.m_customData == null)
			{
				return false;
			}
			if (!player.m_customData.TryGetValue("valheimoverhaul.hearthstone.cooldownUntil", out var value) || string.IsNullOrEmpty(value))
			{
				return false;
			}
			if (!long.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result))
			{
				return false;
			}
			long ticks = DateTime.UtcNow.Ticks;
			if (result <= ticks)
			{
				player.m_customData.Remove("valheimoverhaul.hearthstone.cooldownUntil");
				return false;
			}
			remainingSeconds = (float)TimeSpan.FromTicks(result - ticks).TotalSeconds;
			return remainingSeconds > 0f;
		}

		internal static void Start(Player player)
		{
			if (player?.m_customData != null)
			{
				float num = Math.Max(0f, HearthstoneConfig.CooldownMinutes.Value);
				if (num <= 0f)
				{
					player.m_customData.Remove("valheimoverhaul.hearthstone.cooldownUntil");
					return;
				}
				DateTime dateTime = DateTime.UtcNow.AddMinutes(num);
				player.m_customData["valheimoverhaul.hearthstone.cooldownUntil"] = dateTime.Ticks.ToString(CultureInfo.InvariantCulture);
			}
		}

		internal static string FormatRemaining(float seconds)
		{
			if (seconds < 0f)
			{
				seconds = 0f;
			}
			int num = (int)Math.Ceiling(seconds);
			int num2 = num / 60;
			int num3 = num % 60;
			if (num2 <= 0)
			{
				return string.Format(CultureInfo.InvariantCulture, "{0}s", num3);
			}
			return string.Format(CultureInfo.InvariantCulture, "{0}m {1:D2}s", num2, num3);
		}

		internal static string FormatCompact(float seconds)
		{
			if (seconds < 0f)
			{
				seconds = 0f;
			}
			int num = (int)Math.Ceiling(seconds);
			int num2 = num / 60;
			int num3 = num % 60;
			if (num2 <= 0)
			{
				return string.Format(CultureInfo.InvariantCulture, "{0}", num3);
			}
			return string.Format(CultureInfo.InvariantCulture, "{0}:{1:D2}", num2, num3);
		}
	}
	internal static class HearthstoneItem
	{
		internal static GameObject Prefab;

		internal static Recipe Recipe;

		private static bool _prefabCreated;

		private static readonly string[] MeshPrefabCandidates = new string[7] { "SurtlingCore", "Thunderstone", "Crystal", "Ruby", "Amber", "Flint", "Wishbone" };

		internal static bool IsHearthstone(ItemData item)
		{
			if (item?.m_shared == null)
			{
				return false;
			}
			if (item.m_shared.m_name == "$item_hearthstone")
			{
				return true;
			}
			if ((Object)(object)item.m_dropPrefab != (Object)null && !((object)item.m_dropPrefab).Equals((object?)null))
			{
				return ((Object)item.m_dropPrefab).name == "VO_Hearthstone";
			}
			return false;
		}

		internal static int CountInInventory(Player player)
		{
			if (((player != null) ? ((Humanoid)player).GetInventory() : null) == null)
			{
				return 0;
			}
			int num = 0;
			foreach (ItemData allItem in ((Humanoid)player).GetInventory().GetAllItems())
			{
				if (IsHearthstone(allItem))
				{
					num++;
				}
			}
			return num;
		}

		internal static bool IsOwnedBy(ItemData item, Player player)
		{
			if (item == null || (Object)(object)player == (Object)null)
			{
				return false;
			}
			if (item.m_crafterID == 0L)
			{
				return true;
			}
			return item.m_crafterID == player.GetPlayerID();
		}

		internal static void ClaimOwnership(ItemData item, Player player)
		{
			if (item != null && !((Object)(object)player == (Object)null) && item.m_crafterID == 0L)
			{
				item.m_crafterID = player.GetPlayerID();
				item.m_crafterName = player.GetPlayerName();
			}
		}

		internal static void TryRegister(ObjectDB odb)
		{
			if ((Object)(object)odb == (Object)null || !IsObjectDbReady(odb))
			{
				return;
			}
			try
			{
				SanitizeObjectDb(odb);
				if ((Object)(object)Prefab == (Object)null || ((object)Prefab).Equals((object?)null))
				{
					Prefab = FindExisting(odb);
					_prefabCreated = (Object)(object)Prefab != (Object)null;
				}
				if ((Object)(object)Prefab != (Object)null && !((object)Prefab).Equals((object?)null) && ShouldRebuildPrefab(odb))
				{
					odb.m_items.Remove(Prefab);
					Object.Destroy((Object)(object)Prefab);
					Prefab = null;
					_prefabCreated = false;
				}
				if ((Object)(object)Prefab == (Object)null || ((object)Prefab).Equals((object?)null))
				{
					if (!CreatePrefab(odb))
					{
						return;
					}
				}
				else
				{
					ItemDrop component = Prefab.GetComponent<ItemDrop>();
					if (component?.m_itemData != null)
					{
						EnsureUniqueShared(component);
						ApplyItemStats(component.m_itemData.m_shared);
						component.m_itemData.m_dropPrefab = Prefab;
						((Object)component).name = "VO_Hearthstone";
						((Object)Prefab).name = "VO_Hearthstone";
					}
					if (!odb.m_items.Contains(Prefab))
					{
						odb.m_items.Add(Prefab);
					}
				}
				EnsureRecipe(odb);
				RegisterInLookups(odb);
				if ((Object)(object)ZNetScene.instance != (Object)null)
				{
					TryRegisterZNetScene(ZNetScene.instance);
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("TryRegister failed (non-fatal): " + ex));
			}
		}

		internal static void TryRegisterZNetScene(ZNetScene scene)
		{
			if ((Object)(object)scene == (Object)null || (Object)(object)Prefab == (Object)null || ((object)Prefab).Equals((object?)null))
			{
				return;
			}
			int stableHashCode = StringExtensionMethods.GetStableHashCode("VO_Hearthstone");
			if (scene.m_namedPrefabs == null || !scene.m_namedPrefabs.ContainsKey(stableHashCode))
			{
				if (scene.m_prefabs != null && !scene.m_prefabs.Contains(Prefab))
				{
					scene.m_prefabs.Add(Prefab);
				}
				if (scene.m_namedPrefabs != null)
				{
					scene.m_namedPrefabs[stableHashCode] = Prefab;
				}
			}
		}

		internal static void UnlockKnownRecipe(Player player)
		{
			if (player?.m_knownRecipes != null && !player.m_knownRecipes.Contains("$item_hearthstone"))
			{
				player.m_knownRecipes.Add("$item_hearthstone");
			}
		}

		internal static void EnsureAvailable(Player player, List<Recipe> available)
		{
			if ((Object)(object)player == (Object)null || available == null || (Object)(object)Recipe == (Object)null || (Object)(object)Recipe.m_item == (Object)null)
			{
				return;
			}
			UnlockKnownRecipe(player);
			if ((Object)(object)Recipe.m_craftingStation == (Object)null && (Object)(object)ObjectDB.instance != (Object)null)
			{
				EnsureRecipe(ObjectDB.instance);
			}
			if ((Object)(object)Recipe.m_craftingStation == (Object)null)
			{
				Plugin.Log.LogWarning((object)"Hearthstone recipe still has no crafting station.");
				return;
			}
			CraftingStation currentCraftingStation = player.GetCurrentCraftingStation();
			if ((Object)(object)currentCraftingStation == (Object)null || !IsWorkbenchStation(currentCraftingStation))
			{
				return;
			}
			if ((Object)(object)Recipe.m_craftingStation == (Object)null || Recipe.m_craftingStation.m_name != currentCraftingStation.m_name)
			{
				Recipe.m_craftingStation = currentCraftingStation;
			}
			for (int i = 0; i < available.Count; i++)
			{
				if ((Object)(object)available[i] == (Object)(object)Recipe || ((Object)(object)available[i] != (Object)null && (Object)(object)available[i].m_item != (Object)null && available[i].m_item.m_itemData != null && available[i].m_item.m_itemData.m_shared != null && available[i].m_item.m_itemData.m_shared.m_name == "$item_hearthstone"))
				{
					return;
				}
			}
			available.Add(Recipe);
			Plugin.Log.LogInfo((object)("Injected Hearthstone into craft list at station " + currentCraftingStation.m_name));
		}

		private static bool IsWorkbenchStation(CraftingStation station)
		{
			if ((Object)(object)station == (Object)null)
			{
				return false;
			}
			string obj = station.m_name ?? string.Empty;
			string text = ((Object)station).name ?? string.Empty;
			if (obj.IndexOf("workbench", StringComparison.OrdinalIgnoreCase) < 0)
			{
				return text.IndexOf("workbench", StringComparison.OrdinalIgnoreCase) >= 0;
			}
			return true;
		}

		internal static void GiveToPlayer(Player player)
		{
			if ((Object)(object)player == (Object)null)
			{
				return;
			}
			if (((Object)(object)Prefab == (Object)null || ((object)Prefab).Equals((object?)null)) && (Object)(object)ObjectDB.instance != (Object)null)
			{
				TryRegister(ObjectDB.instance);
			}
			if ((Object)(object)Prefab == (Object)null || ((object)Prefab).Equals((object?)null))
			{
				Plugin.Log.LogWarning((object)"Cannot give Hearthstone — prefab missing.");
				return;
			}
			Inventory inventory = ((Humanoid)player).GetInventory();
			if (inventory != null)
			{
				ItemData val = Prefab.GetComponent<ItemDrop>().m_itemData.Clone();
				val.m_stack = 1;
				val.m_quality = 1;
				val.m_durability = val.m_shared.m_maxDurability;
				val.m_crafterID = player.GetPlayerID();
				val.m_crafterName = player.GetPlayerName();
				val.m_dropPrefab = Prefab;
				val.m_equipped = false;
				EnsureDropPrefab(val);
				if (!inventory.AddItem(val))
				{
					((Character)player).Message((MessageType)2, "Inventory full", 0, (Sprite)null);
				}
				else
				{
					((Character)player).Message((MessageType)2, "$item_hearthstone", 0, (Sprite)null);
				}
			}
		}

		internal static void ApplyItemStats(SharedData shared)
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			if (shared != null)
			{
				shared.m_name = "$item_hearthstone";
				shared.m_description = "$item_hearthstone_desc";
				shared.m_subtitle = "$item_hearthstone_subtitle";
				shared.m_weight = HearthstoneConfig.Weight.Value;
				shared.m_maxStackSize = 1;
				shared.m_maxQuality = 1;
				shared.m_itemType = (ItemType)16;
				shared.m_teleportable = true;
				shared.m_equipDuration = 0f;
				shared.m_useDurability = true;
				shared.m_maxDurability = Mathf.Max(1, HearthstoneConfig.Uses.Value);
				shared.m_useDurabilityDrain = 0f;
				shared.m_durabilityDrain = 0f;
				shared.m_destroyBroken = true;
				shared.m_canBeReparied = false;
				shared.m_food = 0f;
				shared.m_foodStamina = 0f;
				shared.m_foodEitr = 0f;
				shared.m_foodBurnTime = 0f;
				shared.m_consumeStatusEffect = null;
				shared.m_equipStatusEffect = null;
				shared.m_questItem = false;
				shared.m_dlc = string.Empty;
				HearthstoneVisuals.ApplyIcon(shared);
			}
		}

		internal static void EnsureDropPrefab(ItemData item)
		{
			if (item != null)
			{
				if (((Object)(object)Prefab == (Object)null || ((object)Prefab).Equals((object?)null)) && (Object)(object)ObjectDB.instance != (Object)null)
				{
					TryRegister(ObjectDB.instance);
				}
				if ((Object)(object)Prefab != (Object)null && !((object)Prefab).Equals((object?)null))
				{
					item.m_dropPrefab = Prefab;
				}
			}
		}

		internal static string BuildTooltip(ItemData item)
		{
			EnsureDropPrefab(item);
			int num = ((item != null) ? Mathf.Max(0, Mathf.CeilToInt(item.m_durability)) : 0);
			int num2 = ((item?.m_shared != null) ? Mathf.Max(1, Mathf.CeilToInt(item.m_shared.m_maxDurability)) : HearthstoneConfig.Uses.Value);
			string text = Localization.instance.Localize("$item_hearthstone_flavor");
			string text2 = Localization.instance.Localize("$item_hearthstone_desc");
			string text3 = Localization.instance.Localize("$item_hearthstone_uses", new string[2]
			{
				num.ToString(),
				num2.ToString()
			});
			string text4 = Localization.instance.Localize("$item_hearthstone_usetip");
			string text5 = ((item != null) ? item.GetWeight(-1).ToString("0.0") : HearthstoneConfig.Weight.Value.ToString("0.0"));
			return text + "\n\n" + text2 + "\n\n" + text3 + "\n" + text4 + "\n$item_weight: <color=orange>" + text5 + "</color>";
		}

		internal static void ConsumeOneUse(Player player, ItemData item)
		{
			if ((Object)(object)player == (Object)null || item == null)
			{
				return;
			}
			item.m_durability = Mathf.Max(0f, item.m_durability - 1f);
			Inventory inventory = ((Humanoid)player).GetInventory();
			if (item.m_durability > 0f)
			{
				if (inventory != null)
				{
					inventory.Changed();
				}
			}
			else if (inventory != null)
			{
				inventory.RemoveItem(item);
			}
		}

		private static void EnsureUniqueShared(ItemDrop itemDrop)
		{
			if (itemDrop?.m_itemData?.m_shared != null)
			{
				object? obj = ((object)itemDrop.m_itemData.m_shared).GetType().GetMethod("MemberwiseClone", BindingFlags.Instance | BindingFlags.NonPublic)?.Invoke(itemDrop.m_itemData.m_shared, null);
				SharedData val = (SharedData)((obj is SharedData) ? obj : null);
				if (val != null)
				{
					itemDrop.m_itemData.m_shared = val;
				}
			}
		}

		private static bool ShouldRebuildPrefab(ObjectDB odb)
		{
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Invalid comparison between Unknown and I4
			if ((Object)(object)Prefab == (Object)null || ((object)Prefab).Equals((object?)null))
			{
				return false;
			}
			GameObject itemPrefab = odb.GetItemPrefab("SurtlingCore");
			if ((Object)(object)itemPrefab == (Object)null || ((object)itemPrefab).Equals((object?)null))
			{
				return false;
			}
			ItemDrop component = Prefab.GetComponent<ItemDrop>();
			if (component?.m_itemData?.m_shared == null)
			{
				return true;
			}
			if ((int)component.m_itemData.m_shared.m_itemType != 16)
			{
				return true;
			}
			if (component.m_itemData.m_shared.m_name != "$item_hearthstone")
			{
				return true;
			}
			return false;
		}

		private static GameObject FindExisting(ObjectDB odb)
		{
			try
			{
				GameObject itemPrefab = odb.GetItemPrefab("VO_Hearthstone");
				if ((Object)(object)itemPrefab != (Object)null && !((object)itemPrefab).Equals((object?)null))
				{
					return itemPrefab;
				}
			}
			catch
			{
			}
			if (odb.m_items == null)
			{
				return null;
			}
			foreach (GameObject item in odb.m_items)
			{
				if ((Object)(object)item != (Object)null && !((object)item).Equals((object?)null) && ((Object)item).name == "VO_Hearthstone")
				{
					return item;
				}
			}
			return null;
		}

		internal static void SanitizeObjectDb(ObjectDB odb)
		{
			if (odb?.m_items != null)
			{
				int num = odb.m_items.RemoveAll((GameObject go) => (Object)(object)go == (Object)null || ((object)go).Equals((object?)null));
				if (num > 0)
				{
					Plugin.Log.LogWarning((object)("Removed " + num + " null prefab(s) from ObjectDB.m_items."));
				}
			}
		}

		private static void RegisterInLookups(ObjectDB odb)
		{
			if (!((Object)(object)odb == (Object)null) && !((Object)(object)Prefab == (Object)null) && !((object)Prefab).Equals((object?)null))
			{
				int stableHashCode = StringExtensionMethods.GetStableHashCode("VO_Hearthstone");
				if (odb.m_itemByHash != null)
				{
					odb.m_itemByHash[stableHashCode] = Prefab;
				}
				ItemDrop component = Prefab.GetComponent<ItemDrop>();
				if (component?.m_itemData?.m_shared != null && odb.m_itemByData != null)
				{
					odb.m_itemByData[component.m_itemData.m_shared] = Prefab;
				}
			}
		}

		private static bool CreatePrefab(ObjectDB odb)
		{
			//IL_01f0: Unknown result type (might be due to invalid IL or missing references)
			if (_prefabCreated && (Object)(object)Prefab != (Object)null && !((object)Prefab).Equals((object?)null))
			{
				return true;
			}
			GameObject val = null;
			string text = null;
			string[] meshPrefabCandidates = MeshPrefabCandidates;
			foreach (string text2 in meshPrefabCandidates)
			{
				val = odb.GetItemPrefab(text2);
				if ((Object)(object)val != (Object)null && !((object)val).Equals((object?)null))
				{
					text = text2;
					break;
				}
			}
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Log.LogError((object)"No suitable vanilla item prefab found to clone for Hearthstone.");
				return false;
			}
			bool activeSelf = val.activeSelf;
			val.SetActive(false);
			Prefab = Object.Instantiate<GameObject>(val);
			val.SetActive(activeSelf);
			((Object)Prefab).name = "VO_Hearthstone";
			Prefab.SetActive(false);
			Object.DontDestroyOnLoad((Object)(object)Prefab);
			if (((Object)Prefab).name.EndsWith("(Clone)", StringComparison.Ordinal))
			{
				((Object)Prefab).name = "VO_Hearthstone";
			}
			ItemDrop component = Prefab.GetComponent<ItemDrop>();
			if ((Object)(object)component == (Object)null)
			{
				Plugin.Log.LogError((object)("Cloned prefab has no ItemDrop (" + text + ")."));
				Object.Destroy((Object)(object)Prefab);
				Prefab = null;
				return false;
			}
			EnsureUniqueShared(component);
			ApplyItemStats(component.m_itemData.m_shared);
			component.m_itemData.m_durability = component.m_itemData.m_shared.m_maxDurability;
			component.m_itemData.m_quality = 1;
			component.m_itemData.m_stack = 1;
			component.m_itemData.m_crafterID = 0L;
			component.m_itemData.m_crafterName = string.Empty;
			component.m_itemData.m_dropPrefab = Prefab;
			component.m_itemData.m_equipped = false;
			component.m_autoPickup = true;
			component.m_autoDestroy = true;
			((Object)component).name = "VO_Hearthstone";
			ZNetView component2 = Prefab.GetComponent<ZNetView>();
			if ((Object)(object)component2 != (Object)null)
			{
				component2.m_persistent = true;
				component2.m_distant = false;
				component2.m_type = (ObjectType)0;
			}
			Piece component3 = Prefab.GetComponent<Piece>();
			if ((Object)(object)component3 != (Object)null)
			{
				Object.Destroy((Object)(object)component3);
			}
			if (!odb.m_items.Contains(Prefab))
			{
				odb.m_items.Add(Prefab);
			}
			_prefabCreated = true;
			Plugin.Log.LogInfo((object)("Created Hearthstone prefab from " + text + " (own SharedData + ZNet hash 'VO_Hearthstone')."));
			return true;
		}

		private static void EnsureRecipe(ObjectDB odb)
		{
			if ((Object)(object)Prefab == (Object)null || ((object)Prefab).Equals((object?)null))
			{
				return;
			}
			ItemDrop component = Prefab.GetComponent<ItemDrop>();
			if ((Object)(object)component == (Object)null)
			{
				return;
			}
			string text = "Recipe_VO_Hearthstone";
			Recipe val = Recipe;
			if ((Object)(object)val == (Object)null && odb.m_recipes != null)
			{
				foreach (Recipe recipe in odb.m_recipes)
				{
					if ((Object)(object)recipe != (Object)null && ((Object)recipe).name == text)
					{
						val = recipe;
						break;
					}
				}
			}
			CraftingStation val2 = FindWorkbench(odb);
			if ((Object)(object)val == (Object)null)
			{
				GameObject itemPrefab = odb.GetItemPrefab("FineWood");
				GameObject itemPrefab2 = odb.GetItemPrefab("Resin");
				GameObject itemPrefab3 = odb.GetItemPrefab("GreydwarfEye");
				GameObject itemPrefab4 = odb.GetItemPrefab("SurtlingCore");
				if ((Object)(object)itemPrefab == (Object)null || (Object)(object)itemPrefab2 == (Object)null || (Object)(object)itemPrefab3 == (Object)null || (Object)(object)itemPrefab4 == (Object)null)
				{
					Plugin.Log.LogWarning((object)"Missing recipe materials for Hearthstone.");
					return;
				}
				val = ScriptableObject.CreateInstance<Recipe>();
				((Object)val).name = text;
				val.m_item = component;
				val.m_amount = 1;
				val.m_enabled = true;
				val.m_resources = (Requirement[])(object)new Requirement[4]
				{
					NewReq(itemPrefab, 10),
					NewReq(itemPrefab2, 10),
					NewReq(itemPrefab3, 5),
					NewReq(itemPrefab4, 2)
				};
				odb.m_recipes.Add(val);
				Plugin.Log.LogInfo((object)"Added Hearthstone recipe.");
			}
			val.m_item = component;
			val.m_enabled = true;
			val.m_minStationLevel = 1;
			if ((Object)(object)val2 != (Object)null)
			{
				val.m_craftingStation = val2;
			}
			if (odb.m_recipes != null && !odb.m_recipes.Contains(val))
			{
				odb.m_recipes.Add(val);
			}
			Recipe = val;
			string text2 = (((Object)(object)val2 != (Object)null) ? (((Object)val2).name + " / " + val2.m_name) : "NULL");
			Plugin.Log.LogInfo((object)("Hearthstone recipe OK. Station=" + text2));
		}

		private static Requirement NewReq(GameObject prefab, int amount)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Expected O, but got Unknown
			return new Requirement
			{
				m_resItem = prefab.GetComponent<ItemDrop>(),
				m_amount = amount,
				m_amountPerLevel = 0,
				m_recover = false
			};
		}

		private static CraftingStation FindWorkbench(ObjectDB odb)
		{
			if ((Object)(object)ZNetScene.instance != (Object)null)
			{
				GameObject prefab = ZNetScene.instance.GetPrefab("piece_workbench");
				if ((Object)(object)prefab != (Object)null)
				{
					CraftingStation component = prefab.GetComponent<CraftingStation>();
					if ((Object)(object)component != (Object)null)
					{
						return component;
					}
				}
			}
			if (odb?.m_recipes == null)
			{
				return null;
			}
			foreach (Recipe recipe in odb.m_recipes)
			{
				if (!((Object)(object)recipe?.m_craftingStation == (Object)null))
				{
					string name = ((Object)recipe.m_craftingStation).name;
					string text = recipe.m_craftingStation.m_name ?? string.Empty;
					if (name == "piece_workbench" || name.IndexOf("workbench", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("workbench", StringComparison.OrdinalIgnoreCase) >= 0)
					{
						return recipe.m_craftingStation;
					}
				}
			}
			return null;
		}

		private static bool IsObjectDbReady(ObjectDB odb)
		{
			if (odb.m_items != null && odb.m_items.Count > 0)
			{
				return (Object)(object)odb.GetItemPrefab("Amber") != (Object)null;
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(ObjectDB), "Awake")]
	internal static class ObjectDB_Awake_Patch
	{
		private static void Postfix(ObjectDB __instance)
		{
			HearthstoneItem.TryRegister(__instance);
		}
	}
	[HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")]
	internal static class ObjectDB_CopyOtherDB_Patch
	{
		private static void Prefix(ObjectDB other)
		{
			HearthstoneItem.SanitizeObjectDb(other);
		}

		private static void Postfix(ObjectDB __instance)
		{
			HearthstoneItem.TryRegister(__instance);
		}
	}
	[HarmonyPatch(typeof(ZNetScene), "Awake")]
	internal static class ZNetScene_Awake_Patch
	{
		private static void Postfix(ZNetScene __instance)
		{
			if ((Object)(object)ObjectDB.instance != (Object)null)
			{
				HearthstoneItem.TryRegister(ObjectDB.instance);
			}
			HearthstoneItem.TryRegisterZNetScene(__instance);
		}
	}
	[HarmonyPatch(typeof(Player), "UpdateKnownRecipesList")]
	internal static class Player_UpdateKnownRecipesList_Patch
	{
		private static void Postfix(Player __instance)
		{
			HearthstoneItem.UnlockKnownRecipe(__instance);
		}
	}
	[HarmonyPatch(typeof(Player), "OnSpawned")]
	internal static class Player_OnSpawned_Patch
	{
		private static void Postfix(Player __instance)
		{
			HearthstoneItem.UnlockKnownRecipe(__instance);
			if (((__instance != null) ? ((Humanoid)__instance).GetInventory() : null) == null)
			{
				return;
			}
			foreach (ItemData allItem in ((Humanoid)__instance).GetInventory().GetAllItems())
			{
				if (HearthstoneItem.IsHearthstone(allItem))
				{
					HearthstoneItem.EnsureDropPrefab(allItem);
				}
			}
		}
	}
	[HarmonyPatch(typeof(Player), "GetAvailableRecipes")]
	internal static class Player_GetAvailableRecipes_Patch
	{
		private static void Postfix(Player __instance, ref List<Recipe> available)
		{
			if (HearthstoneConfig.EnableMod.Value)
			{
				HearthstoneItem.EnsureAvailable(__instance, available);
			}
		}
	}
	internal static class HearthstoneTeleport
	{
		internal static bool TryGetDestination(Player player, out Vector3 position, out string failToken)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			position = Vector3.zero;
			failToken = null;
			if ((Object)(object)player == (Object)null || (Object)(object)Game.instance == (Object)null)
			{
				failToken = "$msg_hearthstone_nobed";
				return false;
			}
			PlayerProfile playerProfile = Game.instance.GetPlayerProfile();
			if (playerProfile == null)
			{
				failToken = "$msg_hearthstone_nobed";
				return false;
			}
			if (HearthstoneConfig.RequireBoundBed.Value)
			{
				if (!playerProfile.HaveCustomSpawnPoint())
				{
					failToken = "$msg_hearthstone_nobed";
					return false;
				}
				position = playerProfile.GetCustomSpawnPoint();
				return true;
			}
			if (playerProfile.HaveCustomSpawnPoint())
			{
				position = playerProfile.GetCustomSpawnPoint();
				return true;
			}
			position = playerProfile.GetHomePoint();
			return true;
		}

		internal static bool CanTeleportInventory(Player player, out string failToken)
		{
			failToken = null;
			if ((Object)(object)player == (Object)null)
			{
				return false;
			}
			if (HearthstoneConfig.AllowTeleportWithRestrictedItems.Value)
			{
				return true;
			}
			Inventory inventory = ((Humanoid)player).GetInventory();
			if (inventory == null)
			{
				return true;
			}
			if (inventory.IsTeleportable())
			{
				return true;
			}
			failToken = "$msg_noteleport";
			return false;
		}

		internal static bool TryTeleport(Player player)
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			if (!TryGetDestination(player, out var position, out var failToken))
			{
				if (!string.IsNullOrEmpty(failToken))
				{
					((Character)player).Message((MessageType)2, failToken, 0, (Sprite)null);
				}
				return false;
			}
			if (!CanTeleportInventory(player, out var failToken2))
			{
				if (!string.IsNullOrEmpty(failToken2))
				{
					((Character)player).Message((MessageType)2, failToken2, 0, (Sprite)null);
				}
				return false;
			}
			Quaternion rotation = ((Component)player).transform.rotation;
			if (!((Character)player).TeleportTo(position, rotation, true))
			{
				((Character)player).Message((MessageType)2, "$msg_hearthstone_blocked", 0, (Sprite)null);
				return false;
			}
			return true;
		}
	}
	internal static class HearthstoneVisuals
	{
		private static Sprite _icon;

		private static MethodInfo _loadImage;

		internal static Sprite GetIcon()
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Expected O, but got Unknown
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_icon != (Object)null)
			{
				return _icon;
			}
			byte[] array = LoadEmbeddedPng();
			if (array == null || array.Length == 0)
			{
				Plugin.Log.LogWarning((object)"Hearthstone icon resource missing.");
				return null;
			}
			Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false);
			if (!TryLoadImage(val, array))
			{
				Plugin.Log.LogWarning((object)"Failed to LoadImage hearthstone icon.");
				return null;
			}
			((Texture)val).wrapMode = (TextureWrapMode)1;
			((Texture)val).filterMode = (FilterMode)1;
			((Object)val).name = "VO_Hearthstone_Icon";
			_icon = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f);
			((Object)_icon).name = "VO_Hearthstone_Icon";
			return _icon;
		}

		internal static void ApplyIcon(SharedData shared)
		{
			Sprite icon = GetIcon();
			if (shared != null && !((Object)(object)icon == (Object)null))
			{
				shared.m_icons = (Sprite[])(object)new Sprite[1] { icon };
			}
		}

		private static bool TryLoadImage(Texture2D tex, byte[] bytes)
		{
			if (_loadImage == null)
			{
				Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
				for (int i = 0; i < assemblies.Length; i++)
				{
					Type type = assemblies[i].GetType("UnityEngine.ImageConversion");
					if (!(type == null))
					{
						_loadImage = type.GetMethod("LoadImage", BindingFlags.Static | BindingFlags.Public, null, new Type[2]
						{
							typeof(Texture2D),
							typeof(byte[])
						}, null);
						if (_loadImage != null)
						{
							break;
						}
					}
				}
			}
			if (_loadImage == null)
			{
				return false;
			}
			object obj = _loadImage.Invoke(null, new object[2] { tex, bytes });
			bool flag = default(bool);
			int num;
			if (obj is bool)
			{
				flag = (bool)obj;
				num = 1;
			}
			else
			{
				num = 0;
			}
			return (byte)((uint)num & (flag ? 1u : 0u)) != 0;
		}

		private static byte[] LoadEmbeddedPng()
		{
			Assembly assembly = typeof(HearthstoneVisuals).Assembly;
			string text = null;
			string[] manifestResourceNames = assembly.GetManifestResourceNames();
			foreach (string text2 in manifestResourceNames)
			{
				if (text2.EndsWith("hearthstone_icon.png", StringComparison.OrdinalIgnoreCase))
				{
					text = text2;
					break;
				}
			}
			if (text == null)
			{
				return null;
			}
			using Stream stream = assembly.GetManifestResourceStream(text);
			if (stream == null)
			{
				return null;
			}
			using MemoryStream memoryStream = new MemoryStream();
			stream.CopyTo(memoryStream);
			return memoryStream.ToArray();
		}
	}
	[HarmonyPatch(typeof(Localization), "SetupLanguage")]
	internal static class Localization_SetupLanguage_Patch
	{
		private static void Postfix(Localization __instance, string language)
		{
			Inject(__instance, language);
		}

		internal static void Inject(Localization loc, string language)
		{
			if (loc != null)
			{
				if (language != null && (language.StartsWith("Spanish") || language == "Español" || language == "es" || language.IndexOf("Spanish", StringComparison.OrdinalIgnoreCase) >= 0))
				{
					Add(loc, "item_hearthstone", "Piedra del hogar");
					Add(loc, "item_hearthstone_subtitle", "Reliquia del hogar");
					Add(loc, "item_hearthstone_flavor", "<color=#E8C56B><i>«Return to thy hearth and home.»</i></color>");
					Add(loc, "item_hearthstone_desc", "Una piedra cálida que recuerda el fuego de tu cama vinculada.\nCanalízala con <color=orange>clic derecho</color> para volver a casa.");
					Add(loc, "item_hearthstone_uses", "Usos: <color=orange>$1 / $2</color>");
					Add(loc, "item_hearthstone_usetip", "<color=yellow>Quédate quieto mientras canalizas. Moverte cancela el ritual.</color>");
					Add(loc, "hud_hearthstone_casting", "Canalizando el hogar");
					Add(loc, "msg_hearthstone_nobed", "No tienes una cama vinculada.");
					Add(loc, "msg_hearthstone_cooldown", "La Piedra del hogar se está recuperando ($1)");
					Add(loc, "msg_hearthstone_notowner", "Esta Piedra del hogar pertenece a otro vikingo.");
					Add(loc, "msg_hearthstone_alreadyhave", "Ya posees una Piedra del hogar.");
					Add(loc, "msg_hearthstone_cancelled", "Canalización cancelada.");
					Add(loc, "msg_hearthstone_casting", "Canalizando el hogar...");
					Add(loc, "msg_hearthstone_blocked", "No se puede teletransportar ahora.");
				}
				else
				{
					Add(loc, "item_hearthstone", "Hearthstone");
					Add(loc, "item_hearthstone_subtitle", "Hearth relic");
					Add(loc, "item_hearthstone_flavor", "<color=#E8C56B><i>«Return to thy hearth and home.»</i></color>");
					Add(loc, "item_hearthstone_desc", "A warm stone that remembers the fire of your bound bed.\n<color=orange>Right-click</color> to channel and return home.");
					Add(loc, "item_hearthstone_uses", "Uses: <color=orange>$1 / $2</color>");
					Add(loc, "item_hearthstone_usetip", "<color=yellow>Stand still while channeling. Moving cancels the ritual.</color>");
					Add(loc, "hud_hearthstone_casting", "Channeling home");
					Add(loc, "msg_hearthstone_nobed", "You have no bound bed.");
					Add(loc, "msg_hearthstone_cooldown", "Hearthstone is recovering ($1)");
					Add(loc, "msg_hearthstone_notowner", "This Hearthstone belongs to another viking.");
					Add(loc, "msg_hearthstone_alreadyhave", "You already have a Hearthstone.");
					Add(loc, "msg_hearthstone_cancelled", "Channel cancelled.");
					Add(loc, "msg_hearthstone_casting", "Channeling home...");
					Add(loc, "msg_hearthstone_blocked", "Cannot teleport right now.");
				}
			}
		}

		private static void Add(Localization loc, string key, string value)
		{
			loc.AddWord(key, value);
		}
	}
	[HarmonyPatch(typeof(FejdStartup), "Awake")]
	internal static class FejdStartup_Localization_Patch
	{
		private static void Postfix()
		{
			if (Localization.instance != null)
			{
				Localization_SetupLanguage_Patch.Inject(Localization.instance, Localization.instance.GetSelectedLanguage());
			}
		}
	}
	[HarmonyPatch(typeof(Humanoid), "UseItem")]
	internal static class Humanoid_UseItem_Patch
	{
		private static bool Prefix(Humanoid __instance, ItemData item)
		{
			Player val = (Player)(object)((__instance is Player) ? __instance : null);
			if (val == null || (Object)(object)val != (Object)(object)Player.m_localPlayer)
			{
				return true;
			}
			if (!HearthstoneConfig.EnableMod.Value || !HearthstoneItem.IsHearthstone(item))
			{
				return true;
			}
			HearthstoneItem.EnsureDropPrefab(item);
			HearthstoneCaster.TryBegin(val, item);
			return false;
		}
	}
	[HarmonyPatch(typeof(Humanoid), "DropItem")]
	internal static class Humanoid_DropItem_Patch
	{
		private static void Prefix(ItemData item)
		{
			if (HearthstoneItem.IsHearthstone(item))
			{
				HearthstoneItem.EnsureDropPrefab(item);
			}
		}
	}
	[HarmonyPatch(typeof(ItemDrop), "DropItem")]
	internal static class ItemDrop_DropItem_Patch
	{
		private static void Prefix(ItemData item)
		{
			if (HearthstoneItem.IsHearthstone(item))
			{
				HearthstoneItem.EnsureDropPrefab(item);
			}
		}

		private static void Postfix(ItemDrop __result)
		{
			if ((Object)(object)__result == (Object)null)
			{
				return;
			}
			if (!((Component)__result).gameObject.activeSelf)
			{
				((Component)__result).gameObject.SetActive(true);
			}
			if (HearthstoneItem.IsHearthstone(__result.m_itemData))
			{
				__result.m_itemData.m_dropPrefab = HearthstoneItem.Prefab;
				((Object)__result).name = "VO_Hearthstone";
				if ((Object)(object)ZNetScene.instance != (Object)null)
				{
					HearthstoneItem.TryRegisterZNetScene(ZNetScene.instance);
				}
			}
		}
	}
	[HarmonyPatch(typeof(ItemData), "GetTooltip", new Type[]
	{
		typeof(ItemData),
		typeof(int),
		typeof(bool),
		typeof(float),
		typeof(int)
	})]
	internal static class ItemData_GetTooltip_Static_Patch
	{
		private static bool Prefix(ItemData item, ref string __result)
		{
			if (!HearthstoneConfig.EnableMod.Value || !HearthstoneItem.IsHearthstone(item))
			{
				return true;
			}
			__result = HearthstoneItem.BuildTooltip(item);
			return false;
		}
	}
	[HarmonyPatch(typeof(ItemData), "GetTooltip", new Type[] { typeof(int) })]
	internal static class ItemData_GetTooltip_Instance_Patch
	{
		private static bool Prefix(ItemData __instance, ref string __result)
		{
			if (!HearthstoneConfig.EnableMod.Value || !HearthstoneItem.IsHearthstone(__instance))
			{
				return true;
			}
			__result = HearthstoneItem.BuildTooltip(__instance);
			return false;
		}
	}
	[HarmonyPatch(typeof(Player), "UpdateActionQueue")]
	internal static class Player_UpdateActionQueue_Patch
	{
		private static bool Prefix(Player __instance, float dt)
		{
			if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer)
			{
				return true;
			}
			return !HearthstoneCaster.TryUpdateActionQueue(__instance, dt);
		}
	}
	[HarmonyPatch(typeof(Hud), "UpdateActionProgress")]
	internal static class Hud_UpdateActionProgress_Patch
	{
		private static void Postfix(Player player)
		{
			if (!((Object)(object)player != (Object)(object)Player.m_localPlayer) && HearthstoneCaster.IsCasting)
			{
				HearthstoneCaster.EnsureActionBarVisible(player);
			}
		}
	}
	[HarmonyPatch(typeof(Humanoid), "EquipItem")]
	internal static class Humanoid_EquipItem_Patch
	{
		private static bool Prefix(ItemData item)
		{
			return !HearthstoneItem.IsHearthstone(item);
		}
	}
	[HarmonyPatch(typeof(Player), "SetWeaponLoaded")]
	internal static class Player_SetWeaponLoaded_Patch
	{
		private static bool Prefix(Player __instance, ItemData item)
		{
			if (!HearthstoneItem.IsHearthstone(item))
			{
				return true;
			}
			if ((Object)(object)__instance == (Object)(object)Player.m_localPlayer && HearthstoneCaster.IsCasting)
			{
				HearthstoneCaster.CompleteFromActionQueue(__instance, item);
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(Player), "Update")]
	internal static class Player_Update_Patch
	{
		private static void Postfix(Player __instance)
		{
			if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer))
			{
				HearthstoneCaster.Update(__instance, Time.deltaTime);
			}
		}
	}
	[HarmonyPatch(typeof(Player), "OnDamaged")]
	internal static class Player_OnDamaged_Patch
	{
		private static void Prefix(Player __instance, HitData hit)
		{
			if (HearthstoneConfig.EnableMod.Value && HearthstoneConfig.CancelOnDamage.Value && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && HearthstoneCaster.IsCasting && hit != null && !(hit.GetTotalDamage() <= 0f))
			{
				HearthstoneCaster.Cancel(__instance, showMessage: true);
			}
		}
	}
	[HarmonyPatch(typeof(Character), "Jump")]
	internal static class Character_Jump_Patch
	{
		private static void Prefix(Character __instance)
		{
			if (HearthstoneConfig.EnableMod.Value && HearthstoneConfig.CancelOnJump.Value)
			{
				Player val = (Player)(object)((__instance is Player) ? __instance : null);
				if (!((Object)(object)val == (Object)null) && !((Object)(object)val != (Object)(object)Player.m_localPlayer) && HearthstoneCaster.IsCasting)
				{
					HearthstoneCaster.Cancel(val, showMessage: true);
				}
			}
		}
	}
	[HarmonyPatch(typeof(InventoryGui), "DoCrafting")]
	internal static class InventoryGui_DoCrafting_Patch
	{
		private static bool Prefix(Player player)
		{
			if (!HearthstoneConfig.EnableMod.Value || (Object)(object)player == (Object)null)
			{
				return true;
			}
			InventoryGui instance = InventoryGui.instance;
			Recipe val = (((Object)(object)instance != (Object)null) ? instance.m_craftRecipe : null);
			if (val?.m_item?.m_itemData == null)
			{
				return true;
			}
			if (!HearthstoneItem.IsHearthstone(val.m_item.m_itemData))
			{
				return true;
			}
			if (HearthstoneItem.CountInInventory(player) <= 0)
			{
				return true;
			}
			((Character)player).Message((MessageType)2, "$msg_hearthstone_alreadyhave", 0, (Sprite)null);
			return false;
		}
	}
	[HarmonyPatch(typeof(InventoryGrid), "UpdateGui")]
	internal static class InventoryGrid_UpdateGui_Patch
	{
		private static void Postfix(InventoryGrid __instance, Player player)
		{
			HearthstoneInventoryUi.ApplyCooldownOverlays(__instance, player);
		}
	}
	[HarmonyPatch(typeof(HotkeyBar), "UpdateIcons")]
	internal static class HotkeyBar_UpdateIcons_Patch
	{
		private static void Postfix(HotkeyBar __instance, Player player)
		{
			HearthstoneInventoryUi.ApplyHotkeyCooldown(__instance, player);
		}
	}
	[HarmonyPatch(typeof(Terminal), "InitTerminal")]
	internal static class Terminal_InitTerminal_Patch
	{
		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static ConsoleEvent <>9__0_0;

			internal void <Postfix>b__0_0(ConsoleEventArgs args)
			{
				Player localPlayer = Player.m_localPlayer;
				if ((Object)(object)localPlayer == (Object)null)
				{
					Terminal context = args.Context;
					if (context != null)
					{
						context.AddString("No local player.");
					}
					return;
				}
				HearthstoneItem.GiveToPlayer(localPlayer);
				Terminal context2 = args.Context;
				if (context2 != null)
				{
					context2.AddString("Gave Hearthstone.");
				}
			}
		}

		private static void Postfix()
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Expected O, but got Unknown
			object obj = <>c.<>9__0_0;
			if (obj == null)
			{
				ConsoleEvent val = delegate(ConsoleEventArgs args)
				{
					Player localPlayer = Player.m_localPlayer;
					if ((Object)(object)localPlayer == (Object)null)
					{
						Terminal context = args.Context;
						if (context != null)
						{
							context.AddString("No local player.");
						}
					}
					else
					{
						HearthstoneItem.GiveToPlayer(localPlayer);
						Terminal context2 = args.Context;
						if (context2 != null)
						{
							context2.AddString("Gave Hearthstone.");
						}
					}
				};
				<>c.<>9__0_0 = val;
				obj = (object)val;
			}
			new ConsoleCommand("hearthstone", "Give yourself a Hearthstone (cheat)", (ConsoleEvent)obj, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, true);
		}
	}
	internal static class HearthstoneInventoryUi
	{
		private static readonly Dictionary<Image, Color> OriginalIconColors = new Dictionary<Image, Color>();

		internal static void ApplyCooldownOverlays(InventoryGrid grid, Player player)
		{
			if ((Object)(object)grid == (Object)null || (Object)(object)player == (Object)null || !HearthstoneConfig.EnableMod.Value || !HearthstoneCooldown.IsOnCooldown(player, out var remainingSeconds))
			{
				return;
			}
			string label = HearthstoneCooldown.FormatCompact(remainingSeconds);
			float cooldownFill = GetCooldownFill(remainingSeconds);
			List<Element> elements = grid.m_elements;
			if (elements == null)
			{
				return;
			}
			Inventory inventory = grid.m_inventory;
			if (inventory == null)
			{
				return;
			}
			foreach (Element item in elements)
			{
				if (item != null && item.m_pos.x >= 0 && HearthstoneItem.IsHearthstone(inventory.GetItemAt(item.m_pos.x, item.m_pos.y)))
				{
					ApplyElementCooldown(item.m_icon, item.m_amount, item.m_durability, label, cooldownFill);
				}
			}
		}

		internal static void ApplyHotkeyCooldown(HotkeyBar bar, Player player)
		{
			if ((Object)(object)bar == (Object)null || (Object)(object)player == (Object)null || !HearthstoneConfig.EnableMod.Value || !HearthstoneCooldown.IsOnCooldown(player, out var remainingSeconds))
			{
				return;
			}
			string label = HearthstoneCooldown.FormatCompact(remainingSeconds);
			float cooldownFill = GetCooldownFill(remainingSeconds);
			if (bar.m_elements == null || bar.m_items == null)
			{
				return;
			}
			for (int i = 0; i < bar.m_elements.Count && i < bar.m_items.Count; i++)
			{
				if (HearthstoneItem.IsHearthstone(bar.m_items[i]))
				{
					ElementData val = bar.m_elements[i];
					if (val != null)
					{
						ApplyElementCooldown(val.m_icon, val.m_amount, val.m_durability, label, cooldownFill);
					}
				}
			}
		}

		private static void ApplyElementCooldown(Image icon, TMP_Text amount, GuiBar durability, string label, float fill)
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: 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_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)amount != (Object)null)
			{
				((Component)amount).gameObject.SetActive(true);
				amount.text = label;
				((Graphic)amount).color = new Color(1f, 0.85f, 0.35f, 1f);
			}
			if ((Object)(object)icon != (Object)null)
			{
				if (!OriginalIconColors.ContainsKey(icon))
				{
					OriginalIconColors[icon] = ((Graphic)icon).color;
				}
				Color val = OriginalIconColors[icon];
				((Graphic)icon).color = new Color(val.r * 0.45f, val.g * 0.45f, val.b * 0.45f, val.a);
			}
			if ((Object)(object)durability != (Object)null)
			{
				((Component)durability).gameObject.SetActive(true);
				durability.SetValue(Mathf.Clamp01(fill));
			}
		}

		private static float GetCooldownFill(float remainingSeconds)
		{
			float num = Mathf.Max(1f, HearthstoneConfig.CooldownMinutes.Value * 60f);
			return Mathf.Clamp01(1f - remainingSeconds / num);
		}
	}
	[BepInPlugin("valheimoverhaul.hearthstone", "Hearthstone", "1.4.1")]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "valheimoverhaul.hearthstone";

		public const string PluginName = "Hearthstone";

		public const string PluginVersion = "1.4.1";

		internal const string PrefabName = "VO_Hearthstone";

		internal const string ItemToken = "$item_hearthstone";

		internal const string CooldownCustomDataKey = "valheimoverhaul.hearthstone.cooldownUntil";

		internal static Plugin Instance;

		internal static ManualLogSource Log;

		private void Awake()
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			HearthstoneConfig.Bind(((BaseUnityPlugin)this).Config);
			new Harmony("valheimoverhaul.hearthstone").PatchAll();
			Log.LogInfo((object)"Hearthstone 1.4.1 loaded.");
		}
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}