Decompiled source of EasyWeapon v1.1.0

plugins/EasyWeapon/EasyWeapon.dll

Decompiled a week ago
using System;
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("EasyWeapon")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.1.0.0")]
[assembly: AssemblyInformationalVersion("1.1.0")]
[assembly: AssemblyProduct("EasyWeapon")]
[assembly: AssemblyTitle("EasyWeapon")]
[assembly: AssemblyVersion("1.1.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 EasyWeapon
{
	internal static class ChainLightningTuning
	{
		internal const string RedPrefabName = "ChainLightningRed";

		private const string ChainPrefabPrefix = "ChainLightning";

		private static bool weaponApplied;

		private static bool effectApplied;

		internal static void ApplyWeaponProcChance(string source)
		{
			try
			{
				if (weaponApplied)
				{
					return;
				}
				if (!EasyWeaponPlugin.ChainLightningEnabled.Value)
				{
					weaponApplied = true;
					EasyWeaponPlugin.Log.LogInfo((object)("[" + source + "] 连锁闪电强化已关闭(Enabled=false),武器侧不改。"));
					return;
				}
				ObjectDB instance = ObjectDB.instance;
				if ((Object)(object)instance == (Object)null)
				{
					EasyWeaponPlugin.Log.LogWarning((object)("[" + source + "] ObjectDB 还没就绪,武器侧稍后重试。"));
					return;
				}
				if (instance.m_items == null)
				{
					EasyWeaponPlugin.Log.LogWarning((object)("[" + source + "] ObjectDB.m_items 为 null,跳过。"));
					return;
				}
				float num = Mathf.Clamp01(EasyWeaponPlugin.ChainProcChance.Value);
				bool value = EasyWeaponPlugin.ChainLightningVerbose.Value;
				StringBuilder stringBuilder = new StringBuilder();
				int num2 = 0;
				int num3 = 0;
				foreach (GameObject item in instance.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)
					{
						int num4 = 0;
						num4 += SetProcChance(shared.m_attack, num, shared.m_name, "主攻击", stringBuilder, value);
						num4 += SetProcChance(shared.m_secondaryAttack, num, shared.m_name, "副攻击", stringBuilder, value);
						if (num4 > 0)
						{
							num2 += num4;
							num3++;
						}
					}
				}
				weaponApplied = true;
				EasyWeaponPlugin.Log.LogInfo((object)$"[{source}] 武器连锁触发率 → {num:0.###}(主/副攻击统一):命中 {num2} 个攻击槽 / {num3} 件武器(共扫 {instance.m_items.Count} 件物品)。");
				if (value && stringBuilder.Length > 0)
				{
					EasyWeaponPlugin.Log.LogInfo((object)("---- 武器连锁触发率改动明细 ----" + Environment.NewLine + stringBuilder));
				}
			}
			catch (Exception ex)
			{
				EasyWeaponPlugin.Log.LogError((object)("[武器连锁] 应用失败(游戏本身不受影响):" + ex));
			}
		}

		private static int SetProcChance(Attack atk, float chance, string itemKey, string slot, StringBuilder detail, bool verbose)
		{
			if (atk == null)
			{
				return 0;
			}
			if (atk.m_spawnOnHitChance <= 0f)
			{
				return 0;
			}
			if ((Object)(object)atk.m_spawnOnHit == (Object)null)
			{
				return 0;
			}
			if (!((Object)atk.m_spawnOnHit).name.StartsWith("ChainLightning", StringComparison.Ordinal))
			{
				return 0;
			}
			float spawnOnHitChance = atk.m_spawnOnHitChance;
			atk.m_spawnOnHitChance = chance;
			if (verbose && detail.Length < 1600)
			{
				detail.AppendFormat("     {0}({1})→ {2}:{3:0.###} → {4:0.###}", itemKey, slot, ((Object)atk.m_spawnOnHit).name, spawnOnHitChance, chance);
				detail.Append(Environment.NewLine);
			}
			return 1;
		}

		internal static void ApplyChainEffectTuning(string source)
		{
			try
			{
				if (effectApplied)
				{
					return;
				}
				if (!EasyWeaponPlugin.ChainLightningEnabled.Value)
				{
					effectApplied = true;
					EasyWeaponPlugin.Log.LogInfo((object)("[" + source + "] 连锁闪电强化已关闭(Enabled=false),特效侧不改。"));
					return;
				}
				ZNetScene instance = ZNetScene.instance;
				if ((Object)(object)instance == (Object)null)
				{
					EasyWeaponPlugin.Log.LogWarning((object)("[" + source + "] ZNetScene 还没就绪,特效侧稍后重试。"));
					return;
				}
				GameObject val = FindPrefab(instance, "ChainLightningRed");
				if ((Object)(object)val == (Object)null)
				{
					EasyWeaponPlugin.Log.LogError((object)("[" + source + "] 找不到预制体 ChainLightningRed —— 连锁特效参数不会生效(游戏更新可能改了名字)。"));
					return;
				}
				Aoe component = val.GetComponent<Aoe>();
				if ((Object)(object)component == (Object)null)
				{
					EasyWeaponPlugin.Log.LogError((object)("[" + source + "] 预制体 ChainLightningRed 上没有 Aoe 组件 —— 参数不会生效(游戏更新可能改了结构)。"));
					return;
				}
				float num = Mathf.Clamp01(EasyWeaponPlugin.RedStartChance.Value);
				float num2 = Mathf.Clamp01(EasyWeaponPlugin.RedChancePerTarget.Value);
				float num3 = Mathf.Max(0f, EasyWeaponPlugin.RedFalloff.Value);
				float num4 = Mathf.Max(0f, EasyWeaponPlugin.RedStartDelay.Value);
				float num5 = Mathf.Max(0.1f, EasyWeaponPlugin.RedRadius.Value);
				float num6 = Mathf.Max(0f, EasyWeaponPlugin.RedLightningDamage.Value);
				float num7 = EasyWeaponPlugin.RedTtl.Value;
				bool flag = num7 > 0f;
				if (flag)
				{
					num7 = Mathf.Max(0.1f, num7);
				}
				int num8 = Mathf.Max(0, EasyWeaponPlugin.RedMinTargets.Value);
				int num9 = Mathf.Max(0, EasyWeaponPlugin.RedMaxTargets.Value);
				if (num8 > num9)
				{
					int num10 = num8;
					num8 = num9;
					num9 = num10;
					EasyWeaponPlugin.Log.LogWarning((object)$"[{source}] MinTargets({num9}) 大于 MaxTargets({num8}),已在本次运行中自动交换(请修正配置)。");
				}
				float chainStartChance = component.m_chainStartChance;
				float chainChancePerTarget = component.m_chainChancePerTarget;
				int chainMinTargets = component.m_chainMinTargets;
				int chainMaxTargets = component.m_chainMaxTargets;
				float chainStartChanceFalloff = component.m_chainStartChanceFalloff;
				float chainStartDelay = component.m_chainStartDelay;
				float radius = component.m_radius;
				float ttl = component.m_ttl;
				float lightning = component.m_damage.m_lightning;
				component.m_chainStartChance = num;
				component.m_chainChancePerTarget = num2;
				component.m_chainMinTargets = num8;
				component.m_chainMaxTargets = num9;
				component.m_chainStartChanceFalloff = num3;
				component.m_chainStartDelay = num4;
				component.m_radius = num5;
				if (flag)
				{
					component.m_ttl = num7;
				}
				component.m_damage.m_lightning = num6;
				effectApplied = true;
				EasyWeaponPlugin.Log.LogInfo((object)string.Format("[{0}] 连锁特效 {1} 已改写:" + Environment.NewLine + "     起始判定   {2:0.###} → {3:0.###}" + Environment.NewLine + "     每目标几率 {4:0.###} → {5:0.###}" + Environment.NewLine + "     目标数     {6}~{7} → {8}~{9}" + Environment.NewLine + "     逐跳衰减   {10:0.###} → {11:0.###}", source, "ChainLightningRed", chainStartChance, num, chainChancePerTarget, num2, chainMinTargets, chainMaxTargets, num8, num9, chainStartChanceFalloff, num3));
				string text = (flag ? $"存活 {ttl:0.##} → {num7:0.##} s" : $"存活 {ttl:0.##} s(保持游戏默认,未改动)");
				EasyWeaponPlugin.Log.LogInfo((object)$"     起始延迟 {chainStartDelay:0.###} → {num4:0.###} s|半径 {radius:0.##} → {num5:0.##} m|每跳闪电伤害 {lightning:0.##} → {num6:0.##}|{text}");
				if ((Object)(object)component.m_chainObj == (Object)null)
				{
					EasyWeaponPlugin.Log.LogWarning((object)("[" + source + "] ⚠\ufe0f ChainLightningRed 的 m_chainObj 为空 —— 该特效不会继续往下一跳传播(原版如此?)。"));
				}
			}
			catch (Exception ex)
			{
				EasyWeaponPlugin.Log.LogError((object)("[连锁特效] 应用失败(游戏本身不受影响):" + ex));
			}
		}

		private static GameObject FindPrefab(ZNetScene scene, string name)
		{
			GameObject prefab = scene.GetPrefab(name);
			if ((Object)(object)prefab != (Object)null)
			{
				return prefab;
			}
			if (scene.m_prefabs != null)
			{
				foreach (GameObject prefab2 in scene.m_prefabs)
				{
					if ((Object)(object)prefab2 != (Object)null && ((Object)prefab2).name == name)
					{
						return prefab2;
					}
				}
			}
			return null;
		}
	}
	[HarmonyPatch(typeof(ObjectDB), "Awake")]
	internal static class ChainProcOnObjectDbPatch
	{
		[HarmonyPostfix]
		private static void Postfix()
		{
			ChainLightningTuning.ApplyWeaponProcChance("ObjectDB.Awake");
		}
	}
	[HarmonyPatch(typeof(ZNetScene), "Awake")]
	internal static class ChainEffectOnZNetScenePatch
	{
		[HarmonyPostfix]
		private static void Postfix()
		{
			ChainLightningTuning.ApplyChainEffectTuning("ZNetScene.Awake");
		}
	}
	[BepInPlugin("easyweapon.client.only", "EasyWeapon", "1.1.0")]
	public class EasyWeaponPlugin : BaseUnityPlugin
	{
		public const string Guid = "easyweapon.client.only";

		public const string PluginName = "EasyWeapon";

		public const string PluginVersion = "1.1.0";

		internal static ManualLogSource Log;

		internal static ConfigEntry<bool> ReloadSpeedEnabled;

		internal static ConfigEntry<float> ReloadTimeMultiplier;

		internal static ConfigEntry<bool> AffectCrossbows;

		internal static ConfigEntry<bool> AffectGrapplingHook;

		internal static ConfigEntry<bool> AffectStaves;

		internal static ConfigEntry<bool> AffectOtherReloadWeapons;

		internal static ConfigEntry<bool> ReloadSpeedVerbose;

		internal static ConfigEntry<bool> UninterruptibleEnabled;

		internal static ConfigEntry<bool> ProtectOnRun;

		internal static ConfigEntry<bool> ProtectOnJump;

		internal static ConfigEntry<bool> ProtectOnDodge;

		internal static ConfigEntry<bool> UninterruptibleVerbose;

		internal static ConfigEntry<bool> ChainLightningEnabled;

		internal static ConfigEntry<float> ChainProcChance;

		internal static ConfigEntry<float> RedStartChance;

		internal static ConfigEntry<float> RedChancePerTarget;

		internal static ConfigEntry<int> RedMinTargets;

		internal static ConfigEntry<int> RedMaxTargets;

		internal static ConfigEntry<float> RedFalloff;

		internal static ConfigEntry<float> RedStartDelay;

		internal static ConfigEntry<float> RedRadius;

		internal static ConfigEntry<float> RedTtl;

		internal static ConfigEntry<float> RedLightningDamage;

		internal static ConfigEntry<bool> ChainLightningVerbose;

		private Harmony harmony;

		private void Awake()
		{
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Expected O, but got Unknown
			//IL_01f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0200: Expected O, but got Unknown
			//IL_0233: Unknown result type (might be due to invalid IL or missing references)
			//IL_023d: Expected O, but got Unknown
			//IL_0270: Unknown result type (might be due to invalid IL or missing references)
			//IL_027a: Expected O, but got Unknown
			//IL_02a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ac: Expected O, but got Unknown
			//IL_02d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02de: Expected O, but got Unknown
			//IL_0311: Unknown result type (might be due to invalid IL or missing references)
			//IL_031b: Expected O, but got Unknown
			//IL_034e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0358: Expected O, but got Unknown
			//IL_038b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0395: Expected O, but got Unknown
			//IL_03c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d2: Expected O, but got Unknown
			//IL_0405: Unknown result type (might be due to invalid IL or missing references)
			//IL_040f: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			ReloadSpeedEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - Reload Speed", "Enabled", true, "装填时间倍率总开关。\n生效对象:弩、钩索(默认),以及可选的闪电法杖 / 其它走装填机制的武器。");
			ReloadTimeMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("1 - Reload Speed", "ReloadTimeMultiplier", 0.5f, new ConfigDescription("装填时间倍率:0.5 = 装填时间减半(更快)。\n⚠\ufe0f 这是「时间」倍率,不是「速度」倍率 —— 想快一倍就填 0.5,填 2 会变慢。\n原版数值:弩 3.5 秒(随弩技能升到 1.75 秒)、钩索 2.0 秒(不吃技能)。", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.05f, 2f), Array.Empty<object>()));
			AffectCrossbows = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - Reload Speed", "Crossbows", true, "弩(CrossbowArbalest / CrossbowRipper 及其变体 / CrossbowGold 及其变体)。");
			AffectGrapplingHook = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - Reload Speed", "GrapplingHook", true, "钩索。\n注意:游戏里它的本地化键拼写是 $item_graplinghook(少一个 p),不是笔误。");
			AffectStaves = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - Reload Speed", "Staves", false, "法杖(目前走装填机制的是闪电法杖,充能 1.9 秒)。\n默认关闭 —— 只想要弩和钩索变快的话别开。");
			AffectOtherReloadWeapons = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - Reload Speed", "OtherReloadWeapons", false, "其它「需要装填」的武器(游戏更新后新加的、本模组还不认识的)。\n默认关闭:宁可不动,也不误伤没见过的武器。");
			ReloadSpeedVerbose = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - Reload Speed", "Verbose", true, "首次遇到某件武器时在日志里记一条(含前后耗时与所用倍率),便于自证生效。\n同一件武器只记一次,不会刷屏。");
			UninterruptibleEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("2 - Uninterruptible Reload", "Enabled", true, "装填进度不被打断总开关。\n只保护装填动作 —— 队列里的装备动作在奔跑/跳跃/翻滚时**仍然按原版被清掉**。");
			ProtectOnRun = ((BaseUnityPlugin)this).Config.Bind<bool>("2 - Uninterruptible Reload", "OnRun", true, "奔跑时不打断装填(原版 Player.CheckRun 每帧清空动作队列)。");
			ProtectOnJump = ((BaseUnityPlugin)this).Config.Bind<bool>("2 - Uninterruptible Reload", "OnJump", true, "跳跃时不打断装填(原版 Player.OnJump 第一条指令就清空动作队列)。");
			ProtectOnDodge = ((BaseUnityPlugin)this).Config.Bind<bool>("2 - Uninterruptible Reload", "OnDodge", true, "闪避翻滚时不打断装填(原版 Player.UpdateDodge 会清空动作队列)。");
			UninterruptibleVerbose = ((BaseUnityPlugin)this).Config.Bind<bool>("2 - Uninterruptible Reload", "Verbose", true, "每次新的装填动作被保护时,在日志里记一条(同一个装填动作只记一次)。");
			ChainLightningEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("3 - Chain Lightning", "Enabled", true, "连锁闪电强化总开关(改的是 prefab 静态数据,纯客户端生效)。\n⚠\ufe0f 特效参数只改「雷血 / BloodLightning」那一族用的 ChainLightningRed;\n   另一族 ChainLightning(闪电附魔那批武器用的)本模组**不动**。\n   但武器侧的触发几率是对**所有**连锁武器统一的。");
			ChainProcChance = ((BaseUnityPlugin)this).Config.Bind<float>("3 - Chain Lightning", "WeaponProcChance", 0.66f, new ConfigDescription("所有「命中时生成连锁预制体」的攻击槽,主/副攻击统一用这个几率。\n原版:主攻击 0.25、副攻击 0.20。\n识别判据与游戏自己的 Attack.SpawnOnHit 完全一致(m_spawnOnHitChance > 0、\nm_spawnOnHit 非空,且目标预制体名以 ChainLightning 开头)\n⇒ 不写死武器名单,游戏日后新增连锁武器会自动跟上。", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			RedStartChance = ((BaseUnityPlugin)this).Config.Bind<float>("3 - Chain Lightning", "RedStartChance", 1f, new ConfigDescription("ChainLightningRed 的起始判定 m_chainStartChance(原版 0.9)。\n⚠\ufe0f 判定发生在特效存活期间**每帧一次**(延迟 RedStartDelay 之后开始),\n   所以 1 = 只要特效还在就必定去找目标 —— 它不是「每次挥击的触发率」,\n   真正的触发率在武器侧(WeaponProcChance)。", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			RedChancePerTarget = ((BaseUnityPlugin)this).Config.Bind<float>("3 - Chain Lightning", "RedChancePerTarget", 0.66f, new ConfigDescription("每个候选目标被链上的几率 m_chainChancePerTarget(原版 0.3)—— 各目标独立判定。", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			RedMinTargets = ((BaseUnityPlugin)this).Config.Bind<int>("3 - Chain Lightning", "RedMinTargets", 4, new ConfigDescription("一次连锁最少链几个目标(原版 2)。", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 32), Array.Empty<object>()));
			RedMaxTargets = ((BaseUnityPlugin)this).Config.Bind<int>("3 - Chain Lightning", "RedMaxTargets", 6, new ConfigDescription("一次连锁最多链几个目标(原版 4)。实际个数在 Min~Max 之间随机。", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 32), Array.Empty<object>()));
			RedFalloff = ((BaseUnityPlugin)this).Config.Bind<float>("3 - Chain Lightning", "RedFalloff", 0.8f, new ConfigDescription("逐跳衰减 m_chainStartChanceFalloff(原版 0.6):\n传给下一跳对象的几率 = 本跳几率 × 该值。填 1 = 不衰减。", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			RedStartDelay = ((BaseUnityPlugin)this).Config.Bind<float>("3 - Chain Lightning", "RedStartDelay", 0.18f, new ConfigDescription("特效生成后多久开始判定(秒),原版 0.18。", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 5f), Array.Empty<object>()));
			RedRadius = ((BaseUnityPlugin)this).Config.Bind<float>("3 - Chain Lightning", "RedRadius", 12f, new ConfigDescription("连锁判定半径(米),原版 8。", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 64f), Array.Empty<object>()));
			RedTtl = ((BaseUnityPlugin)this).Config.Bind<float>("3 - Chain Lightning", "RedTtl", -1f, new ConfigDescription("连锁特效存活时长(秒)。\n默认 -1 = 保持游戏默认值(3 秒),本模组**完全不碰**这个字段 ——\n将来游戏改了默认值也不会被本模组顶掉。\n填正数(0.1 ~ 30)才会覆盖。\n⚠\ufe0f 起始判定是「存活期间每帧一次」⇒ 它同时是连锁的判定窗口,填小了会明显削弱连锁。", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-1f, 30f), Array.Empty<object>()));
			RedLightningDamage = ((BaseUnityPlugin)this).Config.Bind<float>("3 - Chain Lightning", "RedLightningDamage", 90f, new ConfigDescription("每一跳的闪电伤害,原版 75。", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10000f), Array.Empty<object>()));
			ChainLightningVerbose = ((BaseUnityPlugin)this).Config.Bind<bool>("3 - Chain Lightning", "Verbose", true, "在日志里打印每条改动的前后数值(便于自证生效,不刷屏)。");
			Log.LogInfo((object)"EasyWeapon 1.1.0 开始挂载 Harmony 补丁……");
			if (UninterruptibleEnabled.Value)
			{
				UninterruptibleReload.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("easyweapon.client.only");
			Type[] array = new Type[7]
			{
				typeof(WeaponLoadingTimePatch),
				typeof(CheckRunMarkerPatch),
				typeof(OnJumpMarkerPatch),
				typeof(UpdateDodgeMarkerPatch),
				typeof(ProtectedReloadClearPatch),
				typeof(ChainProcOnObjectDbPatch),
				typeof(ChainEffectOnZNetScenePatch)
			};
			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(ItemData), "GetWeaponLoadingTime", (Type[])null, (Type[])null), "ItemData.GetWeaponLoadingTime(装填时间倍率)");
			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(Player), "OnJump", (Type[])null, (Type[])null), "Player.OnJump(跳跃来源标记)");
			AddTarget(list, AccessTools.Method(typeof(Player), "UpdateDodge", new Type[1] { typeof(float) }, (Type[])null), "Player.UpdateDodge(float)(翻滚来源标记)");
			AddTarget(list, AccessTools.Method(typeof(Player), "ClearActionQueue", (Type[])null, (Type[])null), "Player.ClearActionQueue(装填不被打断)");
			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(连锁闪电:特效参数)");
			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}");
				if (patchInfo == null || patchInfo.Prefixes == null)
				{
					continue;
				}
				foreach (Patch prefix in patchInfo.Prefixes)
				{
					if (prefix.owner != "easyweapon.client.only")
					{
						Log.LogInfo((object)$"      来自其它模组的 prefix:{prefix.owner}(优先级 {prefix.priority})");
					}
				}
			}
			MethodBase methodBase = AccessTools.Method(typeof(Humanoid), "ClearActionQueue", (Type[])null, (Type[])null);
			if (methodBase != null)
			{
				Patches patchInfo2 = Harmony.GetPatchInfo(methodBase);
				int num3 = ((patchInfo2 != null && patchInfo2.Prefixes != null) ? patchInfo2.Prefixes.Count : 0);
				Log.LogInfo((object)$"  [诊断] Humanoid.ClearActionQueue()(空实现)prefix={num3};(实际执行的是 Player 的重写,见上一行)");
			}
			if (!UninterruptibleReload.QueueFieldResolved)
			{
				Log.LogError((object)"  !! 反射不到 Player.m_actionQueue —— 「装填不被打断」不会生效(游戏更新可能改了这个字段名)。");
			}
			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 enum ReloadWeaponKind
	{
		Unknown,
		Crossbow,
		GrapplingHook,
		Staff,
		Other
	}
	internal static class ReloadClassifier
	{
		internal static string Normalize(string raw)
		{
			if (string.IsNullOrEmpty(raw))
			{
				return string.Empty;
			}
			string text = raw.Trim();
			if (text.Length > 0 && text[0] == '$')
			{
				int num = text.IndexOf('_');
				text = ((num >= 0) ? text.Substring(num + 1) : text.Substring(1));
			}
			StringBuilder stringBuilder = new StringBuilder(text.Length);
			string text2 = text;
			foreach (char c in text2)
			{
				if (c != '_' && c != ' ' && c != '-' && c != '.')
				{
					stringBuilder.Append(char.ToLowerInvariant(c));
				}
			}
			return stringBuilder.ToString();
		}

		internal static ReloadWeaponKind Classify(ItemData item)
		{
			if (item == null || item.m_shared == null)
			{
				return ReloadWeaponKind.Unknown;
			}
			return ClassifyKey(item.m_shared.m_name);
		}

		internal static ReloadWeaponKind ClassifyKey(string rawKey)
		{
			string text = Normalize(rawKey);
			if (text.Length == 0)
			{
				return ReloadWeaponKind.Unknown;
			}
			if (text == "graplinghook" || text == "grapplinghook")
			{
				return ReloadWeaponKind.GrapplingHook;
			}
			if (text.StartsWith("crossbow", StringComparison.Ordinal))
			{
				return ReloadWeaponKind.Crossbow;
			}
			if (text.StartsWith("staff", StringComparison.Ordinal))
			{
				return ReloadWeaponKind.Staff;
			}
			return ReloadWeaponKind.Other;
		}

		internal static bool IsAffected(ReloadWeaponKind kind)
		{
			return kind switch
			{
				ReloadWeaponKind.Crossbow => EasyWeaponPlugin.AffectCrossbows.Value, 
				ReloadWeaponKind.GrapplingHook => EasyWeaponPlugin.AffectGrapplingHook.Value, 
				ReloadWeaponKind.Staff => EasyWeaponPlugin.AffectStaves.Value, 
				ReloadWeaponKind.Other => EasyWeaponPlugin.AffectOtherReloadWeapons.Value, 
				_ => false, 
			};
		}

		internal static string Describe(ReloadWeaponKind kind)
		{
			return kind switch
			{
				ReloadWeaponKind.Crossbow => "弩", 
				ReloadWeaponKind.GrapplingHook => "钩索", 
				ReloadWeaponKind.Staff => "法杖", 
				ReloadWeaponKind.Other => "其它装填武器", 
				_ => "未识别", 
			};
		}
	}
	[HarmonyPatch(typeof(ItemData), "GetWeaponLoadingTime")]
	internal static class WeaponLoadingTimePatch
	{
		private static readonly HashSet<string> logged = new HashSet<string>();

		private static bool announcedError;

		[HarmonyPostfix]
		private static void Postfix(ItemData __instance, ref float __result)
		{
			try
			{
				if (!EasyWeaponPlugin.ReloadSpeedEnabled.Value || __instance == null || __instance.m_shared == null)
				{
					return;
				}
				Attack attack = __instance.m_shared.m_attack;
				if (attack == null || !attack.m_requiresReload)
				{
					return;
				}
				ReloadWeaponKind kind = ReloadClassifier.Classify(__instance);
				string text = __instance.m_shared.m_name ?? "?";
				if (!ReloadClassifier.IsAffected(kind))
				{
					LogOnce("skip:" + text, $"[装填] 跳过 {text}({ReloadClassifier.Describe(kind)}):该类别的开关是关的。");
					return;
				}
				float value = EasyWeaponPlugin.ReloadTimeMultiplier.Value;
				float num = __result;
				float num2 = num * value;
				if (!(num <= 0f))
				{
					__result = num2;
					LogOnce("hit:" + text, $"[装填] {text}({ReloadClassifier.Describe(kind)}):{num:F2}s → {num2:F2}s(倍率 {value})");
				}
			}
			catch (Exception ex)
			{
				if (!announcedError)
				{
					announcedError = true;
					EasyWeaponPlugin.Log.LogWarning((object)("[装填] 计算倍率时出错,本次按原版处理:" + ex.Message));
				}
			}
		}

		private static void LogOnce(string dedupKey, string message)
		{
			if (EasyWeaponPlugin.ReloadSpeedVerbose.Value && logged.Add(dedupKey))
			{
				EasyWeaponPlugin.Log.LogInfo((object)message);
			}
		}
	}
	internal static class ActionQueueAccess
	{
		private static FieldRef<Player, List<MinorActionData>> queueRef;

		private static bool initTried;

		internal static bool QueueFieldResolved { get; private set; }

		internal static void Init()
		{
			if (initTried)
			{
				return;
			}
			initTried = true;
			try
			{
				queueRef = AccessTools.FieldRefAccess<Player, List<MinorActionData>>("m_actionQueue");
				QueueFieldResolved = queueRef != null;
			}
			catch (Exception ex)
			{
				QueueFieldResolved = false;
				EasyWeaponPlugin.Log.LogError((object)("反射 Player.m_actionQueue 失败:" + ex.Message));
			}
		}

		internal static List<MinorActionData> Get(Player player)
		{
			if (queueRef == null || (Object)(object)player == (Object)null)
			{
				return null;
			}
			try
			{
				return queueRef.Invoke(player);
			}
			catch (Exception)
			{
				return null;
			}
		}
	}
	internal static class InterruptSource
	{
		private const int DepthCap = 1000;

		private static int runDepth;

		private static int jumpDepth;

		private static int dodgeDepth;

		internal static void EnterRun()
		{
			if (runDepth < 1000)
			{
				runDepth++;
			}
		}

		internal static void ExitRun()
		{
			if (runDepth > 0)
			{
				runDepth--;
			}
		}

		internal static void EnterJump()
		{
			if (jumpDepth < 1000)
			{
				jumpDepth++;
			}
		}

		internal static void ExitJump()
		{
			if (jumpDepth > 0)
			{
				jumpDepth--;
			}
		}

		internal static void EnterDodge()
		{
			if (dodgeDepth < 1000)
			{
				dodgeDepth++;
			}
		}

		internal static void ExitDodge()
		{
			if (dodgeDepth > 0)
			{
				dodgeDepth--;
			}
		}

		internal static bool IsProtectedSource()
		{
			if (runDepth > 0 && EasyWeaponPlugin.ProtectOnRun.Value)
			{
				return true;
			}
			if (jumpDepth > 0 && EasyWeaponPlugin.ProtectOnJump.Value)
			{
				return true;
			}
			if (dodgeDepth > 0 && EasyWeaponPlugin.ProtectOnDodge.Value)
			{
				return true;
			}
			return false;
		}

		internal static string DescribeCurrent()
		{
			if (runDepth > 0)
			{
				return "奔跑";
			}
			if (jumpDepth > 0)
			{
				return "跳跃";
			}
			if (dodgeDepth > 0)
			{
				return "闪避翻滚";
			}
			return "未知";
		}
	}
	[HarmonyPatch(typeof(Player), "CheckRun", new Type[]
	{
		typeof(Vector3),
		typeof(float)
	})]
	internal static class CheckRunMarkerPatch
	{
		[HarmonyPrefix]
		private static void Prefix()
		{
			InterruptSource.EnterRun();
		}

		[HarmonyPostfix]
		private static void Postfix()
		{
			InterruptSource.ExitRun();
		}
	}
	[HarmonyPatch(typeof(Player), "OnJump")]
	internal static class OnJumpMarkerPatch
	{
		[HarmonyPrefix]
		private static void Prefix()
		{
			InterruptSource.EnterJump();
		}

		[HarmonyPostfix]
		private static void Postfix()
		{
			InterruptSource.ExitJump();
		}
	}
	[HarmonyPatch(typeof(Player), "UpdateDodge", new Type[] { typeof(float) })]
	internal static class UpdateDodgeMarkerPatch
	{
		[HarmonyPrefix]
		private static void Prefix()
		{
			InterruptSource.EnterDodge();
		}

		[HarmonyPostfix]
		private static void Postfix()
		{
			InterruptSource.ExitDodge();
		}
	}
	[HarmonyPatch(typeof(Player), "ClearActionQueue")]
	[HarmonyPriority(200)]
	internal static class ProtectedReloadClearPatch
	{
		private static MinorActionData lastLogged;

		private static bool announcedError;

		[HarmonyPrefix]
		private static bool Prefix(Player __instance)
		{
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Invalid comparison between Unknown and I4
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Invalid comparison between Unknown and I4
			try
			{
				if (!EasyWeaponPlugin.UninterruptibleEnabled.Value)
				{
					return true;
				}
				if (!InterruptSource.IsProtectedSource())
				{
					return true;
				}
				List<MinorActionData> list = ActionQueueAccess.Get(__instance);
				if (list == null || list.Count == 0)
				{
					return true;
				}
				bool flag = false;
				for (int i = 0; i < list.Count; i++)
				{
					MinorActionData val = list[i];
					if (val != null && (int)val.m_type == 2)
					{
						flag = true;
						break;
					}
				}
				if (!flag)
				{
					return true;
				}
				int num = 0;
				MinorActionData kept = null;
				for (int num2 = list.Count - 1; num2 >= 0; num2--)
				{
					MinorActionData val2 = list[num2];
					if (val2 != null && (int)val2.m_type == 2)
					{
						kept = val2;
					}
					else
					{
						list.RemoveAt(num2);
						num++;
					}
				}
				LogOnce(kept, num, list.Count);
				return false;
			}
			catch (Exception ex)
			{
				if (!announcedError)
				{
					announcedError = true;
					EasyWeaponPlugin.Log.LogWarning((object)("装填保护:判定出错,本次交给原版清空:" + ex.Message));
				}
				return true;
			}
		}

		private static void LogOnce(MinorActionData kept, int removed, int remain)
		{
			if (!EasyWeaponPlugin.UninterruptibleVerbose.Value || (kept != null && lastLogged == kept))
			{
				return;
			}
			lastLogged = kept;
			string text = "?";
			try
			{
				if (kept != null && kept.m_item != null && kept.m_item.m_shared != null)
				{
					text = kept.m_item.m_shared.m_name;
				}
			}
			catch (Exception)
			{
			}
			float num = kept?.m_time ?? 0f;
			float num2 = kept?.m_duration ?? 0f;
			EasyWeaponPlugin.Log.LogInfo((object)$"[装填保护] {InterruptSource.DescribeCurrent()}触发的清空:保留装填动作「{text}」(进度 {num:F2}s / {num2:F2}s),移除其它动作 {removed} 个,队列现有 {remain} 条。");
		}
	}
	internal static class UninterruptibleReload
	{
		internal static bool QueueFieldResolved => ActionQueueAccess.QueueFieldResolved;

		internal static void Init()
		{
			ActionQueueAccess.Init();
		}
	}
}