Decompiled source of RepairTweaks v1.0.0

plugins/TXC.RepairTweaks.dll

Decompiled a week 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 HarmonyLib;
using Jotunn.Entities;
using Jotunn.Managers;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8.1", FrameworkDisplayName = ".NET Framework 4.8.1")]
[assembly: AssemblyCompany("TXC.RepairTweaks")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("TXC.RepairTweaks")]
[assembly: AssemblyTitle("TXC.RepairTweaks")]
[assembly: AssemblyVersion("1.0.0.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 TXC.RepairTweaks
{
	internal sealed class RepairInfoCommand : ConsoleCommand
	{
		public override string Name => "repairtweaks_info";

		public override string Help => "TXC Repair Tweaks: station settings + whether each damaged item can be repaired at the current station";

		public override void Run(string[] args)
		{
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.AppendLine("Stations: " + Stations.Describe());
			stringBuilder.AppendLine($"Button: {Plugin.RepairButton.Value}, auto-repair: {Plugin.AutoRepair.Value}, cost: {Plugin.Cost.Value}");
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer != (Object)null)
			{
				CraftingStation currentCraftingStation = localPlayer.GetCurrentCraftingStation();
				StationMode? stationMode = (((Object)(object)currentCraftingStation != (Object)null) ? Stations.GetMode(currentCraftingStation) : ((StationMode?)null));
				stringBuilder.AppendLine(((Object)(object)currentCraftingStation == (Object)null) ? "Current station: none" : (string.Format("Current station: {0} level {1}, mode {2}", Utils.GetPrefabName(((Component)currentCraftingStation).gameObject), currentCraftingStation.GetLevel(true), stationMode.HasValue ? stationMode.Value.ToString() : "vanilla (no setting)") + (localPlayer.NoCostCheat() ? " (no-cost cheat on)" : string.Empty)));
				foreach (ItemData item in from i in ((Humanoid)localPlayer).GetInventory().GetAllItems()
					where i.m_shared.m_useDurability && i.m_durability < i.GetMaxDurability()
					select i)
				{
					float num = 1f - item.m_durability / item.GetMaxDurability();
					Dictionary<string, int> cost = Repairer.GetCost(item, num, localPlayer);
					string text = ((cost.Count == 0) ? "free" : string.Join(", ", cost.Select((KeyValuePair<string, int> c) => $"{c.Value} {c.Key}")));
					Recipe recipe = Stations.GetRecipe(item);
					string text2 = (((Object)(object)recipe?.m_craftingStation != (Object)null) ? Utils.GetPrefabName(((Component)recipe.m_craftingStation).gameObject) : "none");
					string text3 = (((Object)(object)currentCraftingStation == (Object)null || (Object)(object)InventoryGui.instance == (Object)null) ? "no station" : (Repairer.CanRepair(InventoryGui.instance, item) ? "repairable here" : "NOT repairable here"));
					stringBuilder.AppendLine($"  {item.m_shared.m_name} {item.m_quality}* ({num:P0} damaged, crafted at {text2} level {recipe?.m_minStationLevel ?? 0}): {text3}, cost {text}");
				}
			}
			string text4 = Localization.instance.Localize(stringBuilder.ToString());
			string[] array = text4.TrimEnd(Array.Empty<char>()).Split(new char[1] { '\n' });
			foreach (string text5 in array)
			{
				Console.instance.Print(text5.TrimEnd(new char[1] { '\r' }));
			}
			Plugin.Log.LogInfo((object)text4);
		}
	}
	public enum Toggle
	{
		Off,
		On
	}
	public enum ButtonMode
	{
		OneItem,
		All
	}
	public enum CostMode
	{
		Free,
		Materials,
		Coins
	}
	public enum StationMode
	{
		Vanilla,
		AssignedAnyLevel,
		All
	}
	[BepInPlugin("txc.repairtweaks", "TXC Repair Tweaks", "1.0.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	[SynchronizationMode(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "txc.repairtweaks";

		public const string PluginName = "TXC Repair Tweaks";

		public const string PluginVersion = "1.0.0";

		private const string RepairSection = "1 - Repair";

		private const string CostSection = "2 - Repair Cost";

		private const string StationsSection = "3 - Stations";

		internal static ManualLogSource Log;

		internal static ConfigEntry<Toggle> AutoRepair;

		internal static ConfigEntry<ButtonMode> RepairButton;

		internal static ConfigEntry<CostMode> Cost;

		internal static ConfigEntry<float> MaterialPercent;

		internal static ConfigEntry<int> CoinsFullRepair;

		private Harmony _harmony;

		private void Awake()
		{
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			AutoRepair = ((BaseUnityPlugin)this).Config.Bind<Toggle>("1 - Repair", "AutoRepair", Toggle.Off, Admin("On = opening a crafting station repairs every damaged item that station can repair (and that the player can pay for), and the repair button is hidden. With TradersExtended, opening a trader that repairs does the same, at the trader's own price."));
			RepairButton = ((BaseUnityPlugin)this).Config.Bind<ButtonMode>("1 - Repair", "ButtonMode", ButtonMode.OneItem, Admin("What the repair button does. OneItem = vanilla, one item per click. All = every repairable item at once. Also applies to the TradersExtended trader repair button. Crafting stations don't use it while AutoRepair is On (the button is hidden)."));
			Cost = ((BaseUnityPlugin)this).Config.Bind<CostMode>("2 - Repair Cost", "CostMode", CostMode.Free, Admin("Repair cost at crafting stations. Free = vanilla. Materials = a share of the item's crafting materials. Coins = coins. Costs scale with missing durability."));
			MaterialPercent = ((BaseUnityPlugin)this).Config.Bind<float>("2 - Repair Cost", "MaterialPercent", 25f, Admin("Materials mode: % of the materials used to craft the item up to its current quality, for a fully broken item. Each material is rounded up.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f)));
			CoinsFullRepair = ((BaseUnityPlugin)this).Config.Bind<int>("2 - Repair Cost", "Coins", 50, Admin("Coins mode: coins for a fully broken item, rounded up.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100000)));
			Stations.Bind(((BaseUnityPlugin)this).Config, "3 - Stations");
			_harmony = new Harmony("txc.repairtweaks");
			_harmony.PatchAll(typeof(RepairPatches));
			TradersExtendedRepair.TryPatch(_harmony);
			CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new RepairInfoCommand());
			Log.LogInfo((object)"TXC Repair Tweaks 1.0.0 loaded.");
		}

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

		internal static ConfigDescription Admin(string description, AcceptableValueBase range = null)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Expected O, but got Unknown
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Expected O, but got Unknown
			return new ConfigDescription(description, range, new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = true
			} });
		}
	}
	internal static class RepairPatches
	{
		private static bool _canRepairErrorLogged;

		[HarmonyPatch(typeof(InventoryGui), "CanRepair")]
		[HarmonyPrefix]
		private static bool CanRepairPrefix(ItemData item, ref bool __result)
		{
			try
			{
				Player localPlayer = Player.m_localPlayer;
				if ((Object)(object)localPlayer == (Object)null || item == null || !item.m_shared.m_canBeReparied)
				{
					return true;
				}
				CraftingStation currentCraftingStation = localPlayer.GetCurrentCraftingStation();
				StationMode? stationMode = (((Object)(object)currentCraftingStation != (Object)null) ? Stations.GetMode(currentCraftingStation) : ((StationMode?)null));
				if (!stationMode.HasValue)
				{
					return true;
				}
				__result = Stations.Allows(stationMode.Value, item, currentCraftingStation);
				return false;
			}
			catch (Exception arg)
			{
				if (!_canRepairErrorLogged)
				{
					_canRepairErrorLogged = true;
					Plugin.Log.LogError((object)$"Repair check failed, using vanilla rules: {arg}");
				}
				return true;
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "RepairOneItem")]
		[HarmonyPrefix]
		private static bool RepairOneItemPrefix(InventoryGui __instance)
		{
			try
			{
				Repairer.Repair(__instance, Plugin.RepairButton.Value == ButtonMode.All, auto: false);
				return false;
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"Repair failed, falling back to vanilla: {arg}");
				return true;
			}
		}

		[HarmonyPatch(typeof(CraftingStation), "Interact")]
		[HarmonyPostfix]
		private static void InteractPostfix(CraftingStation __instance, Humanoid user, bool repeat)
		{
			try
			{
				if (!repeat && Plugin.AutoRepair.Value != Toggle.Off && __instance.m_canRepair)
				{
					Player val = (Player)(object)((user is Player) ? user : null);
					if (!((Object)(object)val == (Object)null) && !((Object)(object)val != (Object)(object)Player.m_localPlayer) && !((Object)(object)val.GetCurrentCraftingStation() != (Object)(object)__instance) && InventoryGui.IsVisible())
					{
						Repairer.Repair(InventoryGui.instance, all: true, auto: true);
					}
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"Auto-repair failed: {arg}");
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "UpdateRepair")]
		[HarmonyPrefix]
		private static bool UpdateRepairPrefix(InventoryGui __instance)
		{
			if (Plugin.AutoRepair.Value == Toggle.Off)
			{
				return true;
			}
			if (((Component)__instance.m_repairButton).gameObject.activeSelf)
			{
				((Component)__instance.m_repairButton).gameObject.SetActive(false);
				((Component)__instance.m_repairPanel).gameObject.SetActive(false);
				((Component)__instance.m_repairPanelSelection).gameObject.SetActive(false);
			}
			return false;
		}
	}
	internal static class Repairer
	{
		private const string CoinsName = "$item_coins";

		internal static readonly Func<InventoryGui, ItemData, bool> CanRepair = AccessTools.MethodDelegate<Func<InventoryGui, ItemData, bool>>(AccessTools.Method(typeof(InventoryGui), "CanRepair", (Type[])null, (Type[])null), (object)null, true);

		internal static void Repair(InventoryGui gui, bool all, bool auto)
		{
			//IL_0288: Unknown result type (might be due to invalid IL or missing references)
			//IL_028d: Unknown result type (might be due to invalid IL or missing references)
			//IL_029b: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a1: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return;
			}
			CraftingStation currentCraftingStation = localPlayer.GetCurrentCraftingStation();
			if (((Object)(object)currentCraftingStation == (Object)null && !localPlayer.NoCostCheat()) || ((Object)(object)currentCraftingStation != (Object)null && !currentCraftingStation.CheckUsable(localPlayer, false)))
			{
				return;
			}
			Inventory inventory = ((Humanoid)localPlayer).GetInventory();
			List<ItemData> list = new List<ItemData>();
			inventory.GetWornItems(list);
			List<ItemData> list2 = list.Where((ItemData item) => CanRepair(gui, item)).ToList();
			if (list2.Count == 0)
			{
				if (!auto)
				{
					((Character)localPlayer).Message((MessageType)2, "No more item to repair", 0, (Sprite)null, false);
				}
				return;
			}
			Dictionary<string, int> dictionary = new Dictionary<string, int>();
			List<ItemData> list3 = new List<ItemData>();
			List<KeyValuePair<ItemData, Dictionary<string, int>>> list4 = new List<KeyValuePair<ItemData, Dictionary<string, int>>>();
			foreach (ItemData item in list2)
			{
				float num = 1f - item.m_durability / item.GetMaxDurability();
				Dictionary<string, int> cost = GetCost(item, num, localPlayer);
				if (!cost.All((KeyValuePair<string, int> c) => inventory.CountItems(c.Key, -1, false) >= c.Value))
				{
					list4.Add(new KeyValuePair<ItemData, Dictionary<string, int>>(item, cost));
					continue;
				}
				foreach (KeyValuePair<string, int> item2 in cost)
				{
					inventory.RemoveItem(item2.Key, item2.Value, -1, false);
					dictionary[item2.Key] = (dictionary.TryGetValue(item2.Key, out var value) ? value : 0) + item2.Value;
				}
				((Character)localPlayer).RaiseSkill((SkillType)107, num);
				item.m_durability = item.GetMaxDurability();
				list3.Add(item);
				if (all)
				{
					continue;
				}
				break;
			}
			if (list3.Count == 0)
			{
				KeyValuePair<ItemData, Dictionary<string, int>> keyValuePair = list4[0];
				string text = ((list4.Count > 1) ? $"\n({list4.Count} items can't be paid for)" : string.Empty);
				((Character)localPlayer).Message((MessageType)2, Localize("Can't repair " + keyValuePair.Key.m_shared.m_name + "\nNeeds: " + Describe(keyValuePair.Value) + text), 0, (Sprite)null, false);
				return;
			}
			if ((Object)(object)currentCraftingStation != (Object)null)
			{
				currentCraftingStation.m_repairItemDoneEffects.Create(((Component)currentCraftingStation).transform.position, Quaternion.identity, (Transform)null, 1f, -1, default(ZDOID));
			}
			string text2 = ((list3.Count == 1) ? Localization.instance.Localize("$msg_repaired", new string[1] { list3[0].m_shared.m_name }) : string.Format("{0} {1} items", auto ? "Auto-repaired" : "Repaired", list3.Count));
			if (dictionary.Count > 0)
			{
				text2 = text2 + "\nCost: " + Localize(Describe(dictionary));
			}
			if (all && list4.Count > 0)
			{
				text2 += $"\n{list4.Count} item(s) not repaired: can't pay";
			}
			((Character)localPlayer).Message((MessageType)2, text2, 0, (Sprite)null, false);
		}

		internal static Dictionary<string, int> GetCost(ItemData item, float missing, Player player)
		{
			Dictionary<string, int> dictionary = new Dictionary<string, int>();
			if (player.NoCostCheat() || missing <= 0f)
			{
				return dictionary;
			}
			switch (Plugin.Cost.Value)
			{
			case CostMode.Coins:
			{
				int num3 = Scale(Plugin.CoinsFullRepair.Value, missing);
				if (num3 > 0)
				{
					dictionary["$item_coins"] = num3;
				}
				break;
			}
			case CostMode.Materials:
			{
				float value = Plugin.MaterialPercent.Value;
				Recipe recipe = Stations.GetRecipe(item);
				if ((Object)(object)recipe == (Object)null || recipe.m_resources == null)
				{
					break;
				}
				Requirement[] resources = recipe.m_resources;
				foreach (Requirement val in resources)
				{
					if (!((Object)(object)val?.m_resItem == (Object)null))
					{
						int num = 0;
						for (int j = 1; j <= item.m_quality; j++)
						{
							num += val.GetAmount(j);
						}
						int num2 = Scale((float)num * value / 100f, missing);
						if (num2 > 0)
						{
							string name = val.m_resItem.m_itemData.m_shared.m_name;
							dictionary[name] = (dictionary.TryGetValue(name, out var value2) ? value2 : 0) + num2;
						}
					}
				}
				break;
			}
			}
			return dictionary;
		}

		private static int Scale(float fullAmount, float missing)
		{
			return Mathf.Max(0, Mathf.CeilToInt(fullAmount * missing - 0.001f));
		}

		private static string Describe(Dictionary<string, int> cost)
		{
			List<string> list = cost.Select((KeyValuePair<string, int> c) => $"{c.Value} {c.Key}").ToList();
			List<string> list2 = new List<string>();
			for (int num = 0; num < list.Count; num += 2)
			{
				list2.Add(string.Join(", ", list.Skip(num).Take(2)));
			}
			return string.Join(",\n", list2);
		}

		private static string Localize(string text)
		{
			return Localization.instance.Localize(text);
		}
	}
	internal static class Stations
	{
		private static readonly (string Key, string Prefab, string Label)[] Known = new(string, string, string)[5]
		{
			("Workbench", "piece_workbench", "Workbench"),
			("Forge", "forge", "Forge"),
			("BlackForge", "blackforge", "Black forge"),
			("GaldrTable", "piece_magetable", "Galdr table"),
			("ArtisanTable", "piece_artisanstation", "Artisan table")
		};

		private static readonly Dictionary<string, ConfigEntry<StationMode>> ModeByPrefab = new Dictionary<string, ConfigEntry<StationMode>>();

		private static readonly Dictionary<string, Recipe> RecipeCache = new Dictionary<string, Recipe>();

		private static ObjectDB _recipeCacheDb;

		private static int _recipeCacheCount;

		internal static void Bind(ConfigFile config, string section)
		{
			(string, string, string)[] known = Known;
			for (int i = 0; i < known.Length; i++)
			{
				var (text, key, text2) = known[i];
				ModeByPrefab[key] = config.Bind<StationMode>(section, text, StationMode.Vanilla, Plugin.Admin("What the " + text2 + " repairs. Vanilla = vanilla rules (each item needs its station level). AssignedAnyLevel = the items it repairs in vanilla, at any " + text2 + " level. All = every repairable item, at any level."));
			}
		}

		internal static StationMode? GetMode(CraftingStation station)
		{
			if (!ModeByPrefab.TryGetValue(Utils.GetPrefabName(((Component)station).gameObject), out var value))
			{
				return null;
			}
			return value.Value;
		}

		internal static bool Allows(StationMode mode, ItemData item, CraftingStation station)
		{
			return mode switch
			{
				StationMode.All => true, 
				StationMode.AssignedAnyLevel => VanillaAllows(item, station, ignoreLevel: true), 
				_ => VanillaAllows(item, station, ignoreLevel: false), 
			};
		}

		internal static bool VanillaAllows(ItemData item, CraftingStation station, bool ignoreLevel)
		{
			Recipe recipe = GetRecipe(item);
			if ((Object)(object)recipe == (Object)null || ((Object)(object)recipe.m_craftingStation == (Object)null && (Object)(object)recipe.m_repairStation == (Object)null))
			{
				return false;
			}
			if (((Object)(object)recipe.m_repairStation != (Object)null && recipe.m_repairStation.m_name == station.m_name) || ((Object)(object)recipe.m_craftingStation != (Object)null && recipe.m_craftingStation.m_name == station.m_name) || item.m_worldLevel < Game.m_worldLevel)
			{
				if (!ignoreLevel)
				{
					return Mathf.Min(station.GetLevel(true), 4) >= recipe.m_minStationLevel;
				}
				return true;
			}
			return false;
		}

		internal static Recipe GetRecipe(ItemData item)
		{
			ObjectDB instance = ObjectDB.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return null;
			}
			if ((Object)(object)instance != (Object)(object)_recipeCacheDb || instance.m_recipes.Count != _recipeCacheCount)
			{
				RecipeCache.Clear();
				_recipeCacheDb = instance;
				_recipeCacheCount = instance.m_recipes.Count;
			}
			string name = item.m_shared.m_name;
			if (!RecipeCache.TryGetValue(name, out var value))
			{
				value = instance.GetRecipe(item);
				RecipeCache[name] = value;
			}
			return value;
		}

		internal static string Describe()
		{
			return string.Join(", ", Known.Select(((string Key, string Prefab, string Label) k) => $"{k.Label}: {ModeByPrefab[k.Prefab].Value}"));
		}
	}
	internal static class TradersExtendedRepair
	{
		internal const string TradersExtendedGuid = "shudnal.TradersExtended";

		private static MethodInfo _repairOneItem;

		private static Func<StoreGui, ItemData> _getItemToRepair;

		private static Func<Trader, bool> _traderCanRepair;

		private static FieldInfo _repairPanelField;

		private static readonly FieldRef<StoreGui, Trader> StoreTrader = AccessTools.FieldRefAccess<StoreGui, Trader>("m_trader");

		private static bool _looping;

		internal static void TryPatch(Harmony harmony)
		{
			//IL_017c: Unknown result type (might be due to invalid IL or missing references)
			//IL_018a: Expected O, but got Unknown
			//IL_019e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ab: Expected O, but got Unknown
			//IL_01d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f5: Expected O, but got Unknown
			//IL_01f5: Expected O, but got Unknown
			if (Chainloader.PluginInfos.ContainsKey("shudnal.TradersExtended"))
			{
				Type type = AccessTools.TypeByName("TradersExtended.RepairPanel");
				_repairOneItem = ((type == null) ? null : AccessTools.Method(type, "RepairOneItem", new Type[1] { typeof(StoreGui) }, (Type[])null));
				MethodInfo methodInfo = ((type == null) ? null : AccessTools.Method(type, "GetItemToRepair", new Type[1] { typeof(StoreGui) }, (Type[])null));
				MethodInfo methodInfo2 = ((type == null) ? null : AccessTools.Method(type, "TraderCanRepair", new Type[1] { typeof(Trader) }, (Type[])null));
				MethodInfo methodInfo3 = ((type == null) ? null : AccessTools.Method(type, "Update", new Type[1] { typeof(StoreGui) }, (Type[])null));
				_repairPanelField = ((type == null) ? null : AccessTools.Field(type, "repairPanel"));
				if (_repairOneItem == null || methodInfo == null || methodInfo2 == null || methodInfo3 == null || _repairPanelField == null)
				{
					Plugin.Log.LogWarning((object)"TradersExtended found, but its trader repair code has changed; ButtonMode/AutoRepair won't apply to trader repairs.");
					return;
				}
				_getItemToRepair = (Func<StoreGui, ItemData>)Delegate.CreateDelegate(typeof(Func<StoreGui, ItemData>), methodInfo);
				_traderCanRepair = (Func<Trader, bool>)Delegate.CreateDelegate(typeof(Func<Trader, bool>), methodInfo2);
				harmony.Patch((MethodBase)_repairOneItem, new HarmonyMethod(typeof(TradersExtendedRepair), "RepairOneItemPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				harmony.Patch((MethodBase)methodInfo3, (HarmonyMethod)null, new HarmonyMethod(typeof(TradersExtendedRepair), "PanelUpdatePostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				harmony.Patch((MethodBase)AccessTools.Method(typeof(StoreGui), "Show", (Type[])null, (Type[])null), new HarmonyMethod(typeof(TradersExtendedRepair), "StoreShowPrefix", (Type[])null), new HarmonyMethod(typeof(TradersExtendedRepair), "StoreShowPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				Plugin.Log.LogInfo((object)"Patched TradersExtended trader repair (follows ButtonMode and AutoRepair).");
			}
		}

		private static bool RepairOneItemPrefix(StoreGui storeGui)
		{
			if (_looping || Plugin.RepairButton.Value != ButtonMode.All)
			{
				return true;
			}
			RepairAll(storeGui, auto: false);
			return false;
		}

		private static void PanelUpdatePostfix()
		{
			if (Plugin.AutoRepair.Value != Toggle.Off)
			{
				object? value = _repairPanelField.GetValue(null);
				GameObject val = (GameObject)((value is GameObject) ? value : null);
				if ((Object)(object)val != (Object)null && val.activeSelf)
				{
					val.SetActive(false);
				}
			}
		}

		private static void StoreShowPrefix(StoreGui __instance, Trader trader, out bool __state)
		{
			__state = (Object)(object)StoreTrader.Invoke(__instance) == (Object)(object)trader && StoreGui.IsVisible();
		}

		private static void StoreShowPostfix(StoreGui __instance, Trader trader, bool __state)
		{
			try
			{
				if (!__state && Plugin.AutoRepair.Value != Toggle.Off && !((Object)(object)trader == (Object)null) && _traderCanRepair(trader) && _getItemToRepair(__instance) != null)
				{
					RepairAll(__instance, auto: true);
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"Trader auto-repair failed: {arg}");
			}
		}

		private static void RepairAll(StoreGui storeGui, bool auto)
		{
			_looping = true;
			int num = 0;
			try
			{
				for (int i = 0; i < 1000; i++)
				{
					ItemData val = _getItemToRepair(storeGui);
					if (val != null || i <= 0)
					{
						_repairOneItem.Invoke(null, new object[1] { storeGui });
						if (val != null && !(val.m_durability < val.GetMaxDurability()))
						{
							num++;
							continue;
						}
						break;
					}
					break;
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"Trader repair-all failed: {arg}");
			}
			finally
			{
				_looping = false;
			}
			if (num > 1 && (Object)(object)Player.m_localPlayer != (Object)null)
			{
				((Character)Player.m_localPlayer).Message((MessageType)2, string.Format("{0} {1} items", auto ? "Auto-repaired" : "Repaired", num), 0, (Sprite)null, false);
			}
		}
	}
}