Decompiled source of ShieldOverflowFix v1.0.0

plugins/ShieldOverflowFix.dll

Decompiled 2 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("ShieldOverflowFix")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("ShieldOverflowFix")]
[assembly: AssemblyTitle("ShieldOverflowFix")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.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;
		}
	}
}
[BepInPlugin("ShieldOverflowFix", "Shield Overflow Fix", "1.0.0")]
public class ShieldOverflowPlugin : BaseUnityPlugin
{
	internal static ConfigEntry<bool> EnableShieldRecastReplace;

	internal static ConfigEntry<bool> EnableShieldOverflowFix;

	internal static ConfigEntry<bool> EnableShieldColorChange;

	internal static ConfigEntry<bool> UseOriginalShieldColorAsStartColor;

	internal static ConfigEntry<string> StartShieldColorHex;

	internal static ConfigEntry<string> DamagedShieldColorHex;

	internal static ConfigEntry<bool> ShowShieldDamageNumbers;

	private void Awake()
	{
		//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
		EnableShieldOverflowFix = ((BaseUnityPlugin)this).Config.Bind<bool>("Combat", "EnableShieldOverflowFix", true, "Fixes shield overflow. Damage beyond the shield's remaining health will spill through instead of being completely blocked.");
		EnableShieldRecastReplace = ((BaseUnityPlugin)this).Config.Bind<bool>("Combat", "EnableShieldRecastReplace", true, "Recasting Staff of Protection refreshes the shield's health instead of only refreshing its timer.");
		ShowShieldDamageNumbers = ((BaseUnityPlugin)this).Config.Bind<bool>("Combat", "ShowShieldDamageNumbers", true, "Show floating damage numbers for damage absorbed by the shield.");
		EnableShieldColorChange = ((BaseUnityPlugin)this).Config.Bind<bool>("Visual", "EnableShieldColorChange", true, "Shield color changes based on how much shield health has been lost.");
		UseOriginalShieldColorAsStartColor = ((BaseUnityPlugin)this).Config.Bind<bool>("Visual", "UseOriginalShieldColorAsStartColor", true, "If true, the shield starts from its vanilla in-game color.");
		StartShieldColorHex = ((BaseUnityPlugin)this).Config.Bind<string>("Visual", "StartShieldColorHex", "#66D9FF80", "Starting shield color when UseOriginalShieldColorAsStartColor is false.");
		DamagedShieldColorHex = ((BaseUnityPlugin)this).Config.Bind<string>("Visual", "DamagedShieldColorHex", "#4DA6FFFF", "Color the shield approaches as it loses health.");
		new Harmony("ShieldOverflowFix").PatchAll();
		((BaseUnityPlugin)this).Logger.LogInfo((object)"ShieldOverflowFix loaded (1.0.0)");
	}
}
internal static class ShieldRefs
{
	internal static readonly FieldRef<SE_Shield, float> TotalAbsorb = AccessTools.FieldRefAccess<SE_Shield, float>("m_totalAbsorbDamage");

	internal static readonly FieldRef<SE_Shield, float> Damage = AccessTools.FieldRefAccess<SE_Shield, float>("m_damage");

	internal static readonly FieldRef<StatusEffect, Character> CharacterRef = AccessTools.FieldRefAccess<StatusEffect, Character>("m_character");

	internal static readonly FieldRef<SE_Shield, EffectList> HitEffects = AccessTools.FieldRefAccess<SE_Shield, EffectList>("m_hitEffects");

	internal static readonly FieldRef<StatusEffect, GameObject[]> StartEffectInstances = AccessTools.FieldRefAccess<StatusEffect, GameObject[]>("m_startEffectInstances");

	internal static float GetRelevantDamage(HitData hit)
	{
		//IL_0002: Unknown result type (might be due to invalid IL or missing references)
		//IL_0007: Unknown result type (might be due to invalid IL or missing references)
		//IL_0008: Unknown result type (might be due to invalid IL or missing references)
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0015: Unknown result type (might be due to invalid IL or missing references)
		//IL_001c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0023: Unknown result type (might be due to invalid IL or missing references)
		//IL_002a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0031: Unknown result type (might be due to invalid IL or missing references)
		//IL_0038: Unknown result type (might be due to invalid IL or missing references)
		DamageTypes damage = hit.m_damage;
		return damage.m_blunt + damage.m_slash + damage.m_pierce + damage.m_fire + damage.m_frost + damage.m_lightning + damage.m_poison + damage.m_spirit;
	}
}
internal static class ShieldRecastController
{
	private static SE_Shield PendingRefreshShield;

	public static void MarkIfStaffRecast(SE_Shield shield, HitData hit, Character attacker)
	{
		if (!ShieldOverflowPlugin.EnableShieldRecastReplace.Value || (Object)(object)shield == (Object)null || hit == null || ((Object)shield).name != "Staff_shield")
		{
			return;
		}
		Character val = ShieldRefs.CharacterRef.Invoke((StatusEffect)(object)shield);
		if (val is Player && !((Object)(object)attacker != (Object)(object)val))
		{
			float relevantDamage = ShieldRefs.GetRelevantDamage(hit);
			if (!(relevantDamage > 0f))
			{
				PendingRefreshShield = shield;
			}
		}
	}

	public static bool TryConsume(StatusEffect effect, out SE_Shield shield)
	{
		shield = null;
		if (!ShieldOverflowPlugin.EnableShieldRecastReplace.Value)
		{
			return false;
		}
		SE_Shield val = (SE_Shield)(object)((effect is SE_Shield) ? effect : null);
		if (val == null)
		{
			return false;
		}
		if (val != PendingRefreshShield)
		{
			return false;
		}
		PendingRefreshShield = null;
		shield = val;
		return true;
	}

	public static void Clear(SE_Shield shield)
	{
		if (PendingRefreshShield == shield)
		{
			PendingRefreshShield = null;
		}
	}
}
[HarmonyPatch(typeof(SE_Shield), "OnDamaged")]
public static class ShieldOverflowPatch
{
	private static bool Prefix(SE_Shield __instance, HitData hit, Character attacker)
	{
		//IL_02a7: Unknown result type (might be due to invalid IL or missing references)
		//IL_02ad: Unknown result type (might be due to invalid IL or missing references)
		//IL_02b2: Unknown result type (might be due to invalid IL or missing references)
		//IL_02b7: Unknown result type (might be due to invalid IL or missing references)
		ShieldRecastController.MarkIfStaffRecast(__instance, hit, attacker);
		float relevantDamage = ShieldRefs.GetRelevantDamage(hit);
		if (relevantDamage <= 0f)
		{
			return false;
		}
		float num = ShieldRefs.TotalAbsorb.Invoke(__instance);
		if (num <= 0f)
		{
			return true;
		}
		float num2 = ShieldRefs.Damage.Invoke(__instance);
		float num3 = num - num2;
		if (num3 <= 0f)
		{
			return true;
		}
		float num4;
		if (relevantDamage <= num3)
		{
			num4 = relevantDamage;
			ShieldRefs.Damage.Invoke(__instance) = num2 + relevantDamage;
			hit.m_damage.m_blunt = 0f;
			hit.m_damage.m_slash = 0f;
			hit.m_damage.m_pierce = 0f;
			hit.m_damage.m_fire = 0f;
			hit.m_damage.m_frost = 0f;
			hit.m_damage.m_lightning = 0f;
			hit.m_damage.m_poison = 0f;
			hit.m_damage.m_spirit = 0f;
		}
		else
		{
			num4 = num3;
			if (ShieldOverflowPlugin.EnableShieldOverflowFix.Value)
			{
				float num5 = relevantDamage - num3;
				ShieldRefs.Damage.Invoke(__instance) = num + 0.01f;
				float num6 = num5 / relevantDamage;
				hit.m_damage.m_blunt *= num6;
				hit.m_damage.m_slash *= num6;
				hit.m_damage.m_pierce *= num6;
				hit.m_damage.m_fire *= num6;
				hit.m_damage.m_frost *= num6;
				hit.m_damage.m_lightning *= num6;
				hit.m_damage.m_poison *= num6;
				hit.m_damage.m_spirit *= num6;
			}
			else
			{
				ShieldRefs.Damage.Invoke(__instance) = num + 0.01f;
				hit.m_damage.m_blunt = 0f;
				hit.m_damage.m_slash = 0f;
				hit.m_damage.m_pierce = 0f;
				hit.m_damage.m_fire = 0f;
				hit.m_damage.m_frost = 0f;
				hit.m_damage.m_lightning = 0f;
				hit.m_damage.m_poison = 0f;
				hit.m_damage.m_spirit = 0f;
			}
		}
		Character val = ShieldRefs.CharacterRef.Invoke((StatusEffect)(object)__instance);
		if ((Object)(object)val != (Object)null)
		{
			ShieldRefs.HitEffects.Invoke(__instance).Create(hit.m_point, Quaternion.LookRotation(-hit.m_dir), ((Component)val).transform, 1f, -1);
			ShieldColorController.ApplyShieldStateColor(__instance);
			if (ShieldOverflowPlugin.ShowShieldDamageNumbers.Value && num4 > 0f)
			{
				ShieldDamageText.Show(hit, val, num4);
			}
		}
		return false;
	}
}
[HarmonyPatch(typeof(StatusEffect), "ResetTime")]
public static class ShieldResetTimePatch
{
	private static void Postfix(StatusEffect __instance)
	{
		if (ShieldRecastController.TryConsume(__instance, out var shield))
		{
			ShieldRefs.Damage.Invoke(shield) = 0f;
			ShieldColorController.ApplyShieldStateColor(shield);
		}
	}
}
public static class ShieldColorController
{
	private sealed class TrackedMaterial
	{
		public Material Material;

		public Color OriginalColor;

		public bool HasColor;

		public bool HasBaseColor;

		public bool HasTintColor;

		public bool HasEmissionColor;
	}

	private static readonly Dictionary<SE_Shield, List<TrackedMaterial>> Cache = new Dictionary<SE_Shield, List<TrackedMaterial>>();

	public static void ApplyShieldStateColor(SE_Shield shield)
	{
		//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
		//IL_0128: Unknown result type (might be due to invalid IL or missing references)
		//IL_0122: Unknown result type (might be due to invalid IL or missing references)
		//IL_012d: Unknown result type (might be due to invalid IL or missing references)
		//IL_012f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0131: Unknown result type (might be due to invalid IL or missing references)
		//IL_0134: Unknown result type (might be due to invalid IL or missing references)
		//IL_0139: Unknown result type (might be due to invalid IL or missing references)
		//IL_013d: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)shield == (Object)null)
		{
			return;
		}
		float num = ShieldRefs.TotalAbsorb.Invoke(shield);
		if (num <= 0f)
		{
			return;
		}
		List<TrackedMaterial> materials = GetMaterials(shield);
		if (materials.Count == 0)
		{
			return;
		}
		float num2 = Mathf.Clamp(ShieldRefs.Damage.Invoke(shield), 0f, num);
		float num3 = (ShieldOverflowPlugin.EnableShieldColorChange.Value ? Mathf.Clamp01(num2 / num) : 0f);
		Color val = ParseColor(ShieldOverflowPlugin.StartShieldColorHex.Value, new Color(0.4f, 0.85f, 1f, 0.5f));
		Color val2 = ParseColor(ShieldOverflowPlugin.DamagedShieldColorHex.Value, new Color(0.3f, 0.65f, 1f, 1f));
		for (int num4 = materials.Count - 1; num4 >= 0; num4--)
		{
			TrackedMaterial trackedMaterial = materials[num4];
			if (trackedMaterial == null || (Object)(object)trackedMaterial.Material == (Object)null)
			{
				materials.RemoveAt(num4);
			}
			else
			{
				Color val3 = (ShieldOverflowPlugin.UseOriginalShieldColorAsStartColor.Value ? trackedMaterial.OriginalColor : val);
				Color color = Color.Lerp(val3, val2, num3);
				ApplyColor(trackedMaterial, color);
			}
		}
	}

	public static void ClearShield(SE_Shield shield)
	{
		//IL_0061: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)shield == (Object)null)
		{
			return;
		}
		ShieldRecastController.Clear(shield);
		if (!Cache.TryGetValue(shield, out var value))
		{
			return;
		}
		foreach (TrackedMaterial item in value)
		{
			if (item != null && (Object)(object)item.Material != (Object)null)
			{
				ApplyColor(item, item.OriginalColor);
			}
		}
		Cache.Remove(shield);
	}

	private static List<TrackedMaterial> GetMaterials(SE_Shield shield)
	{
		//IL_013b: Unknown result type (might be due to invalid IL or missing references)
		//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)
		if (Cache.TryGetValue(shield, out var value))
		{
			return value;
		}
		List<TrackedMaterial> list = new List<TrackedMaterial>();
		GameObject[] array = ShieldRefs.StartEffectInstances.Invoke((StatusEffect)(object)shield);
		if (array != null)
		{
			GameObject[] array2 = array;
			foreach (GameObject val in array2)
			{
				if (!Object.op_Implicit((Object)(object)val))
				{
					continue;
				}
				Renderer[] componentsInChildren = val.GetComponentsInChildren<Renderer>(true);
				Renderer[] array3 = componentsInChildren;
				foreach (Renderer val2 in array3)
				{
					if (!Object.op_Implicit((Object)(object)val2))
					{
						continue;
					}
					Material[] materials = val2.materials;
					if (materials == null || materials.Length == 0)
					{
						continue;
					}
					Material[] array4 = materials;
					foreach (Material val3 in array4)
					{
						if (Object.op_Implicit((Object)(object)val3))
						{
							TrackedMaterial trackedMaterial = new TrackedMaterial
							{
								Material = val3,
								HasColor = val3.HasProperty("_Color"),
								HasBaseColor = val3.HasProperty("_BaseColor"),
								HasTintColor = val3.HasProperty("_TintColor"),
								HasEmissionColor = val3.HasProperty("_EmissionColor")
							};
							trackedMaterial.OriginalColor = ReadColor(trackedMaterial, Color.white);
							list.Add(trackedMaterial);
						}
					}
				}
			}
		}
		Cache[shield] = list;
		return list;
	}

	private static Color ReadColor(TrackedMaterial tracked, Color fallback)
	{
		//IL_0018: Unknown result type (might be due to invalid IL or missing references)
		//IL_001d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0030: Unknown result type (might be due to invalid IL or missing references)
		//IL_0035: Unknown result type (might be due to invalid IL or missing references)
		//IL_0070: Unknown result type (might be due to invalid IL or missing references)
		//IL_004a: Unknown result type (might be due to invalid IL or missing references)
		//IL_004f: Unknown result type (might be due to invalid IL or missing references)
		//IL_006c: Unknown result type (might be due to invalid IL or missing references)
		//IL_006d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0064: Unknown result type (might be due to invalid IL or missing references)
		//IL_0069: Unknown result type (might be due to invalid IL or missing references)
		Material material = tracked.Material;
		if (tracked.HasColor)
		{
			return material.GetColor("_Color");
		}
		if (tracked.HasBaseColor)
		{
			return material.GetColor("_BaseColor");
		}
		if (tracked.HasTintColor)
		{
			return material.GetColor("_TintColor");
		}
		if (tracked.HasEmissionColor)
		{
			return material.GetColor("_EmissionColor");
		}
		return fallback;
	}

	private static void ApplyColor(TrackedMaterial tracked, Color color)
	{
		//IL_0018: Unknown result type (might be due to invalid IL or missing references)
		//IL_002f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0046: Unknown result type (might be due to invalid IL or missing references)
		//IL_005f: Unknown result type (might be due to invalid IL or missing references)
		Material material = tracked.Material;
		if (tracked.HasColor)
		{
			material.SetColor("_Color", color);
		}
		if (tracked.HasBaseColor)
		{
			material.SetColor("_BaseColor", color);
		}
		if (tracked.HasTintColor)
		{
			material.SetColor("_TintColor", color);
		}
		if (tracked.HasEmissionColor)
		{
			material.SetColor("_EmissionColor", color);
		}
	}

	private static Color ParseColor(string value, Color fallback)
	{
		//IL_000b: Unknown result type (might be due to invalid IL or missing references)
		//IL_000c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0044: Unknown result type (might be due to invalid IL or missing references)
		//IL_0040: Unknown result type (might be due to invalid IL or missing references)
		//IL_0041: Unknown result type (might be due to invalid IL or missing references)
		//IL_003c: Unknown result type (might be due to invalid IL or missing references)
		//IL_003d: Unknown result type (might be due to invalid IL or missing references)
		if (string.IsNullOrWhiteSpace(value))
		{
			return fallback;
		}
		if (!value.StartsWith("#"))
		{
			value = "#" + value;
		}
		Color result = default(Color);
		if (ColorUtility.TryParseHtmlString(value, ref result))
		{
			return result;
		}
		return fallback;
	}
}
public static class ShieldDamageText
{
	public static void Show(HitData hit, Character character, float amount)
	{
		//IL_002c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0031: Unknown result type (might be due to invalid IL or missing references)
		//IL_0032: Unknown result type (might be due to invalid IL or missing references)
		//IL_0033: Unknown result type (might be due to invalid IL or missing references)
		//IL_004e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0042: Unknown result type (might be due to invalid IL or missing references)
		//IL_0047: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)DamageText.instance == (Object)null) && !((Object)(object)character == (Object)null) && !(amount <= 0f))
		{
			Vector3 val = hit.m_point;
			if (val == Vector3.zero)
			{
				val = character.GetCenterPoint();
			}
			DamageText.instance.ShowText((TextType)0, val, amount, false);
		}
	}
}
[HarmonyPatch(typeof(StatusEffect), "UpdateStatusEffect")]
public static class ShieldUpdatePatch
{
	private static void Postfix(StatusEffect __instance)
	{
		SE_Shield val = (SE_Shield)(object)((__instance is SE_Shield) ? __instance : null);
		if (val != null)
		{
			ShieldColorController.ApplyShieldStateColor(val);
		}
	}
}
[HarmonyPatch(typeof(StatusEffect), "Stop")]
public static class ShieldStopPatch
{
	private static void Postfix(StatusEffect __instance)
	{
		SE_Shield val = (SE_Shield)(object)((__instance is SE_Shield) ? __instance : null);
		if (val != null)
		{
			ShieldColorController.ClearShield(val);
		}
	}
}