Decompiled source of WiresDamageVignette v0.2.5

WiresDamageVignette.dll

Decompiled 3 days ago
using System;
using System.Collections;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Networking;

[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("WiresDamageVignette")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("WiresDamageVignette")]
[assembly: AssemblyTitle("WiresDamageVignette")]
[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 WiresDamageVignette
{
	internal static class DamageGate
	{
		private static Player _player;

		private static float _previousHealth;

		private static float _previousMaximum;

		private static bool _hasDamage;

		private static bool _initialized;

		private static float _pendingDirectFlash;

		internal static bool HasTakenDamage => _hasDamage;

		internal static void Observe(Player player)
		{
			if ((Object)(object)player == (Object)null || (Object)(object)player != (Object)(object)_player)
			{
				Reset();
				_player = player;
			}
			if ((Object)(object)player == (Object)null)
			{
				return;
			}
			float health = ((Character)player).GetHealth();
			float maxHealth = ((Character)player).GetMaxHealth();
			if (!_initialized)
			{
				_previousHealth = health;
				_previousMaximum = maxHealth;
				_initialized = true;
				return;
			}
			if (maxHealth > 0.001f && health >= maxHealth - 0.025f)
			{
				_hasDamage = false;
			}
			else if (health < _previousHealth - 0.025f && maxHealth >= _previousMaximum - 0.025f)
			{
				_hasDamage = true;
			}
			_previousHealth = health;
			_previousMaximum = maxHealth;
		}

		internal static void OnActualDamage(Player player, float healthBefore, HitData hit, bool triggerEffects)
		{
			if ((Object)(object)player == (Object)null || (Object)(object)player != (Object)(object)Player.m_localPlayer)
			{
				return;
			}
			if ((Object)(object)player != (Object)(object)_player)
			{
				_player = player;
				_initialized = false;
				_hasDamage = false;
				_pendingDirectFlash = 0f;
			}
			float num = healthBefore - ((Character)player).GetHealth();
			if (!(num <= 0.025f))
			{
				_hasDamage = true;
				if (IsDirectHit(hit, triggerEffects))
				{
					float num2 = Mathf.Clamp01(num / Mathf.Max(1f, ((Character)player).GetMaxHealth()));
					float num3 = Mathf.Lerp(0.7f, 1f, Mathf.Sqrt(Mathf.Clamp01(num2 * 3f)));
					_pendingDirectFlash = Mathf.Max(_pendingDirectFlash, num3);
				}
			}
		}

		internal static float ConsumeDirectFlash()
		{
			float pendingDirectFlash = _pendingDirectFlash;
			_pendingDirectFlash = 0f;
			return pendingDirectFlash;
		}

		private static bool IsDirectHit(HitData hit, bool triggerEffects)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//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_0076: Expected I4, but got Unknown
			if (hit == null)
			{
				return false;
			}
			HitType hitType = hit.m_hitType;
			switch ((int)hitType)
			{
			case 4:
			case 5:
			case 6:
			case 7:
			case 8:
			case 9:
			case 10:
			case 20:
			case 21:
			case 22:
				return false;
			case 1:
			case 2:
			case 3:
			case 11:
			case 12:
			case 13:
			case 14:
			case 15:
			case 16:
			case 17:
			case 18:
			case 19:
			case 23:
			case 24:
				return true;
			case 0:
				return triggerEffects;
			default:
				return false;
			}
		}

		internal static void Reset()
		{
			_player = null;
			_previousHealth = 0f;
			_previousMaximum = 0f;
			_hasDamage = false;
			_initialized = false;
			_pendingDirectFlash = 0f;
		}
	}
	[HarmonyPatch(typeof(Character), "ApplyDamage")]
	internal static class ActualDamagePatch
	{
		[HarmonyPrefix]
		private static void Prefix(Character __instance, out float __state)
		{
			__state = (((Object)(object)__instance == (Object)(object)Player.m_localPlayer) ? __instance.GetHealth() : 0f);
		}

		[HarmonyPostfix]
		private static void Postfix(Character __instance, HitData hit, bool triggerEffects, float __state)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			if ((Object)(object)__instance == (Object)(object)Player.m_localPlayer)
			{
				DamageGate.OnActualDamage((Player)__instance, __state, hit, triggerEffects);
			}
		}
	}
	internal sealed class HeartbeatSound : MonoBehaviour
	{
		private const string ClipFileName = "heartbeat.wav";

		private AudioSource _source;

		private AudioClip _clip;

		private Coroutine _loading;

		private bool _ready;

		private ManualLogSource _log;

		private void Awake()
		{
			_log = Logger.CreateLogSource("Wire's Damage Vignette Audio");
			_source = ((Component)this).gameObject.AddComponent<AudioSource>();
			_source.playOnAwake = false;
			_source.loop = true;
			_source.spatialBlend = 0f;
			_source.dopplerLevel = 0f;
			_source.priority = 96;
			_source.volume = 0f;
			_source.ignoreListenerPause = false;
			string text = Path.Combine(Path.GetDirectoryName(typeof(Plugin).Assembly.Location), "heartbeat.wav");
			if (!File.Exists(text))
			{
				_log.LogError((object)("Heartbeat recording not found: " + text));
			}
			else
			{
				_loading = ((MonoBehaviour)this).StartCoroutine(LoadClip(text));
			}
		}

		private IEnumerator LoadClip(string file)
		{
			string absoluteUri = new Uri(file).AbsoluteUri;
			UnityWebRequest request = UnityWebRequestMultimedia.GetAudioClip(absoluteUri, (AudioType)20);
			try
			{
				yield return request.SendWebRequest();
				if ((int)request.result != 1)
				{
					_log.LogError((object)("Couldn't load heartbeat: " + request.error));
					yield break;
				}
				AudioClip content = DownloadHandlerAudioClip.GetContent(request);
				if ((Object)(object)content == (Object)null)
				{
					_log.LogError((object)"Heartbeat loader returned an empty AudioClip.");
					yield break;
				}
				_clip = content;
				((Object)_clip).name = "Wire_DamageVignette_Heartbeat_Loop";
				_source.clip = _clip;
				_ready = true;
				_log.LogInfo((object)("Heartbeat ready: " + _clip.length.ToString("F2") + "s, " + _clip.channels + " channel(s)."));
			}
			finally
			{
				((IDisposable)request)?.Dispose();
			}
			_loading = null;
		}

		internal void UpdateSound(bool active, float severity, float volume, VolumeCurve curve, float pitch)
		{
			if (!((Object)(object)_source == (Object)null) && _ready)
			{
				float num = Mathf.Clamp01(severity);
				float num2 = 1.4912069f;
				float num3 = ((curve == VolumeCurve.Exponential) ? (0.58f * Mathf.Pow(1.6034484f, 2f * num)) : Mathf.Lerp(0.58f, num2, num));
				float num4 = (active ? Mathf.Clamp01(volume * 2.4f * num3) : 0f);
				if ((Object)(object)AudioMan.instance != (Object)null && (Object)(object)AudioMan.instance.m_guiMixer != (Object)null)
				{
					_source.outputAudioMixerGroup = AudioMan.instance.m_guiMixer;
				}
				_source.volume = Mathf.MoveTowards(_source.volume, num4, Time.unscaledDeltaTime * 0.75f);
				_source.pitch = Mathf.MoveTowards(_source.pitch, Mathf.Clamp(pitch, 0.85f, 1.4f), Time.unscaledDeltaTime * 0.4f);
				if (active && !_source.isPlaying)
				{
					_source.Play();
				}
				else if (!active && _source.isPlaying && _source.volume <= 0.0001f)
				{
					_source.Stop();
				}
			}
		}

		internal void StopNow()
		{
			if (!((Object)(object)_source == (Object)null))
			{
				_source.volume = 0f;
				_source.Stop();
			}
		}

		private void OnDestroy()
		{
			StopNow();
			if (_loading != null)
			{
				((MonoBehaviour)this).StopCoroutine(_loading);
			}
			if ((Object)(object)_clip != (Object)null)
			{
				Object.Destroy((Object)(object)_clip);
			}
			if (_log != null)
			{
				Logger.Sources.Remove((ILogSource)(object)_log);
			}
		}
	}
	internal enum VolumeCurve
	{
		Exponential,
		Linear
	}
	[BepInPlugin("wire.valheim.healthvignetting", "Wire's Damage Vignette", "0.2.5")]
	[BepInProcess("valheim.exe")]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string Guid = "wire.valheim.healthvignetting";

		public const string Name = "Wire's Damage Vignette";

		public const string Version = "0.2.5";

		internal static ConfigEntry<bool> Enabled;

		internal static ConfigEntry<float> StartHealthPercent;

		internal static ConfigEntry<float> MaxOpacity;

		internal static ConfigEntry<bool> Pulse;

		internal static ConfigEntry<bool> HeartbeatEnabled;

		internal static ConfigEntry<float> HeartbeatVolume;

		internal static ConfigEntry<float> HeartbeatStartPercent;

		internal static ConfigEntry<VolumeCurve> HeartbeatCurve;

		internal static ConfigEntry<bool> HitFlashEnabled;

		internal static ConfigEntry<float> HitFlashOpacity;

		internal static ConfigEntry<float> HitFlashDuration;

		private Harmony _harmony;

		private void Awake()
		{
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Expected O, but got Unknown
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Expected O, but got Unknown
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Expected O, but got Unknown
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: Expected O, but got Unknown
			//IL_01c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cc: Expected O, but got Unknown
			//IL_01ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0209: Expected O, but got Unknown
			//IL_023f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0249: Expected O, but got Unknown
			//IL_02c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d1: Expected O, but got Unknown
			//IL_039d: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a7: Expected O, but got Unknown
			//IL_0418: Unknown result type (might be due to invalid IL or missing references)
			//IL_0422: Expected O, but got Unknown
			//IL_0477: Unknown result type (might be due to invalid IL or missing references)
			//IL_0481: Expected O, but got Unknown
			Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Vignette", "Enabled", true, "Display a red, texture-free vignette while below the configured health percentage.");
			StartHealthPercent = ((BaseUnityPlugin)this).Config.Bind<float>("Vignette", "Start below health (%)", 65f, new ConfigDescription("Health percentage where the vignette begins. Intensity increases smoothly toward zero health.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 100f), Array.Empty<object>()));
			MaxOpacity = ((BaseUnityPlugin)this).Config.Bind<float>("Vignette", "Maximum opacity", 0.76f, new ConfigDescription("Maximum red-edge opacity at zero health. Does not darken the center of the screen.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			Pulse = ((BaseUnityPlugin)this).Config.Bind<bool>("Vignette", "Pulse", true, "Subtle pulsing as health drops; pulse intensity increases the lower your health gets.");
			HeartbeatEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Heartbeat", "Enabled", true, "Play the included recorded heartbeat loop below the separate heartbeat threshold.");
			HeartbeatStartPercent = ((BaseUnityPlugin)this).Config.Bind<float>("Heartbeat", "Start below health (%)", 40f, new ConfigDescription("Health percentage where the heartbeat begins; independent of the red vignette.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 100f), Array.Empty<object>()));
			HeartbeatCurve = ((BaseUnityPlugin)this).Config.Bind<VolumeCurve>("Heartbeat", "Loudness curve", VolumeCurve.Exponential, "Exponential builds faster as health falls. Linear increases evenly toward zero health.");
			HeartbeatVolume = ((BaseUnityPlugin)this).Config.Bind<float>("Heartbeat", "Volume", 0.5f, new ConfigDescription("Heartbeat loudness, routed through the game's SFX/GUI mixer and therefore controlled by both the in-game SFX and master volume settings.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			HitFlashEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Damage flash", "Enabled", true, "Briefly flash a soft red vignette when a direct hit actually reduces health. Damage-over-time ticks never trigger the flash.");
			HitFlashOpacity = ((BaseUnityPlugin)this).Config.Bind<float>("Damage flash", "Flash opacity", 0.2f, new ConfigDescription("Additional red-edge opacity added on top of the persistent low-health vignette on a direct hit, up to 0.20. Combined opacity is capped at 0.96.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 0.2f), Array.Empty<object>()));
			HitFlashDuration = ((BaseUnityPlugin)this).Config.Bind<float>("Damage flash", "Flash duration", 0.6f, new ConfigDescription("Total lifetime of the direct-hit flash in seconds. It appears almost immediately (~0.025 seconds) then fades out smoothly over the remaining time.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.15f, 1.5f), Array.Empty<object>()));
			ConfigEntry<bool> val = ((BaseUnityPlugin)this).Config.Bind<bool>("Internal", "Heartbeat volume updated to 0.1.1", false, new ConfigDescription("Internal upgrade marker.", (AcceptableValueBase)null, new object[1]
			{
				new ConfigurationManagerAttributes
				{
					Browsable = false
				}
			}));
			bool value = val.Value;
			if (!val.Value)
			{
				if (Mathf.Abs(HeartbeatVolume.Value - 0.28f) < 0.0001f)
				{
					HeartbeatVolume.Value = 0.38f;
				}
				val.Value = true;
				((BaseUnityPlugin)this).Config.Save();
			}
			ConfigEntry<bool> val2 = ((BaseUnityPlugin)this).Config.Bind<bool>("Internal", "Migrated to 0.2.0", false, new ConfigDescription("One-time default migration.", (AcceptableValueBase)null, new object[1]
			{
				new ConfigurationManagerAttributes
				{
					Browsable = false
				}
			}));
			bool value2 = val2.Value;
			if (!val2.Value)
			{
				if (Mathf.Abs(StartHealthPercent.Value - 50f) < 0.001f)
				{
					StartHealthPercent.Value = 65f;
				}
				if (value)
				{
					float value3 = HeartbeatVolume.Value;
					if (Mathf.Abs(value3 - 0.38f) < 0.001f)
					{
						HeartbeatVolume.Value = 0.5f;
					}
					else
					{
						HeartbeatVolume.Value = Mathf.Clamp01(value3 / 1.2f);
					}
				}
				val2.Value = true;
				((BaseUnityPlugin)this).Config.Save();
			}
			ConfigEntry<bool> val3 = ((BaseUnityPlugin)this).Config.Bind<bool>("Internal", "Migrated to 0.2.1", false, new ConfigDescription("Heartbeat volume scale migration.", (AcceptableValueBase)null, new object[1]
			{
				new ConfigurationManagerAttributes
				{
					Browsable = false
				}
			}));
			if (!val3.Value)
			{
				if (value2)
				{
					HeartbeatVolume.Value = Mathf.Clamp01(HeartbeatVolume.Value * 0.5f);
				}
				val3.Value = true;
				((BaseUnityPlugin)this).Config.Save();
			}
			ConfigEntry<bool> val4 = ((BaseUnityPlugin)this).Config.Bind<bool>("Internal", "Migrated flash duration to 0.2.4", false, new ConfigDescription("One-time hit flash duration default upgrade.", (AcceptableValueBase)null, new object[1]
			{
				new ConfigurationManagerAttributes
				{
					Browsable = false
				}
			}));
			if (!val4.Value)
			{
				if (Mathf.Abs(HitFlashDuration.Value - 0.34f) < 0.0001f)
				{
					HitFlashDuration.Value = 0.6f;
				}
				val4.Value = true;
				((BaseUnityPlugin)this).Config.Save();
			}
			RemoveLegacyColorSettings();
			_harmony = new Harmony("wire.valheim.healthvignetting");
			_harmony.PatchAll();
			((Component)this).gameObject.AddComponent<HealthVignetteDriver>();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Wire's Damage Vignette 0.2.5 loaded.");
		}

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

		private void RemoveLegacyColorSettings()
		{
			string[] array = new string[8] { "Freezing", "Frost damage", "Burning", "Poisoned", "Smoke", "Spirit", "Lightning", "Tared" };
			foreach (string text in array)
			{
				ConfigEntry<bool> val = ((BaseUnityPlugin)this).Config.Bind<bool>("Status vignettes", text, true, "Removed in 0.2.2.");
				((BaseUnityPlugin)this).Config.Remove(((ConfigEntryBase)val).Definition);
			}
			((BaseUnityPlugin)this).Config.Save();
		}
	}
	internal sealed class ConfigurationManagerAttributes
	{
		public bool? Browsable = false;
	}
	internal sealed class HealthVignetteDriver : MonoBehaviour
	{
		private const int Rings = 18;

		private const int Segments = 72;

		private static readonly int SrcBlend = Shader.PropertyToID("_SrcBlend");

		private static readonly int DstBlend = Shader.PropertyToID("_DstBlend");

		private static readonly int Cull = Shader.PropertyToID("_Cull");

		private static readonly int ZWrite = Shader.PropertyToID("_ZWrite");

		private static readonly int ZTest = Shader.PropertyToID("_ZTest");

		private Material _overlay;

		private Camera _worldCamera;

		private float _strength;

		private float _flashElapsed = 999f;

		private float _flashStrength;

		private float _flashAttackStartAlpha;

		private float _pulsePhase;

		private HeartbeatSound _sound;

		private void OnEnable()
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Expected O, but got Unknown
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Expected O, but got Unknown
			Camera.onPostRender = (CameraCallback)Delegate.Combine((Delegate?)(object)Camera.onPostRender, (Delegate?)new CameraCallback(OnCameraPostRender));
			_sound = ((Component)this).gameObject.AddComponent<HeartbeatSound>();
		}

		private void OnDisable()
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Expected O, but got Unknown
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Expected O, but got Unknown
			Camera.onPostRender = (CameraCallback)Delegate.Remove((Delegate?)(object)Camera.onPostRender, (Delegate?)new CameraCallback(OnCameraPostRender));
			if ((Object)(object)_sound != (Object)null)
			{
				_sound.StopNow();
			}
			DamageGate.Reset();
		}

		private void OnDestroy()
		{
			if ((Object)(object)_overlay != (Object)null)
			{
				Object.Destroy((Object)(object)_overlay);
			}
		}

		private void Update()
		{
			GameCamera instance = GameCamera.instance;
			_worldCamera = (((Object)(object)instance != (Object)null) ? ((Component)instance).GetComponent<Camera>() : null);
			Player localPlayer = Player.m_localPlayer;
			int num;
			float num2;
			if ((Object)(object)localPlayer != (Object)null && !((Character)localPlayer).IsDead() && !((Character)localPlayer).IsTeleporting() && !GameCamera.InFreeFly() && (Object)(object)_worldCamera != (Object)null)
			{
				num = ((((Character)localPlayer).GetMaxHealth() > 0.001f) ? 1 : 0);
				if (num != 0)
				{
					num2 = 100f * Mathf.Clamp01(((Character)localPlayer).GetHealth() / ((Character)localPlayer).GetMaxHealth());
					goto IL_0084;
				}
			}
			else
			{
				num = 0;
			}
			num2 = 100f;
			goto IL_0084;
			IL_0084:
			float num3 = num2;
			float num4 = Mathf.Max(1f, Plugin.StartHealthPercent.Value);
			DamageGate.Observe((num != 0) ? localPlayer : null);
			bool hasTakenDamage = DamageGate.HasTakenDamage;
			float num5 = DamageGate.ConsumeDirectFlash();
			if (num == 0)
			{
				_flashElapsed = 999f;
				_flashStrength = 0f;
				_flashAttackStartAlpha = 0f;
			}
			else if (num5 > 0f)
			{
				_flashAttackStartAlpha = EvaluateFlashAlpha();
				_flashElapsed = 0f;
				_flashStrength = Mathf.Clamp01(num5);
			}
			else
			{
				_flashElapsed += Time.unscaledDeltaTime;
			}
			float num6 = ((((uint)num & (hasTakenDamage ? 1u : 0u)) != 0 && Plugin.Enabled.Value) ? Mathf.Clamp01((num4 - num3) / num4) : 0f);
			_strength = Mathf.MoveTowards(_strength, num6, Time.unscaledDeltaTime * 2.2f);
			float num7 = Mathf.Lerp(1.18f, 0.78f, _strength);
			_pulsePhase += Time.unscaledDeltaTime / num7;
			_pulsePhase -= Mathf.Floor(_pulsePhase);
			float num8 = Mathf.Max(1f, Plugin.HeartbeatStartPercent.Value);
			bool flag = ((uint)num & (hasTakenDamage ? 1u : 0u)) != 0 && Plugin.HeartbeatEnabled.Value && num3 <= num8;
			float num9 = (flag ? Mathf.Clamp01((num8 - num3) / num8) : 0f);
			if ((Object)(object)_sound != (Object)null)
			{
				_sound.UpdateSound(flag, num9, Plugin.HeartbeatVolume.Value, Plugin.HeartbeatCurve.Value, Mathf.Lerp(0.95f, 1.3f, Mathf.Clamp01(num9 * 2f)));
			}
		}

		private void OnCameraPostRender(Camera cam)
		{
			//IL_0182: Unknown result type (might be due to invalid IL or missing references)
			//IL_0187: Unknown result type (might be due to invalid IL or missing references)
			//IL_018d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0196: Unknown result type (might be due to invalid IL or missing references)
			//IL_019b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dc: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_worldCamera == (Object)null || (Object)(object)cam != (Object)(object)_worldCamera)
			{
				return;
			}
			float num = EvaluateFlashAlpha();
			if ((_strength <= 0.001f && num <= 0.001f) || !EnsureMaterial())
			{
				return;
			}
			float num2 = 0f;
			if (Plugin.Pulse.Value)
			{
				num2 = Peak(_pulsePhase, 0.12f, 0.068f) + 0.58f * Peak(_pulsePhase, 0.31f, 0.078f);
			}
			float num3 = Mathf.Clamp01(Plugin.MaxOpacity.Value);
			float num4 = Mathf.Min(num3, Mathf.Clamp01(_strength * num3 * (1f + num2 * (0.04f + 0.23f * _strength))));
			float num5 = Mathf.Min(0.96f, num4 + Mathf.Min(0.2f, num));
			Color tint = default(Color);
			((Color)(ref tint))..ctor(0.81f, 0.025f, 0.055f);
			_overlay.SetPass(0);
			GL.PushMatrix();
			GL.LoadOrtho();
			GL.Begin(4);
			for (int i = 0; i < 18; i++)
			{
				float num6 = (float)i / 18f;
				float num7 = ((float)i + 1f) / 18f;
				float alpha = RadialAlpha(num6) * num5;
				float alpha2 = RadialAlpha(num7) * num5;
				for (int j = 0; j < 72; j++)
				{
					float angle = (float)Math.PI * 2f * (float)j / 72f;
					float angle2 = (float)Math.PI * 2f * ((float)j + 1f) / 72f;
					Vector2 p = Point(num6, angle);
					Vector2 p2 = Point(num6, angle2);
					Vector2 p3 = Point(num7, angle);
					Vector2 p4 = Point(num7, angle2);
					Vertex(p, alpha, tint);
					Vertex(p3, alpha2, tint);
					Vertex(p4, alpha2, tint);
					Vertex(p, alpha, tint);
					Vertex(p4, alpha2, tint);
					Vertex(p2, alpha, tint);
				}
			}
			GL.End();
			GL.PopMatrix();
		}

		private float EvaluateFlashAlpha()
		{
			if (!Plugin.HitFlashEnabled.Value)
			{
				return 0f;
			}
			float num = Mathf.Max(0.06f, Plugin.HitFlashDuration.Value);
			if (_flashElapsed >= num)
			{
				return 0f;
			}
			float num2 = Mathf.Min(0.025f, num * 0.12f);
			float num3 = Mathf.Clamp(Plugin.HitFlashOpacity.Value * _flashStrength, 0f, 0.2f);
			float num4 = Mathf.Max(_flashAttackStartAlpha, num3);
			if (_flashElapsed < num2)
			{
				float num5 = Mathf.Clamp01(_flashElapsed / num2);
				return Mathf.Lerp(_flashAttackStartAlpha, num4, Mathf.SmoothStep(0f, 1f, num5));
			}
			float num6 = Mathf.Clamp01((_flashElapsed - num2) / Mathf.Max(0.001f, num - num2));
			return num4 * (1f - Mathf.SmoothStep(0f, 1f, num6));
		}

		private bool EnsureMaterial()
		{
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Expected O, but got Unknown
			if ((Object)(object)_overlay != (Object)null)
			{
				return true;
			}
			Shader val = Shader.Find("Hidden/Internal-Colored");
			if ((Object)(object)val == (Object)null)
			{
				val = Shader.Find("Sprites/Default");
			}
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			_overlay = new Material(val);
			((Object)_overlay).hideFlags = (HideFlags)61;
			_overlay.SetInt(SrcBlend, 5);
			_overlay.SetInt(DstBlend, 10);
			_overlay.SetInt(Cull, 0);
			_overlay.SetInt(ZWrite, 0);
			_overlay.SetInt(ZTest, 8);
			return true;
		}

		private static Vector2 Point(float r, float angle)
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			float num = Mathf.Cos(angle);
			float num2 = Mathf.Sin(angle);
			float num3 = 0.5f / Mathf.Max(1E-05f, Mathf.Max(Mathf.Abs(num), Mathf.Abs(num2)));
			return new Vector2(0.5f + num * num3 * r, 0.5f + num2 * num3 * r);
		}

		private static float RadialAlpha(float radius)
		{
			float num = Mathf.Clamp01((radius - 0.1f) / 0.9f);
			return Mathf.Pow(num * num * (3f - 2f * num), 1.35f);
		}

		private static float Peak(float position, float center, float spread)
		{
			float num = Mathf.Abs(position - center);
			num = Mathf.Min(num, 1f - num);
			float num2 = num / spread;
			return Mathf.Exp((0f - num2) * num2 * 2f);
		}

		private static void Vertex(Vector2 p, float alpha, Color tint)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: 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_0013: 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_0023: Unknown result type (might be due to invalid IL or missing references)
			GL.Color(new Color(tint.r, tint.g, tint.b, alpha));
			GL.Vertex3(p.x, p.y, 0f);
		}
	}
}