Decompiled source of BreakableShields v2.0.0

BreakableShields.dll

Decompiled 2 months ago
using System;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Landfall.TABS;
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("BreakableShields")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("BreakableShields")]
[assembly: AssemblyTitle("BreakableShields")]
[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 BreakableShields
{
	[HarmonyPatch(typeof(Holdable), "Start")]
	internal static class HoldableStartPatch
	{
		private static void Postfix(Holdable __instance)
		{
			if (Plugin.Enabled.Value && !((Object)(object)__instance == (Object)null))
			{
				ShieldHealth.EnsureOn(__instance);
			}
		}
	}
	[HarmonyPatch(typeof(Holdable), "WasGrabbed")]
	internal static class HoldableGrabPatch
	{
		private static void Postfix(Holdable __instance)
		{
			if (Plugin.Enabled.Value && !((Object)(object)__instance == (Object)null))
			{
				ShieldHealth shieldHealth = ShieldHealth.EnsureOn(__instance);
				if ((Object)(object)shieldHealth != (Object)null)
				{
					shieldHealth.InitStats();
					shieldHealth.TryApplyHolderHealth();
					shieldHealth.BuildExtendedCatch();
				}
			}
		}
	}
	[HarmonyPatch(typeof(BlockMove), "ProjectileBlock")]
	internal static class BlockMoveProjectilePatch
	{
		private static void Postfix(BlockMove __instance, GameObject projectile, HitData hit, bool __result)
		{
			//IL_0140: 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_0138: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			//IL_018b: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.Enabled.Value || !__result || (Object)(object)__instance == (Object)null)
			{
				return;
			}
			ShieldHealth shieldHealth = ((Component)__instance).GetComponentInParent<ShieldHealth>();
			if ((Object)(object)shieldHealth == (Object)null && (Object)(object)__instance.rig != (Object)null)
			{
				shieldHealth = ((Component)__instance.rig).GetComponentInParent<ShieldHealth>();
			}
			if ((Object)(object)shieldHealth == (Object)null)
			{
				DataHandler componentInChildren = ((Component)((Component)__instance).transform.root).GetComponentInChildren<DataHandler>();
				if ((Object)(object)componentInChildren != (Object)null)
				{
					HoldingHandler component = ((Component)componentInChildren).GetComponent<HoldingHandler>();
					if ((Object)(object)component != (Object)null)
					{
						if ((Object)(object)component.leftObject != (Object)null)
						{
							shieldHealth = ((Component)component.leftObject).GetComponent<ShieldHealth>() ?? ShieldHealth.EnsureOn(component.leftObject);
						}
						if ((Object)(object)shieldHealth == (Object)null && (Object)(object)component.rightObject != (Object)null)
						{
							shieldHealth = ((Component)component.rightObject).GetComponent<ShieldHealth>() ?? ShieldHealth.EnsureOn(component.rightObject);
						}
					}
				}
			}
			if (!((Object)(object)shieldHealth == (Object)null) && !shieldHealth.broken)
			{
				float num = 0f;
				ProjectileHit val = (((Object)(object)projectile != (Object)null) ? projectile.GetComponent<ProjectileHit>() : null);
				if ((Object)(object)val != (Object)null)
				{
					num = val.damage;
				}
				if (num <= 0f)
				{
					num = 25f;
				}
				num *= Plugin.ProjectileDamageMultiplier.Value;
				Vector3 direction = ((hit != null) ? (-hit.normal) : Vector3.forward);
				Unit damager = null;
				TeamHolder val2 = (((Object)(object)projectile != (Object)null) ? projectile.GetComponent<TeamHolder>() : null);
				if ((Object)(object)val2 != (Object)null && (Object)(object)val2.spawner != (Object)null)
				{
					damager = val2.spawner.GetComponentInParent<Unit>();
				}
				shieldHealth.ApplyDamage(num, direction, damager, "ProjectileBlock");
			}
		}
	}
	[HarmonyPatch(typeof(CollisionWeapon), "OnCollisionEnter")]
	internal static class CollisionWeaponShieldPatch
	{
		private static void Prefix(CollisionWeapon __instance, Collision collision)
		{
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.Enabled.Value || (Object)(object)__instance == (Object)null || collision == null || (Object)(object)collision.rigidbody == (Object)null)
			{
				return;
			}
			Holdable componentInParent = ((Component)collision.rigidbody).GetComponentInParent<Holdable>();
			if ((Object)(object)componentInParent == (Object)null || !componentInParent.held || !ShieldHealth.IsShieldObject(((Component)componentInParent).gameObject))
			{
				return;
			}
			if ((Object)(object)componentInParent.holderData != (Object)null)
			{
				Unit componentInParent2 = ((Component)__instance).GetComponentInParent<Unit>();
				if ((Object)(object)componentInParent2 == (Object)null)
				{
					Holdable component = ((Component)__instance).GetComponent<Holdable>();
					if ((Object)(object)component != (Object)null && (Object)(object)component.holderData != (Object)null)
					{
						componentInParent2 = ((Component)component.holderData).GetComponentInParent<Unit>();
					}
				}
				Unit componentInParent3 = ((Component)componentInParent.holderData).GetComponentInParent<Unit>();
				if ((Object)(object)componentInParent2 != (Object)null && (Object)(object)componentInParent3 != (Object)null && componentInParent2.Team == componentInParent3.Team)
				{
					return;
				}
			}
			ShieldHealth.EnsureOn(componentInParent);
		}
	}
	[HarmonyPatch(typeof(ShieldHealth), "TakeDamage")]
	internal static class ShieldTakeDamageMultPatch
	{
		private static void Prefix(ref float damage)
		{
			if (Plugin.Enabled.Value)
			{
				damage *= Plugin.MeleeDamageMultiplier.Value;
			}
		}
	}
	[HarmonyPatch(typeof(WeaponHandler), "Start")]
	internal static class WeaponHandlerStartPatch
	{
		private static void Postfix(WeaponHandler __instance)
		{
			if (Plugin.Enabled.Value && !((Object)(object)__instance == (Object)null))
			{
				TryAttach(__instance.leftWeapon);
				TryAttach(__instance.rightWeapon);
			}
		}

		private static void TryAttach(Weapon weapon)
		{
			if ((Object)(object)weapon == (Object)null)
			{
				return;
			}
			Holdable component = ((Component)weapon).GetComponent<Holdable>();
			if ((Object)(object)component != (Object)null)
			{
				ShieldHealth shieldHealth = ShieldHealth.EnsureOn(component);
				if ((Object)(object)shieldHealth != (Object)null)
				{
					shieldHealth.TryApplyHolderHealth();
				}
			}
		}
	}
	[HarmonyPatch(typeof(SurfaceBlock), "DoEffect", new Type[]
	{
		typeof(HitData),
		typeof(GameObject)
	})]
	internal static class SurfaceBlockProjectHitPatch
	{
		private static void Prefix(ref HitData hit, GameObject projectile)
		{
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.Enabled.Value || hit == null || (Object)(object)hit.collider == (Object)null)
			{
				return;
			}
			ShieldExtendedCatch component = ((Component)hit.collider).GetComponent<ShieldExtendedCatch>();
			if ((Object)(object)component == (Object)null)
			{
				return;
			}
			Collider visibleCollider = component.visibleCollider;
			if (!((Object)(object)visibleCollider == (Object)null) && visibleCollider.enabled)
			{
				Vector3 val = visibleCollider.ClosestPoint(hit.point);
				hit.point = val;
				if ((Object)(object)projectile != (Object)null)
				{
					projectile.transform.position = val;
				}
			}
		}
	}
	[BepInPlugin("local.breakableshields", "BreakableShields", "2.0.0")]
	public class Plugin : BaseUnityPlugin
	{
		public const string GUID = "local.breakableshields";

		public const string Name = "BreakableShields";

		public const string Version = "2.0.0";

		internal static Plugin Instance;

		internal static ManualLogSource Log;

		internal static ConfigEntry<bool> Enabled;

		internal static ConfigEntry<float> BaseHealth;

		internal static ConfigEntry<float> HolderHealthMultiplier;

		internal static ConfigEntry<float> MeleeDamageMultiplier;

		internal static ConfigEntry<float> ProjectileDamageMultiplier;

		internal static ConfigEntry<bool> BreakDropsShield;

		internal static ConfigEntry<bool> DisableBlockOnBreak;

		internal static ConfigEntry<bool> DebugLog;

		internal static ConfigEntry<float> ExtendedCatchScale;

		internal static ConfigEntry<float> BashBaseDamage;

		internal static ConfigEntry<float> BashStaggerPerDamage;

		private void Awake()
		{
			//IL_0192: Unknown result type (might be due to invalid IL or missing references)
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enable breakable shields.");
			DebugLog = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "DebugLog", false, "Log shield attach/damage/break events.");
			BaseHealth = ((BaseUnityPlugin)this).Config.Bind<float>("Health", "BaseHealth", 200f, "Base shield HP. Final = BaseHealth + HolderHealthMultiplier * holder max HP.");
			HolderHealthMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Health", "HolderHealthMultiplier", 3f, "Shield HP adds this * holder's maxHealth.");
			MeleeDamageMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Damage", "MeleeDamageMultiplier", 3f, "Multiplier for melee damage applied to shields.");
			ProjectileDamageMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Damage", "ProjectileDamageMultiplier", 1f, "Multiplier for projectile damage applied to shields.");
			BreakDropsShield = ((BaseUnityPlugin)this).Config.Bind<bool>("Break", "DropOnBreak", true, "Drop the shield from the unit's hands when HP reaches 0.");
			DisableBlockOnBreak = ((BaseUnityPlugin)this).Config.Bind<bool>("Break", "DisableBlockOnBreak", true, "Disable projectile blocking when the shield breaks.");
			ExtendedCatchScale = ((BaseUnityPlugin)this).Config.Bind<float>("Catch", "ExtendedCatchScale", 1.3f, "Multiplier for the invisible catch collider. 1.3 = 30% larger catch zone around the visible shield. Hit positions on this zone are projected back onto the visible shield so arrows still appear to hit the shield.");
			BashBaseDamage = ((BaseUnityPlugin)this).Config.Bind<float>("Bash", "BashBaseDamage", 100f, "Fallback damage value used by the shield bash stagger calculation when the shield's own CollisionWeapon deals no damage.");
			BashStaggerPerDamage = ((BaseUnityPlugin)this).Config.Bind<float>("Bash", "BashStaggerPerDamage", 0.005f, "Stagger duration (seconds) per point of damage actually dealt by a shield bash. Default 0.005 means 100 damage = 0.5s. Stagger prevents movement and attacking, but does not ragdoll the target.");
			new Harmony("local.breakableshields").PatchAll();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"BreakableShields 2.0.0 loaded.");
		}

		internal static void Dbg(string msg)
		{
			if (DebugLog != null && DebugLog.Value)
			{
				Log.LogInfo((object)msg);
			}
		}
	}
	public class ShieldHealth : Damagable
	{
		public float maxHealth = 400f;

		public float health = 400f;

		public bool broken;

		private Holdable _holdable;

		private BlockMove _blockMove;

		private BlockMoveHealth _blockMoveHealth;

		private Rigidbody _rig;

		private bool _initialized;

		private bool _statsFromHolderApplied;

		private GameObject _extendedCatchGo;

		private Collider _extendedCatchCollider;

		private ShieldExtendedCatch _extendedCatchMarker;

		private bool _catchBuilt;

		private float _lastBashTime;

		private static readonly MethodInfo DontWalkForMethod = typeof(DataHandler).GetMethod("DontWalkFor", BindingFlags.Instance | BindingFlags.NonPublic);

		private static readonly FieldInfo LeftHandJointField = typeof(HoldingHandler).GetField("leftHandJoint", BindingFlags.Instance | BindingFlags.NonPublic);

		private static readonly FieldInfo RightHandJointField = typeof(HoldingHandler).GetField("rightHandJoint", BindingFlags.Instance | BindingFlags.NonPublic);

		private static readonly FieldInfo UnitApiField = typeof(WeaponHandler).GetField("m_unitAPI", BindingFlags.Instance | BindingFlags.NonPublic);

		private static readonly FieldInfo WhUnitField = typeof(WeaponHandler).GetField("unit", BindingFlags.Instance | BindingFlags.NonPublic);

		private static readonly FieldInfo WhDataField = typeof(WeaponHandler).GetField("data", BindingFlags.Instance | BindingFlags.NonPublic);

		public static bool IsShieldObject(GameObject go)
		{
			if ((Object)(object)go == (Object)null)
			{
				return false;
			}
			if ((Object)(object)go.GetComponentInChildren<BlockMove>(true) != (Object)null)
			{
				return true;
			}
			if ((Object)(object)go.GetComponentInChildren<SurfaceBlock>(true) != (Object)null)
			{
				return true;
			}
			string name = ((Object)go).name;
			if (string.IsNullOrEmpty(name))
			{
				return false;
			}
			name = name.ToLowerInvariant();
			if (!name.Contains("shield") && !name.Contains("buckler"))
			{
				return name.Contains("pavise");
			}
			return true;
		}

		public static ShieldHealth EnsureOn(Holdable holdable)
		{
			if ((Object)(object)holdable == (Object)null)
			{
				return null;
			}
			ShieldHealth component = ((Component)holdable).GetComponent<ShieldHealth>();
			if ((Object)(object)component != (Object)null)
			{
				return component;
			}
			if (!IsShieldObject(((Component)holdable).gameObject))
			{
				return null;
			}
			return ((Component)holdable).gameObject.AddComponent<ShieldHealth>();
		}

		private void Awake()
		{
			_holdable = ((Component)this).GetComponent<Holdable>();
			_blockMove = ((Component)this).GetComponentInChildren<BlockMove>(true);
			_blockMoveHealth = ((Component)this).GetComponentInChildren<BlockMoveHealth>(true);
			_rig = ((Component)this).GetComponent<Rigidbody>();
			if ((Object)(object)_rig == (Object)null)
			{
				_rig = ((Component)this).GetComponentInChildren<Rigidbody>();
			}
			CollisionWeapon[] componentsInChildren = ((Component)this).GetComponentsInChildren<CollisionWeapon>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				if ((Object)(object)componentsInChildren[i] != (Object)null)
				{
					componentsInChildren[i].AddDealDamageAction((Action<Collision, float, Vector3>)OnBashDealDamage);
				}
			}
		}

		private void OnBashDealDamage(Collision collision, float damage, Vector3 direction)
		{
			//IL_0145: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.Enabled.Value || broken || collision == null || (Object)(object)collision.rigidbody == (Object)null)
			{
				return;
			}
			float num = damage;
			if (num <= 0f)
			{
				num = Mathf.Max(0f, Plugin.BashBaseDamage.Value);
			}
			float num2 = Mathf.Max(0f, Plugin.BashStaggerPerDamage.Value);
			float num3 = num * num2;
			if (num3 <= 0f || Time.time - _lastBashTime < 0.25f)
			{
				return;
			}
			_lastBashTime = Time.time;
			Unit val = ((Component)collision.rigidbody).GetComponentInParent<Unit>();
			if ((Object)(object)val == (Object)null)
			{
				val = ((Component)collision.transform.root).GetComponent<Unit>();
			}
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			Unit val2 = null;
			if ((Object)(object)_holdable != (Object)null && (Object)(object)_holdable.holderData != (Object)null)
			{
				val2 = ((Component)_holdable.holderData).GetComponentInParent<Unit>();
			}
			if ((Object)(object)val2 == (Object)null)
			{
				val2 = ((Component)this).GetComponentInParent<Unit>();
			}
			if ((Object)(object)val2 != (Object)null && (Object)(object)val2 == (Object)(object)val)
			{
				return;
			}
			if ((Object)(object)val2 != (Object)null)
			{
				TeamHolder component = ((Component)val2).GetComponent<TeamHolder>();
				TeamHolder component2 = ((Component)val).GetComponent<TeamHolder>();
				if ((Object)(object)component != (Object)null && (Object)(object)component2 != (Object)null && component.team == component2.team)
				{
					return;
				}
			}
			Plugin.Dbg("[BreakableShields] Bash dealt " + num.ToString("0.#") + " dmg -> stagger " + num3.ToString("0.###") + "s on " + ((Object)((Component)val).gameObject).name);
			ApplyStagger(val, num3);
		}

		private void Start()
		{
			InitStats();
			if ((Object)(object)_holdable != (Object)null && _holdable.held)
			{
				BuildExtendedCatch();
			}
		}

		private void Update()
		{
			if (_catchBuilt && !((Object)(object)_extendedCatchGo == (Object)null) && (Object)(object)_holdable != (Object)null && !_holdable.held)
			{
				DestroyExtendedCatch(allowRebuild: true);
			}
		}

		private void OnDestroy()
		{
			DestroyExtendedCatch();
		}

		public void InitStats()
		{
			if (!_initialized)
			{
				_initialized = true;
				maxHealth = Mathf.Max(1f, Plugin.BaseHealth.Value);
				health = maxHealth;
				if ((Object)(object)_blockMoveHealth != (Object)null)
				{
					((Behaviour)_blockMoveHealth).enabled = false;
				}
				TryApplyHolderHealth();
				Plugin.Dbg("[BreakableShields] Init " + ((Object)((Component)this).gameObject).name + " HP=" + maxHealth);
			}
		}

		public void TryApplyHolderHealth()
		{
			if (!broken && !_statsFromHolderApplied && !((Object)(object)_holdable == (Object)null) && !((Object)(object)_holdable.holderData == (Object)null))
			{
				float num = _holdable.holderData.maxHealth;
				if (num <= 0f)
				{
					num = _holdable.holderData.health;
				}
				if (!(num <= 0f))
				{
					float num2 = Plugin.BaseHealth.Value + Plugin.HolderHealthMultiplier.Value * num;
					maxHealth = Mathf.Max(1f, num2);
					health = maxHealth;
					_statsFromHolderApplied = true;
					Plugin.Dbg("[BreakableShields] Stats from holder " + ((Object)((Component)this).gameObject).name + " holderHP=" + num + " shieldHP=" + maxHealth);
				}
			}
		}

		public override void TakeDamage(float damage, Vector3 direction, Unit damager = null, DamageType damageType = (DamageType)0)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			ApplyDamage(damage, direction, damager, "TakeDamage");
		}

		public void ApplyDamage(float damage, Vector3 direction, Unit damager, string source)
		{
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.Enabled.Value || broken)
			{
				return;
			}
			if (!_initialized)
			{
				InitStats();
			}
			if (!_statsFromHolderApplied)
			{
				TryApplyHolderHealth();
			}
			if (!(damage <= 0f) && !float.IsNaN(damage) && !float.IsInfinity(damage) && (!((Object)(object)_holdable != (Object)null) || _holdable.held || broken))
			{
				health -= damage;
				Plugin.Dbg("[BreakableShields] " + ((Object)((Component)this).gameObject).name + " -" + damage.ToString("0.#") + " via " + source + " => " + health.ToString("0.#") + "/" + maxHealth.ToString("0.#"));
				if (health <= 0f)
				{
					Break(direction, damager);
				}
			}
		}

		public void Break(Vector3 direction, Unit damager)
		{
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			if (broken)
			{
				return;
			}
			broken = true;
			health = 0f;
			Plugin.Dbg("[BreakableShields] BREAK " + ((Object)((Component)this).gameObject).name);
			DestroyExtendedCatch();
			if (Plugin.DisableBlockOnBreak.Value)
			{
				if ((Object)(object)_blockMove != (Object)null)
				{
					_blockMove.SetDisabled();
				}
				SurfaceBlock[] componentsInChildren = ((Component)this).GetComponentsInChildren<SurfaceBlock>(true);
				for (int i = 0; i < componentsInChildren.Length; i++)
				{
					((Behaviour)componentsInChildren[i]).enabled = false;
				}
			}
			if (!((Object)((Component)this).gameObject).name.EndsWith("_Broken"))
			{
				((Object)((Component)this).gameObject).name = ((Object)((Component)this).gameObject).name + "_Broken";
			}
			if (Plugin.BreakDropsShield.Value)
			{
				ForceDropCompletely();
			}
			if ((Object)(object)_rig != (Object)null)
			{
				_rig.isKinematic = false;
				if (((Vector3)(ref direction)).sqrMagnitude > 0.01f)
				{
					_rig.AddForce(((Vector3)(ref direction)).normalized * 8f + Vector3.up * 2f, (ForceMode)1);
				}
			}
		}

		public void ForceDropCompletely()
		{
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Invalid comparison between Unknown and I4
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Invalid comparison between Unknown and I4
			//IL_01a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_holdable == (Object)null)
			{
				return;
			}
			HoldingHandler val = null;
			DataHandler holderData = _holdable.holderData;
			if ((Object)(object)holderData != (Object)null)
			{
				val = ((Component)holderData).GetComponent<HoldingHandler>();
			}
			if ((Object)(object)val == (Object)null && (Object)(object)_holdable.holdingHandler != (Object)null)
			{
				val = _holdable.holdingHandler;
			}
			bool ignoreDissarm = _holdable.ignoreDissarm;
			_holdable.ignoreDissarm = false;
			try
			{
				bool flag = false;
				bool flag2 = false;
				if ((Object)(object)val != (Object)null)
				{
					bool flag3 = (Object)(object)val.rightObject == (Object)(object)_holdable;
					bool flag4 = (Object)(object)val.leftObject == (Object)(object)_holdable;
					bool flag5 = flag3 && (int)val.leftHandActivity == 1;
					bool flag6 = flag4 && (int)val.rightHandActivity == 2;
					if (!flag3 && !flag4)
					{
						WeaponHandler component = ((Component)val).GetComponent<WeaponHandler>();
						if ((Object)(object)component != (Object)null)
						{
							if ((Object)(object)component.leftWeapon != (Object)null && (Object)(object)((Component)component.leftWeapon).gameObject == (Object)(object)((Component)this).gameObject)
							{
								component.leftWeapon = null;
								flag = true;
							}
							if ((Object)(object)component.rightWeapon != (Object)null && (Object)(object)((Component)component.rightWeapon).gameObject == (Object)(object)((Component)this).gameObject)
							{
								component.rightWeapon = null;
								flag2 = true;
							}
						}
						val.LetGoOfWeapon(((Component)this).gameObject);
						if (_holdable.held)
						{
							_holdable.WasDropped();
						}
					}
					else
					{
						if (_holdable.held)
						{
							_holdable.WasDropped();
						}
						flag2 = flag3 || flag6;
						flag = flag4 || flag5;
						if (flag2)
						{
							val.rightHandActivity = (HandActivity)0;
						}
						if (flag)
						{
							val.leftHandActivity = (HandActivity)0;
						}
						DestroyJointField(val, RightHandJointField, flag2);
						DestroyJointField(val, LeftHandJointField, flag);
						if (flag3)
						{
							if ((Object)(object)_holdable.rig != (Object)null)
							{
								_holdable.rig.isKinematic = false;
							}
							if ((Object)(object)((Component)_holdable).GetComponent<SetInterpolation>() == (Object)null)
							{
								((Component)_holdable).gameObject.AddComponent<SetInterpolation>();
							}
							val.rightObject = null;
						}
						if (flag4)
						{
							if ((Object)(object)_holdable.rig != (Object)null)
							{
								_holdable.rig.isKinematic = false;
							}
							if ((Object)(object)((Component)_holdable).GetComponent<SetInterpolation>() == (Object)null)
							{
								((Component)_holdable).gameObject.AddComponent<SetInterpolation>();
							}
							val.leftObject = null;
						}
						if ((Object)(object)_holdable.rig != (Object)null)
						{
							_holdable.rig.isKinematic = false;
						}
						WeaponHandler component2 = ((Component)val).GetComponent<WeaponHandler>();
						if ((Object)(object)component2 != (Object)null)
						{
							if ((Object)(object)component2.leftWeapon != (Object)null && (Object)(object)((Component)component2.leftWeapon).gameObject == (Object)(object)((Component)this).gameObject)
							{
								component2.leftWeapon = null;
								flag = true;
							}
							if ((Object)(object)component2.rightWeapon != (Object)null && (Object)(object)((Component)component2.rightWeapon).gameObject == (Object)(object)((Component)this).gameObject)
							{
								component2.rightWeapon = null;
								flag2 = true;
							}
						}
					}
					ReenableHandColliders(val, flag, flag2);
					WeaponHandler component3 = ((Component)val).GetComponent<WeaponHandler>();
					if ((Object)(object)component3 != (Object)null)
					{
						EquipFistsForFreedHands(component3, flag, flag2);
					}
				}
				else if (_holdable.held)
				{
					_holdable.WasDropped();
					if ((Object)(object)_holdable.rig != (Object)null)
					{
						_holdable.rig.isKinematic = false;
					}
				}
				if ((Object)(object)holderData != (Object)null)
				{
					BreakJointsToHolder(((Component)holderData).transform.root);
				}
			}
			finally
			{
				_holdable.ignoreDissarm = ignoreDissarm;
			}
		}

		private static void EquipFistsForFreedHands(WeaponHandler wh, bool left, bool right)
		{
			if ((Object)(object)wh == (Object)null || (!left && !right))
			{
				return;
			}
			DataHandler val = (DataHandler)((WhDataField != null) ? ((object)/*isinst with value type is only supported in some contexts*/) : ((object)((Component)wh).GetComponent<DataHandler>()));
			if ((Object)(object)val != (Object)null && val.Dead)
			{
				return;
			}
			GameObject fistRefernce = wh.fistRefernce;
			if ((Object)(object)fistRefernce == (Object)null)
			{
				if ((Object)(object)wh.leftWeapon == (Object)null && (Object)(object)wh.rightWeapon == (Object)null)
				{
					wh.UseHands();
				}
				return;
			}
			MeleeWeapon component = fistRefernce.GetComponent<MeleeWeapon>();
			CollisionWeapon component2 = fistRefernce.GetComponent<CollisionWeapon>();
			CollisionSound component3 = fistRefernce.GetComponent<CollisionSound>();
			if ((Object)(object)component == (Object)null || (Object)(object)component2 == (Object)null)
			{
				if ((Object)(object)wh.leftWeapon == (Object)null && (Object)(object)wh.rightWeapon == (Object)null)
				{
					wh.UseHands();
				}
				return;
			}
			Unit val2 = (Unit)((WhUnitField != null) ? ((object)/*isinst with value type is only supported in some contexts*/) : ((object)((Component)wh).GetComponentInParent<Unit>()));
			object obj = ((UnitApiField != null) ? UnitApiField.GetValue(wh) : null);
			if (obj == null && (Object)(object)val2 != (Object)null)
			{
				Component[] components = ((Component)val2).GetComponents<Component>();
				for (int i = 0; i < components.Length; i++)
				{
					if ((Object)(object)components[i] != (Object)null && ((object)components[i]).GetType().Name == "UnitAPI")
					{
						obj = components[i];
						break;
					}
				}
			}
			if (right && (Object)(object)wh.rightWeapon == (Object)null)
			{
				HandRight componentInChildren = ((Component)wh).GetComponentInChildren<HandRight>();
				if ((Object)(object)componentInChildren != (Object)null)
				{
					MeleeWeapon val3 = EnsureFistOnHand(((Component)componentInChildren).gameObject, component, component2, component3);
					wh.SetWeapon((Weapon)(object)val3, (HandType)0);
					Plugin.Dbg("[BreakableShields] Equipped fist on RIGHT hand");
				}
			}
			if (left && (Object)(object)wh.leftWeapon == (Object)null)
			{
				HandLeft componentInChildren2 = ((Component)wh).GetComponentInChildren<HandLeft>();
				if ((Object)(object)componentInChildren2 != (Object)null)
				{
					MeleeWeapon val4 = EnsureFistOnHand(((Component)componentInChildren2).gameObject, component, component2, component3);
					wh.SetWeapon((Weapon)(object)val4, (HandType)1);
					Plugin.Dbg("[BreakableShields] Equipped fist on LEFT hand");
				}
			}
			Weapon val5 = null;
			if ((Object)(object)wh.rightWeapon != (Object)null && !IsFistWeapon(wh.rightWeapon))
			{
				val5 = wh.rightWeapon;
			}
			else if ((Object)(object)wh.leftWeapon != (Object)null && !IsFistWeapon(wh.leftWeapon))
			{
				val5 = wh.leftWeapon;
			}
			else if ((Object)(object)wh.rightWeapon != (Object)null)
			{
				val5 = wh.rightWeapon;
			}
			else if ((Object)(object)wh.leftWeapon != (Object)null)
			{
				val5 = wh.leftWeapon;
			}
			if ((Object)(object)val2 != (Object)null && (Object)(object)val5 != (Object)null)
			{
				val2.m_AttackDistance = val5.maxRange;
				val2.m_PreferedDistance = val5.maxRange - 0.3f;
			}
			if (obj != null)
			{
				MethodInfo method = obj.GetType().GetMethod("UpdateECSValues", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (method != null)
				{
					method.Invoke(obj, null);
				}
			}
		}

		private static bool IsFistWeapon(Weapon weapon)
		{
			if ((Object)(object)weapon == (Object)null)
			{
				return false;
			}
			if (!((Object)(object)((Component)weapon).GetComponent<HandLeft>() != (Object)null) && !((Object)(object)((Component)weapon).GetComponent<HandRight>() != (Object)null) && !((Object)(object)((Component)weapon).GetComponentInParent<HandLeft>() != (Object)null))
			{
				return (Object)(object)((Component)weapon).GetComponentInParent<HandRight>() != (Object)null;
			}
			return true;
		}

		private static MeleeWeapon EnsureFistOnHand(GameObject handGo, MeleeWeapon srcMelee, CollisionWeapon srcCol, CollisionSound srcSound)
		{
			MeleeWeapon component = handGo.GetComponent<MeleeWeapon>();
			CollisionWeapon component2 = handGo.GetComponent<CollisionWeapon>();
			if ((Object)(object)component != (Object)null && (Object)(object)component2 != (Object)null)
			{
				CopyMeleeStats(component, srcMelee);
				CopyCollisionStats(component2, srcCol);
				return component;
			}
			if ((Object)(object)component != (Object)null)
			{
				Object.Destroy((Object)(object)component);
			}
			if ((Object)(object)component2 != (Object)null)
			{
				Object.Destroy((Object)(object)component2);
			}
			MeleeWeapon obj = handGo.AddComponent<MeleeWeapon>();
			CollisionWeapon dst = handGo.AddComponent<CollisionWeapon>();
			if ((Object)(object)srcSound != (Object)null)
			{
				CollisionSound val = handGo.GetComponent<CollisionSound>();
				if ((Object)(object)val == (Object)null)
				{
					val = handGo.AddComponent<CollisionSound>();
				}
				val.SoundEffectRef = srcSound.SoundEffectRef;
			}
			CopyMeleeStats(obj, srcMelee);
			CopyCollisionStats(dst, srcCol);
			return obj;
		}

		private static void CopyMeleeStats(MeleeWeapon dst, MeleeWeapon src)
		{
			dst.forceCurve = src.forceCurve;
			dst.curveForce = src.curveForce;
			((Weapon)dst).internalCooldown = ((Weapon)src).internalCooldown;
			((Weapon)dst).maxRange = ((Weapon)src).maxRange;
			dst.setDirectionContinious = src.setDirectionContinious;
			dst.SoundRef = src.SoundRef;
			dst.soundDelay = src.soundDelay;
			dst.canDealDamageOutSideOfSwing = true;
			dst.canDealDamage = true;
		}

		private static void CopyCollisionStats(CollisionWeapon dst, CollisionWeapon src)
		{
			dst.impactMultiplier = src.impactMultiplier;
			dst.damage = src.damage;
			dst.onImpactForce = src.onImpactForce;
		}

		private static void ReenableHandColliders(HoldingHandler hh, bool left, bool right)
		{
			if ((Object)(object)hh == (Object)null)
			{
				return;
			}
			if (right)
			{
				HandRight componentInChildren = ((Component)hh).GetComponentInChildren<HandRight>();
				if ((Object)(object)componentInChildren != (Object)null)
				{
					Collider[] componentsInChildren = ((Component)componentInChildren).GetComponentsInChildren<Collider>(true);
					for (int i = 0; i < componentsInChildren.Length; i++)
					{
						componentsInChildren[i].enabled = true;
					}
					Rigidbody component = ((Component)componentInChildren).GetComponent<Rigidbody>();
					if ((Object)(object)component != (Object)null)
					{
						component.isKinematic = false;
					}
				}
			}
			if (!left)
			{
				return;
			}
			HandLeft componentInChildren2 = ((Component)hh).GetComponentInChildren<HandLeft>();
			if ((Object)(object)componentInChildren2 != (Object)null)
			{
				Collider[] componentsInChildren2 = ((Component)componentInChildren2).GetComponentsInChildren<Collider>(true);
				for (int j = 0; j < componentsInChildren2.Length; j++)
				{
					componentsInChildren2[j].enabled = true;
				}
				Rigidbody component2 = ((Component)componentInChildren2).GetComponent<Rigidbody>();
				if ((Object)(object)component2 != (Object)null)
				{
					component2.isKinematic = false;
				}
			}
		}

		private static void DestroyJointField(HoldingHandler hh, FieldInfo field, bool should)
		{
			if (should && !(field == null))
			{
				object? value = field.GetValue(hh);
				ConfigurableJoint val = (ConfigurableJoint)((value is ConfigurableJoint) ? value : null);
				if (val != null && (Object)(object)val != (Object)null)
				{
					Object.Destroy((Object)(object)val);
					field.SetValue(hh, null);
				}
			}
		}

		private void BreakJointsToHolder(Transform holderRoot)
		{
			if ((Object)(object)holderRoot == (Object)null)
			{
				return;
			}
			ConfigurableJoint[] componentsInChildren = ((Component)this).GetComponentsInChildren<ConfigurableJoint>(true);
			foreach (ConfigurableJoint val in componentsInChildren)
			{
				if (!((Object)(object)val == (Object)null))
				{
					Rigidbody connectedBody = ((Joint)val).connectedBody;
					if ((Object)(object)connectedBody != (Object)null && (Object)(object)((Component)connectedBody).transform.root == (Object)(object)holderRoot)
					{
						Object.Destroy((Object)(object)val);
					}
				}
			}
			ConfigurableJoint[] componentsInChildren2 = ((Component)holderRoot).GetComponentsInChildren<ConfigurableJoint>(true);
			foreach (ConfigurableJoint val2 in componentsInChildren2)
			{
				if (!((Object)(object)val2 == (Object)null) && !((Object)(object)((Joint)val2).connectedBody == (Object)null) && ((Object)(object)((Component)((Joint)val2).connectedBody).transform == (Object)(object)((Component)this).transform || ((Component)((Joint)val2).connectedBody).transform.IsChildOf(((Component)this).transform)))
				{
					Object.Destroy((Object)(object)val2);
				}
			}
		}

		public void BuildExtendedCatch()
		{
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Expected O, but got Unknown
			//IL_0137: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: 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_0162: Unknown result type (might be due to invalid IL or missing references)
			//IL_0167: Unknown result type (might be due to invalid IL or missing references)
			//IL_016d: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0174: Unknown result type (might be due to invalid IL or missing references)
			//IL_0178: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c8: Unknown result type (might be due to invalid IL or missing references)
			if (_catchBuilt || broken || (Object)(object)_blockMove == (Object)null)
			{
				return;
			}
			float num = Mathf.Max(1.01f, Plugin.ExtendedCatchScale.Value);
			Collider val = null;
			SurfaceBlock[] componentsInChildren = ((Component)this).GetComponentsInChildren<SurfaceBlock>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				if (!((Object)(object)componentsInChildren[i] == (Object)null))
				{
					Collider component = ((Component)componentsInChildren[i]).GetComponent<Collider>();
					if ((Object)(object)component != (Object)null && component.enabled && !component.isTrigger)
					{
						val = component;
						break;
					}
				}
			}
			if ((Object)(object)val == (Object)null)
			{
				Collider[] componentsInChildren2 = ((Component)this).GetComponentsInChildren<Collider>(true);
				for (int j = 0; j < componentsInChildren2.Length; j++)
				{
					if ((Object)(object)componentsInChildren2[j] != (Object)null && componentsInChildren2[j].enabled && !componentsInChildren2[j].isTrigger)
					{
						val = componentsInChildren2[j];
						break;
					}
				}
			}
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Dbg("[BreakableShields] ExtendedCatch skipped: no visible collider for " + ((Object)((Component)this).gameObject).name);
				_catchBuilt = true;
				return;
			}
			_extendedCatchGo = new GameObject("ShieldExtendedCatch");
			_extendedCatchGo.transform.SetParent(((Component)val).transform, false);
			_extendedCatchGo.transform.localRotation = Quaternion.identity;
			_extendedCatchGo.transform.localScale = Vector3.one * num;
			Vector3 forward = ((Component)val).transform.forward;
			Bounds bounds = val.bounds;
			float num2 = 2f * Mathf.Abs(Vector3.Dot(forward, ((Bounds)(ref bounds)).extents));
			float num3 = (num - 1f) * 0.5f * Mathf.Max(num2, 0.01f);
			Transform transform = _extendedCatchGo.transform;
			bounds = val.bounds;
			transform.position = ((Bounds)(ref bounds)).center + forward * num3;
			Collider val2 = CopyColliderTo(val, _extendedCatchGo);
			if ((Object)(object)val2 == (Object)null)
			{
				Object.Destroy((Object)(object)_extendedCatchGo);
				_extendedCatchGo = null;
				Plugin.Dbg("[BreakableShields] ExtendedCatch skipped: unsupported collider type " + ((object)val).GetType().Name + " on " + ((Object)((Component)this).gameObject).name);
				_catchBuilt = true;
				return;
			}
			val2.isTrigger = false;
			_extendedCatchCollider = val2;
			_extendedCatchMarker = _extendedCatchGo.AddComponent<ShieldExtendedCatch>();
			_extendedCatchMarker.visibleCollider = val;
			_extendedCatchGo.AddComponent<SurfaceBlock>().blockMove = _blockMove;
			_catchBuilt = true;
			Plugin.Dbg("[BreakableShields] ExtendedCatch built for " + ((Object)((Component)this).gameObject).name + " scale=" + num.ToString("0.##") + " outwardOffset=" + num3.ToString("0.###"));
		}

		private static Collider CopyColliderTo(Collider src, GameObject dstGo)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Expected O, but got Unknown
			//IL_002b: 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)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Expected O, but got Unknown
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Expected O, but got Unknown
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Expected O, but got Unknown
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)src == (Object)null || (Object)(object)dstGo == (Object)null)
			{
				return null;
			}
			if (src is BoxCollider)
			{
				BoxCollider val = (BoxCollider)src;
				BoxCollider obj = dstGo.AddComponent<BoxCollider>();
				obj.center = val.center;
				obj.size = val.size;
				return (Collider)(object)obj;
			}
			if (src is SphereCollider)
			{
				SphereCollider val2 = (SphereCollider)src;
				SphereCollider obj2 = dstGo.AddComponent<SphereCollider>();
				obj2.center = val2.center;
				obj2.radius = val2.radius;
				return (Collider)(object)obj2;
			}
			if (src is CapsuleCollider)
			{
				CapsuleCollider val3 = (CapsuleCollider)src;
				CapsuleCollider obj3 = dstGo.AddComponent<CapsuleCollider>();
				obj3.center = val3.center;
				obj3.radius = val3.radius;
				obj3.height = val3.height;
				obj3.direction = val3.direction;
				return (Collider)(object)obj3;
			}
			if (src is MeshCollider)
			{
				MeshCollider val4 = (MeshCollider)src;
				MeshCollider obj4 = dstGo.AddComponent<MeshCollider>();
				obj4.sharedMesh = val4.sharedMesh;
				obj4.convex = val4.convex;
				obj4.cookingOptions = val4.cookingOptions;
				return (Collider)(object)obj4;
			}
			return null;
		}

		public void DestroyExtendedCatch(bool allowRebuild = false)
		{
			if ((Object)(object)_extendedCatchGo != (Object)null)
			{
				Object.Destroy((Object)(object)_extendedCatchGo);
				_extendedCatchGo = null;
				_extendedCatchCollider = null;
				_extendedCatchMarker = null;
			}
			if (allowRebuild)
			{
				_catchBuilt = false;
			}
		}

		public void ApplyStagger(Unit target, float duration)
		{
			if ((Object)(object)target == (Object)null || (Object)(object)target.data == (Object)null || duration <= 0f)
			{
				return;
			}
			DataHandler data = target.data;
			MethodInfo dontWalkForMethod = DontWalkForMethod;
			if (dontWalkForMethod != null)
			{
				try
				{
					dontWalkForMethod.Invoke(data, new object[1] { duration });
				}
				catch (Exception)
				{
				}
			}
			if ((Object)(object)data.weaponHandler != (Object)null)
			{
				data.weaponHandler.DelayAttackCounter(duration * 2f);
				Weapon rightWeapon = data.weaponHandler.rightWeapon;
				MeleeWeapon val = (MeleeWeapon)(object)((rightWeapon is MeleeWeapon) ? rightWeapon : null);
				if (val != null)
				{
					val.StopSwing();
				}
				Weapon leftWeapon = data.weaponHandler.leftWeapon;
				MeleeWeapon val2 = (MeleeWeapon)(object)((leftWeapon is MeleeWeapon) ? leftWeapon : null);
				if (val2 != null)
				{
					val2.StopSwing();
				}
			}
		}
	}
	public class ShieldExtendedCatch : MonoBehaviour
	{
		public Collider visibleCollider;
	}
}