Decompiled source of EasyGear v1.0.3

plugins/EasyGear/EasyGear.dll

Decompiled 5 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
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: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("EasyGear")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.3.0")]
[assembly: AssemblyInformationalVersion("1.0.3")]
[assembly: AssemblyProduct("EasyGear")]
[assembly: AssemblyTitle("EasyGear")]
[assembly: AssemblyVersion("1.0.3.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 EasyGear
{
	[HarmonyPatch(typeof(Player), "DamageArmorDurability", new Type[] { typeof(HitData) })]
	internal static class PlayerDamageArmorDurabilityPatch
	{
		private static readonly FieldInfo F_Chest = AccessTools.Field(typeof(Humanoid), "m_chestItem");

		private static readonly FieldInfo F_Leg = AccessTools.Field(typeof(Humanoid), "m_legItem");

		private static readonly FieldInfo F_Helmet = AccessTools.Field(typeof(Humanoid), "m_helmetItem");

		private static readonly FieldInfo F_Shoulder = AccessTools.Field(typeof(Humanoid), "m_shoulderItem");

		private static bool reported;

		internal static bool FieldsResolved
		{
			get
			{
				if (F_Chest != null && F_Leg != null && F_Helmet != null)
				{
					return F_Shoulder != null;
				}
				return false;
			}
		}

		private static float mult0 => Mathf.Max(0.01f, EasyGearPlugin.DurabilityLifetimeMultiplier.Value);

		private static bool Active()
		{
			if (!EasyGearPlugin.DurabilityEnabled.Value)
			{
				return false;
			}
			string value = EasyGearPlugin.DurabilityMode.Value;
			if (!(value == "LossReduction") && !(value == "Both"))
			{
				return false;
			}
			return EasyGearPlugin.DurabilityLifetimeMultiplier.Value > 1.0001f;
		}

		[HarmonyPrefix]
		private static void Prefix(Player __instance, out float[] __state)
		{
			__state = null;
			if (!((Object)(object)__instance == (Object)null) && Active() && FieldsResolved && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer))
			{
				__state = new float[4]
				{
					DurabilityOf(__instance, F_Chest),
					DurabilityOf(__instance, F_Leg),
					DurabilityOf(__instance, F_Helmet),
					DurabilityOf(__instance, F_Shoulder)
				};
			}
		}

		[HarmonyPostfix]
		private static void Postfix(Player __instance, HitData hit, float[] __state)
		{
			if (__state != null && !((Object)(object)__instance == (Object)null) && hit != null)
			{
				float num = hit.GetTotalPhysicalDamage() + hit.GetTotalElementalDamage();
				if (!(num <= 0f))
				{
					float num2 = Mathf.Max(0.01f, EasyGearPlugin.DurabilityLifetimeMultiplier.Value);
					float cost = num / num2;
					Correct(__instance, F_Chest, __state[0], cost);
					Correct(__instance, F_Leg, __state[1], cost);
					Correct(__instance, F_Helmet, __state[2], cost);
					Correct(__instance, F_Shoulder, __state[3], cost);
				}
			}
		}

		private static ItemData ItemAt(Player p, FieldInfo f)
		{
			if (f == null)
			{
				return null;
			}
			try
			{
				object? value = f.GetValue(p);
				return (ItemData)((value is ItemData) ? value : null);
			}
			catch
			{
				return null;
			}
		}

		private static float DurabilityOf(Player p, FieldInfo f)
		{
			return ItemAt(p, f)?.m_durability ?? float.NaN;
		}

		private static void Correct(Player p, FieldInfo f, float before, float cost)
		{
			if (float.IsNaN(before))
			{
				return;
			}
			ItemData val = ItemAt(p, f);
			if (val == null || val.m_durability >= before - 0.0001f)
			{
				return;
			}
			float num = Mathf.Max(0f, before - cost);
			if (!(num <= val.m_durability + 0.0001f))
			{
				val.m_durability = num;
				if (!reported)
				{
					reported = true;
					EasyGearPlugin.Log.LogInfo((object)string.Format("护甲耐久倍率已生效(LossReduction ÷{0:0.##}):{1} 受击伤害 {2:0.##} → 应扣 {3:0.##}(耐久 {4:0.##} → {5:0.##})", mult0, (val.m_shared != null) ? val.m_shared.m_name : "(?)", cost * mult0, cost, before, num));
				}
			}
		}
	}
	internal static class AutoRepair
	{
		private static MethodInfo miCanRepair;

		private static MethodInfo miUpdateRepair;

		private static MethodInfo miMessage;

		private static MethodInfo miRaiseSkill;

		private static MethodInfo miLocalize;

		private static Type messageTypeEnum;

		private static Type skillTypeEnum;

		private const int VanillaRepairSkillValue = 107;

		private static bool running;

		internal static void Init()
		{
			Type typeFromHandle = typeof(InventoryGui);
			miCanRepair = AccessTools.Method(typeFromHandle, "CanRepair", new Type[1] { typeof(ItemData) }, (Type[])null);
			miUpdateRepair = AccessTools.Method(typeFromHandle, "UpdateRepair", (Type[])null, (Type[])null);
			if (miCanRepair == null)
			{
				EasyGearPlugin.Log.LogError((object)"找不到 InventoryGui.CanRepair —— 自动修理无法生效(游戏版本可能已变更,请反馈)。");
			}
			miMessage = FindMethod(typeof(Character), "Message", 5);
			if (miMessage != null)
			{
				messageTypeEnum = miMessage.GetParameters()[0].ParameterType;
			}
			miRaiseSkill = FindMethod(typeof(Character), "RaiseSkill", 2);
			if (miRaiseSkill != null)
			{
				skillTypeEnum = miRaiseSkill.GetParameters()[0].ParameterType;
			}
			miLocalize = AccessTools.Method(typeof(Localization), "Localize", new Type[1] { typeof(string) }, (Type[])null);
		}

		private static MethodInfo FindMethod(Type type, string name, int paramCount)
		{
			try
			{
				MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				for (int i = 0; i < methods.Length; i++)
				{
					if (methods[i].Name == name && methods[i].GetParameters().Length == paramCount)
					{
						return methods[i];
					}
				}
			}
			catch (Exception ex)
			{
				EasyGearPlugin.Log.LogWarning((object)("查找 " + type.Name + "." + name + " 失败:" + ex.Message));
			}
			return null;
		}

		private static bool CanRepair(InventoryGui gui, ItemData item)
		{
			if (miCanRepair == null || (Object)(object)gui == (Object)null || item == null)
			{
				return false;
			}
			try
			{
				object obj = miCanRepair.Invoke(gui, new object[1] { item });
				return obj is bool && (bool)obj;
			}
			catch (Exception ex)
			{
				EasyGearPlugin.Log.LogError((object)("调用 InventoryGui.CanRepair 失败:" + ex.Message));
				return false;
			}
		}

		private static bool IsDamaged(ItemData item)
		{
			if (item == null)
			{
				return false;
			}
			float maxDurability = item.GetMaxDurability();
			if (maxDurability > 0f)
			{
				return item.m_durability < maxDurability - 0.001f;
			}
			return false;
		}

		internal static int Begin(InventoryGui gui, bool includeBackpack, int intervalMs)
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return 0;
			}
			CraftingStation currentCraftingStation = localPlayer.GetCurrentCraftingStation();
			if ((Object)(object)currentCraftingStation == (Object)null)
			{
				return 0;
			}
			if (!currentCraftingStation.CheckUsable(localPlayer, false))
			{
				return 0;
			}
			Inventory inventory = ((Humanoid)localPlayer).GetInventory();
			if (inventory == null)
			{
				return 0;
			}
			List<ItemData> allItems = inventory.GetAllItems();
			if (allItems == null || allItems.Count == 0)
			{
				return 0;
			}
			List<ItemData> list = new List<ItemData>();
			try
			{
				inventory.GetWornItems(list);
			}
			catch (Exception ex)
			{
				EasyGearPlugin.Log.LogWarning((object)("取「穿戴中的物品」失败,本次按全部物品处理:" + ex.Message));
			}
			List<ItemData> list2 = new List<ItemData>();
			for (int i = 0; i < allItems.Count; i++)
			{
				ItemData item = allItems[i];
				if (IsDamaged(item) && CanRepair(gui, item) && (list.Contains(item) || includeBackpack))
				{
					list2.Add(item);
				}
			}
			if (list2.Count == 0)
			{
				return 0;
			}
			if (intervalMs <= 0 || (Object)(object)EasyGearPlugin.Instance == (Object)null)
			{
				int num = RepairAll(list2, currentCraftingStation, list);
				running = false;
				Finish(currentCraftingStation, num, 0);
				return num;
			}
			if (running)
			{
				return 0;
			}
			running = true;
			((MonoBehaviour)EasyGearPlugin.Instance).StartCoroutine(RepairSequence(list2, currentCraftingStation, list, intervalMs));
			return list2.Count;
		}

		private static IEnumerator RepairSequence(List<ItemData> todo, CraftingStation station, List<ItemData> worn, int intervalMs)
		{
			float wait = Mathf.Max(0.01f, (float)intervalMs / 1000f);
			int done = 0;
			int aborted = 0;
			for (int i = 0; i < todo.Count; i++)
			{
				ItemData val = todo[i];
				if (val != null)
				{
					Player localPlayer = Player.m_localPlayer;
					CraftingStation val2 = (((Object)(object)localPlayer == (Object)null) ? null : localPlayer.GetCurrentCraftingStation());
					if ((Object)(object)localPlayer == (Object)null || (Object)(object)val2 != (Object)(object)station || !station.CheckUsable(localPlayer, false))
					{
						aborted = todo.Count - i;
						break;
					}
					try
					{
						RepairOne(localPlayer, val, station, worn.Contains(val));
						done++;
					}
					catch (Exception ex)
					{
						EasyGearPlugin.Log.LogError((object)("自动修理某件物品时出错(继续修下一件):" + ex.Message));
					}
					if (i < todo.Count - 1)
					{
						yield return (object)new WaitForSecondsRealtime(wait);
					}
				}
			}
			running = false;
			Finish(station, done, aborted);
		}

		private static int RepairAll(List<ItemData> todo, CraftingStation station, List<ItemData> worn)
		{
			int num = 0;
			for (int i = 0; i < todo.Count; i++)
			{
				try
				{
					if (todo[i] != null)
					{
						RepairOne(Player.m_localPlayer, todo[i], station, worn.Contains(todo[i]));
						num++;
					}
				}
				catch (Exception ex)
				{
					EasyGearPlugin.Log.LogError((object)("自动修理某件物品时出错:" + ex.Message));
				}
			}
			return num;
		}

		private static void RepairOne(Player player, ItemData item, CraftingStation station, bool announce)
		{
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			float maxDurability = item.GetMaxDurability();
			if (maxDurability <= 0f)
			{
				return;
			}
			if (miRaiseSkill != null && skillTypeEnum != null)
			{
				try
				{
					miRaiseSkill.Invoke(player, new object[2]
					{
						Enum.ToObject(skillTypeEnum, 107),
						1f - item.m_durability / maxDurability
					});
				}
				catch (Exception ex)
				{
					EasyGearPlugin.Log.LogWarning((object)("加修理熟练度失败(不影响修理):" + ex.Message));
				}
			}
			item.m_durability = maxDurability;
			if ((Object)(object)station != (Object)null && station.m_repairItemDoneEffects != null && (Object)(object)((Component)station).transform != (Object)null)
			{
				try
				{
					station.m_repairItemDoneEffects.Create(((Component)station).transform.position, Quaternion.identity, (Transform)null, 1f, -1, default(ZDOID));
				}
				catch (Exception ex2)
				{
					EasyGearPlugin.Log.LogWarning((object)("播放修理特效失败(不影响修理本身):" + ex2.Message));
				}
			}
			if (announce)
			{
				ShowMessage("已修复 " + LocalizeName(item));
			}
		}

		private static string LocalizeName(ItemData item)
		{
			string text = ((item.m_shared == null) ? null : item.m_shared.m_name);
			if (string.IsNullOrEmpty(text))
			{
				if (!((Object)(object)item.m_dropPrefab != (Object)null))
				{
					return "物品";
				}
				return ((Object)item.m_dropPrefab).name;
			}
			if (miLocalize != null)
			{
				try
				{
					object obj = miLocalize.Invoke(Localization.instance, new object[1] { text });
					if (obj is string && !string.IsNullOrEmpty((string)obj))
					{
						return (string)obj;
					}
				}
				catch
				{
				}
			}
			return text;
		}

		private static void Finish(CraftingStation station, int done, int aborted)
		{
			string text = (((Object)(object)station == (Object)null) ? "?" : station.m_name);
			if (aborted > 0)
			{
				EasyGearPlugin.Log.LogInfo((object)$"自动修理:「{text}」修好 {done} 件后中断(还剩 {aborted} 件没修)—— 你离开了站点或站点失效。");
			}
			else if (done > 0)
			{
				EasyGearPlugin.Log.LogInfo((object)$"自动修理:「{text}」修好 {done} 件(逐件间隔 {EasyGearPlugin.AutoRepairIntervalMs.Value}ms)。");
			}
			if (done > 0 && EasyGearPlugin.AutoRepairShowMessage.Value)
			{
				ShowMessage($"自动修理:{done} 件({text})");
			}
			try
			{
				InventoryGui instance = InventoryGui.instance;
				if ((Object)(object)instance != (Object)null && miUpdateRepair != null)
				{
					miUpdateRepair.Invoke(instance, null);
				}
			}
			catch (Exception ex)
			{
				EasyGearPlugin.Log.LogWarning((object)("刷新修理面板失败(不影响已修好的物品):" + ex.Message));
			}
		}

		internal static void ShowMessage(string text)
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || miMessage == null || messageTypeEnum == null)
			{
				return;
			}
			try
			{
				miMessage.Invoke(localPlayer, new object[5]
				{
					Enum.ToObject(messageTypeEnum, 2),
					text,
					0,
					null,
					false
				});
			}
			catch (Exception ex)
			{
				EasyGearPlugin.Log.LogWarning((object)("显示提示失败(不影响修理):" + ex.Message));
			}
		}
	}
	[BepInPlugin("easygear.client.only", "EasyGear", "1.0.3")]
	public class EasyGearPlugin : BaseUnityPlugin
	{
		public const string Guid = "easygear.client.only";

		public const string PluginName = "EasyGear";

		public const string PluginVersion = "1.0.3";

		internal static ManualLogSource Log;

		internal static EasyGearPlugin Instance;

		internal static ConfigEntry<bool> DurabilityEnabled;

		internal static ConfigEntry<string> DurabilityMode;

		internal static ConfigEntry<float> DurabilityLifetimeMultiplier;

		internal static ConfigEntry<bool> AreaRepairEnabled;

		internal static ConfigEntry<float> AreaRepairRadius;

		internal static ConfigEntry<bool> AreaRepairVerbose;

		internal static ConfigEntry<bool> AutoRepairEnabled;

		internal static ConfigEntry<bool> AutoRepairIncludeBackpack;

		internal static ConfigEntry<int> AutoRepairIntervalMs;

		internal static ConfigEntry<bool> AutoRepairShowMessage;

		internal static ConfigEntry<bool> AutoRepairVerbose;

		internal static ConfigEntry<bool> EquipWhileRunningEnabled;

		private Harmony harmony;

		private void Awake()
		{
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Expected O, but got Unknown
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Expected O, but got Unknown
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Expected O, but got Unknown
			//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b0: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			Instance = this;
			DurabilityEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - Item Durability", "Enabled", true, "耐久修改开关。覆盖武器、工具、弓箭、盾牌、护甲、锤子、锄头等。");
			DurabilityMode = ((BaseUnityPlugin)this).Config.Bind<string>("1 - Item Durability", "Mode", "LossReduction", new ConfigDescription("耐久的实现方式:\n  LossReduction = 耐久消耗 ÷ 倍率。装备明显更耐用,但物品提示里的耐久数字下降很慢,不容易一眼看出。\n  MaxDurability = 耐久上限 × 倍率。物品提示里的上限直接变成 5 倍,一眼可见。\n    注意:已有的装备需要先用锤子修一次才会满。\n  Both = 两者都做(寿命约 ×25,慎用)。", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[3] { "LossReduction", "MaxDurability", "Both" }), Array.Empty<object>()));
			DurabilityLifetimeMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("1 - Item Durability", "LifetimeMultiplier", 5f, new ConfigDescription("耐久倍率:5 = 同样的装备能用 5 倍久。", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 100f), Array.Empty<object>()));
			AreaRepairEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("2 - Area Repair", "Enabled", true, "锤子「范围修理」开关:用锤子的普通修理动作时,顺带修理附近的建筑部件。");
			AreaRepairRadius = ((BaseUnityPlugin)this).Config.Bind<float>("2 - Area Repair", "Radius", 30f, new ConfigDescription("范围修理半径(米),以你鼠标指向的那个部件为中心。默认 30 米。", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 100f), Array.Empty<object>()));
			AreaRepairVerbose = ((BaseUnityPlugin)this).Config.Bind<bool>("2 - Area Repair", "Verbose", true, "打开后在日志里逐次记录修好了几个部件(排查用)。");
			AutoRepairEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("3 - Auto Repair At Station", "Enabled", true, "打开工作台 / 熔炉(制造站)时,自动把身上受损的装备、工具、武器修满。\n身上穿戴的那批走的是游戏原版的修理函数,所以涨熟练度、修理特效、\n「已修复 xxx」提示都与手动点修理按钮完全一致;修理不消耗材料(原版修理本来就免费)。");
			AutoRepairIncludeBackpack = ((BaseUnityPlugin)this).Config.Bind<bool>("3 - Auto Repair At Station", "IncludeBackpackItems", true, "顺便修理背包里【没穿戴】的装备/工具/武器。\ntrue(默认)= 背包里的也一起修好;false = 只修身上穿戴的(= 原版修理按钮的范围)。\n注意:原版修理按钮只修身上穿戴的,背包那批是本模组额外补的。");
			AutoRepairIntervalMs = ((BaseUnityPlugin)this).Config.Bind<int>("3 - Auto Repair At Station", "IntervalMilliseconds", 150, new ConfigDescription("逐件修理的间隔(毫秒)。装备多的时候一件件修,能看清耐久条一根根回满。\n0 = 一次性全部修好(原来的行为,会一瞬间全满)。建议 100 - 200。", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 2000), Array.Empty<object>()));
			AutoRepairShowMessage = ((BaseUnityPlugin)this).Config.Bind<bool>("3 - Auto Repair At Station", "ShowMessage", false, "在屏幕上再显示一行「自动修理:N 件(站点名)」。\n默认关闭 —— 原版本来就对每件修好的物品各弹一条「已修复 xxx」,够看了。");
			AutoRepairVerbose = ((BaseUnityPlugin)this).Config.Bind<bool>("3 - Auto Repair At Station", "Verbose", false, "排查用:即使本次没有物品需要修理,也在日志里记一行(确认模组确实触发了)。");
			EquipWhileRunningEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("4 - Equip While Running", "Enabled", true, "跑步时也能切换武器 / 工具(解除原版限制)。\n原版在奔跑时会每帧清空「装备动作队列」,导致带抽拿动画的武器/工具\n按数字键后动作被取消、看起来完全没反应。\n打开(默认)后:跑步中也能正常拿出/收回。\n⚠\ufe0f 只拦「跑步」发起的取消 —— 攻击、跳跃、翻滚时的取消保持原版行为。");
			Log.LogInfo((object)"EasyGear 1.0.3 开始挂载 Harmony 补丁……");
			AutoRepair.Init();
			ApplyPatches();
			VerifyPatches();
		}

		private void ApplyPatches()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			harmony = new Harmony("easygear.client.only");
			Type[] array = new Type[7]
			{
				typeof(ObjectDbAwakePatch),
				typeof(ZNetSceneAwakePatch),
				typeof(PlayerRepairPatch),
				typeof(InventoryGuiShowPatch),
				typeof(PlayerCheckRunPatch),
				typeof(ClearActionQueuePatch),
				typeof(PlayerDamageArmorDurabilityPatch)
			};
			int num = 0;
			Type[] array2 = array;
			foreach (Type type in array2)
			{
				try
				{
					harmony.CreateClassProcessor(type).Patch();
					Log.LogInfo((object)("  已挂载补丁类:" + type.Name));
					num++;
				}
				catch (Exception ex)
				{
					Log.LogError((object)("  挂载失败 " + type.Name + ":" + ex.Message));
				}
			}
			Log.LogInfo((object)$"Harmony 补丁挂载完成:{num}/{array.Length} 成功。");
		}

		private void VerifyPatches()
		{
			List<MethodBase> list = new List<MethodBase>();
			AddTarget(list, AccessTools.Method(typeof(ObjectDB), "Awake", (Type[])null, (Type[])null), "ObjectDB.Awake(耐久改写入口)");
			AddTarget(list, AccessTools.Method(typeof(ZNetScene), "Awake", (Type[])null, (Type[])null), "ZNetScene.Awake(耐久改写兜底)");
			AddTarget(list, AccessTools.Method(typeof(Player), "Repair", (Type[])null, (Type[])null), "Player.Repair(范围修理)");
			AddTarget(list, AccessTools.Method(typeof(InventoryGui), "Show", new Type[2]
			{
				typeof(Container),
				typeof(int)
			}, (Type[])null), "InventoryGui.Show(Container,int)(进站自动修理)");
			AddTarget(list, AccessTools.Method(typeof(Player), "CheckRun", new Type[2]
			{
				typeof(Vector3),
				typeof(float)
			}, (Type[])null), "Player.CheckRun(Vector3,float)(跑步可切换装备·标记)");
			AddTarget(list, AccessTools.Method(typeof(Humanoid), "ClearActionQueue", (Type[])null, (Type[])null), "Humanoid.ClearActionQueue(跑步可切换装备·拦截)");
			MethodBase methodBase = AccessTools.Method(typeof(Player), "DamageArmorDurability", new Type[1] { typeof(HitData) }, (Type[])null);
			AddTarget(list, methodBase, "Player.DamageArmorDurability(HitData)(护甲耐久倍率)");
			if (methodBase != null && methodBase.DeclaringType != typeof(Player))
			{
				Log.LogError((object)("  !! DamageArmorDurability 解析到了 " + methodBase.DeclaringType.Name + ",而不是 Player 的重写 —— 护甲倍率可能不会生效"));
			}
			if (!PlayerDamageArmorDurabilityPatch.FieldsResolved)
			{
				Log.LogError((object)"  !! 反射不到护甲槽位字段(m_chestItem/m_legItem/m_helmetItem/m_shoulderItem) —— 护甲耐久倍率不会生效");
			}
			Log.LogInfo((object)"---- 补丁挂载自检 ----");
			foreach (MethodBase item in list)
			{
				Patches patchInfo = Harmony.GetPatchInfo(item);
				int num = ((patchInfo != null && patchInfo.Prefixes != null) ? patchInfo.Prefixes.Count : 0);
				int num2 = ((patchInfo != null && patchInfo.Postfixes != null) ? patchInfo.Postfixes.Count : 0);
				string text = ((num + num2 > 0) ? "OK" : "!! 未挂上 !!");
				Log.LogInfo((object)$"  {item.DeclaringType.Name}.{item.Name}()  prefix={num} postfix={num2}  {text}");
			}
			Log.LogInfo((object)$"  (目标方法 {list.Count} 个,全部已核对)");
			Log.LogInfo((object)"-----------------------");
		}

		private static void AddTarget(List<MethodBase> targets, MethodBase m, string label)
		{
			if (m == null)
			{
				Log.LogError((object)("  !! 找不到目标方法,对应功能不会生效:" + label));
			}
			else
			{
				targets.Add(m);
			}
		}

		private void OnDestroy()
		{
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}
	}
	internal static class ObjectDbApplier
	{
		private static readonly Dictionary<SharedData, float> OrigDurabilityDrain = new Dictionary<SharedData, float>();

		private static readonly Dictionary<SharedData, float> OrigMaxDurability = new Dictionary<SharedData, float>();

		private static bool appliedOnce;

		internal static bool AppliedOnce => appliedOnce;

		internal static void ApplyIfReady(string source)
		{
			try
			{
				ObjectDB instance = ObjectDB.instance;
				if ((Object)(object)instance == (Object)null)
				{
					EasyGearPlugin.Log.LogWarning((object)("[" + source + "] ObjectDB 还没就绪,稍后重试。"));
				}
				else if (instance.m_items == null)
				{
					EasyGearPlugin.Log.LogWarning((object)("[" + source + "] ObjectDB.m_items 为 null,跳过。"));
				}
				else
				{
					Apply(instance, source);
				}
			}
			catch (Exception ex)
			{
				EasyGearPlugin.Log.LogError((object)("[" + source + "] 应用失败(游戏本身不受影响):" + ex));
			}
		}

		private static void Apply(ObjectDB db, string source)
		{
			bool value = EasyGearPlugin.DurabilityEnabled.Value;
			float num = Mathf.Max(0.01f, EasyGearPlugin.DurabilityLifetimeMultiplier.Value);
			string value2 = EasyGearPlugin.DurabilityMode.Value;
			bool flag = value2 == "LossReduction" || value2 == "Both";
			bool flag2 = value2 == "MaxDurability" || value2 == "Both";
			int num2 = 0;
			int num3 = 0;
			StringBuilder stringBuilder = new StringBuilder();
			foreach (GameObject item in db.m_items)
			{
				if ((Object)(object)item == (Object)null)
				{
					continue;
				}
				ItemDrop component = item.GetComponent<ItemDrop>();
				if ((Object)(object)component == (Object)null || component.m_itemData == null)
				{
					continue;
				}
				SharedData shared = component.m_itemData.m_shared;
				if (shared == null || !value || !shared.m_useDurability)
				{
					continue;
				}
				if (flag && shared.m_useDurabilityDrain > 0f)
				{
					if (!OrigDurabilityDrain.TryGetValue(shared, out var value3))
					{
						value3 = shared.m_useDurabilityDrain;
						OrigDurabilityDrain[shared] = value3;
					}
					float num4 = (shared.m_useDurabilityDrain = value3 / num);
					num2++;
					if (stringBuilder.Length < 1200)
					{
						stringBuilder.AppendFormat("     {0}: 每次消耗 {1:0.####} -> {2:0.####}{3}", shared.m_name, value3, num4, Environment.NewLine);
					}
				}
				if (flag2 && shared.m_maxDurability > 0f)
				{
					if (!OrigMaxDurability.TryGetValue(shared, out var value4))
					{
						value4 = shared.m_maxDurability;
						OrigMaxDurability[shared] = value4;
					}
					shared.m_maxDurability = value4 * num;
					num3++;
				}
			}
			appliedOnce = true;
			string text = ((value2 == "Both") ? string.Format("消耗 ÷{0}({1} 件) + 上限 ×{0}({2} 件)", num, num2, num3) : ((!(value2 == "MaxDurability")) ? $"消耗 ÷{num}({num2} 件)" : $"上限 ×{num}({num3} 件)"));
			if (!value)
			{
				text = "已关闭(Enabled=false)";
			}
			EasyGearPlugin.Log.LogInfo((object)$"[{source}] 已处理 {db.m_items.Count} 件物品 → 耐久 {value2}:{text}");
			if (stringBuilder.Length > 0)
			{
				EasyGearPlugin.Log.LogInfo((object)("---- 耐久改动明细(前几件)----" + Environment.NewLine + stringBuilder));
			}
		}
	}
	[HarmonyPatch(typeof(ObjectDB), "Awake")]
	internal static class ObjectDbAwakePatch
	{
		[HarmonyPostfix]
		private static void Postfix()
		{
			ObjectDbApplier.ApplyIfReady("ObjectDB.Awake");
		}
	}
	[HarmonyPatch(typeof(ZNetScene), "Awake")]
	internal static class ZNetSceneAwakePatch
	{
		[HarmonyPostfix]
		private static void Postfix()
		{
			ObjectDbApplier.ApplyIfReady("ZNetScene.Awake");
		}
	}
	[HarmonyPatch(typeof(Player), "Repair")]
	internal static class PlayerRepairPatch
	{
		private static bool repairing;

		[HarmonyPostfix]
		private static void Postfix(Player __instance)
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			if (repairing || !EasyGearPlugin.AreaRepairEnabled.Value)
			{
				return;
			}
			try
			{
				if ((Object)(object)__instance == (Object)null)
				{
					return;
				}
				Piece hoveringPiece = __instance.GetHoveringPiece();
				if ((Object)(object)hoveringPiece == (Object)null || (Object)(object)((Component)hoveringPiece).transform == (Object)null)
				{
					return;
				}
				Vector3 position = ((Component)hoveringPiece).transform.position;
				float value = EasyGearPlugin.AreaRepairRadius.Value;
				float num = value * value;
				List<WearNTear> allInstances = WearNTear.GetAllInstances();
				if (allInstances == null || allInstances.Count == 0)
				{
					return;
				}
				repairing = true;
				int num2 = 0;
				for (int i = 0; i < allInstances.Count; i++)
				{
					WearNTear val = allInstances[i];
					if ((Object)(object)val == (Object)null)
					{
						continue;
					}
					Transform transform = ((Component)val).transform;
					if (!((Object)(object)transform == (Object)null))
					{
						Vector3 val2 = transform.position - position;
						if (!(((Vector3)(ref val2)).sqrMagnitude > num) && val.Repair())
						{
							num2++;
						}
					}
				}
				repairing = false;
				if (num2 > 0 && EasyGearPlugin.AreaRepairVerbose.Value)
				{
					EasyGearPlugin.Log.LogInfo((object)$"范围修理(半径 {value} 米):额外修好 {num2} 个部件。");
				}
			}
			catch (Exception ex)
			{
				repairing = false;
				EasyGearPlugin.Log.LogError((object)("范围修理失败(普通修理不受影响):" + ex));
			}
		}
	}
	[HarmonyPatch(typeof(InventoryGui), "Show", new Type[]
	{
		typeof(Container),
		typeof(int)
	})]
	internal static class InventoryGuiShowPatch
	{
		private static bool wasVisible;

		[HarmonyPrefix]
		private static void Prefix()
		{
			try
			{
				wasVisible = InventoryGui.IsVisible();
			}
			catch
			{
				wasVisible = false;
			}
		}

		[HarmonyPostfix]
		private static void Postfix(InventoryGui __instance, int activeGroup)
		{
			try
			{
				if (!wasVisible && activeGroup == 3 && EasyGearPlugin.AutoRepairEnabled.Value && AutoRepair.Begin(__instance, EasyGearPlugin.AutoRepairIncludeBackpack.Value, EasyGearPlugin.AutoRepairIntervalMs.Value) <= 0 && EasyGearPlugin.AutoRepairVerbose.Value)
				{
					EasyGearPlugin.Log.LogInfo((object)"自动修理:在制造站触发过检查,本次没有需要修理的物品(或人已不在站点旁)。");
				}
			}
			catch (Exception ex)
			{
				EasyGearPlugin.Log.LogError((object)("自动修理失败(不影响正常游戏):" + ex));
			}
		}
	}
	[HarmonyPatch(typeof(Player), "CheckRun", new Type[]
	{
		typeof(Vector3),
		typeof(float)
	})]
	internal static class PlayerCheckRunPatch
	{
		internal static bool InCheckRun;

		[HarmonyPrefix]
		private static void Prefix()
		{
			InCheckRun = true;
		}

		[HarmonyPostfix]
		private static void Postfix()
		{
			InCheckRun = false;
		}
	}
	[HarmonyPatch(typeof(Humanoid), "ClearActionQueue")]
	internal static class ClearActionQueuePatch
	{
		[HarmonyPrefix]
		private static bool Prefix(Humanoid __instance)
		{
			try
			{
				if (!EasyGearPlugin.EquipWhileRunningEnabled.Value)
				{
					return true;
				}
				if (!PlayerCheckRunPatch.InCheckRun)
				{
					return true;
				}
				Player val = (Player)(object)((__instance is Player) ? __instance : null);
				if ((Object)(object)val == (Object)null || !((Character)val).IsRunning())
				{
					return true;
				}
				return false;
			}
			catch (Exception ex)
			{
				EasyGearPlugin.Log.LogWarning((object)("跑步可切换装备:判定出错,本次交给原版处理:" + ex.Message));
				return true;
			}
		}
	}
}