Decompiled source of HammerRepairRadius v1.0.1

HammerRepairRadius.dll

Decompiled 11 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using ConditionalConfigSync;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("HammerRepairRadius")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.1.0")]
[assembly: AssemblyInformationalVersion("1.0.1")]
[assembly: AssemblyProduct("HammerRepairRadius")]
[assembly: AssemblyTitle("HammerRepairRadius")]
[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 HammerRepairRadius
{
	public enum RepairCenter
	{
		HoveredPieceOrPlayer,
		HoveredPiece,
		Player
	}
	public enum CostMode
	{
		PerSwing,
		PerPiece
	}
	[BepInPlugin("com.dreich.hammerrepairradius", "Hammer Repair Radius", "1.0.1")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class HammerRepairRadiusPlugin : BaseUnityPlugin
	{
		public const string PluginGuid = "com.dreich.hammerrepairradius";

		public const string PluginName = "Hammer Repair Radius";

		public const string PluginVersion = "1.0.1";

		internal const string HammerPrefab = "Hammer";

		internal const string ConfigSyncGuid = "_shudnal.ConditionalConfigSync";

		internal static bool ConfigSyncInstalled;

		private static ConfigEntry<bool> lockConfigurationSetting;

		internal static ManualLogSource Log;

		internal static ConfigEntry<bool> Enabled;

		internal static ConfigEntry<float> BaseRadius;

		internal static ConfigEntry<float> RadiusPerLevel;

		internal static ConfigEntry<float> MaxRadius;

		internal static ConfigEntry<RepairCenter> Center;

		internal static ConfigEntry<bool> RequireCraftingStation;

		internal static ConfigEntry<bool> RespectWards;

		internal static ConfigEntry<bool> OnlyPlayerBuiltPieces;

		internal static ConfigEntry<bool> RespectRepairEnemyStructures;

		internal static ConfigEntry<CostMode> Costs;

		internal static ConfigEntry<bool> EnableHammerUpgrades;

		internal static ConfigEntry<int> HammerMaxLevel;

		internal static ConfigEntry<string> UpgradeRequirements;

		internal static ConfigEntry<int> MaxEffectsPerSwing;

		internal static ConfigEntry<bool> ShowRadiusInTooltip;

		internal static ConfigEntry<bool> LogRepairs;

		private static Harmony harmony;

		private void Awake()
		{
			//IL_01b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01be: Expected O, but got Unknown
			//IL_02b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02be: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			ConfigSyncInstalled = Chainloader.PluginInfos.ContainsKey("_shudnal.ConditionalConfigSync");
			if (ConfigSyncInstalled)
			{
				lockConfigurationSetting = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Lock Configuration", true, "If on, the configuration is locked and can be changed by server admins only.");
				InitConfigSync(lockConfigurationSetting);
			}
			else
			{
				Log.LogInfo((object)"ConditionalConfigSync not found; using local config only (no server sync).");
			}
			Enabled = BindServerControlled("General", "Enabled", defaultValue: true, "Turn area repair on or off. When off, the hammer repairs one piece like vanilla.");
			BaseRadius = BindServerControlled("Radius", "BaseRadius", 5f, "Base repair radius in meters. Radius = BaseRadius + RadiusPerLevel x tool level. With the defaults, a level 1 hammer repairs within 6 m and a level 4 hammer within 9 m. Set BaseRadius to 4 if you want a level 1 hammer to be exactly 5 m.");
			RadiusPerLevel = BindServerControlled("Radius", "RadiusPerLevel", 1f, "Extra meters of radius for every level (quality) of the hammer.");
			MaxRadius = BindServerControlled("Radius", "MaxRadius", 0f, "Upper limit on the radius in meters. 0 = no limit.");
			Center = BindServerControlled("Radius", "RepairCenter", RepairCenter.HoveredPieceOrPlayer, "Where the repair circle is centred. HoveredPieceOrPlayer = the piece you aim at, or yourself if you aim at nothing. HoveredPiece = only works when aiming at a piece (like vanilla). Player = always centred on you.");
			RequireCraftingStation = BindServerControlled("Rules", "RequireCraftingStation", defaultValue: true, "Vanilla rule: a piece only gets repaired if the crafting station it was built with is in range of you.");
			RespectWards = BindServerControlled("Rules", "RespectWards", defaultValue: true, "Skip pieces inside wards you do not have access to.");
			OnlyPlayerBuiltPieces = BindServerControlled("Rules", "OnlyPlayerBuiltPieces", defaultValue: false, "Only repair pieces that a player built (skips dungeon and enemy structures).");
			RespectRepairEnemyStructures = BindServerControlled("Rules", "RespectRepairEnemyStructuresStations", defaultValue: true, "If the Repair Enemy Structures mod is installed, honour its per-structure station requirements during area repair.");
			Costs = BindServerControlled("Costs", "CostMode", CostMode.PerSwing, "PerSwing = stamina and durability are paid once per swing, like a single vanilla repair. PerPiece = paid for every piece repaired (stops when you run out).");
			EnableHammerUpgrades = BindServerControlled("Upgrades", "EnableHammerUpgrades", defaultValue: true, "Vanilla hammers cannot be upgraded, so they stay at level 1. Turn this on to allow upgrading the hammer at the workbench so the radius can grow.");
			HammerMaxLevel = BindServerControlled("Upgrades", "HammerMaxLevel", 4, new ConfigDescription("Highest level the hammer can be upgraded to. Each level needs a higher workbench level.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 10), Array.Empty<object>()));
			UpgradeRequirements = BindServerControlled("Upgrades", "UpgradeRequirements", "Wood:3,Flint:2", "Materials needed per upgrade level, as ItemPrefab:amount pairs separated by commas. The amount is multiplied by (level - 1), so going to level 3 costs twice as much as level 2.");
			MaxEffectsPerSwing = BindClientControlled("Effects", "MaxEffectsPerSwing", 10, "Most repair sound/particle effects played per swing, so big repairs do not get loud. 0 = none.");
			ShowRadiusInTooltip = BindClientControlled("Effects", "ShowRadiusInTooltip", defaultValue: true, "Show the repair radius in the hammer tooltip (also shows the next level's radius in the upgrade screen).");
			LogRepairs = BindClientControlled("Debug", "LogRepairs", defaultValue: false, "Log a line every time an area repair runs.");
			EnableHammerUpgrades.SettingChanged += delegate
			{
				HammerUpgrades.Apply();
			};
			HammerMaxLevel.SettingChanged += delegate
			{
				HammerUpgrades.Apply();
			};
			UpgradeRequirements.SettingChanged += delegate
			{
				HammerUpgrades.Apply();
			};
			harmony = new Harmony("com.dreich.hammerrepairradius");
			harmony.PatchAll();
		}

		private ConfigEntry<T> BindServerControlled<T>(string section, string key, T defaultValue, string description)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Expected O, but got Unknown
			return BindServerControlled(section, key, defaultValue, new ConfigDescription(description, (AcceptableValueBase)null, Array.Empty<object>()));
		}

		private ConfigEntry<T> BindServerControlled<T>(string section, string key, T defaultValue, ConfigDescription description)
		{
			ConfigEntry<T> val = ((BaseUnityPlugin)this).Config.Bind<T>(section, key, defaultValue, description);
			if (ConfigSyncInstalled)
			{
				RegisterSynced<T>(val, serverControlled: true);
			}
			return val;
		}

		private ConfigEntry<T> BindClientControlled<T>(string section, string key, T defaultValue, string description)
		{
			ConfigEntry<T> val = ((BaseUnityPlugin)this).Config.Bind<T>(section, key, defaultValue, description);
			if (ConfigSyncInstalled)
			{
				RegisterSynced<T>(val, serverControlled: false);
			}
			return val;
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		private static void InitConfigSync(ConfigEntry<bool> lockEntry)
		{
			ConfigSyncBridge.Init(lockEntry);
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		private static void RegisterSynced<T>(ConfigEntry<T> entry, bool serverControlled)
		{
			ConfigSyncBridge.Add<T>(entry, serverControlled);
		}

		private void OnDestroy()
		{
			Harmony obj = harmony;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
			harmony = null;
		}

		internal static bool IsHammer(ItemData item)
		{
			if (item == null)
			{
				return false;
			}
			if ((Object)(object)item.m_dropPrefab != (Object)null)
			{
				return ((Object)item.m_dropPrefab).name == "Hammer";
			}
			GameObject val = (((Object)(object)ObjectDB.instance != (Object)null) ? ObjectDB.instance.GetItemPrefab("Hammer") : null);
			ItemDrop val2 = (((Object)(object)val != (Object)null) ? val.GetComponent<ItemDrop>() : null);
			if ((Object)(object)val2 != (Object)null)
			{
				return val2.m_itemData.m_shared == item.m_shared;
			}
			return false;
		}

		internal static float GetRadius(int quality)
		{
			float num = BaseRadius.Value + RadiusPerLevel.Value * (float)Mathf.Max(1, quality);
			if (MaxRadius.Value > 0f)
			{
				num = Mathf.Min(num, MaxRadius.Value);
			}
			return Mathf.Max(0f, num);
		}
	}
	internal static class ConfigSyncBridge
	{
		private static ConfigSync configSync;

		[MethodImpl(MethodImplOptions.NoInlining)]
		internal static void Init(ConfigEntry<bool> lockEntry)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: 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_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Expected O, but got Unknown
			configSync = new ConfigSync("com.dreich.hammerrepairradius")
			{
				DisplayName = "Hammer Repair Radius",
				CurrentVersion = "1.0.1",
				MinimumRequiredVersion = "1.0.1",
				ModRequired = false,
				ModRequirementMode = (ModRequirementMode)1
			};
			((ConditionalConfigSync)configSync).AddLockingConfigEntry<bool>(lockEntry);
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		internal static void Add<T>(ConfigEntry<T> entry, bool serverControlled)
		{
			((ConditionalConfigSync)configSync).AddConfigEntry<T>(entry, (ConfigSyncMode)((!serverControlled) ? 2 : 0));
		}
	}
	internal static class AreaRepair
	{
		private static readonly FieldRef<Character, ZSyncAnimation> ZanimRef = AccessTools.FieldRefAccess<Character, ZSyncAnimation>("m_zanim");

		private static readonly FieldRef<Player, bool> NoPlacementCostRef = AccessTools.FieldRefAccess<Player, bool>("m_noPlacementCost");

		private static readonly Func<Player, float> GetBuildStamina = AccessTools.MethodDelegate<Func<Player, float>>(AccessTools.Method(typeof(Player), "GetBuildStamina", (Type[])null, (Type[])null), (object)null, true);

		private static bool enemyStructuresLookedUp;

		private static Type enemyStationType;

		private static FieldInfo enemyStationNameField;

		private static readonly List<Piece> piecesBuffer = new List<Piece>();

		internal static void Run(Player player, ItemData tool)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: 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_004e: 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_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0308: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01de: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f7: Unknown result type (might be due to invalid IL or missing references)
			Piece hoveringPiece = player.GetHoveringPiece();
			Vector3 center;
			switch (HammerRepairRadiusPlugin.Center.Value)
			{
			case RepairCenter.HoveredPiece:
				if ((Object)(object)hoveringPiece == (Object)null)
				{
					return;
				}
				center = ((Component)hoveringPiece).transform.position;
				break;
			case RepairCenter.Player:
				center = ((Component)player).transform.position;
				break;
			default:
				center = (((Object)(object)hoveringPiece != (Object)null) ? ((Component)hoveringPiece).transform.position : ((Component)player).transform.position);
				break;
			}
			float radius = HammerRepairRadiusPlugin.GetRadius(tool.m_quality);
			piecesBuffer.Clear();
			Piece.GetAllPiecesInRadius(center, radius, piecesBuffer);
			piecesBuffer.Sort(delegate(Piece a, Piece b)
			{
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_000c: 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_0016: Unknown result type (might be due to invalid IL or missing references)
				//IL_0027: Unknown result type (might be due to invalid IL or missing references)
				//IL_002d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0032: Unknown result type (might be due to invalid IL or missing references)
				//IL_0037: Unknown result type (might be due to invalid IL or missing references)
				Vector3 val3 = ((Component)a).transform.position - center;
				float sqrMagnitude = ((Vector3)(ref val3)).sqrMagnitude;
				val3 = ((Component)b).transform.position - center;
				return sqrMagnitude.CompareTo(((Vector3)(ref val3)).sqrMagnitude);
			});
			bool flag = HammerRepairRadiusPlugin.Costs.Value == CostMode.PerPiece;
			float stamina = GetBuildStamina(player);
			int value = HammerRepairRadiusPlugin.MaxEffectsPerSwing.Value;
			int num = 0;
			int num2 = 0;
			int num3 = 0;
			string text = null;
			Piece val = null;
			foreach (Piece item in piecesBuffer)
			{
				if ((Object)(object)item == (Object)null)
				{
					continue;
				}
				WearNTear component = ((Component)item).GetComponent<WearNTear>();
				if ((Object)(object)component == (Object)null || component.GetHealthPercentage() >= 1f || (HammerRepairRadiusPlugin.OnlyPlayerBuiltPieces.Value && !item.IsPlacedByPlayer()))
				{
					continue;
				}
				string missingStation = GetMissingStation(player, item);
				if (missingStation != null)
				{
					num2++;
					if (text == null)
					{
						text = missingStation;
					}
					continue;
				}
				if (HammerRepairRadiusPlugin.RespectWards.Value && !PrivateArea.CheckAccess(((Component)item).transform.position, 0f, false, false))
				{
					num3++;
					continue;
				}
				if (flag && !CanAfford(player, tool, stamina))
				{
					break;
				}
				if (component.Repair())
				{
					num++;
					val = item;
					if (num <= value)
					{
						item.m_placeEffect.Create(((Component)item).transform.position, ((Component)item).transform.rotation, (Transform)null, 1f, -1, ((Character)player).GetZDOID());
					}
					if (flag)
					{
						PayCosts(player, tool, stamina);
					}
				}
			}
			piecesBuffer.Clear();
			if (num > 0)
			{
				player.FaceLookDirection();
				ZSyncAnimation val2 = ZanimRef.Invoke((Character)(object)player);
				if ((Object)(object)val2 != (Object)null)
				{
					val2.SetTrigger(tool.m_shared.m_attack.m_attackAnimation);
				}
				if (!flag)
				{
					PayCosts(player, tool, stamina);
				}
				string text2 = ((num == 1) ? Localization.instance.Localize("$msg_repaired", new string[1] { val.m_name }) : $"Repaired {num} pieces");
				((Character)player).Message((MessageType)1, text2, 0, (Sprite)null, false);
			}
			else if (num2 > 0)
			{
				string text3 = ((text != null) ? Localization.instance.Localize(text) : "crafting station");
				((Character)player).Message((MessageType)2, "Requires a nearby " + text3 + " to repair", 0, (Sprite)null, false);
			}
			else if (num3 > 0)
			{
				PrivateArea.CheckAccess(center, radius, true, false);
				((Character)player).Message((MessageType)2, "$msg_privatezone", 0, (Sprite)null, false);
			}
			else if ((Object)(object)hoveringPiece != (Object)null)
			{
				((Character)player).Message((MessageType)1, hoveringPiece.m_name + " $msg_doesnotneedrepair", 0, (Sprite)null, false);
			}
			else
			{
				((Character)player).Message((MessageType)1, "Nothing nearby needs repair", 0, (Sprite)null, false);
			}
			if (HammerRepairRadiusPlugin.LogRepairs.Value)
			{
				HammerRepairRadiusPlugin.Log.LogInfo((object)($"Area repair r={radius:0.#}m (tool level {tool.m_quality}): repaired {num}, " + $"blocked by station {num2}, blocked by ward {num3}"));
			}
		}

		private static string GetMissingStation(Player player, Piece piece)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			Vector3 position = ((Component)player).transform.position;
			if (HammerRepairRadiusPlugin.RequireCraftingStation.Value && !NoPlacementCostRef.Invoke(player) && (Object)(object)piece.m_craftingStation != (Object)null && !Object.op_Implicit((Object)(object)CraftingStation.HaveBuildStationInRange(piece.m_craftingStation.m_name, position)) && !ZoneSystem.instance.GetGlobalKey((GlobalKeys)27))
			{
				return piece.m_craftingStation.m_name;
			}
			if (HammerRepairRadiusPlugin.RespectRepairEnemyStructures.Value)
			{
				if (!enemyStructuresLookedUp)
				{
					enemyStructuresLookedUp = true;
					enemyStationType = AccessTools.TypeByName("RepairEnemyStructures.RepairRequiresStation");
					if (enemyStationType != null)
					{
						enemyStationNameField = AccessTools.Field(enemyStationType, "StationName");
					}
				}
				if (enemyStationType != null && enemyStationNameField != null)
				{
					Component component = ((Component)piece).GetComponent(enemyStationType);
					if ((Object)(object)component != (Object)null)
					{
						string text = enemyStationNameField.GetValue(component) as string;
						if (!string.IsNullOrEmpty(text) && !Object.op_Implicit((Object)(object)CraftingStation.HaveBuildStationInRange(text, position)))
						{
							return text;
						}
					}
				}
			}
			return null;
		}

		private static bool CanAfford(Player player, ItemData tool, float stamina)
		{
			if (!((Character)player).HaveStamina(stamina))
			{
				return false;
			}
			float attackEitr = tool.m_shared.m_attack.m_attackEitr;
			if (attackEitr > 0f && !((Character)player).HaveEitr(attackEitr))
			{
				return false;
			}
			if (tool.m_shared.m_useDurability && tool.m_durability <= 0f)
			{
				return false;
			}
			return true;
		}

		private static void PayCosts(Player player, ItemData tool, float stamina)
		{
			((Character)player).UseStamina(stamina);
			((Character)player).UseEitr(tool.m_shared.m_attack.m_attackEitr);
			if (tool.m_shared.m_useDurability)
			{
				tool.m_durability = Mathf.Max(0f, tool.m_durability - tool.m_shared.m_useDurabilityDrain * Game.m_durabilityRate);
			}
		}
	}
	internal static class HammerUpgrades
	{
		private const string HammerPrefab = "Hammer";

		private static Recipe cachedRecipe;

		private static Requirement[] originalResources;

		private static int originalMaxQuality = -1;

		private static SharedData cachedShared;

		internal static void Apply()
		{
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Unknown result type (might be due to invalid IL or missing references)
			//IL_0145: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_015f: Unknown result type (might be due to invalid IL or missing references)
			//IL_016c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0179: Unknown result type (might be due to invalid IL or missing references)
			//IL_0182: Expected O, but got Unknown
			//IL_024a: Unknown result type (might be due to invalid IL or missing references)
			//IL_024f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0257: Unknown result type (might be due to invalid IL or missing references)
			//IL_025e: Unknown result type (might be due to invalid IL or missing references)
			//IL_026b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0277: Expected O, but got Unknown
			ObjectDB instance = ObjectDB.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return;
			}
			GameObject itemPrefab = instance.GetItemPrefab("Hammer");
			ItemDrop val = (((Object)(object)itemPrefab != (Object)null) ? itemPrefab.GetComponent<ItemDrop>() : null);
			Recipe val2 = ((IEnumerable<Recipe>)instance.m_recipes).FirstOrDefault((Func<Recipe, bool>)((Recipe r) => (Object)(object)r != (Object)null && (Object)(object)r.m_item != (Object)null && ((Object)r.m_item).name == "Hammer"));
			if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null)
			{
				HammerRepairRadiusPlugin.Log.LogWarning((object)"Could not find the Hammer item or recipe; upgrades not applied.");
				return;
			}
			SharedData shared = val.m_itemData.m_shared;
			if (cachedShared != shared)
			{
				cachedShared = shared;
				originalMaxQuality = shared.m_maxQuality;
			}
			if ((Object)(object)cachedRecipe != (Object)(object)val2)
			{
				cachedRecipe = val2;
				originalResources = val2.m_resources;
			}
			if (!HammerRepairRadiusPlugin.EnableHammerUpgrades.Value)
			{
				shared.m_maxQuality = originalMaxQuality;
				val2.m_resources = originalResources;
				return;
			}
			shared.m_maxQuality = Mathf.Max(1, HammerRepairRadiusPlugin.HammerMaxLevel.Value);
			Dictionary<string, int> dictionary = ParseRequirements(HammerRepairRadiusPlugin.UpgradeRequirements.Value);
			List<Requirement> list = new List<Requirement>();
			Requirement[] array = originalResources;
			foreach (Requirement val3 in array)
			{
				if (val3 != null)
				{
					Requirement val4 = new Requirement
					{
						m_resItem = val3.m_resItem,
						m_amount = val3.m_amount,
						m_extraAmountOnlyOneIngredient = val3.m_extraAmountOnlyOneIngredient,
						m_upgraderResource = val3.m_upgraderResource,
						m_recover = val3.m_recover,
						m_amountPerLevel = 0
					};
					string text = (((Object)(object)val3.m_resItem != (Object)null) ? ((Object)val3.m_resItem).name : null);
					if (text != null && dictionary.TryGetValue(text, out var value))
					{
						val4.m_amountPerLevel = value;
						dictionary.Remove(text);
					}
					list.Add(val4);
				}
			}
			foreach (KeyValuePair<string, int> item in dictionary)
			{
				GameObject itemPrefab2 = instance.GetItemPrefab(item.Key);
				ItemDrop val5 = (((Object)(object)itemPrefab2 != (Object)null) ? itemPrefab2.GetComponent<ItemDrop>() : null);
				if ((Object)(object)val5 == (Object)null)
				{
					HammerRepairRadiusPlugin.Log.LogWarning((object)("UpgradeRequirements: item prefab '" + item.Key + "' not found."));
					continue;
				}
				list.Add(new Requirement
				{
					m_resItem = val5,
					m_amount = 0,
					m_amountPerLevel = item.Value,
					m_recover = true
				});
			}
			val2.m_resources = list.ToArray();
		}

		private static Dictionary<string, int> ParseRequirements(string value)
		{
			Dictionary<string, int> dictionary = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
			string[] array = value.Split(new char[1] { ',' });
			for (int i = 0; i < array.Length; i++)
			{
				string[] array2 = array[i].Split(new char[1] { ':' });
				if (array2.Length == 2)
				{
					string text = array2[0].Trim();
					if (text.Length != 0 && int.TryParse(array2[1].Trim(), out var result) && result > 0)
					{
						dictionary[text] = result;
					}
				}
			}
			return dictionary;
		}
	}
	[HarmonyPatch(typeof(Player), "Repair")]
	internal static class PlayerRepairPatch
	{
		private static bool Prefix(Player __instance, ItemData toolItem)
		{
			if (!HammerRepairRadiusPlugin.Enabled.Value)
			{
				return true;
			}
			if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer || !((Character)__instance).InPlaceMode())
			{
				return true;
			}
			if (!HammerRepairRadiusPlugin.IsHammer(toolItem))
			{
				return true;
			}
			AreaRepair.Run(__instance, toolItem);
			return false;
		}
	}
	[HarmonyPatch]
	internal static class ObjectDBPatches
	{
		[HarmonyPostfix]
		[HarmonyPatch(typeof(ObjectDB), "Awake")]
		private static void AwakePostfix()
		{
			HammerUpgrades.Apply();
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")]
		private static void CopyOtherDBPostfix()
		{
			HammerUpgrades.Apply();
		}
	}
	[HarmonyPatch]
	internal static class TooltipPatch
	{
		private static MethodBase TargetMethod()
		{
			return AccessTools.GetDeclaredMethods(typeof(ItemData)).First((MethodInfo m) => m.Name == "GetTooltip" && m.IsStatic && m.GetParameters().Length >= 2 && m.GetParameters()[0].ParameterType == typeof(ItemData) && m.GetParameters()[1].ParameterType == typeof(int));
		}

		private static void Postfix(ItemData item, int qualityLevel, ref string __result)
		{
			if (HammerRepairRadiusPlugin.ShowRadiusInTooltip.Value && HammerRepairRadiusPlugin.Enabled.Value && HammerRepairRadiusPlugin.IsHammer(item))
			{
				StringBuilder stringBuilder = new StringBuilder(__result);
				stringBuilder.Append($"\nRepair radius: <color=orange>{HammerRepairRadiusPlugin.GetRadius(qualityLevel):0.#} m</color>");
				__result = stringBuilder.ToString();
			}
		}
	}
}