Decompiled source of HammerUpgrades v1.0.1

plugins/HammerUpgrades/HammerUpgrades.dll

Decompiled 2 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
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 Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("Hammer Upgrades")]
[assembly: AssemblyDescription("Quality-based upgrades for Valheim's vanilla Hammer.")]
[assembly: AssemblyCompany("LEGIOmods")]
[assembly: AssemblyProduct("Hammer Upgrades")]
[assembly: AssemblyCopyright("HammerUpgrades by LEGIOmods, Copyright 2026.")]
[assembly: ComVisible(false)]
[assembly: Guid("e4473c9c-3aaa-47d7-8e30-95a6ed132292")]
[assembly: AssemblyFileVersion("1.0.1.0")]
[assembly: AssemblyMetadata("AI_Assisted_Creation", "This assembly was partially or fully created with the assistance of Generative AI for code, localization, documentation, and package preparation.")]
[assembly: AssemblyMetadata("AI_Model_Vendor", "OpenAI")]
[assembly: AssemblyMetadata("AI_Agent", "OpenAI Codex")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("1.0.1.0")]
[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 HammerUpgrades
{
	[BepInPlugin("domen.valheim.hammerupgrades", "Hammer Upgrades", "1.0.1")]
	public sealed class HammerUpgradesPlugin : BaseUnityPlugin
	{
		public const string PluginGuid = "domen.valheim.hammerupgrades";

		public const string PluginName = "Hammer Upgrades";

		public const string PluginVersion = "1.0.1";

		private Harmony harmony;

		internal static HammerUpgradesPlugin Instance { get; private set; }

		internal static ManualLogSource Log => ((BaseUnityPlugin)Instance).Logger;

		internal HammerUpgradeConfig Settings { get; private set; }

		private void Awake()
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Expected O, but got Unknown
			Instance = this;
			try
			{
				Settings = new HammerUpgradeConfig(((BaseUnityPlugin)this).Config);
				HammerUpgradeSystem.Initialize(Settings, ((BaseUnityPlugin)this).Logger);
				harmony = new Harmony("domen.valheim.hammerupgrades");
				harmony.PatchAll(typeof(HammerUpgradesPlugin).Assembly);
				if ((Object)(object)ObjectDB.instance != (Object)null)
				{
					HammerUpgradeSystem.Configure(ObjectDB.instance);
				}
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Hammer Upgrades 1.0.1 initialized.");
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)"Hammer Upgrades could not be initialized.");
				((BaseUnityPlugin)this).Logger.LogError((object)ex);
				Harmony obj = harmony;
				if (obj != null)
				{
					obj.UnpatchSelf();
				}
			}
		}

		private void OnDestroy()
		{
			Harmony obj = harmony;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
			HammerUpgradeSystem.Reset();
			if (Instance == this)
			{
				Instance = null;
			}
		}
	}
	internal sealed class HammerUpgradeConfig
	{
		internal ConfigEntry<float> AreaRepairRadiusQ3 { get; }

		internal ConfigEntry<float> AreaRepairRadiusQ4 { get; }

		internal ConfigEntry<float> AreaRepairStaminaCostPerPiece { get; }

		internal ConfigEntry<float> Q4BuildStaminaMultiplier { get; }

		internal ConfigEntry<float> Q4RepairStaminaMultiplier { get; }

		internal HammerUpgradeConfig(ConfigFile config)
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Expected O, but got Unknown
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Expected O, but got Unknown
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Expected O, but got Unknown
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Expected O, but got Unknown
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Expected O, but got Unknown
			AreaRepairRadiusQ3 = config.Bind<float>("Area Repair", "AreaRepairRadiusQ3", 5f, new ConfigDescription("Radius in meters for quality-3 area repair. / Radius in Metern für die Flächenreparatur auf Qualitätsstufe 3.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>()));
			AreaRepairRadiusQ4 = config.Bind<float>("Area Repair", "AreaRepairRadiusQ4", 15f, new ConfigDescription("Radius in meters for quality-4 area repair. / Radius in Metern für die Flächenreparatur auf Qualitätsstufe 4.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>()));
			AreaRepairStaminaCostPerPiece = config.Bind<float>("Area Repair", "AreaRepairStaminaCostPerPiece", 0f, new ConfigDescription("Stamina per additional piece. 0 uses Valheim's current Hammer build/repair cost. / Ausdauer je zusätzlichem Bauteil. 0 verwendet Valheims aktuelle Hammer-Bau-/Reparaturkosten.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>()));
			Q4BuildStaminaMultiplier = config.Bind<float>("Quality 4", "Q4BuildStaminaMultiplier", 0.5f, new ConfigDescription("Multiplier for quality-4 Hammer placement stamina. / Multiplikator für die Bauausdauer des Hammers auf Qualitätsstufe 4.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 2f), Array.Empty<object>()));
			Q4RepairStaminaMultiplier = config.Bind<float>("Quality 4", "Q4RepairStaminaMultiplier", 0.5f, new ConfigDescription("Multiplier for quality-4 additional area-repair stamina. / Multiplikator für zusätzliche Flächenreparaturen auf Qualitätsstufe 4.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 2f), Array.Empty<object>()));
		}
	}
	internal static class HammerUpgradeSystem
	{
		private sealed class DirectRepairContext
		{
			internal Player Player { get; }

			internal ItemData Tool { get; }

			internal Piece TargetPiece { get; }

			internal WearNTear TargetWear { get; }

			internal bool DirectRepairSucceeded { get; set; }

			internal DirectRepairContext(Player player, ItemData tool, Piece targetPiece, WearNTear targetWear)
			{
				Player = player;
				Tool = tool;
				TargetPiece = targetPiece;
				TargetWear = targetWear;
			}
		}

		internal const string HammerPrefabName = "Hammer";

		private static readonly string[] UpgradeResourceNames = new string[6] { "Wood", "Stone", "RoundLog", "FineWood", "YmirRemains", "YggdrasilWood" };

		private static readonly Dictionary<Requirement, string> HammerRequirements = new Dictionary<Requirement, string>();

		private static readonly MethodInfo GetRightItemMethod = AccessTools.Method(typeof(Humanoid), "GetRightItem", (Type[])null, (Type[])null);

		private static readonly MethodInfo GetBuildStaminaMethod = AccessTools.Method(typeof(Player), "GetBuildStamina", (Type[])null, (Type[])null);

		private static readonly MethodInfo CheckCanRemovePieceMethod = AccessTools.Method(typeof(Player), "CheckCanRemovePiece", (Type[])null, (Type[])null);

		private static HammerUpgradeConfig settings;

		private static ManualLogSource log;

		private static SharedData hammerSharedData;

		private static Recipe hammerRecipe;

		private static bool isConfigured;

		private static bool configurationLogged;

		[ThreadStatic]
		private static DirectRepairContext directRepairContext;

		internal static void Initialize(HammerUpgradeConfig config, ManualLogSource logger)
		{
			if (GetRightItemMethod == null || GetBuildStaminaMethod == null || CheckCanRemovePieceMethod == null)
			{
				throw new MissingMethodException("Valheim 1.0.12 Hammer bindings changed: GetRightItem, GetBuildStamina, or CheckCanRemovePiece is missing.");
			}
			settings = config;
			log = logger;
		}

		internal static void Reset()
		{
			HammerRequirements.Clear();
			hammerSharedData = null;
			hammerRecipe = null;
			isConfigured = false;
			directRepairContext = null;
			configurationLogged = false;
		}

		internal static bool Configure(ObjectDB objectDatabase)
		{
			//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_0201: Unknown result type (might be due to invalid IL or missing references)
			//IL_0208: Unknown result type (might be due to invalid IL or missing references)
			//IL_020f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0216: Unknown result type (might be due to invalid IL or missing references)
			//IL_021d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0229: Expected O, but got Unknown
			HammerRequirements.Clear();
			hammerSharedData = null;
			hammerRecipe = null;
			isConfigured = false;
			if ((Object)(object)objectDatabase == (Object)null)
			{
				return false;
			}
			GameObject itemPrefab = objectDatabase.GetItemPrefab("Hammer");
			ItemDrop hammerDrop = (((Object)(object)itemPrefab == (Object)null) ? null : itemPrefab.GetComponent<ItemDrop>());
			if ((Object)(object)hammerDrop == (Object)null)
			{
				ManualLogSource obj = log;
				if (obj != null)
				{
					obj.LogDebug((object)"Vanilla Hammer prefab is not available in this ObjectDB yet; configuration deferred.");
				}
				return false;
			}
			Recipe val = ((IEnumerable<Recipe>)objectDatabase.m_recipes).FirstOrDefault((Func<Recipe, bool>)((Recipe candidate) => (Object)(object)candidate != (Object)null && (Object)(object)candidate.m_item != (Object)null && (candidate.m_item == hammerDrop || ((Object)((Component)candidate.m_item).gameObject).name == "Hammer")));
			if ((Object)(object)val == (Object)null)
			{
				ManualLogSource obj2 = log;
				if (obj2 != null)
				{
					obj2.LogError((object)"Vanilla recipe for prefab 'Hammer' was not found; upgrades remain disabled.");
				}
				return false;
			}
			Dictionary<string, ItemDrop> dictionary = new Dictionary<string, ItemDrop>(StringComparer.Ordinal);
			string[] upgradeResourceNames = UpgradeResourceNames;
			foreach (string text in upgradeResourceNames)
			{
				GameObject itemPrefab2 = objectDatabase.GetItemPrefab(text);
				ItemDrop val2 = (((Object)(object)itemPrefab2 == (Object)null) ? null : itemPrefab2.GetComponent<ItemDrop>());
				if ((Object)(object)val2 == (Object)null)
				{
					ManualLogSource obj3 = log;
					if (obj3 != null)
					{
						obj3.LogError((object)("Required vanilla resource prefab '" + text + "' was not found; upgrades remain disabled."));
					}
					return false;
				}
				dictionary.Add(text, val2);
			}
			if ((Object)(object)val.m_repairStation == (Object)null || ((Object)((Component)val.m_repairStation).gameObject).name != "piece_workbench")
			{
				ManualLogSource obj4 = log;
				if (obj4 != null)
				{
					obj4.LogError((object)"The vanilla Hammer recipe does not reference 'piece_workbench' as its upgrade/repair station; upgrades remain disabled.");
				}
				return false;
			}
			List<Requirement> list = ((val.m_resources == null) ? new List<Requirement>() : val.m_resources.Where((Requirement requirement) => requirement != null).ToList());
			upgradeResourceNames = UpgradeResourceNames;
			foreach (string resourceName in upgradeResourceNames)
			{
				if (list.All((Requirement requirement) => GetRequirementResourceName(requirement) != resourceName))
				{
					list.Add(new Requirement
					{
						m_resItem = dictionary[resourceName],
						m_amount = 0,
						m_amountPerLevel = 0,
						m_extraAmountOnlyOneIngredient = 0,
						m_upgraderResource = false,
						m_recover = true
					});
				}
			}
			hammerDrop.m_itemData.m_shared.m_maxQuality = 4;
			val.m_minStationLevel = 1;
			val.m_resources = list.ToArray();
			hammerSharedData = hammerDrop.m_itemData.m_shared;
			hammerRecipe = val;
			HammerRequirements.Clear();
			foreach (Requirement item in list)
			{
				string requirementResourceName = GetRequirementResourceName(item);
				if (UpgradeResourceNames.Contains(requirementResourceName))
				{
					HammerRequirements[item] = requirementResourceName;
				}
			}
			isConfigured = true;
			if (!configurationLogged)
			{
				configurationLogged = true;
				ManualLogSource obj5 = log;
				if (obj5 != null)
				{
					obj5.LogInfo((object)"Configured vanilla Hammer quality 1-4, exact upgrade costs, durability tiers, and area repair.");
				}
			}
			return true;
		}

		internal static bool IsVanillaHammer(ItemData item)
		{
			if (!isConfigured || item == null || item.m_shared == null)
			{
				return false;
			}
			if (item.m_shared == hammerSharedData)
			{
				return true;
			}
			if ((Object)(object)item.m_dropPrefab != (Object)null)
			{
				return ((Object)item.m_dropPrefab).name == "Hammer";
			}
			return false;
		}

		internal static bool IsHammerRecipe(Recipe recipe)
		{
			if (!isConfigured || (Object)(object)recipe == (Object)null)
			{
				return false;
			}
			if (recipe == hammerRecipe)
			{
				return true;
			}
			if ((Object)(object)recipe.m_item != (Object)null)
			{
				return ((Object)((Component)recipe.m_item).gameObject).name == "Hammer";
			}
			return false;
		}

		internal static bool TryGetUpgradeAmount(Requirement requirement, int quality, out int amount)
		{
			amount = 0;
			if (quality <= 1 || requirement == null || !HammerRequirements.TryGetValue(requirement, out var value))
			{
				return false;
			}
			switch (quality)
			{
			case 2:
				amount = ((value == "Wood") ? 5 : ((value == "Stone") ? 2 : 0));
				return true;
			case 3:
				amount = ((value == "RoundLog") ? 2 : ((value == "FineWood") ? 1 : 0));
				return true;
			case 4:
				amount = ((value == "YmirRemains") ? 1 : ((value == "YggdrasilWood") ? 2 : 0));
				return true;
			default:
				return true;
			}
		}

		internal static bool TryGetHammerDurability(ItemData item, int quality, out float durability)
		{
			durability = 0f;
			if (!IsVanillaHammer(item))
			{
				return false;
			}
			switch (quality)
			{
			case 2:
				durability = 300f;
				return true;
			case 3:
				durability = 500f;
				return true;
			case 4:
				durability = 1000f;
				return true;
			default:
				return false;
			}
		}

		internal static int GetHammerStationLevel(int quality)
		{
			return quality switch
			{
				2 => 2, 
				3 => 3, 
				4 => 5, 
				_ => 1, 
			};
		}

		internal static string AppendUpgradeTooltip(ItemData item, int quality, string tooltip)
		{
			if (!IsVanillaHammer(item) || quality < 1 || quality > 4)
			{
				return tooltip;
			}
			bool flag = Localization.instance != null && string.Equals(Localization.instance.GetSelectedLanguage(), "German", StringComparison.OrdinalIgnoreCase);
			StringBuilder stringBuilder = new StringBuilder(tooltip ?? string.Empty);
			if (stringBuilder.Length > 0 && stringBuilder[stringBuilder.Length - 1] != '\n')
			{
				stringBuilder.AppendLine();
			}
			stringBuilder.AppendLine();
			stringBuilder.AppendLine(flag ? "<color=orange>Hammer-Upgrades:</color>" : "<color=orange>Hammer upgrades:</color>");
			switch (quality)
			{
			case 1:
				stringBuilder.Append(flag ? "Vanilla-Verhalten" : "Vanilla behavior");
				break;
			case 2:
				stringBuilder.Append(flag ? "Maximale Haltbarkeit: <color=orange>300</color>" : "Maximum durability: <color=orange>300</color>");
				break;
			case 3:
				stringBuilder.AppendLine(flag ? "Maximale Haltbarkeit: <color=orange>500</color>" : "Maximum durability: <color=orange>500</color>");
				stringBuilder.AppendFormat(flag ? "Flächenreparatur: <color=orange>{0:0.#} m</color>\n" : "Area repair: <color=orange>{0:0.#} m</color>\n", settings.AreaRepairRadiusQ3.Value);
				stringBuilder.Append(flag ? "Reparatur ohne nahe Werkstation" : "Repairs without a nearby crafting station");
				break;
			case 4:
				stringBuilder.AppendLine(flag ? "Maximale Haltbarkeit: <color=orange>1000</color>" : "Maximum durability: <color=orange>1000</color>");
				stringBuilder.AppendFormat(flag ? "Flächenreparatur: <color=orange>{0:0.#} m</color>\n" : "Area repair: <color=orange>{0:0.#} m</color>\n", settings.AreaRepairRadiusQ4.Value);
				stringBuilder.AppendLine(flag ? "Reparatur ohne nahe Werkstation" : "Repairs without a nearby crafting station");
				stringBuilder.AppendFormat(flag ? "Bau-Ausdauerverbrauch: <color=orange>{0:0.#} %</color>\n" : "Building stamina use: <color=orange>{0:0.#}%</color>\n", settings.Q4BuildStaminaMultiplier.Value * 100f);
				stringBuilder.AppendFormat(flag ? "Flächenreparatur-Ausdauerverbrauch: <color=orange>{0:0.#} %</color>" : "Area-repair stamina use: <color=orange>{0:0.#}%</color>", settings.Q4RepairStaminaMultiplier.Value * 100f);
				break;
			}
			return stringBuilder.ToString();
		}

		internal static bool IsQualityFourPlacement(Player player)
		{
			if ((Object)(object)player == (Object)null || (Object)(object)player != (Object)(object)Player.m_localPlayer || !((Character)player).InPlaceMode())
			{
				return false;
			}
			ItemData rightItem = GetRightItem(player);
			if (!IsVanillaHammer(rightItem) || rightItem.m_quality != 4)
			{
				return false;
			}
			Piece selectedPiece = player.GetSelectedPiece();
			if ((Object)(object)selectedPiece != (Object)null && !selectedPiece.m_repairPiece)
			{
				return !selectedPiece.m_removePiece;
			}
			return false;
		}

		internal static float ApplyBuildStaminaMultiplier(Player player, float stamina)
		{
			if (!IsQualityFourPlacement(player))
			{
				return stamina;
			}
			return stamina * settings.Q4BuildStaminaMultiplier.Value;
		}

		internal static bool HavePlacementStamina(Character character, float vanillaRequirement)
		{
			Player player = (Player)(object)((character is Player) ? character : null);
			if (IsQualityFourPlacement(player))
			{
				return character.HaveStamina(GetBuildStamina(player));
			}
			return character.HaveStamina(vanillaRequirement);
		}

		internal static void BeginDirectRepair(Player player, ItemData tool)
		{
			directRepairContext = null;
			if (!((Object)(object)player == (Object)null) && !((Object)(object)player != (Object)(object)Player.m_localPlayer) && IsVanillaHammer(tool) && tool.m_quality >= 3 && tool.m_quality <= 4)
			{
				Piece hoveringPiece = player.GetHoveringPiece();
				WearNTear val = (((Object)(object)hoveringPiece == (Object)null) ? null : ((Component)hoveringPiece).GetComponent<WearNTear>());
				if (!((Object)(object)val == (Object)null))
				{
					directRepairContext = new DirectRepairContext(player, tool, hoveringPiece, val);
				}
			}
		}

		internal static bool CanRepairPieceWithoutStation(Player player, Piece piece)
		{
			if (!CanUseStationlessHammerRepair(player, piece))
			{
				return CheckCanRemovePiece(player, piece);
			}
			return true;
		}

		internal static void ObserveWearNTearRepair(WearNTear wear, bool repaired)
		{
			DirectRepairContext directRepairContext = HammerUpgradeSystem.directRepairContext;
			if (repaired && directRepairContext != null && directRepairContext.TargetWear == wear)
			{
				directRepairContext.DirectRepairSucceeded = true;
			}
		}

		internal static void CompleteDirectRepair(Player player)
		{
			DirectRepairContext directRepairContext = HammerUpgradeSystem.directRepairContext;
			HammerUpgradeSystem.directRepairContext = null;
			if (directRepairContext == null || !directRepairContext.DirectRepairSucceeded || directRepairContext.Player != player)
			{
				return;
			}
			try
			{
				RepairArea(directRepairContext);
			}
			catch (Exception ex)
			{
				ManualLogSource obj = log;
				if (obj != null)
				{
					obj.LogError((object)"Area repair failed after a successful vanilla repair.");
				}
				ManualLogSource obj2 = log;
				if (obj2 != null)
				{
					obj2.LogError((object)ex);
				}
			}
		}

		internal static void CancelDirectRepair()
		{
			directRepairContext = null;
		}

		private static void RepairArea(DirectRepairContext context)
		{
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			int quality = context.Tool.m_quality;
			float num = ((quality == 3) ? settings.AreaRepairRadiusQ3.Value : settings.AreaRepairRadiusQ4.Value);
			if (num <= 0f)
			{
				return;
			}
			Vector3 center = ((Component)context.TargetPiece).transform.position;
			List<Piece> list = new List<Piece>();
			Piece.GetAllPiecesInRadius(center, num, list);
			list.Sort((Piece left, Piece right) => DistanceSquared(left, center).CompareTo(DistanceSquared(right, center)));
			float value = settings.AreaRepairStaminaCostPerPiece.Value;
			float num2 = ((value > 0f) ? value : GetBuildStamina(context.Player));
			float num3 = ((quality == 4) ? (num2 * settings.Q4RepairStaminaMultiplier.Value) : num2);
			num3 = Mathf.Max(0f, num3);
			int num4 = 0;
			foreach (Piece item in list)
			{
				if (CanAreaRepair(context, item, out var wear))
				{
					if (!((Character)context.Player).HaveStamina(num3))
					{
						break;
					}
					if (wear.Repair())
					{
						((Character)context.Player).UseStamina(num3);
						CreateRepairEffect(item, context.Player);
						num4++;
					}
				}
			}
			ShowAreaRepairMessage(context.Player, num4);
		}

		private static void CreateRepairEffect(Piece piece, Player player)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: 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)
			if (!((Object)(object)piece == (Object)null) && !((Object)(object)player == (Object)null) && piece.m_placeEffect != null)
			{
				piece.m_placeEffect.Create(((Component)piece).transform.position, ((Component)piece).transform.rotation, (Transform)null, 1f, -1, ((Character)player).GetZDOID());
			}
		}

		private static void ShowAreaRepairMessage(Player player, int repairedPieces)
		{
			string text = ((Localization.instance != null && string.Equals(Localization.instance.GetSelectedLanguage(), "German", StringComparison.OrdinalIgnoreCase)) ? $"Flächenreparatur: {repairedPieces} zusätzliche Bauteile repariert" : $"Area repair: repaired {repairedPieces} additional pieces");
			((Character)player).Message((MessageType)1, text, 0, (Sprite)null, false);
		}

		private static bool CanAreaRepair(DirectRepairContext context, Piece candidate, out WearNTear wear)
		{
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			wear = null;
			if ((Object)(object)candidate == (Object)null || candidate == context.TargetPiece || !candidate.IsPlacedByPlayer())
			{
				return false;
			}
			wear = ((Component)candidate).GetComponent<WearNTear>();
			if ((Object)(object)wear == (Object)null || wear.GetHealthPercentage() >= 1f)
			{
				return false;
			}
			if (!PrivateArea.CheckAccess(((Component)candidate).transform.position, 0f, false, false))
			{
				return false;
			}
			return CanRepairPieceWithoutStation(context.Player, candidate);
		}

		private static bool CanUseStationlessHammerRepair(Player player, Piece piece)
		{
			if ((Object)(object)player == (Object)null || (Object)(object)player != (Object)(object)Player.m_localPlayer || (Object)(object)piece == (Object)null || !piece.IsPlacedByPlayer())
			{
				return false;
			}
			ItemData rightItem = GetRightItem(player);
			if (IsVanillaHammer(rightItem) && rightItem.m_quality >= 3)
			{
				return rightItem.m_quality <= 4;
			}
			return false;
		}

		private static float DistanceSquared(Piece piece, Vector3 center)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)piece == (Object)null))
			{
				Vector3 val = ((Component)piece).transform.position - center;
				return ((Vector3)(ref val)).sqrMagnitude;
			}
			return float.MaxValue;
		}

		private static string GetRequirementResourceName(Requirement requirement)
		{
			if (!((Object)(object)requirement?.m_resItem == (Object)null))
			{
				return ((Object)((Component)requirement.m_resItem).gameObject).name;
			}
			return string.Empty;
		}

		private static ItemData GetRightItem(Player player)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Expected O, but got Unknown
			return (ItemData)GetRightItemMethod.Invoke(player, null);
		}

		private static float GetBuildStamina(Player player)
		{
			return (float)GetBuildStaminaMethod.Invoke(player, null);
		}

		private static bool CheckCanRemovePiece(Player player, Piece piece)
		{
			return (bool)CheckCanRemovePieceMethod.Invoke(player, new object[1] { piece });
		}
	}
	[HarmonyPatch(typeof(ObjectDB), "Awake")]
	internal static class ObjectDbAwakePatch
	{
		private static void Postfix(ObjectDB __instance)
		{
			HammerUpgradeSystem.Configure(__instance);
		}
	}
	[HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")]
	internal static class ObjectDbCopyPatch
	{
		private static void Postfix(ObjectDB __instance)
		{
			HammerUpgradeSystem.Configure(__instance);
		}
	}
	[HarmonyPatch(typeof(Requirement), "GetAmount")]
	internal static class HammerRequirementAmountPatch
	{
		private static bool Prefix(Requirement __instance, int __0, ref int __result)
		{
			if (!HammerUpgradeSystem.TryGetUpgradeAmount(__instance, __0, out var amount))
			{
				return true;
			}
			__result = amount;
			return false;
		}
	}
	[HarmonyPatch(typeof(Recipe), "GetRequiredStationLevel")]
	internal static class HammerRequiredStationLevelPatch
	{
		private static bool Prefix(Recipe __instance, int __0, ref int __result)
		{
			if (!HammerUpgradeSystem.IsHammerRecipe(__instance))
			{
				return true;
			}
			__result = HammerUpgradeSystem.GetHammerStationLevel(__0);
			return false;
		}
	}
	[HarmonyPatch(typeof(ItemData), "GetMaxDurability", new Type[] { typeof(int) })]
	internal static class HammerMaxDurabilityPatch
	{
		private static bool Prefix(ItemData __instance, int __0, ref float __result)
		{
			if (!HammerUpgradeSystem.TryGetHammerDurability(__instance, __0, out var durability))
			{
				return true;
			}
			__result = durability;
			return false;
		}
	}
	[HarmonyPatch(typeof(ItemData), "GetTooltip", new Type[]
	{
		typeof(ItemData),
		typeof(int),
		typeof(bool),
		typeof(float),
		typeof(int),
		typeof(bool)
	})]
	internal static class HammerTooltipPatch
	{
		private static void Postfix(ItemData __0, int __1, ref string __result)
		{
			__result = HammerUpgradeSystem.AppendUpgradeTooltip(__0, __1, __result);
		}
	}
	[HarmonyPatch(typeof(Player), "Repair")]
	internal static class PlayerRepairPatch
	{
		private static void Prefix(Player __instance, ItemData toolItem)
		{
			HammerUpgradeSystem.BeginDirectRepair(__instance, toolItem);
		}

		private static void Postfix(Player __instance)
		{
			HammerUpgradeSystem.CompleteDirectRepair(__instance);
		}

		private static Exception Finalizer(Exception __exception)
		{
			if (__exception != null)
			{
				HammerUpgradeSystem.CancelDirectRepair();
			}
			return __exception;
		}

		private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			List<CodeInstruction> list = new List<CodeInstruction>(instructions);
			MethodInfo methodInfo = AccessTools.Method(typeof(Player), "CheckCanRemovePiece", new Type[1] { typeof(Piece) }, (Type[])null);
			MethodInfo operand = AccessTools.Method(typeof(HammerUpgradeSystem), "CanRepairPieceWithoutStation", (Type[])null, (Type[])null);
			int num = 0;
			for (int i = 0; i < list.Count; i++)
			{
				if (CodeInstructionExtensions.Calls(list[i], methodInfo))
				{
					list[i].opcode = OpCodes.Call;
					list[i].operand = operand;
					num++;
				}
			}
			if (num != 1)
			{
				throw new InvalidOperationException($"Expected one station check in Player.Repair, found {num}; refusing to alter repair behavior.");
			}
			return list;
		}
	}
	[HarmonyPatch(typeof(WearNTear), "Repair")]
	internal static class WearNTearRepairPatch
	{
		private static void Postfix(WearNTear __instance, bool __result)
		{
			HammerUpgradeSystem.ObserveWearNTearRepair(__instance, __result);
		}
	}
	[HarmonyPatch(typeof(Player), "GetBuildStamina")]
	internal static class HammerBuildStaminaCostPatch
	{
		private static void Postfix(Player __instance, ref float __result)
		{
			__result = HammerUpgradeSystem.ApplyBuildStaminaMultiplier(__instance, __result);
		}
	}
	[HarmonyPatch(typeof(Player), "UpdatePlacement")]
	internal static class HammerBuildStaminaCheckPatch
	{
		private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			List<CodeInstruction> list = new List<CodeInstruction>(instructions);
			MethodInfo methodInfo = AccessTools.Method(typeof(Character), "HaveStamina", new Type[1] { typeof(float) }, (Type[])null);
			MethodInfo operand = AccessTools.Method(typeof(HammerUpgradeSystem), "HavePlacementStamina", (Type[])null, (Type[])null);
			List<int> list2 = new List<int>();
			for (int i = 0; i < list.Count; i++)
			{
				if (CodeInstructionExtensions.Calls(list[i], methodInfo))
				{
					list2.Add(i);
				}
			}
			if (list2.Count == 2)
			{
				int index = list2[1];
				list[index].opcode = OpCodes.Call;
				list[index].operand = operand;
				return list;
			}
			throw new InvalidOperationException($"Expected two stamina checks in Player.UpdatePlacement, found {list2.Count}; refusing to apply a partial Hammer stamina patch.");
		}
	}
}