Decompiled source of BloodColor v1.0.0

BepInEx/plugins/BloodColor/BloodColor.dll

Decompiled 10 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Rendering.Universal;
using UnityEngine.SceneManagement;
using UnityEngine.VFX;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("BloodColor")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("BloodColor")]
[assembly: AssemblyTitle("BloodColor")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[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 BloodColor
{
	public enum TintMode
	{
		Replace,
		Multiply,
		Vanilla
	}
	internal class BloodConfig
	{
		public const string DefaultHex = "B01C1C";

		private const int DefaultR = 176;

		private const int DefaultG = 28;

		private const int DefaultB = 28;

		public ConfigEntry<string> Hex;

		public ConfigEntry<int> R;

		public ConfigEntry<int> G;

		public ConfigEntry<int> B;

		public ConfigEntry<TintMode> Mode;

		public ConfigEntry<float> Opacity;

		public ConfigEntry<float> Intensity;

		public ConfigEntry<bool> EnableBlood;

		public ConfigEntry<bool> DoParticles;

		public ConfigEntry<bool> DoDecals;

		public ConfigEntry<bool> LogEffects;

		public Color Tint = Color.red;

		private bool _syncing;

		public float AlphaFactor => ((Mode.Value == TintMode.Vanilla) ? 1f : Tint.a) * Opacity.Value;

		public event Action Changed;

		public BloodConfig(ConfigFile file)
		{
			//IL_0001: 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_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Expected O, but got Unknown
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Expected O, but got Unknown
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Expected O, but got Unknown
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Expected O, but got Unknown
			//IL_0149: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Expected O, but got Unknown
			Hex = file.Bind<string>("Blood", "Color", "B01C1C", "Blood colour as a hex code, like B01C1C. Paste one from any colour picker. RGB, RRGGBB or RRGGBBAA, # optional, and names like 'red' or 'lime' work too.\nThis and the R/G/B sliders below are the same setting - change either one and the other follows.\nHeads up: you can't type letters into this box from the in-game Mod Menu. Use the sliders there, or edit this file.");
			R = file.Bind<int>("Blood", "R", 176, new ConfigDescription("Red, 0-255. Moves with the Color setting.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 255), Array.Empty<object>()));
			G = file.Bind<int>("Blood", "G", 28, new ConfigDescription("Green, 0-255. Moves with the Color setting.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 255), Array.Empty<object>()));
			B = file.Bind<int>("Blood", "B", 28, new ConfigDescription("Blue, 0-255. Moves with the Color setting.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 255), Array.Empty<object>()));
			Mode = file.Bind<TintMode>("Blood", "Mode", TintMode.Replace, "Replace = use your colour as-is.\nMultiply = tint the original, which keeps the built-in shading but can only darken.\nVanilla = don't recolour. Opacity, Intensity and EnableBlood still work.");
			Opacity = file.Bind<float>("Blood", "Opacity", 1f, new ConfigDescription("How visible blood is. 1 is normal, 0 is invisible.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			Intensity = file.Bind<float>("Blood", "Intensity", 1f, new ConfigDescription("Brightness. Above 1 goes HDR, which is how you get blood that glows. A hex code can't describe anything brighter than 1 on its own, hence this.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 8f), Array.Empty<object>()));
			EnableBlood = file.Bind<bool>("Blood", "EnableBlood", true, "Turn this off for no blood at all. Separate from the game's own Blood option - either one being off means no blood.");
			DoParticles = file.Bind<bool>("Targets", "Particles", true, "Recolour the blood spray.");
			DoDecals = file.Bind<bool>("Targets", "Decals", true, "Recolour the splatter left on the ground.");
			LogEffects = file.Bind<bool>("Advanced", "LogEffects", false, "Dump the blood effects the mod found to the BepInEx log - shaders, materials, VFX properties. Turn this on before reporting a problem.");
			PullFromHex();
			file.SettingChanged += delegate(object _, SettingChangedEventArgs e)
			{
				if (!_syncing)
				{
					if ((object)e.ChangedSetting == Hex)
					{
						PullFromHex();
					}
					else if ((object)e.ChangedSetting == R || (object)e.ChangedSetting == G || (object)e.ChangedSetting == B)
					{
						PullFromSliders();
					}
					this.Changed?.Invoke();
				}
			};
		}

		private void PullFromHex()
		{
			//IL_0046: 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)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			if (!TryParse(Hex.Value, out var color))
			{
				Plugin.Log.LogWarning((object)("Couldn't read colour '" + Hex.Value + "', using B01C1C instead."));
				TryParse("B01C1C", out color);
			}
			Tint = color;
			_syncing = true;
			R.Value = To255(color.r);
			G.Value = To255(color.g);
			B.Value = To255(color.b);
			_syncing = false;
		}

		private void PullFromSliders()
		{
			//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)
			//IL_0079: 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)
			Tint = new Color((float)R.Value / 255f, (float)G.Value / 255f, (float)B.Value / 255f, Tint.a);
			_syncing = true;
			Hex.Value = ((Tint.a >= 1f) ? ColorUtility.ToHtmlStringRGB(Tint) : ColorUtility.ToHtmlStringRGBA(Tint));
			_syncing = false;
		}

		private static int To255(float v)
		{
			return Mathf.Clamp(Mathf.RoundToInt(v * 255f), 0, 255);
		}

		public static bool TryParse(string raw, out Color color)
		{
			//IL_0001: 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)
			color = Color.red;
			if (string.IsNullOrEmpty(raw))
			{
				return false;
			}
			string text = raw.Trim();
			if (text.Length == 0)
			{
				return false;
			}
			if (text[0] != '#' && !char.IsLetter(text[0]))
			{
				text = "#" + text;
			}
			return ColorUtility.TryParseHtmlString(text, ref color);
		}

		public Color CombineRgb(Color original)
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: 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_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: 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)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			Color val = default(Color);
			switch (Mode.Value)
			{
			case TintMode.Replace:
				((Color)(ref val))..ctor(Tint.r, Tint.g, Tint.b, original.a);
				break;
			case TintMode.Multiply:
				((Color)(ref val))..ctor(original.r * Tint.r, original.g * Tint.g, original.b * Tint.b, original.a);
				break;
			default:
				val = original;
				break;
			}
			float value = Intensity.Value;
			return new Color(val.r * value, val.g * value, val.b * value, original.a);
		}

		public Color Combine(Color original)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//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_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			Color result = CombineRgb(original);
			result.a = Mathf.Clamp01(original.a * AlphaFactor);
			return result;
		}
	}
	internal static class BloodTinter
	{
		private class ParticleTarget
		{
			public ParticleSystem System;

			public string Owner;

			public MinMaxGradient Original;

			public ParticleSystemRenderer Renderer;

			public int ColorProp = -1;

			public Color OriginalMaterialColor;
		}

		private class DecalTarget
		{
			public string Name;

			public List<DecalProjector> Projectors;

			public Material Material;

			public int ColorProp = -1;

			public Color OriginalColor;

			public float OriginalFade;
		}

		private class VfxTarget
		{
			public VisualEffect Effect;

			public string Property;

			public bool IsGradient;

			public Color OriginalColor;

			public Gradient OriginalGradient;
		}

		private class Original
		{
			public Material Material;

			public float Fade;
		}

		public static readonly string[] ParticleNames = new string[3] { "Blood", "BloodSmall", "BloodDirectional" };

		public const string DecalPrefix = "BloodDecal";

		private static readonly string[] DecalNames = new string[3] { "BloodDecal1", "BloodDecal2", "BloodDecal3" };

		public const string VfxName = "SmallBloodExplosion";

		private static readonly string[] ColorProps = new string[5] { "_BaseColor", "_Color", "_TintColor", "_MainColor", "_UnlitColor" };

		private static readonly List<ParticleTarget> Particles = new List<ParticleTarget>();

		private static readonly List<DecalTarget> Decals = new List<DecalTarget>();

		private static readonly Dictionary<string, Original> Pristine = new Dictionary<string, Original>();

		private static VfxTarget Vfx;

		private static readonly MaterialPropertyBlock Block = new MaterialPropertyBlock();

		private static bool _warnedVfx;

		private static bool _warnedDecal;

		private static BloodConfig Cfg => Plugin.Cfg;

		public static int FindParticles()
		{
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: Unknown result type (might be due to invalid IL or missing references)
			List<ParticleTarget> list = new List<ParticleTarget>(Particles);
			Particles.Clear();
			Dictionary<string, ParticleType> particles = ParticleManager._particles;
			if (particles == null || particles.Count == 0)
			{
				return 0;
			}
			string[] particleNames = ParticleNames;
			foreach (string text in particleNames)
			{
				if (!particles.TryGetValue(text, out var value) || (Object)(object)value?.ParticleSystem == (Object)null)
				{
					continue;
				}
				ParticleSystem[] componentsInChildren = ((Component)value.ParticleSystem).GetComponentsInChildren<ParticleSystem>(true);
				foreach (ParticleSystem ps in componentsInChildren)
				{
					ParticleTarget particleTarget = list.Find((ParticleTarget x) => x.System == ps);
					if (particleTarget == null)
					{
						ParticleTarget obj = new ParticleTarget
						{
							System = ps,
							Owner = text
						};
						MainModule main = ps.main;
						obj.Original = Copy(((MainModule)(ref main)).startColor);
						obj.Renderer = ((Component)ps).GetComponent<ParticleSystemRenderer>();
						particleTarget = obj;
						Material val = (Object.op_Implicit((Object)(object)particleTarget.Renderer) ? ((Renderer)particleTarget.Renderer).sharedMaterial : null);
						if ((Object)(object)val != (Object)null)
						{
							particleTarget.ColorProp = FindColorProp(val);
							if (particleTarget.ColorProp >= 0)
							{
								particleTarget.OriginalMaterialColor = val.GetColor(particleTarget.ColorProp);
							}
						}
					}
					Particles.Add(particleTarget);
				}
			}
			return Particles.Count;
		}

		public static int FindDecals()
		{
			//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_0166: Expected O, but got Unknown
			//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
			List<DecalTarget> list = new List<DecalTarget>(Decals);
			Decals.Clear();
			Dictionary<string, List<DecalProjector>> decals = DecalManager._decals;
			if (decals == null || decals.Count == 0)
			{
				DestroyMaterials(list);
				return 0;
			}
			string[] decalNames = DecalNames;
			foreach (string text in decalNames)
			{
				if (!decals.TryGetValue(text, out var pool) || pool == null || pool.Count == 0)
				{
					continue;
				}
				DecalTarget decalTarget = list.Find((DecalTarget x) => x.Projectors == pool);
				if (decalTarget != null)
				{
					Decals.Add(decalTarget);
					continue;
				}
				DecalProjector val = pool[0];
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				if (!Pristine.TryGetValue(text, out var value) || (Object)(object)value.Material == (Object)null)
				{
					if ((Object)(object)val.material == (Object)null)
					{
						continue;
					}
					value = new Original
					{
						Material = val.material,
						Fade = val.fadeFactor
					};
					Pristine[text] = value;
				}
				DecalTarget decalTarget2 = new DecalTarget
				{
					Name = text,
					Projectors = pool,
					Material = new Material(value.Material)
					{
						name = ((Object)value.Material).name + " (BloodColor)"
					},
					OriginalFade = value.Fade
				};
				decalTarget2.ColorProp = FindColorProp(decalTarget2.Material);
				if (decalTarget2.ColorProp >= 0)
				{
					decalTarget2.OriginalColor = decalTarget2.Material.GetColor(decalTarget2.ColorProp);
				}
				else if (!_warnedDecal)
				{
					_warnedDecal = true;
					ManualLogSource log = Plugin.Log;
					string[] obj = new string[5] { "Decal ", text, " uses shader '", null, null };
					Shader shader = decalTarget2.Material.shader;
					obj[3] = ((shader != null) ? ((Object)shader).name : null);
					obj[4] = "' and I can't find a colour property on it. Turn on LogEffects and send me the shader name.";
					log.LogWarning((object)string.Concat(obj));
				}
				foreach (DecalProjector item in pool)
				{
					if ((Object)(object)item != (Object)null)
					{
						item.material = decalTarget2.Material;
					}
				}
				Decals.Add(decalTarget2);
			}
			list.RemoveAll((DecalTarget x) => Decals.Contains(x));
			DestroyMaterials(list);
			return Decals.Count;
		}

		public static int FindVfx()
		{
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			VfxTarget vfx = Vfx;
			Vfx = null;
			Dictionary<string, VisualEffect> allVfx = VFXManager._allVfx;
			if (allVfx == null || !allVfx.TryGetValue("SmallBloodExplosion", out var value) || (Object)(object)value == (Object)null)
			{
				return 0;
			}
			if (vfx != null && vfx.Effect == value)
			{
				Vfx = vfx;
				return 1;
			}
			foreach (string item in ExposedNames(value))
			{
				if (value.HasVector4(item))
				{
					Vfx = new VfxTarget
					{
						Effect = value,
						Property = item,
						OriginalColor = Color.op_Implicit(value.GetVector4(item))
					};
					break;
				}
				if (value.HasGradient(item))
				{
					Vfx = new VfxTarget
					{
						Effect = value,
						Property = item,
						IsGradient = true,
						OriginalGradient = value.GetGradient(item)
					};
					break;
				}
			}
			if (Vfx == null)
			{
				if (!_warnedVfx)
				{
					_warnedVfx = true;
					Plugin.Log.LogDebug((object)"SmallBloodExplosion exposes no colour property; gib burst left alone.");
				}
				return 0;
			}
			Plugin.Log.LogInfo((object)("SmallBloodExplosion: using property '" + Vfx.Property + "'."));
			return 1;
		}

		public static void ResetVfxWarning()
		{
			_warnedVfx = false;
		}

		private static List<string> ExposedNames(VisualEffect effect)
		{
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: 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_00a6: 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)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			List<string> list = new List<string>();
			VisualEffectAsset visualEffectAsset = effect.visualEffectAsset;
			if ((Object)(object)visualEffectAsset == (Object)null)
			{
				return list;
			}
			List<VFXExposedProperty> list2 = new List<VFXExposedProperty>();
			try
			{
				visualEffectAsset.GetExposedProperties(list2);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogDebug((object)("Couldn't read exposed properties off SmallBloodExplosion: " + ex.Message));
				return list;
			}
			foreach (VFXExposedProperty item in list2)
			{
				if (item.type == typeof(Vector4) || item.type == typeof(Color) || item.type == typeof(Gradient))
				{
					list.Add(item.name);
				}
			}
			return list;
		}

		public static void Apply()
		{
			if (Cfg.DoParticles.Value)
			{
				ApplyParticles();
			}
			if (Cfg.DoDecals.Value)
			{
				ApplyDecals();
			}
			if (Vfx != null && (Object)(object)Vfx.Effect != (Object)null)
			{
				ApplyVfx();
			}
		}

		private static void ApplyParticles()
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: 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)
			//IL_003d: 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)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			foreach (ParticleTarget particle in Particles)
			{
				if (!((Object)(object)particle.System == (Object)null))
				{
					MainModule main = particle.System.main;
					((MainModule)(ref main)).startColor = BuildStartColor(particle.Original);
					if (!((Object)(object)particle.Renderer == (Object)null) && particle.ColorProp >= 0)
					{
						Color val = Cfg.CombineRgb(particle.OriginalMaterialColor);
						val.a = particle.OriginalMaterialColor.a;
						((Renderer)particle.Renderer).GetPropertyBlock(Block);
						Block.SetColor(particle.ColorProp, val);
						((Renderer)particle.Renderer).SetPropertyBlock(Block);
					}
				}
			}
		}

		private static void ApplyDecals()
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			foreach (DecalTarget decal in Decals)
			{
				if ((Object)(object)decal.Material != (Object)null && decal.ColorProp >= 0)
				{
					Color val = Cfg.Combine(decal.OriginalColor);
					val.a = decal.OriginalColor.a;
					decal.Material.SetColor(decal.ColorProp, val);
				}
				float fadeFactor = Mathf.Clamp01(decal.OriginalFade * Cfg.AlphaFactor);
				foreach (DecalProjector projector in decal.Projectors)
				{
					if ((Object)(object)projector != (Object)null)
					{
						projector.fadeFactor = fadeFactor;
					}
				}
			}
		}

		private static void ApplyVfx()
		{
			//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)
			if (Vfx.IsGradient)
			{
				Vfx.Effect.SetGradient(Vfx.Property, TintGradient(Vfx.OriginalGradient));
			}
			else
			{
				Vfx.Effect.SetVector4(Vfx.Property, Color.op_Implicit(Cfg.Combine(Vfx.OriginalColor)));
			}
		}

		private static MinMaxGradient BuildStartColor(MinMaxGradient src)
		{
			//IL_002b: 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_0046: 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)
			//IL_0061: Expected I4, but got Unknown
			//IL_0068: 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_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			bool flag = Cfg.Mode.Value == TintMode.Vanilla;
			float alphaFactor = Cfg.AlphaFactor;
			float scale = (flag ? 1f : (1f / Mathf.Max(0.0001f, MaxLuminance(src))));
			ParticleSystemGradientMode mode = ((MinMaxGradient)(ref src)).mode;
			switch ((int)mode)
			{
			case 0:
				return new MinMaxGradient(Flatten(((MinMaxGradient)(ref src)).color, flag, scale, alphaFactor));
			case 2:
				return new MinMaxGradient(Flatten(((MinMaxGradient)(ref src)).colorMin, flag, scale, alphaFactor), Flatten(((MinMaxGradient)(ref src)).colorMax, flag, scale, alphaFactor));
			case 1:
			case 4:
			{
				MinMaxGradient result = default(MinMaxGradient);
				((MinMaxGradient)(ref result))..ctor(FlattenGradient(((MinMaxGradient)(ref src)).gradient, flag, scale, alphaFactor));
				((MinMaxGradient)(ref result)).mode = ((MinMaxGradient)(ref src)).mode;
				return result;
			}
			case 3:
				return new MinMaxGradient(FlattenGradient(((MinMaxGradient)(ref src)).gradientMin, flag, scale, alphaFactor), FlattenGradient(((MinMaxGradient)(ref src)).gradientMax, flag, scale, alphaFactor));
			default:
				return src;
			}
		}

		private static Color Flatten(Color c, bool vanilla, float scale, float alpha)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: 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_0024: Unknown result type (might be due to invalid IL or missing references)
			float num = Mathf.Clamp01(c.a * alpha);
			if (vanilla)
			{
				return new Color(c.r, c.g, c.b, num);
			}
			float num2 = Mathf.Clamp01(((Color)(ref c)).grayscale * scale);
			return new Color(num2, num2, num2, num);
		}

		private static Gradient FlattenGradient(Gradient src, bool vanilla, float scale, float alpha)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: 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_0038: 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)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: 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_00c8: Expected O, but got Unknown
			if (src == null)
			{
				return null;
			}
			GradientColorKey[] colorKeys = src.colorKeys;
			GradientColorKey[] array = (GradientColorKey[])(object)new GradientColorKey[colorKeys.Length];
			for (int i = 0; i < colorKeys.Length; i++)
			{
				Color val = Flatten(colorKeys[i].color, vanilla, scale, 1f);
				array[i] = new GradientColorKey(val, colorKeys[i].time);
			}
			GradientAlphaKey[] alphaKeys = src.alphaKeys;
			GradientAlphaKey[] array2 = (GradientAlphaKey[])(object)new GradientAlphaKey[alphaKeys.Length];
			for (int j = 0; j < alphaKeys.Length; j++)
			{
				array2[j] = new GradientAlphaKey(Mathf.Clamp01(alphaKeys[j].alpha * alpha), alphaKeys[j].time);
			}
			Gradient val2 = new Gradient
			{
				mode = src.mode
			};
			val2.SetKeys(array, array2);
			return val2;
		}

		private static float MaxLuminance(MinMaxGradient g)
		{
			//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_0022: Expected I4, but got Unknown
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: 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)
			ParticleSystemGradientMode mode = ((MinMaxGradient)(ref g)).mode;
			Color val;
			switch ((int)mode)
			{
			case 0:
				val = ((MinMaxGradient)(ref g)).color;
				return ((Color)(ref val)).grayscale;
			case 2:
			{
				val = ((MinMaxGradient)(ref g)).colorMin;
				float grayscale = ((Color)(ref val)).grayscale;
				val = ((MinMaxGradient)(ref g)).colorMax;
				return Mathf.Max(grayscale, ((Color)(ref val)).grayscale);
			}
			case 1:
			case 4:
				return MaxLuminance(((MinMaxGradient)(ref g)).gradient);
			case 3:
				return Mathf.Max(MaxLuminance(((MinMaxGradient)(ref g)).gradientMin), MaxLuminance(((MinMaxGradient)(ref g)).gradientMax));
			default:
				return 1f;
			}
		}

		private static float MaxLuminance(Gradient g)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			if (g == null)
			{
				return 1f;
			}
			float num = 0f;
			GradientColorKey[] colorKeys = g.colorKeys;
			for (int i = 0; i < colorKeys.Length; i++)
			{
				GradientColorKey val = colorKeys[i];
				num = Mathf.Max(num, ((Color)(ref val.color)).grayscale);
			}
			return num;
		}

		private static Gradient TintGradient(Gradient src)
		{
			//IL_002a: 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_0041: 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_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Expected O, but got Unknown
			if (src == null)
			{
				return null;
			}
			GradientColorKey[] colorKeys = src.colorKeys;
			GradientColorKey[] array = (GradientColorKey[])(object)new GradientColorKey[colorKeys.Length];
			for (int i = 0; i < colorKeys.Length; i++)
			{
				array[i] = new GradientColorKey(Cfg.CombineRgb(colorKeys[i].color), colorKeys[i].time);
			}
			GradientAlphaKey[] alphaKeys = src.alphaKeys;
			GradientAlphaKey[] array2 = (GradientAlphaKey[])(object)new GradientAlphaKey[alphaKeys.Length];
			float alphaFactor = Cfg.AlphaFactor;
			for (int j = 0; j < alphaKeys.Length; j++)
			{
				array2[j] = new GradientAlphaKey(Mathf.Clamp01(alphaKeys[j].alpha * alphaFactor), alphaKeys[j].time);
			}
			Gradient val = new Gradient
			{
				mode = src.mode
			};
			val.SetKeys(array, array2);
			return val;
		}

		private static MinMaxGradient Copy(MinMaxGradient src)
		{
			//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_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Expected I4, but got Unknown
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: 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)
			ParticleSystemGradientMode mode = ((MinMaxGradient)(ref src)).mode;
			switch (mode - 1)
			{
			case 0:
			case 3:
			{
				MinMaxGradient result = default(MinMaxGradient);
				((MinMaxGradient)(ref result))..ctor(Copy(((MinMaxGradient)(ref src)).gradient));
				((MinMaxGradient)(ref result)).mode = ((MinMaxGradient)(ref src)).mode;
				return result;
			}
			case 2:
				return new MinMaxGradient(Copy(((MinMaxGradient)(ref src)).gradientMin), Copy(((MinMaxGradient)(ref src)).gradientMax));
			default:
				return src;
			}
		}

		private static Gradient Copy(Gradient src)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: 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_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Expected O, but got Unknown
			if (src == null)
			{
				return null;
			}
			Gradient val = new Gradient
			{
				mode = src.mode
			};
			val.SetKeys(src.colorKeys, src.alphaKeys);
			return val;
		}

		private static int FindColorProp(Material mat)
		{
			string[] colorProps = ColorProps;
			for (int i = 0; i < colorProps.Length; i++)
			{
				int num = Shader.PropertyToID(colorProps[i]);
				if (mat.HasProperty(num))
				{
					return num;
				}
			}
			return -1;
		}

		public static void Clear()
		{
			Particles.Clear();
			DestroyMaterials(Decals);
			Decals.Clear();
			Pristine.Clear();
			Vfx = null;
		}

		private static void DestroyMaterials(IEnumerable<DecalTarget> targets)
		{
			foreach (DecalTarget target in targets)
			{
				if ((Object)(object)target.Material != (Object)null)
				{
					Object.Destroy((Object)(object)target.Material);
				}
			}
		}

		public static void LogEffects()
		{
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.AppendLine("---- BloodColor: what I found ----");
			stringBuilder.AppendLine($"Particles ({Particles.Count}):");
			foreach (ParticleTarget particle in Particles)
			{
				if (!((Object)(object)particle.System == (Object)null))
				{
					Material val = (Object.op_Implicit((Object)(object)particle.Renderer) ? ((Renderer)particle.Renderer).sharedMaterial : null);
					stringBuilder.AppendLine("  [" + particle.Owner + "] " + PathOf(((Component)particle.System).transform));
					stringBuilder.AppendLine($"      startColor : {((MinMaxGradient)(ref particle.Original)).mode} {DescribeStartColor(particle.Original)}");
					stringBuilder.AppendLine("      material   : " + (Object.op_Implicit((Object)(object)val) ? ((Object)val).name : "none"));
					stringBuilder.AppendLine("      shader     : " + ((Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)val.shader)) ? ((Object)val.shader).name : "none"));
					stringBuilder.AppendLine("      mat colour : " + MaterialColor(val));
				}
			}
			stringBuilder.AppendLine($"Decals ({Decals.Count}):");
			foreach (DecalTarget decal in Decals)
			{
				stringBuilder.AppendLine($"  [{decal.Name}] {decal.Projectors.Count} projectors");
				stringBuilder.AppendLine("      shader     : " + ((Object.op_Implicit((Object)(object)decal.Material) && Object.op_Implicit((Object)(object)decal.Material.shader)) ? ((Object)decal.Material.shader).name : "none"));
				stringBuilder.AppendLine("      colour     : " + ((decal.ColorProp >= 0) ? ((object)Unsafe.As<Color, Color>(ref decal.OriginalColor)/*cast due to .constrained prefix*/).ToString() : "no property found"));
				stringBuilder.AppendLine($"      fade       : {decal.OriginalFade}");
			}
			stringBuilder.AppendLine("VFX SmallBloodExplosion:");
			stringBuilder.AppendLine((Vfx == null) ? "      no colour property found" : ("      using '" + Vfx.Property + "'"));
			stringBuilder.Append(VfxProperties());
			Plugin.Log.LogInfo((object)stringBuilder.ToString());
		}

		private static string DescribeStartColor(MinMaxGradient g)
		{
			//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_0022: Expected I4, but got Unknown
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: 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_0050: Unknown result type (might be due to invalid IL or missing references)
			ParticleSystemGradientMode mode = ((MinMaxGradient)(ref g)).mode;
			switch ((int)mode)
			{
			case 0:
				return ((object)((MinMaxGradient)(ref g)).color/*cast due to .constrained prefix*/).ToString();
			case 2:
				return $"{((MinMaxGradient)(ref g)).colorMin} .. {((MinMaxGradient)(ref g)).colorMax}";
			case 1:
			case 4:
			{
				Gradient gradient = ((MinMaxGradient)(ref g)).gradient;
				return $"{((gradient != null) ? gradient.colorKeys.Length : 0)} colour key(s)";
			}
			case 3:
			{
				Gradient gradientMin = ((MinMaxGradient)(ref g)).gradientMin;
				object arg = ((gradientMin != null) ? gradientMin.colorKeys.Length : 0);
				Gradient gradientMax = ((MinMaxGradient)(ref g)).gradientMax;
				return $"{arg} + {((gradientMax != null) ? gradientMax.colorKeys.Length : 0)} key(s)";
			}
			default:
				return string.Empty;
			}
		}

		private static string MaterialColor(Material mat)
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)mat == (Object)null)
			{
				return "none";
			}
			string[] colorProps = ColorProps;
			foreach (string text in colorProps)
			{
				int num = Shader.PropertyToID(text);
				if (mat.HasProperty(num))
				{
					return $"{text} = {mat.GetColor(num)}";
				}
			}
			return "no known colour property";
		}

		private static string VfxProperties()
		{
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			Dictionary<string, VisualEffect> allVfx = VFXManager._allVfx;
			if (allVfx == null || !allVfx.TryGetValue("SmallBloodExplosion", out var value) || (Object)(object)value == (Object)null)
			{
				return "      (not in this scene)\n";
			}
			StringBuilder stringBuilder = new StringBuilder();
			VisualEffectAsset visualEffectAsset = value.visualEffectAsset;
			stringBuilder.AppendLine("      asset      : " + (((Object)(object)visualEffectAsset != (Object)null) ? ((Object)visualEffectAsset).name : "none"));
			if ((Object)(object)visualEffectAsset == (Object)null)
			{
				return stringBuilder.ToString();
			}
			List<VFXExposedProperty> list = new List<VFXExposedProperty>();
			try
			{
				visualEffectAsset.GetExposedProperties(list);
			}
			catch (Exception ex)
			{
				stringBuilder.AppendLine("      (couldn't read exposed properties: " + ex.Message + ")");
				return stringBuilder.ToString();
			}
			if (list.Count == 0)
			{
				stringBuilder.AppendLine("      exposes nothing at all - this effect can't be recoloured");
				return stringBuilder.ToString();
			}
			stringBuilder.AppendLine($"      exposes ({list.Count}):");
			foreach (VFXExposedProperty item in list)
			{
				stringBuilder.AppendLine("        " + item.name + " : " + item.type?.Name);
			}
			return stringBuilder.ToString();
		}

		private static string PathOf(Transform t)
		{
			StringBuilder stringBuilder = new StringBuilder(((Object)t).name);
			Transform parent = t.parent;
			while ((Object)(object)parent != (Object)null)
			{
				stringBuilder.Insert(0, ((Object)parent).name + "/");
				parent = parent.parent;
			}
			return stringBuilder.ToString();
		}
	}
	[HarmonyPatch(typeof(ParticleManager), "Awake")]
	internal static class ParticleManagerAwake
	{
		private static void Postfix()
		{
			Plugin.QueueRefresh();
		}
	}
	[HarmonyPatch(typeof(DecalManager), "Awake")]
	internal static class DecalManagerAwake
	{
		private static void Postfix()
		{
			Plugin.QueueRefresh();
		}
	}
	[HarmonyPatch(typeof(VFXManager), "Awake")]
	internal static class VfxManagerAwake
	{
		private static void Postfix()
		{
			Plugin.QueueRefresh();
		}
	}
	[HarmonyPatch(typeof(ParticleManager), "Play", new Type[]
	{
		typeof(string),
		typeof(Vector3),
		typeof(Vector3)
	})]
	internal static class ParticleManagerPlay
	{
		private static bool Prefix(string type)
		{
			if (!Plugin.BloodOff)
			{
				return true;
			}
			string[] particleNames = BloodTinter.ParticleNames;
			foreach (string b in particleNames)
			{
				if (string.Equals(type, b, StringComparison.Ordinal))
				{
					return false;
				}
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(DecalManager), "SpawnDecal")]
	internal static class DecalManagerSpawnDecal
	{
		private static bool Prefix(string decalName)
		{
			if (Plugin.BloodOff && decalName != null)
			{
				return !decalName.StartsWith("BloodDecal", StringComparison.Ordinal);
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(VFXManager), "Play", new Type[]
	{
		typeof(string),
		typeof(Vector3),
		typeof(Vector3)
	})]
	internal static class VfxManagerPlay
	{
		private static bool Prefix(string type)
		{
			if (Plugin.BloodOff)
			{
				return !string.Equals(type, "SmallBloodExplosion", StringComparison.Ordinal);
			}
			return true;
		}
	}
	[BepInPlugin("com.zoe.howtofish.bloodcolor", "BloodColor", "1.0.0")]
	public class Plugin : BaseUnityPlugin
	{
		public const string Guid = "com.zoe.howtofish.bloodcolor";

		public const string Name = "BloodColor";

		public const string Version = "1.0.0";

		internal static ManualLogSource Log;

		internal static BloodConfig Cfg;

		internal static bool BloodOff;

		private Harmony _harmony;

		private static bool _refreshQueued;

		private bool _loggedFailure;

		private void Awake()
		{
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			Cfg = new BloodConfig(((BaseUnityPlugin)this).Config);
			BloodOff = !Cfg.EnableBlood.Value;
			Cfg.Changed += OnConfigChanged;
			try
			{
				_harmony = new Harmony("com.zoe.howtofish.bloodcolor");
				_harmony.PatchAll(typeof(Plugin).Assembly);
			}
			catch (Exception ex)
			{
				Log.LogError((object)("Couldn't apply patches, BloodColor is doing nothing this session. Probably a game update moved something, see Patches.cs.\n" + ex));
				return;
			}
			SceneManager.sceneLoaded += OnSceneLoaded;
			QueueRefresh();
			Log.LogInfo((object)string.Format("{0} {1} loaded. Colour {2}, mode {3}.", "BloodColor", "1.0.0", Cfg.Hex.Value, Cfg.Mode.Value));
		}

		private void OnDestroy()
		{
			SceneManager.sceneLoaded -= OnSceneLoaded;
			if (Cfg != null)
			{
				Cfg.Changed -= OnConfigChanged;
			}
			BloodTinter.Clear();
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}

		internal static void QueueRefresh()
		{
			_refreshQueued = true;
		}

		private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
		{
			QueueRefresh();
		}

		private void Update()
		{
			if (!_refreshQueued)
			{
				return;
			}
			_refreshQueued = false;
			try
			{
				Refresh();
			}
			catch (Exception arg)
			{
				if (!_loggedFailure)
				{
					_loggedFailure = true;
					Log.LogError((object)$"Refresh failed, not going to report this again: {arg}");
				}
			}
		}

		private void Refresh()
		{
			int num = BloodTinter.FindParticles();
			int num2 = BloodTinter.FindDecals();
			int num3 = BloodTinter.FindVfx();
			if (num + num2 + num3 != 0)
			{
				BloodTinter.Apply();
				string arg = ((num3 > 0) ? $", {num3} vfx" : string.Empty);
				Log.LogInfo((object)$"Recoloured {num} particle systems, {num2} decal pools{arg}.");
				if (Cfg.LogEffects.Value)
				{
					BloodTinter.LogEffects();
				}
			}
		}

		private void OnConfigChanged()
		{
			BloodOff = !Cfg.EnableBlood.Value;
			try
			{
				BloodTinter.Apply();
				if (Cfg.LogEffects.Value)
				{
					BloodTinter.LogEffects();
				}
				Log.LogInfo((object)($"Config changed: {Cfg.Hex.Value}, {Cfg.Mode.Value}, opacity {Cfg.Opacity.Value}, " + string.Format("intensity {0}, blood {1}.", Cfg.Intensity.Value, Cfg.EnableBlood.Value ? "on" : "off")));
			}
			catch (Exception arg)
			{
				Log.LogError((object)$"Couldn't apply that config change: {arg}");
			}
		}
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}