Decompiled source of BlazingElite v0.2.0

plugins/MuckBlazing.dll

Decompiled a day 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 BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")]
[assembly: AssemblyCompany("MuckBlazing")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Some hostile Muck mobs spawn as Blazing elites with more health, more damage, and a fire trail.")]
[assembly: AssemblyFileVersion("0.2.0.0")]
[assembly: AssemblyInformationalVersion("0.2.0+879fc7ac66fec639f2f84b4b7a65d5c61c9ed734")]
[assembly: AssemblyProduct("Blazing Elite")]
[assembly: AssemblyTitle("MuckBlazing")]
[assembly: InternalsVisibleTo("MuckBlazing.Tests")]
[assembly: AssemblyVersion("0.2.0.0")]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class IsReadOnlyAttribute : Attribute
	{
	}
}
namespace MuckBlazing
{
	internal sealed class BlazingConfig
	{
		public readonly ConfigEntry<float> Chance;

		public readonly ConfigEntry<bool> IncludeNeutral;

		public readonly ConfigEntry<float> HealthFactor;

		public readonly ConfigEntry<float> DamageFactor;

		public readonly ConfigEntry<float> TrailDamageFraction;

		public readonly ConfigEntry<int> TrailBaseDamage;

		public readonly ConfigEntry<int> TrailTickCap;

		public readonly ConfigEntry<float> TickInterval;

		public readonly ConfigEntry<float> Radius;

		public readonly ConfigEntry<float> HeightTolerance;

		public readonly ConfigEntry<float> Lifetime;

		public readonly ConfigEntry<float> DropInterval;

		public readonly ConfigEntry<float> MinSpacing;

		public readonly ConfigEntry<float> TintStrength;

		public readonly ConfigEntry<Color> TintColor;

		public readonly ConfigEntry<bool> VerboseLogging;

		public BlazingConfig(ConfigFile cfg)
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Expected O, but got Unknown
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Expected O, but got Unknown
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Expected O, but got Unknown
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Expected O, but got Unknown
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Expected O, but got Unknown
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Expected O, but got Unknown
			//IL_0194: Unknown result type (might be due to invalid IL or missing references)
			//IL_019e: Expected O, but got Unknown
			//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d7: Expected O, but got Unknown
			//IL_0206: Unknown result type (might be due to invalid IL or missing references)
			//IL_0210: 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_0278: Unknown result type (might be due to invalid IL or missing references)
			//IL_0282: Expected O, but got Unknown
			//IL_02b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bb: Expected O, but got Unknown
			//IL_02ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f4: Expected O, but got Unknown
			//IL_0319: Unknown result type (might be due to invalid IL or missing references)
			Chance = cfg.Bind<float>("Spawn", "Chance", 0.1f, new ConfigDescription("Chance from 0 to 1 that an eligible mob spawns Blazing. Not from the wiki. RoR2 elites come from director credits, not a flat chance. Set this to 1 so every eligible mob is Blazing.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			IncludeNeutral = cfg.Bind<bool>("Spawn", "IncludeNeutral", false, "When true, neutral mobs can roll Blazing. Not from the wiki. Bosses and guardians never roll, whatever this is set to.");
			HealthFactor = cfg.Bind<float>("Stats", "HealthFactor", 4f, new ConfigDescription("Health multiplier for a Blazing mob. 4 is the RoR2 wiki tier 1 elite health.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.05f, 100f), Array.Empty<object>()));
			DamageFactor = cfg.Bind<float>("Stats", "DamageFactor", 2f, new ConfigDescription("Damage multiplier for a Blazing mob. 2 is the RoR2 wiki tier 1 elite damage. It is written to mob.multiplier, which Muck applies to melee attacks (SpawnAttackFx) and projectiles. HealthFactor divided by this is applied to bossMultiplier so the HP product stays at HealthFactor. The fire trail does not use this.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.05f, 100f), Array.Empty<object>()));
			TrailDamageFraction = cfg.Bind<float>("Trail", "TrailDamageFraction", 1.5f, new ConfigDescription("Trail damage per second as a fraction of TrailBaseDamage only. 1.5 is the RoR2 wiki 150% damage per second. It is not multiplied by DamageFactor.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.05f, 10f), Array.Empty<object>()));
			TrailBaseDamage = cfg.Bind<int>("Trail", "TrailBaseDamage", 15, new ConfigDescription("Base damage the trail fraction applies to. Not from the wiki. 15 is the Goblin and Dave melee baseDamage in a pre-Update-4 asset dump.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 500), Array.Empty<object>()));
			TrailTickCap = cfg.Bind<int>("Trail", "TrailTickCap", 15, new ConfigDescription("Maximum damage of one trail tick as this mod sends it, after the fraction. The host then multiplies the tick by the day's mob damage multiplier and applies armor, so a capped tick lands at 15 x that multiplier (about 79 on Normal at day 10). Not from the wiki. Default 15.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 500), Array.Empty<object>()));
			TickInterval = cfg.Bind<float>("Trail", "TickInterval", 0.5f, new ConfigDescription("Seconds between trail damage ticks on the local player. Not from the wiki. Values below 0.05 are raised to 0.05.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.05f, 10f), Array.Empty<object>()));
			Radius = cfg.Bind<float>("Trail", "Radius", 1.5f, new ConfigDescription("Horizontal radius, in meters, of a fresh ember. The sphere is drawn at this radius, and the burn zone shrinks with it. Not from the wiki.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.05f, 20f), Array.Empty<object>()));
			HeightTolerance = cfg.Bind<float>("Trail", "HeightTolerance", 2f, new ConfigDescription("How far above or below an ember the player can be and still take damage, in meters. Not from the wiki.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 20f), Array.Empty<object>()));
			Lifetime = cfg.Bind<float>("Trail", "Lifetime", 3f, new ConfigDescription("Seconds an ember keeps dealing damage and stays visible. The sphere and its burn zone shrink to half size, not to nothing. Not from the wiki.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.05f, 30f), Array.Empty<object>()));
			DropInterval = cfg.Bind<float>("Trail", "DropInterval", 0.25f, new ConfigDescription("Seconds between ember drop attempts. Not from the wiki. Values below 0.05 are raised to 0.05.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.05f, 5f), Array.Empty<object>()));
			MinSpacing = cfg.Bind<float>("Trail", "MinSpacing", 1f, new ConfigDescription("Minimum distance in meters from the previous ember before another one drops. Not from the wiki.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 20f), Array.Empty<object>()));
			TintStrength = cfg.Bind<float>("Visual", "TintStrength", 0.6f, new ConfigDescription("How far each mob material color moves toward TintColor. 0 leaves the mob unchanged. 1 replaces the color. Not from the wiki.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			TintColor = cfg.Bind<Color>("Visual", "TintColor", new Color(1f, 0.45f, 0.1f, 1f), "Color blended into the mob. The embers use it too, at 0.25 alpha, read when the first ember is drawn. Not from the wiki. Default is 1, 0.45, 0.1.");
			VerboseLogging = cfg.Bind<bool>("Debug", "VerboseLogging", false, "When true, log each Blazing mob id as the component is attached. Not from the wiki.");
		}
	}
	internal sealed class BlazingElite : MonoBehaviour
	{
		private HitableMob body;

		private float nextDrop;

		private bool hasLast;

		private Vector3 lastDrop;

		private void Start()
		{
			body = ((Component)this).GetComponent<HitableMob>();
			if ((Object)(object)body == (Object)null)
			{
				body = ((Component)this).GetComponentInChildren<HitableMob>(true);
			}
			Tint();
		}

		private void Update()
		{
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: 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_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: 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_00c9: 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_00d5: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)body != (Object)null && ((Hitable)body).hp <= 0)
			{
				return;
			}
			BlazingConfig cfg = BlazingPlugin.Cfg;
			float num = BlazingLimits.Interval(cfg.DropInterval.Value);
			if (Time.time < nextDrop)
			{
				return;
			}
			nextDrop = Time.time + num;
			Vector3 position = ((Component)this).transform.position;
			if (!hasLast || !(Vector3.Distance(position, lastDrop) < cfg.MinSpacing.Value))
			{
				float radius = BlazingLimits.Positive(cfg.Radius.Value, 1.5f);
				float num2 = BlazingLimits.Positive(cfg.Lifetime.Value, 3f);
				if (Ember.TrySpawn(position, radius, num2))
				{
					hasLast = true;
					lastDrop = position;
					BlazingTrail.Field.Add(position.x, position.y, position.z, Time.time, Time.time + num2, 1f);
				}
			}
		}

		private void Tint()
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: 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)
			Color value = BlazingPlugin.Cfg.TintColor.Value;
			float value2 = BlazingPlugin.Cfg.TintStrength.Value;
			Renderer[] componentsInChildren = ((Component)this).GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val in componentsInChildren)
			{
				if (!OnceClaim.TryClaim(val))
				{
					continue;
				}
				Material[] materials = val.materials;
				List<Material> list = new List<Material>();
				foreach (Material val2 in materials)
				{
					if (!((Object)(object)val2 == (Object)null))
					{
						list.Add(val2);
						if (val2.HasProperty("_Color"))
						{
							val2.color = Color.Lerp(val2.color, value, value2);
						}
					}
				}
				if (list.Count != 0)
				{
					((Component)val).gameObject.AddComponent<TintCleanup>().Hold(list);
				}
			}
		}
	}
	internal static class BlazingLimits
	{
		public const float MinInterval = 0.05f;

		public static float Interval(float value)
		{
			if (!(value >= 0.05f))
			{
				return 0.05f;
			}
			return value;
		}

		public static float Positive(float value, float fallback)
		{
			if (!(value > 0f))
			{
				return fallback;
			}
			return value;
		}
	}
	[BepInPlugin("evan.muck.blazingelite", "Blazing Elite", "0.2.0")]
	public class BlazingPlugin : BaseUnityPlugin
	{
		public const string Guid = "evan.muck.blazingelite";

		public const string Name = "Blazing Elite";

		public const string Version = "0.2.0";

		internal static ManualLogSource Log;

		internal static BlazingConfig Cfg;

		private void Awake()
		{
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			Log = ((BaseUnityPlugin)this).Logger;
			Cfg = new BlazingConfig(((BaseUnityPlugin)this).Config);
			BlazingSeed.Warn = delegate(string message)
			{
				Log.LogWarning((object)message);
			};
			BlazingRunner.Ensure();
			try
			{
				new Harmony("evan.muck.blazingelite").PatchAll(typeof(BlazingPlugin).Assembly);
			}
			catch (Exception arg)
			{
				Log.LogError((object)$"Blazing patch failed, mod disabled: {arg}");
				BlazingRunner.Teardown();
				return;
			}
			Log.LogInfo((object)"Blazing Elite 0.2.0 loaded. All players should install this mod.");
		}
	}
	internal static class BlazingRoll
	{
		public static bool IsBlazing(int seed, int mobId, float chance)
		{
			if (!(chance > 0f))
			{
				return false;
			}
			return Hash01.Of(seed, mobId) < (double)chance;
		}
	}
	internal static class BlazingRules
	{
		public static bool Eligible(bool isBoss, bool isNeutral, int guardianType, bool includeNeutral)
		{
			if (isBoss)
			{
				return false;
			}
			if (guardianType != -1)
			{
				return false;
			}
			if (isNeutral && !includeNeutral)
			{
				return false;
			}
			return true;
		}
	}
	internal sealed class BlazingRunner : MonoBehaviour
	{
		private static BlazingRunner instance;

		public static void Ensure()
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Expected O, but got Unknown
			if (!((Object)(object)instance != (Object)null))
			{
				GameObject val = new GameObject("MuckBlazing");
				Object.DontDestroyOnLoad((Object)val);
				instance = val.AddComponent<BlazingRunner>();
			}
		}

		public static void Teardown()
		{
			if (!((Object)(object)instance == (Object)null))
			{
				GameObject gameObject = ((Component)instance).gameObject;
				instance = null;
				Object.Destroy((Object)(object)gameObject);
			}
		}

		private void OnEnable()
		{
			SceneManager.activeSceneChanged += OnSceneChanged;
			LogFingerprint("startup");
		}

		private void OnDisable()
		{
			SceneManager.activeSceneChanged -= OnSceneChanged;
		}

		private void OnDestroy()
		{
			if ((Object)(object)instance == (Object)(object)this)
			{
				instance = null;
			}
			Ember.DestroyAll();
			BlazingTrail.Field.Clear();
			BlazingTrail.Gate.Reset();
		}

		private static void OnSceneChanged(Scene previous, Scene next)
		{
			Ember.DestroyAll();
			BlazingTrail.Field.Clear();
			BlazingTrail.Gate.Reset();
			LogFingerprint(((Scene)(ref next)).name);
		}

		private void Update()
		{
			//IL_006a: 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_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			BlazingTrail.Field.Prune(Time.time);
			if (!Ember.CanShow || (Object)(object)PlayerMovement.Instance == (Object)null)
			{
				return;
			}
			LocalClient val = LocalClient.instance;
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			Dictionary<int, PlayerManager> players = GameManager.players;
			if (players == null || !players.TryGetValue(val.myId, out var value) || (Object)(object)value == (Object)null || value.dead)
			{
				return;
			}
			Vector3 position = ((Component)PlayerMovement.Instance).transform.position;
			BlazingConfig cfg = BlazingPlugin.Cfg;
			float radius = BlazingLimits.Positive(cfg.Radius.Value, 1.5f);
			float num = cfg.HeightTolerance.Value;
			if (float.IsNaN(num) || num < 0f)
			{
				num = 2f;
			}
			if (!(BlazingTrail.Field.Strongest(position.x, position.y, position.z, Time.time, radius, num) > 0f))
			{
				return;
			}
			float interval = BlazingLimits.Interval(cfg.TickInterval.Value);
			if (BlazingTrail.Gate.TryTick(Time.time, interval))
			{
				int num2 = TrailDamage.PerTick(cfg.TrailBaseDamage.Value, cfg.TrailDamageFraction.Value, interval, cfg.TrailTickCap.Value);
				if (num2 > 0)
				{
					ClientSend.PlayerHit(num2, val.myId, 0f, 0, position);
				}
			}
		}

		private static void LogFingerprint(string when)
		{
			BlazingConfig cfg = BlazingPlugin.Cfg;
			if (cfg != null && BlazingPlugin.Log != null)
			{
				ulong num = ConfigFingerprint.Of(cfg.Chance.Value, cfg.IncludeNeutral.Value, cfg.HealthFactor.Value, cfg.DamageFactor.Value);
				BlazingPlugin.Log.LogInfo((object)$"Blazing config {num:X16} at {when}. Chance={cfg.Chance.Value} IncludeNeutral={cfg.IncludeNeutral.Value} HealthFactor={cfg.HealthFactor.Value} DamageFactor={cfg.DamageFactor.Value}. Every peer should log the same hash.");
			}
		}
	}
	internal static class BlazingSeed
	{
		private static bool warned;

		internal static Func<int> ReadSeed;

		internal static Action<string> Warn;

		public static bool TryRead(out int seed)
		{
			try
			{
				Func<int> func = ReadSeed ?? new Func<int>(DefaultRead);
				seed = func();
				return true;
			}
			catch (Exception ex)
			{
				seed = 0;
				if (!warned)
				{
					warned = true;
					Warn?.Invoke("GameManager.GetSeed failed. No mob will be Blazing. " + ex.Message);
				}
				return false;
			}
		}

		private static int DefaultRead()
		{
			return GameManager.GetSeed();
		}
	}
	internal static class BlazingStats
	{
		private const float GridTolerance = 0.0001f;

		public static ScaledMultipliers Apply(float multiplier, float bossMultiplier, float healthFactor, float damageFactor)
		{
			float num = ((!(damageFactor > 0f)) ? 1f : damageFactor);
			float num2 = ((!(healthFactor > 0f)) ? 1f : healthFactor);
			return new ScaledMultipliers(multiplier * num, bossMultiplier * num2 / num);
		}

		public static bool IsPlain(float bossMultiplier)
		{
			if (!(bossMultiplier > 0f) || float.IsInfinity(bossMultiplier))
			{
				return false;
			}
			double num = (double)bossMultiplier * 16.0;
			return Math.Abs(num - Math.Round(num)) <= 0.0015999999595806003;
		}
	}
	internal static class BlazingTrail
	{
		public static readonly TrailField Field = new TrailField();

		public static readonly TickGate Gate = new TickGate();
	}
	internal static class ConfigFingerprint
	{
		public static ulong Of(float chance, bool includeNeutral, float healthFactor, float damageFactor)
		{
			return Hash01.SplitMix64(Hash01.SplitMix64(Hash01.SplitMix64(Hash01.SplitMix64(Bits(chance)) ^ (ulong)(includeNeutral ? 1 : 0)) ^ Bits(healthFactor)) ^ Bits(damageFactor));
		}

		private static ulong Bits(float value)
		{
			return BitConverter.ToUInt32(BitConverter.GetBytes(value), 0);
		}
	}
	internal sealed class Ember : MonoBehaviour
	{
		private static readonly Stack<Ember> pool = new Stack<Ember>();

		private static readonly List<Ember> live = new List<Ember>();

		private static readonly string[] ShaderCandidates = new string[6] { "Sprites/Default", "Legacy Shaders/Particles/Additive", "Particles/Additive", "Particles/Standard Unlit", "Unlit/Color", "Hidden/Internal-Colored" };

		private static Material material;

		private static Mesh sphere;

		private static bool missingLogged;

		private float born;

		private float expires;

		private Vector3 fullScale;

		public static bool CanShow
		{
			get
			{
				if ((Object)(object)material != (Object)null)
				{
					return (Object)(object)sphere != (Object)null;
				}
				return false;
			}
		}

		public static bool TrySpawn(Vector3 position, float radius, float lifetime)
		{
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)GetMaterial() == (Object)null || (Object)(object)GetSphere() == (Object)null)
			{
				return false;
			}
			Ember ember = ((pool.Count > 0) ? pool.Pop() : Create());
			((Component)ember).gameObject.SetActive(true);
			ember.Begin(position, radius, lifetime);
			live.Add(ember);
			return true;
		}

		public static void DestroyAll()
		{
			for (int i = 0; i < live.Count; i++)
			{
				if ((Object)(object)live[i] != (Object)null)
				{
					Object.Destroy((Object)(object)((Component)live[i]).gameObject);
				}
			}
			live.Clear();
			while (pool.Count > 0)
			{
				Ember ember = pool.Pop();
				if ((Object)(object)ember != (Object)null)
				{
					Object.Destroy((Object)(object)((Component)ember).gameObject);
				}
			}
		}

		private static Ember Create()
		{
			//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_001a: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("BlazingEmber");
			val.AddComponent<MeshFilter>().sharedMesh = sphere;
			MeshRenderer obj = val.AddComponent<MeshRenderer>();
			((Renderer)obj).sharedMaterial = material;
			((Renderer)obj).shadowCastingMode = (ShadowCastingMode)0;
			((Renderer)obj).receiveShadows = false;
			return val.AddComponent<Ember>();
		}

		private void Begin(Vector3 position, float radius, float lifetime)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//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_0029: Unknown result type (might be due to invalid IL or missing references)
			((Component)this).transform.position = position;
			fullScale = Vector3.one * EmberSize.Diameter(radius);
			((Component)this).transform.localScale = fullScale;
			born = Time.time;
			expires = born + lifetime;
		}

		private void Update()
		{
			//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)
			float life = expires - born;
			float age = Time.time - born;
			((Component)this).transform.localScale = fullScale * EmberSize.ScaleAt(age, life);
			if (!(Time.time < expires))
			{
				Retire();
			}
		}

		private void Retire()
		{
			for (int i = 0; i < live.Count; i++)
			{
				if (!((Object)(object)live[i] != (Object)(object)this))
				{
					int index = live.Count - 1;
					live[i] = live[index];
					live.RemoveAt(index);
					break;
				}
			}
			((Component)this).gameObject.SetActive(false);
			pool.Push(this);
		}

		private static Material GetMaterial()
		{
			//IL_003f: 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_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: 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: Expected O, but got Unknown
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: 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_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)material != (Object)null)
			{
				return material;
			}
			Color val = (Color)((BlazingPlugin.Cfg != null) ? BlazingPlugin.Cfg.TintColor.Value : new Color(1f, 0.45f, 0.1f, 1f));
			string[] shaderCandidates = ShaderCandidates;
			foreach (string text in shaderCandidates)
			{
				Shader val2 = Shader.Find(text);
				if (!((Object)(object)val2 == (Object)null))
				{
					material = new Material(val2)
					{
						name = "BlazingEmber",
						hideFlags = (HideFlags)32
					};
					TintWrite tintWrite = ShaderTint.For(ShaderTint.KindOf(text), EmberLook.Of(val.r, val.g, val.b));
					if (material.HasProperty("_TintColor"))
					{
						material.SetColor("_TintColor", ToColor(tintWrite.TintColor));
					}
					if (material.HasProperty("_Color"))
					{
						material.color = ToColor(tintWrite.Color);
					}
					if (material.HasProperty("_MainTex"))
					{
						material.mainTexture = (Texture)(object)Texture2D.whiteTexture;
					}
					if (BlazingPlugin.Log != null)
					{
						BlazingPlugin.Log.LogInfo((object)("Blazing embers use shader '" + text + "'."));
					}
					return material;
				}
			}
			if (!missingLogged)
			{
				missingLogged = true;
				if (BlazingPlugin.Log != null)
				{
					BlazingPlugin.Log.LogWarning((object)"No usable built-in shader found for embers. Trail damage is off.");
				}
			}
			return null;
		}

		private static Color ToColor(Rgba c)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			return new Color(c.R, c.G, c.B, c.A);
		}

		private static Mesh GetSphere()
		{
			//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)
			if ((Object)(object)sphere != (Object)null)
			{
				return sphere;
			}
			GameObject val = GameObject.CreatePrimitive((PrimitiveType)0);
			MeshFilter component = val.GetComponent<MeshFilter>();
			Mesh val2 = (((Object)(object)component != (Object)null) ? component.sharedMesh : null);
			Object.DestroyImmediate((Object)(object)val);
			if ((Object)(object)val2 != (Object)null)
			{
				sphere = Object.Instantiate<Mesh>(val2);
				((Object)sphere).name = "BlazingEmber";
				((Object)sphere).hideFlags = (HideFlags)32;
				Color[] array = (Color[])(object)new Color[sphere.vertexCount];
				for (int i = 0; i < array.Length; i++)
				{
					array[i] = Color.white;
				}
				sphere.colors = array;
			}
			if ((Object)(object)sphere == (Object)null && !missingLogged && BlazingPlugin.Log != null)
			{
				BlazingPlugin.Log.LogWarning((object)"No sphere mesh for embers. Trail damage is off.");
			}
			return sphere;
		}
	}
	internal static class EmberLook
	{
		public const float Alpha = 0.25f;

		public static Rgba Of(float r, float g, float b)
		{
			return new Rgba(r, g, b, 0.25f);
		}
	}
	internal static class EmberSize
	{
		public static float Diameter(float radius)
		{
			return BlazingLimits.Positive(radius, 1.5f) * 2f;
		}

		public static float ScaleAt(float age, float life)
		{
			if (!(life > 0f))
			{
				return 0.5f;
			}
			float num = age / life;
			if (!(num > 0f))
			{
				num = 0f;
			}
			if (num > 1f)
			{
				num = 1f;
			}
			return 1f - 0.5f * num;
		}
	}
	internal static class Hash01
	{
		public static ulong SplitMix64(ulong x)
		{
			x += 11400714819323198485uL;
			x = (x ^ (x >> 30)) * 13787848793156543929uL;
			x = (x ^ (x >> 27)) * 10723151780598845931uL;
			return x ^ (x >> 31);
		}

		public static double Of(int a, int b)
		{
			return ToUnit(SplitMix64(((ulong)(uint)a << 32) | (uint)b));
		}

		private static double ToUnit(ulong h)
		{
			return (double)(h >> 11) * 1.1102230246251565E-16;
		}
	}
	internal static class OnceClaim
	{
		private static readonly object Token = new object();

		private static readonly ConditionalWeakTable<object, object> seen = new ConditionalWeakTable<object, object>();

		public static bool TryClaim(object key)
		{
			if (key == null)
			{
				return false;
			}
			if (seen.TryGetValue(key, out var _))
			{
				return false;
			}
			seen.Add(key, Token);
			return true;
		}
	}
	internal readonly struct ScaledMultipliers
	{
		public readonly float Multiplier;

		public readonly float BossMultiplier;

		public ScaledMultipliers(float multiplier, float bossMultiplier)
		{
			Multiplier = multiplier;
			BossMultiplier = bossMultiplier;
		}
	}
	internal enum ShaderKind
	{
		Plain,
		DoubledTint
	}
	internal readonly struct Rgba
	{
		public readonly float R;

		public readonly float G;

		public readonly float B;

		public readonly float A;

		public Rgba(float r, float g, float b, float a)
		{
			R = r;
			G = g;
			B = b;
			A = a;
		}

		public Rgba Scaled(float s)
		{
			return new Rgba(R * s, G * s, B * s, A * s);
		}

		public override string ToString()
		{
			return $"({R}, {G}, {B}, {A})";
		}
	}
	internal readonly struct TintWrite
	{
		public readonly Rgba TintColor;

		public readonly Rgba Color;

		public TintWrite(Rgba tintColor, Rgba color)
		{
			TintColor = tintColor;
			Color = color;
		}
	}
	internal static class ShaderTint
	{
		public static ShaderKind KindOf(string shaderName)
		{
			if (shaderName == null)
			{
				return ShaderKind.Plain;
			}
			bool num = shaderName.IndexOf("Particles/", StringComparison.Ordinal) >= 0;
			bool flag = shaderName.IndexOf("Standard", StringComparison.Ordinal) >= 0;
			if (!num || flag)
			{
				return ShaderKind.Plain;
			}
			return ShaderKind.DoubledTint;
		}

		public static TintWrite For(ShaderKind kind, Rgba intended)
		{
			return new TintWrite((kind == ShaderKind.DoubledTint) ? intended.Scaled(0.5f) : intended, intended);
		}

		public static Rgba Intended(ShaderKind kind, Rgba tintColor)
		{
			if (kind != ShaderKind.DoubledTint)
			{
				return tintColor;
			}
			return tintColor.Scaled(2f);
		}
	}
	[HarmonyPatch(typeof(MobSpawner), "SpawnMob")]
	internal static class SpawnMobPatch
	{
		private static void Prefix(MobSpawner __instance, int mobType, int mobId, float multiplier, float bossMultiplier, int guardianType, out SpawnIntent __state)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Invalid comparison between Unknown and I4
			__state = null;
			try
			{
				BlazingConfig cfg = BlazingPlugin.Cfg;
				MobType obj = __instance.allMobs[mobType];
				bool eligible = BlazingRules.Eligible(isNeutral: (int)obj.behaviour == 0, isBoss: obj.boss, guardianType: guardianType, includeNeutral: cfg.IncludeNeutral.Value);
				int seed;
				bool flag = BlazingSeed.TryRead(out seed);
				bool rolled = flag && BlazingRoll.IsBlazing(seed, mobId, cfg.Chance.Value);
				__state = SpawnPlan.Intend(flag, eligible, rolled, multiplier, bossMultiplier, cfg.HealthFactor.Value, cfg.DamageFactor.Value);
			}
			catch (Exception arg)
			{
				BlazingPlugin.Log.LogError((object)$"Blazing roll failed: {arg}");
			}
		}

		private static void Postfix(int mobId, SpawnIntent __state)
		{
			if (__state == null || !__state.Apply)
			{
				return;
			}
			try
			{
				Mob value = null;
				int num;
				int num2;
				if ((Object)(object)MobManager.Instance != (Object)null && MobManager.Instance.mobs != null && MobManager.Instance.mobs.TryGetValue(mobId, out value))
				{
					num = (((Object)(object)value != (Object)null) ? 1 : 0);
					if (num != 0)
					{
						num2 = (((Object)(object)((Component)value).GetComponent<BlazingElite>() != (Object)null) ? 1 : 0);
						goto IL_0058;
					}
				}
				else
				{
					num = 0;
				}
				num2 = 0;
				goto IL_0058;
				IL_0058:
				bool alreadyAttached = (byte)num2 != 0;
				SpawnAction spawnAction = SpawnPlan.Finish((byte)num != 0, alreadyAttached);
				if (spawnAction == SpawnAction.LeaveUnscaled)
				{
					BlazingPlugin.Log.LogWarning((object)$"Blazing mob {mobId} was not in MobManager.mobs. It was left unscaled.");
					return;
				}
				value.multiplier = __state.Multiplier;
				value.bossMultiplier = __state.BossMultiplier;
				if (spawnAction != SpawnAction.KeepExisting)
				{
					((Component)value).gameObject.AddComponent<BlazingElite>();
					if (BlazingPlugin.Cfg.VerboseLogging.Value)
					{
						BlazingPlugin.Log.LogInfo((object)$"Blazing mob {mobId}.");
					}
				}
			}
			catch (Exception arg)
			{
				BlazingPlugin.Log.LogError((object)$"Blazing attach failed: {arg}");
			}
		}
	}
	internal enum SpawnAction
	{
		LeaveUnscaled,
		KeepExisting,
		Attach
	}
	internal sealed class SpawnIntent
	{
		public bool Apply;

		public float Multiplier;

		public float BossMultiplier;
	}
	internal static class SpawnPlan
	{
		public static SpawnIntent Intend(bool seedOk, bool eligible, bool rolled, float multiplier, float bossMultiplier, float healthFactor, float damageFactor)
		{
			if (!seedOk || !eligible || !rolled || multiplier != 1f || !BlazingStats.IsPlain(bossMultiplier))
			{
				return null;
			}
			ScaledMultipliers scaledMultipliers = BlazingStats.Apply(multiplier, bossMultiplier, healthFactor, damageFactor);
			return new SpawnIntent
			{
				Apply = true,
				Multiplier = scaledMultipliers.Multiplier,
				BossMultiplier = scaledMultipliers.BossMultiplier
			};
		}

		public static SpawnAction Finish(bool mobFound, bool alreadyAttached)
		{
			if (!mobFound)
			{
				return SpawnAction.LeaveUnscaled;
			}
			if (alreadyAttached)
			{
				return SpawnAction.KeepExisting;
			}
			return SpawnAction.Attach;
		}
	}
	internal sealed class TickGate
	{
		private float next = float.NegativeInfinity;

		public bool TryTick(float now, float interval)
		{
			if (now < next)
			{
				return false;
			}
			next = now + interval;
			return true;
		}

		public void Reset()
		{
			next = float.NegativeInfinity;
		}
	}
	internal sealed class TintCleanup : MonoBehaviour
	{
		private readonly List<Material> copies = new List<Material>();

		public void Hold(List<Material> mats)
		{
			copies.AddRange(mats);
		}

		private void OnDestroy()
		{
			for (int i = 0; i < copies.Count; i++)
			{
				if ((Object)(object)copies[i] != (Object)null)
				{
					Object.Destroy((Object)(object)copies[i]);
				}
			}
			copies.Clear();
		}
	}
	internal static class TrailDamage
	{
		public static int PerTick(int baseDamage, float dpsFraction, float interval, int cap)
		{
			if (baseDamage <= 0 || cap <= 0)
			{
				return 0;
			}
			if (!(dpsFraction > 0f) || !(interval > 0f))
			{
				return 0;
			}
			float num = (float)baseDamage * dpsFraction * interval;
			if (float.IsNaN(num) || float.IsInfinity(num))
			{
				return 0;
			}
			int num2 = (int)num;
			if (num2 < 1)
			{
				num2 = 1;
			}
			if (num2 > cap)
			{
				num2 = cap;
			}
			return num2;
		}
	}
	internal sealed class TrailField
	{
		private readonly List<(float x, float y, float z, float bornAt, float expiresAt, float multiplier)> points = new List<(float, float, float, float, float, float)>();

		public int Count => points.Count;

		public void Add(float x, float y, float z, float bornAt, float expiresAt, float multiplier)
		{
			points.Add((x, y, z, bornAt, expiresAt, multiplier));
		}

		public void Prune(float now)
		{
			for (int num = points.Count - 1; num >= 0; num--)
			{
				if (!(points[num].expiresAt > now))
				{
					int index = points.Count - 1;
					points[num] = points[index];
					points.RemoveAt(index);
				}
			}
		}

		public void Clear()
		{
			points.Clear();
		}

		public float Strongest(float x, float y, float z, float now, float radius, float heightTolerance)
		{
			float num = 0f;
			for (int i = 0; i < points.Count; i++)
			{
				(float, float, float, float, float, float) tuple = points[i];
				if (tuple.Item5 <= now)
				{
					continue;
				}
				float num2 = tuple.Item2 - y;
				if (num2 < 0f)
				{
					num2 = 0f - num2;
				}
				if (!(num2 > heightTolerance))
				{
					float num3 = tuple.Item1 - x;
					float num4 = tuple.Item3 - z;
					float num5 = (float)Math.Sqrt(num3 * num3 + num4 * num4);
					float num6 = radius * EmberSize.ScaleAt(now - tuple.Item4, tuple.Item5 - tuple.Item4);
					if (!(num5 > num6) && tuple.Item6 > num)
					{
						num = tuple.Item6;
					}
				}
			}
			return num;
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "MuckBlazing";

		public const string PLUGIN_NAME = "Blazing Elite";

		public const string PLUGIN_VERSION = "0.2.0";
	}
}