Decompiled source of DamageSparks v1.1.0

DamageSparks.dll

Decompiled 2 months ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using PerfectRandom.Sulfur.Core;
using PerfectRandom.Sulfur.Core.Stats;
using PerfectRandom.Sulfur.Core.Units;
using PerfectRandom.Sulfur.Gameplay;
using TMPro;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("SulfurDamageNumbersMod")]
[assembly: AssemblyDescription("SULFUR damage numbers mod for BepInEx 5")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("ryuka_labs")]
[assembly: AssemblyProduct("SulfurDamageNumbersMod")]
[assembly: AssemblyCopyright("")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("c9ebec31-296a-4d97-9959-9804ea595a74")]
[assembly: AssemblyFileVersion("1.1.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.1.0.0")]
namespace SulfurDamageNumbersMod;

internal static class DamageLogPatch
{
	private static bool _applied;

	[ThreadStatic]
	private static bool _handlingPostfix;

	public static void Apply(Harmony harmony)
	{
		//IL_003a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0047: Expected O, but got Unknown
		if (!_applied)
		{
			MethodBase methodBase = TargetMethod();
			if (methodBase == null)
			{
				Plugin.Log.LogError((object)"SULFUR Damage Numbers failed: Unit.CreateDamageLog(float, float, DamageTypes, Hitmesh.Data, DamageSourceData) was not found.");
				return;
			}
			harmony.Patch(methodBase, (HarmonyMethod)null, new HarmonyMethod(typeof(DamageLogPatch), "Postfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			_applied = true;
			Plugin.Log.LogInfo((object)("SULFUR Damage Numbers patched " + methodBase.DeclaringType.FullName + "." + methodBase.Name + "."));
		}
	}

	public static void Reset()
	{
		_applied = false;
		_handlingPostfix = false;
	}

	private static MethodBase TargetMethod()
	{
		return AccessTools.GetDeclaredMethods(typeof(Unit)).FirstOrDefault(delegate(MethodInfo m)
		{
			if (m.Name != "CreateDamageLog")
			{
				return false;
			}
			ParameterInfo[] parameters = m.GetParameters();
			return parameters.Length == 5 && parameters[0].ParameterType == typeof(float) && parameters[1].ParameterType == typeof(float) && parameters[2].ParameterType == typeof(DamageTypes) && parameters[3].ParameterType == typeof(Data) && parameters[4].ParameterType == typeof(DamageSourceData);
		});
	}

	private unsafe static void Postfix(Unit __instance, float __0, float __1, DamageTypes __2, Data __3, DamageSourceData __4)
	{
		//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
		//IL_010b: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f6: Unknown result type (might be due to invalid IL or missing references)
		//IL_017b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0180: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e3: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)__instance == (Object)null || !Plugin.Enabled.Value || _handlingPostfix)
		{
			return;
		}
		_handlingPostfix = true;
		try
		{
			float num = __0;
			if (num < Plugin.MinDamageToShow.Value)
			{
				if (Plugin.DebugLog.Value)
				{
					Plugin.Log.LogInfo((object)("[DamageNumbers] reject low damage amount=" + num + " target=" + SafeName((Object)(object)__instance)));
				}
				return;
			}
			if (!IsAllowedTarget(__instance, out var reason))
			{
				if (Plugin.DebugLog.Value)
				{
					Plugin.Log.LogInfo((object)("[DamageNumbers] reject target: " + reason + " target=" + SafeName((Object)(object)__instance)));
				}
				return;
			}
			if (!IsPlayerExecutedAttack(__4, out reason))
			{
				if (Plugin.DebugLog.Value)
				{
					Plugin.Log.LogInfo((object)("[DamageNumbers] reject source: " + reason + " target=" + SafeName((Object)(object)__instance) + " source=" + DescribeSource(__4)));
				}
				return;
			}
			float hitMultiplier = (((int)((ShapeId)(ref __3.shapeId)).part == 0) ? 0f : Mathf.Max(0f, ((Data)(ref __3)).GetShapeMultiplier()));
			if (Plugin.DebugLog.Value)
			{
				Plugin.Log.LogInfo((object)("[DamageNumbers] accept amount=" + num + " multiplier=" + hitMultiplier + " part=" + ((object)((ShapeId)(ref __3.shapeId)).part/*cast due to .constrained prefix*/).ToString() + " damageType=" + ((object)(*(DamageTypes*)(&__4.damageType))/*cast due to .constrained prefix*/).ToString() + " critical=" + __4.isCritical + " target=" + SafeName((Object)(object)__instance) + " source=" + DescribeSource(__4)));
			}
			DamageNumberManager.RegisterDamage(__instance, __4, num, hitMultiplier);
		}
		catch (Exception ex)
		{
			Plugin.Log.LogWarning((object)("[DamageNumbers] CreateDamageLog postfix failed: " + ex));
		}
		finally
		{
			_handlingPostfix = false;
		}
	}

	private static bool IsAllowedTarget(Unit target, out string reason)
	{
		if (target.isPlayer)
		{
			reason = "target is player";
			return false;
		}
		if (Plugin.RequireNpcTarget.Value && !(target is Npc))
		{
			reason = "target is not Npc";
			return false;
		}
		reason = null;
		return true;
	}

	private static bool IsPlayerExecutedAttack(DamageSourceData sourceData, out string reason)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		//IL_001d: Unknown result type (might be due to invalid IL or missing references)
		//IL_002a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0045: 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_009e: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b1: 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_00d2: 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)
		bool flag = (Object)(object)sourceData.sourceUnit != (Object)null && sourceData.sourceUnit.isPlayer;
		bool flag2 = !sourceData.isPlayer && flag && (Object)(object)sourceData.sourceWeapon == (Object)null && !sourceData.melee;
		if (!sourceData.isPlayer && !flag)
		{
			reason = "sourceData.isPlayer is false and sourceUnit is not the player";
			return false;
		}
		if (flag2 && !Plugin.ShowStatusEffectDamage.Value)
		{
			reason = "player-applied status damage is disabled";
			return false;
		}
		if (Plugin.RequireSourceUnitPlayer.Value && !flag)
		{
			reason = (((Object)(object)sourceData.sourceUnit == (Object)null) ? "sourceUnit is null" : "sourceUnit is not player");
			return false;
		}
		if ((Object)(object)sourceData.sourceWeapon != (Object)null)
		{
			reason = null;
			return true;
		}
		if (sourceData.melee)
		{
			reason = null;
			return true;
		}
		if (flag2)
		{
			reason = null;
			return true;
		}
		if (Plugin.ShowPlayerOwnedSecondaryEffects.Value && !sourceData.states.notCreatedByPlayer)
		{
			reason = null;
			return true;
		}
		reason = "no weapon/melee/player-owned secondary marker";
		return false;
	}

	private static string DescribeSource(DamageSourceData sourceData)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0021: 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_00b3: Unknown result type (might be due to invalid IL or missing references)
		string text = (((Object)(object)sourceData.sourceUnit == (Object)null) ? "null" : SafeName((Object)(object)sourceData.sourceUnit));
		string text2 = (((Object)(object)sourceData.sourceWeapon == (Object)null) ? "null" : ((Object)sourceData.sourceWeapon).name);
		return "isPlayer=" + sourceData.isPlayer + ", melee=" + sourceData.melee + ", weapon=" + text2 + ", unit=" + text + ", instanceId=" + sourceData.instanceId + ", name=" + sourceData.name;
	}

	private static string SafeName(Object obj)
	{
		if (!(obj == (Object)null))
		{
			return obj.name;
		}
		return "null";
	}
}
internal sealed class DamageNumberManager : MonoBehaviour
{
	private struct AggregateEntry
	{
		public float Amount;

		public Vector3 Position;

		public int Frame;

		public float HighestMultiplier;

		public float LastMultiplier;

		public float WeightedMultiplierSum;

		public DamageTypes DamageType;

		public bool AnyCritical;
	}

	private struct PerHitSpreadOffset
	{
		public static readonly PerHitSpreadOffset Zero = new PerHitSpreadOffset
		{
			WorldOffset = Vector3.zero,
			ScreenOffset = Vector2.zero
		};

		public Vector3 WorldOffset;

		public Vector2 ScreenOffset;
	}

	private const int HardMaxActiveNumbers = 256;

	private const int HardMaxNumbersPerFrame = 256;

	private const int HardMaxActiveVanillaNumbers = 64;

	private static DamageNumberManager _instance;

	private readonly Dictionary<AggregateKey, AggregateEntry> _aggregates = new Dictionary<AggregateKey, AggregateEntry>();

	private readonly List<AggregateKey> _flushBuffer = new List<AggregateKey>();

	private readonly Dictionary<PerHitSpreadKey, int> _perHitSpreadCounters = new Dictionary<PerHitSpreadKey, int>();

	private readonly List<ScreenDamageNumberView> _screenPool = new List<ScreenDamageNumberView>();

	private readonly List<DamageNumberView> _worldPool = new List<DamageNumberView>();

	private readonly List<VanillaDamageNumberView> _vanillaPool = new List<VanillaDamageNumberView>();

	private readonly List<Vector2> _crowdingPositions = new List<Vector2>(256);

	private bool _vanillaReady;

	private bool _vanillaBoundaryBroken;

	private int _vanillaFlyIndex;

	private int _perHitSpreadFrame = -1;

	private int _crowdingFrame = -1;

	private int _spawnBudgetFrame = -1;

	private int _spawnedThisFrame;

	private int _droppedThisFrame;

	private int _crowdingSkippedThisFrame;

	private float _lastBudgetLogTime = -999f;

	private bool _inputErrorLogged;

	private Camera _cachedCamera;

	private float _nextCameraLookupTime;

	private Material _screenSharedMaterial;

	private Material _worldSharedMaterial;

	private RenderMode _lastAppliedRenderMode;

	private bool _hasAppliedRenderMode;

	private RectTransform _screenRoot;

	private Transform _worldRoot;

	private Transform _vanillaRoot;

	public static void EnsureExists()
	{
		//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("SULFUR Damage Number Manager");
			Object.DontDestroyOnLoad((Object)val);
			_instance = val.AddComponent<DamageNumberManager>();
		}
	}

	public static void Shutdown()
	{
		if (!((Object)(object)_instance == (Object)null))
		{
			DamageNumberManager instance = _instance;
			_instance = null;
			Object.Destroy((Object)(object)((Component)instance).gameObject);
		}
	}

	public static void RegisterDamage(Unit target, DamageSourceData sourceData, float amount, float hitMultiplier)
	{
		//IL_0022: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)target == (Object)null))
		{
			EnsureExists();
			if ((Object)(object)_instance != (Object)null)
			{
				_instance.RegisterDamageInternal(target, sourceData, amount, hitMultiplier);
			}
		}
	}

	public static void SpawnScreenTestNumber()
	{
		//IL_0034: Unknown result type (might be due to invalid IL or missing references)
		//IL_003e: Unknown result type (might be due to invalid IL or missing references)
		EnsureExists();
		if ((Object)(object)_instance != (Object)null)
		{
			_instance.SpawnScreenFixed("999", new Vector2((float)Screen.width * 0.5f, (float)Screen.height * 0.45f), DamageNumberColor.ForMultiplier(0f));
		}
	}

	private void Update()
	{
		if (!Plugin.DebugSpawnTestOnF8.Value)
		{
			return;
		}
		try
		{
			if (Input.GetKeyDown((KeyCode)289))
			{
				SpawnScreenTestNumber();
				if (Plugin.DebugLog.Value)
				{
					Plugin.Log.LogInfo((object)"[DamageNumbers] F8 test number spawned.");
				}
			}
		}
		catch (Exception ex)
		{
			if (!_inputErrorLogged)
			{
				_inputErrorLogged = true;
				Plugin.Log.LogWarning((object)("[DamageNumbers] F8 debug input is unavailable: " + ex.Message));
			}
		}
	}

	private void RegisterDamageInternal(Unit target, DamageSourceData sourceData, float amount, float hitMultiplier)
	{
		//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_0043: 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_001e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0022: Unknown result type (might be due to invalid IL or missing references)
		//IL_0023: Unknown result type (might be due to invalid IL or missing references)
		//IL_0028: Unknown result type (might be due to invalid IL or missing references)
		//IL_0030: Unknown result type (might be due to invalid IL or missing references)
		//IL_0036: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
		//IL_0070: Unknown result type (might be due to invalid IL or missing references)
		//IL_0071: 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_00a9: 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_00f1: Unknown result type (might be due to invalid IL or missing references)
		Vector3 damagePosition = GetDamagePosition(target);
		if (Plugin.Mode.Value == DisplayMode.PerHit)
		{
			PerHitSpreadOffset nextPerHitSpread = GetNextPerHitSpread(target, sourceData);
			SpawnNumber(damagePosition, amount, hitMultiplier, sourceData.damageType, sourceData.isCritical, useJitter: true, nextPerHitSpread.WorldOffset, nextPerHitSpread.ScreenOffset, applyCrowding: true);
			return;
		}
		AggregateKey key = AggregateKey.Create(target, sourceData);
		if (!_aggregates.TryGetValue(key, out var value))
		{
			value = new AggregateEntry
			{
				Amount = 0f,
				Position = damagePosition,
				Frame = Time.frameCount,
				HighestMultiplier = 0f,
				LastMultiplier = 0f,
				WeightedMultiplierSum = 0f,
				DamageType = sourceData.damageType,
				AnyCritical = false
			};
		}
		value.Amount += amount;
		value.Position = damagePosition;
		value.Frame = Time.frameCount;
		value.LastMultiplier = hitMultiplier;
		value.AnyCritical = value.AnyCritical || sourceData.isCritical;
		value.WeightedMultiplierSum += Mathf.Max(0f, hitMultiplier) * Mathf.Max(0f, amount);
		if (hitMultiplier > value.HighestMultiplier)
		{
			value.HighestMultiplier = hitMultiplier;
		}
		_aggregates[key] = value;
	}

	private void LateUpdate()
	{
		UpdateVanillaAvailability();
		FlushAggregates();
		ApplyRendererSelectionIfChanged();
		int maxActiveNumbers = GetMaxActiveNumbers();
		EnforcePoolLimit(_screenPool, maxActiveNumbers);
		EnforcePoolLimit(_worldPool, maxActiveNumbers);
		EnforcePoolLimit(_vanillaPool, GetMaxActiveVanillaNumbers());
		Camera mainCamera = GetMainCamera();
		float time = Time.time;
		for (int i = 0; i < _screenPool.Count; i++)
		{
			ScreenDamageNumberView screenDamageNumberView = _screenPool[i];
			if (screenDamageNumberView.IsActive)
			{
				screenDamageNumberView.Tick(mainCamera, time, Plugin.ScreenFloatSpeed.Value);
			}
		}
		for (int j = 0; j < _worldPool.Count; j++)
		{
			DamageNumberView damageNumberView = _worldPool[j];
			if (damageNumberView.IsActive)
			{
				damageNumberView.Tick(mainCamera, time);
			}
		}
		TickVanillaPool(mainCamera, time);
		MaybeLogDroppedBudget();
	}

	private void UpdateVanillaAvailability()
	{
		if (_vanillaBoundaryBroken || Plugin.Renderer.Value != RenderMode.Vanilla)
		{
			_vanillaReady = false;
			return;
		}
		try
		{
			VanillaDamageText.Poll();
			_vanillaReady = VanillaDamageText.IsReady;
		}
		catch (Exception e)
		{
			BreakVanillaBoundary(e);
		}
	}

	private void TickVanillaPool(Camera camera, float now)
	{
		if (_vanillaPool.Count == 0)
		{
			return;
		}
		try
		{
			for (int i = 0; i < _vanillaPool.Count; i++)
			{
				VanillaDamageNumberView vanillaDamageNumberView = _vanillaPool[i];
				if (vanillaDamageNumberView.IsActive)
				{
					vanillaDamageNumberView.Tick(camera, now);
				}
			}
		}
		catch (Exception e)
		{
			BreakVanillaBoundary(e);
		}
	}

	private void BreakVanillaBoundary(Exception e)
	{
		_vanillaReady = false;
		if (!_vanillaBoundaryBroken)
		{
			_vanillaBoundaryBroken = true;
			_vanillaPool.Clear();
			if ((Object)(object)_vanillaRoot != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)_vanillaRoot).gameObject);
				_vanillaRoot = null;
			}
			Plugin.Log.LogWarning((object)("[DamageNumbers] The game's damage text renderer failed and was disabled; Renderer=Vanilla falls back to ScreenSpace. " + e));
		}
	}

	private void FlushAggregates()
	{
		//IL_0091: 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_00b3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
		if (_aggregates.Count == 0)
		{
			return;
		}
		_flushBuffer.Clear();
		foreach (KeyValuePair<AggregateKey, AggregateEntry> aggregate in _aggregates)
		{
			if (aggregate.Value.Frame <= Time.frameCount)
			{
				_flushBuffer.Add(aggregate.Key);
			}
		}
		for (int i = 0; i < _flushBuffer.Count; i++)
		{
			AggregateKey key = _flushBuffer[i];
			if (_aggregates.TryGetValue(key, out var value))
			{
				SpawnNumber(value.Position, value.Amount, ResolveAggregateMultiplier(value), value.DamageType, value.AnyCritical, useJitter: false, Vector3.zero, Vector2.zero, applyCrowding: true);
				_aggregates.Remove(key);
			}
		}
	}

	private void SpawnNumber(Vector3 position, float amount, float hitMultiplier, DamageTypes damageType, bool critical, bool useJitter, Vector3 extraWorldJitter, Vector2 extraScreenJitter, bool applyCrowding)
	{
		//IL_0006: 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_0009: 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_00ba: 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_0021: Unknown result type (might be due to invalid IL or missing references)
		//IL_0030: Unknown result type (might be due to invalid IL or missing references)
		//IL_0035: Unknown result type (might be due to invalid IL or missing references)
		//IL_0037: 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_0044: Unknown result type (might be due to invalid IL or missing references)
		//IL_004b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0050: Unknown result type (might be due to invalid IL or missing references)
		//IL_0055: Unknown result type (might be due to invalid IL or missing references)
		//IL_0095: 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_0067: Unknown result type (might be due to invalid IL or missing references)
		//IL_0068: Unknown result type (might be due to invalid IL or missing references)
		//IL_0077: Unknown result type (might be due to invalid IL or missing references)
		//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_00a3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d9: 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_00de: Unknown result type (might be due to invalid IL or missing references)
		//IL_00df: Unknown result type (might be due to invalid IL or missing references)
		//IL_0108: Unknown result type (might be due to invalid IL or missing references)
		//IL_0109: Unknown result type (might be due to invalid IL or missing references)
		//IL_010a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0130: Unknown result type (might be due to invalid IL or missing references)
		//IL_011e: Unknown result type (might be due to invalid IL or missing references)
		//IL_011f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0120: Unknown result type (might be due to invalid IL or missing references)
		EnsureFrameCounters();
		Vector3 val = extraWorldJitter;
		Vector2 val2 = extraScreenJitter;
		if (useJitter)
		{
			if (Plugin.RandomJitter.Value > 0f)
			{
				Vector2 val3 = Random.insideUnitCircle * Plugin.RandomJitter.Value;
				val += new Vector3(val3.x, 0f, val3.y);
			}
			if (Plugin.ScreenJitter.Value > 0f)
			{
				val2 += Random.insideUnitCircle * Plugin.ScreenJitter.Value;
			}
		}
		bool flag = false;
		Vector2 screenPosition;
		if (applyCrowding && Plugin.EnableCrowdingProtection.Value)
		{
			flag = TryGetCrowdingScreenPosition(position, val2, out screenPosition);
			if (flag && IsAreaCrowded(screenPosition))
			{
				_crowdingSkippedThisFrame++;
				return;
			}
		}
		else
		{
			screenPosition = Vector2.zero;
		}
		if (!TryConsumeSpawnBudget())
		{
			return;
		}
		RenderMode renderMode = ResolveActiveRenderMode();
		if (renderMode == RenderMode.Vanilla)
		{
			SpawnVanilla(amount, hitMultiplier, damageType, critical, position + val);
		}
		else
		{
			string text = FormatDamage(amount);
			Color color = DamageNumberColor.ForMultiplier(hitMultiplier);
			if (renderMode == RenderMode.ScreenSpace || renderMode == RenderMode.Both)
			{
				SpawnScreenWorld(text, position, val2, color);
			}
			if (renderMode == RenderMode.WorldTextMeshPro || renderMode == RenderMode.Both)
			{
				SpawnWorld(text, position, val, color);
			}
		}
		if (flag)
		{
			_crowdingPositions.Add(screenPosition);
		}
	}

	private void SpawnScreenWorld(string text, Vector3 worldPosition, Vector2 jitter, Color color)
	{
		//IL_000d: Unknown result type (might be due to invalid IL or missing references)
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0033: Unknown result type (might be due to invalid IL or missing references)
		AcquireScreenView()?.PlayWorld(text, worldPosition, jitter, Mathf.Max(0.05f, Plugin.Lifetime.Value), Mathf.Max(8, Plugin.ScreenFontSize.Value), color);
	}

	private void SpawnScreenFixed(string text, Vector2 screenPosition, Color color)
	{
		//IL_000d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0032: Unknown result type (might be due to invalid IL or missing references)
		AcquireScreenView()?.PlayFixed(text, screenPosition, Mathf.Max(0.05f, Plugin.Lifetime.Value), Mathf.Max(8, Plugin.ScreenFontSize.Value), color);
	}

	private void SpawnWorld(string text, Vector3 worldPosition, Vector3 jitter, Color color)
	{
		//IL_000d: Unknown result type (might be due to invalid IL or missing references)
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0041: Unknown result type (might be due to invalid IL or missing references)
		AcquireWorldView()?.Play(text, worldPosition, jitter, Mathf.Max(0.05f, Plugin.Lifetime.Value), Plugin.FloatSpeed.Value, Plugin.WorldScale.Value, Plugin.FontSize.Value, color);
	}

	private void SpawnVanilla(float amount, float hitMultiplier, DamageTypes damageType, bool critical, Vector3 worldPosition)
	{
		//IL_0020: 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)
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		//IL_0026: 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)
		//IL_0051: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			VanillaDamageNumberView vanillaDamageNumberView = AcquireVanillaView();
			if (vanillaDamageNumberView != null)
			{
				Color color = (Plugin.VanillaUseDamageTypeColors.Value ? VanillaDamageText.GetDamageTypeColor(damageType) : DamageNumberColor.ForMultiplier(hitMultiplier));
				int amount2 = Mathf.Max(1, Mathf.RoundToInt(amount));
				_vanillaFlyIndex++;
				bool flyRight = _vanillaFlyIndex % 2 == 0;
				vanillaDamageNumberView.Play(amount2, color, worldPosition, Plugin.VanillaScale.Value, flyRight, critical);
			}
		}
		catch (Exception e)
		{
			BreakVanillaBoundary(e);
		}
	}

	private RenderMode ResolveActiveRenderMode()
	{
		RenderMode value = Plugin.Renderer.Value;
		if (value != RenderMode.Vanilla)
		{
			return value;
		}
		if (!_vanillaReady)
		{
			return RenderMode.ScreenSpace;
		}
		return RenderMode.Vanilla;
	}

	private VanillaDamageNumberView AcquireVanillaView()
	{
		GameObject textPrefab = VanillaDamageText.TextPrefab;
		if ((Object)(object)textPrefab == (Object)null)
		{
			return null;
		}
		EnsureVanillaRoot();
		int maxActiveVanillaNumbers = GetMaxActiveVanillaNumbers();
		VanillaDamageNumberView vanillaDamageNumberView = null;
		VanillaDamageNumberView vanillaDamageNumberView2 = null;
		int num = 0;
		for (int i = 0; i < _vanillaPool.Count; i++)
		{
			VanillaDamageNumberView vanillaDamageNumberView3 = _vanillaPool[i];
			if (!vanillaDamageNumberView3.IsActive)
			{
				if (vanillaDamageNumberView == null)
				{
					vanillaDamageNumberView = vanillaDamageNumberView3;
				}
				continue;
			}
			num++;
			if (vanillaDamageNumberView2 == null || vanillaDamageNumberView3.StartTime < vanillaDamageNumberView2.StartTime)
			{
				vanillaDamageNumberView2 = vanillaDamageNumberView3;
			}
		}
		if (num < maxActiveVanillaNumbers)
		{
			if (vanillaDamageNumberView != null)
			{
				return vanillaDamageNumberView;
			}
			VanillaDamageNumberView vanillaDamageNumberView4 = VanillaDamageNumberView.TryCreate(_vanillaRoot, textPrefab);
			if (vanillaDamageNumberView4 == null)
			{
				return null;
			}
			_vanillaPool.Add(vanillaDamageNumberView4);
			return vanillaDamageNumberView4;
		}
		if (vanillaDamageNumberView2 != null)
		{
			vanillaDamageNumberView2.Stop();
			return vanillaDamageNumberView2;
		}
		return vanillaDamageNumberView;
	}

	private ScreenDamageNumberView AcquireScreenView()
	{
		EnsureScreenRoot();
		int maxActiveNumbers = GetMaxActiveNumbers();
		ScreenDamageNumberView screenDamageNumberView = null;
		ScreenDamageNumberView screenDamageNumberView2 = null;
		int num = 0;
		for (int i = 0; i < _screenPool.Count; i++)
		{
			ScreenDamageNumberView screenDamageNumberView3 = _screenPool[i];
			if (!screenDamageNumberView3.IsActive)
			{
				if (screenDamageNumberView == null)
				{
					screenDamageNumberView = screenDamageNumberView3;
				}
				continue;
			}
			num++;
			if (screenDamageNumberView2 == null || screenDamageNumberView3.StartTime < screenDamageNumberView2.StartTime)
			{
				screenDamageNumberView2 = screenDamageNumberView3;
			}
		}
		if (num < maxActiveNumbers)
		{
			if (screenDamageNumberView != null)
			{
				return screenDamageNumberView;
			}
			ScreenDamageNumberView screenDamageNumberView4 = new ScreenDamageNumberView(_screenRoot, _screenSharedMaterial);
			if ((Object)(object)_screenSharedMaterial == (Object)null)
			{
				_screenSharedMaterial = screenDamageNumberView4.FontSharedMaterial;
				screenDamageNumberView4.SetSharedMaterial(_screenSharedMaterial);
			}
			_screenPool.Add(screenDamageNumberView4);
			return screenDamageNumberView4;
		}
		if (screenDamageNumberView2 != null)
		{
			screenDamageNumberView2.Stop();
			return screenDamageNumberView2;
		}
		return screenDamageNumberView;
	}

	private DamageNumberView AcquireWorldView()
	{
		EnsureWorldRoot();
		int maxActiveNumbers = GetMaxActiveNumbers();
		DamageNumberView damageNumberView = null;
		DamageNumberView damageNumberView2 = null;
		int num = 0;
		for (int i = 0; i < _worldPool.Count; i++)
		{
			DamageNumberView damageNumberView3 = _worldPool[i];
			if (!damageNumberView3.IsActive)
			{
				if (damageNumberView == null)
				{
					damageNumberView = damageNumberView3;
				}
				continue;
			}
			num++;
			if (damageNumberView2 == null || damageNumberView3.StartTime < damageNumberView2.StartTime)
			{
				damageNumberView2 = damageNumberView3;
			}
		}
		if (num < maxActiveNumbers)
		{
			if (damageNumberView != null)
			{
				return damageNumberView;
			}
			DamageNumberView damageNumberView4 = new DamageNumberView(_worldRoot, _worldSharedMaterial);
			if ((Object)(object)_worldSharedMaterial == (Object)null)
			{
				_worldSharedMaterial = damageNumberView4.FontSharedMaterial;
				damageNumberView4.SetSharedMaterial(_worldSharedMaterial);
			}
			_worldPool.Add(damageNumberView4);
			return damageNumberView4;
		}
		if (damageNumberView2 != null)
		{
			damageNumberView2.Stop();
			return damageNumberView2;
		}
		return damageNumberView;
	}

	private Camera GetMainCamera()
	{
		if ((Object)(object)_cachedCamera != (Object)null && ((Behaviour)_cachedCamera).isActiveAndEnabled)
		{
			return _cachedCamera;
		}
		float unscaledTime = Time.unscaledTime;
		if (unscaledTime < _nextCameraLookupTime)
		{
			return null;
		}
		_nextCameraLookupTime = unscaledTime + 0.5f;
		_cachedCamera = Camera.main;
		return _cachedCamera;
	}

	private bool TryGetCrowdingScreenPosition(Vector3 worldPosition, Vector2 screenJitter, out Vector2 screenPosition)
	{
		//IL_0025: Unknown result type (might be due to invalid IL or missing references)
		//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_002c: 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_0047: Unknown result type (might be due to invalid IL or missing references)
		//IL_004d: Unknown result type (might be due to invalid IL or missing references)
		//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_0059: 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)
		//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)
		Camera mainCamera = GetMainCamera();
		PrepareCrowdingPositions(mainCamera);
		if ((Object)(object)mainCamera == (Object)null)
		{
			screenPosition = Vector2.zero;
			return false;
		}
		Vector3 val = mainCamera.WorldToScreenPoint(worldPosition);
		if (val.z <= 0f)
		{
			screenPosition = Vector2.zero;
			return false;
		}
		screenPosition = new Vector2(val.x, val.y) + screenJitter;
		return true;
	}

	private void PrepareCrowdingPositions(Camera camera)
	{
		//IL_0052: 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_005c: 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)
		//IL_0072: 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_0080: Unknown result type (might be due to invalid IL or missing references)
		//IL_0126: Unknown result type (might be due to invalid IL or missing references)
		//IL_012b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0130: Unknown result type (might be due to invalid IL or missing references)
		//IL_0132: Unknown result type (might be due to invalid IL or missing references)
		//IL_0146: Unknown result type (might be due to invalid IL or missing references)
		//IL_014d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0154: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
		int frameCount = Time.frameCount;
		if (_crowdingFrame == frameCount)
		{
			return;
		}
		_crowdingFrame = frameCount;
		_crowdingPositions.Clear();
		if ((Object)(object)camera == (Object)null)
		{
			return;
		}
		RenderMode renderMode = ResolveActiveRenderMode();
		switch (renderMode)
		{
		case RenderMode.Vanilla:
			try
			{
				for (int k = 0; k < _vanillaPool.Count; k++)
				{
					VanillaDamageNumberView vanillaDamageNumberView = _vanillaPool[k];
					if (vanillaDamageNumberView.IsActive)
					{
						Vector3 val2 = camera.WorldToScreenPoint(vanillaDamageNumberView.CurrentWorldPosition);
						if (val2.z > 0f)
						{
							_crowdingPositions.Add(new Vector2(val2.x, val2.y));
						}
					}
				}
				break;
			}
			catch (Exception e)
			{
				BreakVanillaBoundary(e);
				break;
			}
		default:
			if (renderMode != RenderMode.Both)
			{
				for (int i = 0; i < _worldPool.Count; i++)
				{
					DamageNumberView damageNumberView = _worldPool[i];
					if (damageNumberView.IsActive)
					{
						Vector3 val = camera.WorldToScreenPoint(damageNumberView.CurrentWorldPosition);
						if (val.z > 0f)
						{
							_crowdingPositions.Add(new Vector2(val.x, val.y));
						}
					}
				}
				break;
			}
			goto case RenderMode.ScreenSpace;
		case RenderMode.ScreenSpace:
		{
			for (int j = 0; j < _screenPool.Count; j++)
			{
				ScreenDamageNumberView screenDamageNumberView = _screenPool[j];
				if (screenDamageNumberView.IsActive && screenDamageNumberView.IsVisible)
				{
					_crowdingPositions.Add(screenDamageNumberView.CurrentScreenPosition);
				}
			}
			break;
		}
		}
	}

	private bool IsAreaCrowded(Vector2 screenPosition)
	{
		//IL_003c: 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_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)
		float num = Mathf.Clamp(Plugin.CrowdingRadius.Value, 8f, 120f);
		float num2 = num * num;
		int num3 = Mathf.Clamp(Plugin.MaxNearbyNumbers.Value, 1, 32);
		int num4 = 0;
		for (int i = 0; i < _crowdingPositions.Count; i++)
		{
			Vector2 val = _crowdingPositions[i] - screenPosition;
			if (!(((Vector2)(ref val)).sqrMagnitude > num2))
			{
				num4++;
				if (num4 >= num3)
				{
					return true;
				}
			}
		}
		return false;
	}

	private void EnsureScreenRoot()
	{
		//IL_0041: Unknown result type (might be due to invalid IL or missing references)
		//IL_0047: Expected O, but got Unknown
		if (!((Object)(object)_screenRoot != (Object)null))
		{
			GameObject val = new GameObject("SULFUR Damage Numbers Canvas", new Type[3]
			{
				typeof(RectTransform),
				typeof(Canvas),
				typeof(CanvasScaler)
			});
			val.transform.SetParent(((Component)this).transform, false);
			Canvas component = val.GetComponent<Canvas>();
			component.renderMode = (RenderMode)0;
			component.overrideSorting = true;
			component.sortingOrder = 32760;
			CanvasScaler component2 = val.GetComponent<CanvasScaler>();
			component2.uiScaleMode = (ScaleMode)0;
			component2.scaleFactor = 1f;
			_screenRoot = val.GetComponent<RectTransform>();
		}
	}

	private void EnsureWorldRoot()
	{
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		//IL_001a: Expected O, but got Unknown
		if (!((Object)(object)_worldRoot != (Object)null))
		{
			GameObject val = new GameObject("SULFUR Damage Numbers World Pool");
			val.transform.SetParent(((Component)this).transform, false);
			_worldRoot = val.transform;
		}
	}

	private void EnsureVanillaRoot()
	{
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		//IL_001a: Expected O, but got Unknown
		if (!((Object)(object)_vanillaRoot != (Object)null))
		{
			GameObject val = new GameObject("SULFUR Damage Numbers Vanilla Pool");
			val.transform.SetParent(((Component)this).transform, false);
			_vanillaRoot = val.transform;
		}
	}

	private void ApplyRendererSelectionIfChanged()
	{
		RenderMode renderMode = ResolveActiveRenderMode();
		if (_hasAppliedRenderMode && renderMode == _lastAppliedRenderMode)
		{
			return;
		}
		_lastAppliedRenderMode = renderMode;
		_hasAppliedRenderMode = true;
		bool num = renderMode == RenderMode.ScreenSpace || renderMode == RenderMode.Both;
		bool flag = renderMode == RenderMode.WorldTextMeshPro || renderMode == RenderMode.Both;
		bool flag2 = renderMode == RenderMode.Vanilla;
		if (!num)
		{
			for (int i = 0; i < _screenPool.Count; i++)
			{
				_screenPool[i].Stop();
			}
		}
		if (!flag)
		{
			for (int j = 0; j < _worldPool.Count; j++)
			{
				_worldPool[j].Stop();
			}
		}
		if (flag2 || _vanillaPool.Count <= 0)
		{
			return;
		}
		try
		{
			for (int k = 0; k < _vanillaPool.Count; k++)
			{
				_vanillaPool[k].Stop();
			}
		}
		catch (Exception e)
		{
			BreakVanillaBoundary(e);
		}
	}

	private static void EnforcePoolLimit<T>(List<T> pool, int maxActive) where T : class, IDamageNumberView
	{
		int num = 0;
		for (int i = 0; i < pool.Count; i++)
		{
			if (pool[i].IsActive)
			{
				num++;
			}
		}
		while (num > maxActive)
		{
			T val = null;
			for (int j = 0; j < pool.Count; j++)
			{
				T val2 = pool[j];
				if (val2.IsActive && (val == null || val2.StartTime < val.StartTime))
				{
					val = val2;
				}
			}
			if (val != null)
			{
				val.Stop();
				num--;
				continue;
			}
			break;
		}
	}

	private void EnsureFrameCounters()
	{
		int frameCount = Time.frameCount;
		if (_spawnBudgetFrame != frameCount)
		{
			_spawnBudgetFrame = frameCount;
			_spawnedThisFrame = 0;
			_droppedThisFrame = 0;
			_crowdingSkippedThisFrame = 0;
		}
	}

	private bool TryConsumeSpawnBudget()
	{
		EnsureFrameCounters();
		int num = Mathf.Clamp(Plugin.MaxNumbersPerFrame.Value, 1, 256);
		if (_spawnedThisFrame >= num)
		{
			_droppedThisFrame++;
			return false;
		}
		_spawnedThisFrame++;
		return true;
	}

	private void MaybeLogDroppedBudget()
	{
		if (_spawnBudgetFrame == Time.frameCount && Plugin.DebugLog.Value && (_droppedThisFrame > 0 || _crowdingSkippedThisFrame > 0))
		{
			float unscaledTime = Time.unscaledTime;
			if (!(unscaledTime - _lastBudgetLogTime < 1f))
			{
				_lastBudgetLogTime = unscaledTime;
				Plugin.Log.LogWarning((object)("[DamageNumbers] frame " + _spawnBudgetFrame + ": droppedByFrameBudget=" + _droppedThisFrame + ", skippedByCrowding=" + _crowdingSkippedThisFrame + "."));
			}
		}
	}

	private static int GetMaxActiveNumbers()
	{
		return Mathf.Clamp(Plugin.MaxActiveNumbers.Value, 1, 256);
	}

	private static int GetMaxActiveVanillaNumbers()
	{
		return Mathf.Clamp(Plugin.MaxActiveNumbers.Value, 1, 64);
	}

	private static Vector3 GetDamagePosition(Unit target)
	{
		//IL_0030: Unknown result type (might be due to invalid IL or missing references)
		//IL_0035: Unknown result type (might be due to invalid IL or missing references)
		//IL_003f: 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_0024: Unknown result type (might be due to invalid IL or missing references)
		Npc val = (Npc)(object)((target is Npc) ? target : null);
		if ((Object)(object)val != (Object)null && (Object)(object)val.overhead != (Object)null)
		{
			return val.overhead.position;
		}
		return ((Component)target).transform.position + Vector3.up * 2f;
	}

	private PerHitSpreadOffset GetNextPerHitSpread(Unit target, DamageSourceData sourceData)
	{
		//IL_0024: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d1: 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_00e7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
		if (_perHitSpreadFrame != Time.frameCount)
		{
			_perHitSpreadFrame = Time.frameCount;
			_perHitSpreadCounters.Clear();
		}
		PerHitSpreadKey key = PerHitSpreadKey.Create(target, sourceData);
		if (!_perHitSpreadCounters.TryGetValue(key, out var value))
		{
			value = 0;
		}
		_perHitSpreadCounters[key] = value + 1;
		if (value <= 0)
		{
			return PerHitSpreadOffset.Zero;
		}
		float num = (float)value * 2.3999631f;
		float num2 = Mathf.Sqrt((float)value);
		Vector2 val = default(Vector2);
		((Vector2)(ref val))..ctor(Mathf.Cos(num), Mathf.Sin(num));
		float num3 = Mathf.Min(42f, Mathf.Max(0f, Plugin.PerHitStackScreenSpread.Value) * num2);
		float num4 = Mathf.Min(0.36f, Mathf.Max(0f, Plugin.PerHitStackWorldSpread.Value) * num2);
		return new PerHitSpreadOffset
		{
			ScreenOffset = val * num3,
			WorldOffset = new Vector3(val.x * num4, 0f, val.y * num4)
		};
	}

	private static string FormatDamage(float amount)
	{
		if (Plugin.ShowDecimals.Value)
		{
			float num = Mathf.Round(amount * 10f) / 10f;
			float num2 = Mathf.Round(num);
			if (Mathf.Abs(num - num2) <= 0.0001f)
			{
				int num3 = Mathf.RoundToInt(num2);
				if (num3 <= 0 && amount > 0f)
				{
					num3 = 1;
				}
				return num3.ToString(CultureInfo.InvariantCulture);
			}
			return num.ToString("0.0", CultureInfo.InvariantCulture);
		}
		int num4 = Mathf.RoundToInt(amount);
		if (num4 <= 0)
		{
			num4 = 1;
		}
		return num4.ToString(CultureInfo.InvariantCulture);
	}

	private static float ResolveAggregateMultiplier(AggregateEntry entry)
	{
		switch (Plugin.AggregateColorMode.Value)
		{
		case MergedColorMode.LastHit:
			return entry.LastMultiplier;
		case MergedColorMode.DamageWeightedAverage:
			if (entry.Amount > 0.0001f)
			{
				return entry.WeightedMultiplierSum / entry.Amount;
			}
			return entry.HighestMultiplier;
		default:
			return entry.HighestMultiplier;
		}
	}

	private void OnDestroy()
	{
		_aggregates.Clear();
		_flushBuffer.Clear();
		_perHitSpreadCounters.Clear();
		_crowdingPositions.Clear();
		_screenPool.Clear();
		_worldPool.Clear();
		_vanillaPool.Clear();
		_screenRoot = null;
		_worldRoot = null;
		_vanillaRoot = null;
		_cachedCamera = null;
		_screenSharedMaterial = null;
		_worldSharedMaterial = null;
		if ((Object)(object)_instance == (Object)(object)this)
		{
			_instance = null;
		}
	}
}
internal interface IDamageNumberView
{
	bool IsActive { get; }

	float StartTime { get; }

	void Stop();
}
internal sealed class ScreenDamageNumberView : IDamageNumberView
{
	private static readonly Vector2[] OutlineOffsets = (Vector2[])(object)new Vector2[4]
	{
		new Vector2(-1.15f, -1.15f),
		new Vector2(-1.15f, 1.15f),
		new Vector2(1.15f, -1.15f),
		new Vector2(1.15f, 1.15f)
	};

	private readonly GameObject _gameObject;

	private readonly RectTransform _rectTransform;

	private readonly TextMeshProUGUI[] _outlineTexts;

	private readonly TextMeshProUGUI _text;

	private Vector3 _worldPosition;

	private Vector2 _screenPosition;

	private Vector2 _screenJitter;

	private float _lifetime;

	private bool _fixedScreen;

	public bool IsActive { get; private set; }

	public float StartTime { get; private set; }

	public bool IsVisible { get; private set; }

	public Vector2 CurrentScreenPosition { get; private set; }

	public Material FontSharedMaterial => ((TMP_Text)_text).fontSharedMaterial;

	public ScreenDamageNumberView(RectTransform parent, Material sharedMaterial)
	{
		//IL_001f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0029: Expected O, but got Unknown
		//IL_0052: Unknown result type (might be due to invalid IL or missing references)
		//IL_0062: Unknown result type (might be due to invalid IL or missing references)
		//IL_007c: 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_00d5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
		_gameObject = new GameObject("SULFUR Damage Number Screen", new Type[1] { typeof(RectTransform) });
		_gameObject.transform.SetParent((Transform)(object)parent, false);
		_rectTransform = _gameObject.GetComponent<RectTransform>();
		_rectTransform.anchorMin = Vector2.zero;
		_rectTransform.anchorMax = Vector2.zero;
		_rectTransform.pivot = new Vector2(0.5f, 0.5f);
		_rectTransform.sizeDelta = new Vector2(240f, 80f);
		_outlineTexts = (TextMeshProUGUI[])(object)new TextMeshProUGUI[OutlineOffsets.Length];
		for (int i = 0; i < _outlineTexts.Length; i++)
		{
			_outlineTexts[i] = CreateTextLayer("Outline" + i, OutlineOffsets[i]);
		}
		_text = CreateTextLayer("Face", Vector2.zero);
		if ((Object)(object)sharedMaterial != (Object)null)
		{
			SetSharedMaterial(sharedMaterial);
		}
		else if ((Object)(object)((TMP_Text)_text).fontSharedMaterial != (Object)null)
		{
			SetOutlineSharedMaterial(((TMP_Text)_text).fontSharedMaterial);
		}
		Stop();
	}

	private TextMeshProUGUI CreateTextLayer(string name, Vector2 offset)
	{
		//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_0045: 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_0057: Unknown result type (might be due to invalid IL or missing references)
		//IL_0062: 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_0082: 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)
		GameObject val = new GameObject(name, new Type[3]
		{
			typeof(RectTransform),
			typeof(CanvasRenderer),
			typeof(TextMeshProUGUI)
		});
		val.transform.SetParent((Transform)(object)_rectTransform, false);
		RectTransform component = val.GetComponent<RectTransform>();
		component.anchorMin = Vector2.zero;
		component.anchorMax = Vector2.one;
		component.offsetMin = Vector2.zero;
		component.offsetMax = Vector2.zero;
		component.pivot = new Vector2(0.5f, 0.5f);
		component.anchoredPosition = offset;
		TextMeshProUGUI component2 = val.GetComponent<TextMeshProUGUI>();
		((TMP_Text)component2).alignment = (TextAlignmentOptions)514;
		((TMP_Text)component2).fontStyle = (FontStyles)1;
		((TMP_Text)component2).textWrappingMode = (TextWrappingModes)0;
		((TMP_Text)component2).overflowMode = (TextOverflowModes)0;
		((Graphic)component2).raycastTarget = false;
		return component2;
	}

	public void SetSharedMaterial(Material sharedMaterial)
	{
		if (!((Object)(object)sharedMaterial == (Object)null))
		{
			((TMP_Text)_text).fontSharedMaterial = sharedMaterial;
			SetOutlineSharedMaterial(sharedMaterial);
		}
	}

	private void SetOutlineSharedMaterial(Material sharedMaterial)
	{
		for (int i = 0; i < _outlineTexts.Length; i++)
		{
			((TMP_Text)_outlineTexts[i]).fontSharedMaterial = sharedMaterial;
		}
	}

	public void PlayWorld(string value, Vector3 worldPosition, Vector2 jitter, float lifetime, int fontSize, Color color)
	{
		//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_0008: Unknown result type (might be due to invalid IL or missing references)
		//IL_0009: Unknown result type (might be due to invalid IL or missing references)
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		_worldPosition = worldPosition;
		_screenJitter = jitter;
		_fixedScreen = false;
		PlayCommon(value, lifetime, fontSize, color);
	}

	public void PlayFixed(string value, Vector2 screenPosition, float lifetime, int fontSize, Color color)
	{
		//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_0008: 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_001e: Unknown result type (might be due to invalid IL or missing references)
		_screenPosition = screenPosition;
		_screenJitter = Vector2.zero;
		_fixedScreen = true;
		PlayCommon(value, lifetime, fontSize, color);
	}

	private void PlayCommon(string value, float lifetime, int fontSize, Color color)
	{
		//IL_0047: Unknown result type (might be due to invalid IL or missing references)
		//IL_007f: Unknown result type (might be due to invalid IL or missing references)
		StartTime = Time.time;
		_lifetime = Mathf.Max(0.05f, lifetime);
		color.a = 1f;
		((TMP_Text)_text).text = value;
		((TMP_Text)_text).fontSize = fontSize;
		((Graphic)_text).color = color;
		_text.canvasRenderer.SetAlpha(1f);
		for (int i = 0; i < _outlineTexts.Length; i++)
		{
			TextMeshProUGUI obj = _outlineTexts[i];
			((TMP_Text)obj).text = value;
			((TMP_Text)obj).fontSize = fontSize;
			((Graphic)obj).color = Color.black;
			obj.canvasRenderer.SetAlpha(1f);
			((Behaviour)obj).enabled = true;
		}
		((Behaviour)_text).enabled = true;
		_gameObject.SetActive(true);
		IsVisible = true;
		IsActive = true;
	}

	public void Tick(Camera camera, float now, float floatSpeed)
	{
		//IL_002b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0030: Unknown result type (might be due to invalid IL or missing references)
		//IL_004c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0051: 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_0062: Unknown result type (might be due to invalid IL or missing references)
		//IL_0067: 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_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_0071: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b1: 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_00b8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
		//IL_0090: 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)
		if (!IsActive)
		{
			return;
		}
		float num = now - StartTime;
		if (num >= _lifetime)
		{
			Stop();
			return;
		}
		Vector2 val = default(Vector2);
		if (_fixedScreen)
		{
			val = _screenPosition;
		}
		else
		{
			if ((Object)(object)camera == (Object)null)
			{
				SetLayersEnabled(enabled: false);
				IsVisible = false;
				return;
			}
			Vector3 val2 = _worldPosition + Vector3.up * (num * 0.25f);
			Vector3 val3 = camera.WorldToScreenPoint(val2);
			if (val3.z <= 0f)
			{
				SetLayersEnabled(enabled: false);
				IsVisible = false;
				return;
			}
			((Vector2)(ref val))..ctor(val3.x, val3.y);
		}
		SetLayersEnabled(enabled: true);
		IsVisible = true;
		val += _screenJitter;
		val.y += num * floatSpeed;
		CurrentScreenPosition = val;
		_rectTransform.anchoredPosition = val;
		float alpha = Mathf.Clamp01(1f - num / _lifetime);
		_text.canvasRenderer.SetAlpha(alpha);
		for (int i = 0; i < _outlineTexts.Length; i++)
		{
			_outlineTexts[i].canvasRenderer.SetAlpha(alpha);
		}
	}

	private void SetLayersEnabled(bool enabled)
	{
		((Behaviour)_text).enabled = enabled;
		for (int i = 0; i < _outlineTexts.Length; i++)
		{
			((Behaviour)_outlineTexts[i]).enabled = enabled;
		}
	}

	public void Stop()
	{
		IsActive = false;
		IsVisible = false;
		if ((Object)(object)_text != (Object)null)
		{
			_text.canvasRenderer.SetAlpha(0f);
			((Behaviour)_text).enabled = false;
		}
		if (_outlineTexts != null)
		{
			for (int i = 0; i < _outlineTexts.Length; i++)
			{
				TextMeshProUGUI val = _outlineTexts[i];
				if (!((Object)(object)val == (Object)null))
				{
					val.canvasRenderer.SetAlpha(0f);
					((Behaviour)val).enabled = false;
				}
			}
		}
		if ((Object)(object)_gameObject != (Object)null)
		{
			_gameObject.SetActive(false);
		}
	}
}
internal struct PerHitSpreadKey : IEquatable<PerHitSpreadKey>
{
	private int _targetId;

	private int _frame;

	private int _sourceId;

	public static PerHitSpreadKey Create(Unit target, DamageSourceData sourceData)
	{
		//IL_0002: Unknown result type (might be due to invalid IL or missing references)
		//IL_001e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0010: 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_0026: 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)
		int sourceId = 0;
		if ((Object)(object)sourceData.sourceWeapon != (Object)null)
		{
			sourceId = ((Object)sourceData.sourceWeapon).GetInstanceID();
		}
		else if (sourceData.instanceId != 0)
		{
			sourceId = sourceData.instanceId;
		}
		else if ((Object)(object)sourceData.sourceUnit != (Object)null)
		{
			sourceId = ((Object)sourceData.sourceUnit).GetInstanceID();
		}
		return new PerHitSpreadKey
		{
			_targetId = ((Object)target).GetInstanceID(),
			_frame = Time.frameCount,
			_sourceId = sourceId
		};
	}

	public bool Equals(PerHitSpreadKey other)
	{
		if (_targetId == other._targetId && _frame == other._frame)
		{
			return _sourceId == other._sourceId;
		}
		return false;
	}

	public override bool Equals(object obj)
	{
		if (obj is PerHitSpreadKey)
		{
			return Equals((PerHitSpreadKey)obj);
		}
		return false;
	}

	public override int GetHashCode()
	{
		return (((_targetId * 397) ^ _frame) * 397) ^ _sourceId;
	}
}
internal struct AggregateKey : IEquatable<AggregateKey>
{
	private int _targetId;

	private int _frame;

	private int _sourceId;

	private int _damageType;

	private bool _melee;

	public static AggregateKey Create(Unit target, DamageSourceData sourceData)
	{
		//IL_0002: Unknown result type (might be due to invalid IL or missing references)
		//IL_001e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0010: 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_0026: Unknown result type (might be due to invalid IL or missing references)
		//IL_0074: 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_008b: 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)
		int sourceId = 0;
		if ((Object)(object)sourceData.sourceWeapon != (Object)null)
		{
			sourceId = ((Object)sourceData.sourceWeapon).GetInstanceID();
		}
		else if (sourceData.instanceId != 0)
		{
			sourceId = sourceData.instanceId;
		}
		else if ((Object)(object)sourceData.sourceUnit != (Object)null)
		{
			sourceId = ((Object)sourceData.sourceUnit).GetInstanceID();
		}
		return new AggregateKey
		{
			_targetId = ((Object)target).GetInstanceID(),
			_frame = Time.frameCount,
			_sourceId = sourceId,
			_damageType = Convert.ToInt32(sourceData.damageType),
			_melee = sourceData.melee
		};
	}

	public bool Equals(AggregateKey other)
	{
		if (_targetId == other._targetId && _frame == other._frame && _sourceId == other._sourceId && _damageType == other._damageType)
		{
			return _melee == other._melee;
		}
		return false;
	}

	public override bool Equals(object obj)
	{
		if (obj is AggregateKey)
		{
			return Equals((AggregateKey)obj);
		}
		return false;
	}

	public override int GetHashCode()
	{
		return (((((((_targetId * 397) ^ _frame) * 397) ^ _sourceId) * 397) ^ _damageType) * 397) ^ (_melee ? 1 : 0);
	}
}
internal static class DamageNumberColor
{
	private static readonly Color NormalDamageColor = Color.white;

	private static readonly Color OrangeDamageColor = new Color(1f, 0.5f, 0f, 1f);

	public static Color ForMultiplier(float multiplier)
	{
		//IL_000c: 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)
		//IL_004d: 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_005b: 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_0069: Unknown result type (might be due to invalid IL or missing references)
		if (!Plugin.UseWeakspotColors.Value)
		{
			return NormalDamageColor;
		}
		if (multiplier <= 0f)
		{
			return NormalDamageColor;
		}
		if (Plugin.TreatOneMultiplierAsNormal.Value && Mathf.Abs(multiplier - 1f) <= 0.0001f)
		{
			return NormalDamageColor;
		}
		if (multiplier >= 1.5f)
		{
			return Color.red;
		}
		if (multiplier >= 1f)
		{
			return OrangeDamageColor;
		}
		if (multiplier >= 0.75f)
		{
			return Color.yellow;
		}
		return NormalDamageColor;
	}
}
internal sealed class DamageNumberView : IDamageNumberView
{
	private const int WorldFadeSteps = 10;

	private const float WorldOutlineOffsetFactor = 0.02f;

	private static readonly Vector2[] OutlineDirections = (Vector2[])(object)new Vector2[4]
	{
		new Vector2(-1f, -1f),
		new Vector2(-1f, 1f),
		new Vector2(1f, -1f),
		new Vector2(1f, 1f)
	};

	private readonly GameObject _gameObject;

	private readonly Transform _transform;

	private readonly TextMeshPro[] _outlineTexts;

	private readonly TextMeshPro _text;

	private Vector3 _basePosition;

	private Vector3 _jitter;

	private float _lifetime;

	private float _floatSpeed;

	private Color _baseColor;

	private int _lastFadeStep = -1;

	public bool IsActive { get; private set; }

	public float StartTime { get; private set; }

	public Vector3 CurrentWorldPosition => _transform.position;

	public Material FontSharedMaterial => ((TMP_Text)_text).fontSharedMaterial;

	public DamageNumberView(Transform parent, Material sharedMaterial)
	{
		//IL_0013: Unknown result type (might be due to invalid IL or missing references)
		//IL_001d: Expected O, but got Unknown
		_gameObject = new GameObject("SULFUR Damage Number World");
		_gameObject.transform.SetParent(parent, false);
		_transform = _gameObject.transform;
		_outlineTexts = (TextMeshPro[])(object)new TextMeshPro[OutlineDirections.Length];
		for (int i = 0; i < _outlineTexts.Length; i++)
		{
			_outlineTexts[i] = CreateTextLayer("Outline" + i, 0);
		}
		_text = CreateTextLayer("Face", 1);
		if ((Object)(object)sharedMaterial != (Object)null)
		{
			SetSharedMaterial(sharedMaterial);
		}
		else if ((Object)(object)((TMP_Text)_text).fontSharedMaterial != (Object)null)
		{
			SetOutlineSharedMaterial(((TMP_Text)_text).fontSharedMaterial);
		}
		Stop();
	}

	private TextMeshPro CreateTextLayer(string name, int sortingOrder)
	{
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		GameObject val = new GameObject(name, new Type[1] { typeof(TextMeshPro) });
		val.transform.SetParent(_transform, false);
		TextMeshPro component = val.GetComponent<TextMeshPro>();
		((TMP_Text)component).alignment = (TextAlignmentOptions)514;
		((TMP_Text)component).fontStyle = (FontStyles)1;
		((TMP_Text)component).textWrappingMode = (TextWrappingModes)0;
		((TMP_Text)component).overflowMode = (TextOverflowModes)0;
		component.sortingOrder = sortingOrder;
		return component;
	}

	public void SetSharedMaterial(Material sharedMaterial)
	{
		if (!((Object)(object)sharedMaterial == (Object)null))
		{
			((TMP_Text)_text).fontSharedMaterial = sharedMaterial;
			SetOutlineSharedMaterial(sharedMaterial);
		}
	}

	private void SetOutlineSharedMaterial(Material sharedMaterial)
	{
		for (int i = 0; i < _outlineTexts.Length; i++)
		{
			((TMP_Text)_outlineTexts[i]).fontSharedMaterial = sharedMaterial;
		}
	}

	public void Play(string value, Vector3 position, Vector3 jitter, float lifetime, float floatSpeed, float worldScale, float fontSize, Color color)
	{
		//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_0008: Unknown result type (might be due to invalid IL or missing references)
		//IL_0009: 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_0036: Unknown result type (might be due to invalid IL or missing references)
		//IL_0049: Unknown result type (might be due to invalid IL or missing references)
		//IL_004a: Unknown result type (might be due to invalid IL or missing references)
		//IL_004b: 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_0062: 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_00c3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c8: 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_00d7: 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_00fe: Unknown result type (might be due to invalid IL or missing references)
		_basePosition = position;
		_jitter = jitter;
		StartTime = Time.time;
		_lifetime = Mathf.Max(0.05f, lifetime);
		_floatSpeed = floatSpeed;
		_baseColor = color;
		_lastFadeStep = 10;
		_transform.position = position + jitter;
		_transform.localScale = Vector3.one * worldScale;
		color.a = 1f;
		((TMP_Text)_text).text = value;
		((TMP_Text)_text).fontSize = fontSize;
		((Graphic)_text).color = color;
		float num = Mathf.Max(0.05f, fontSize * 0.02f);
		for (int i = 0; i < _outlineTexts.Length; i++)
		{
			TextMeshPro obj = _outlineTexts[i];
			Vector2 val = OutlineDirections[i];
			obj.transform.localPosition = new Vector3(val.x * num, val.y * num, 0f);
			((TMP_Text)obj).text = value;
			((TMP_Text)obj).fontSize = fontSize;
			((Graphic)obj).color = Color.black;
			((Behaviour)obj).enabled = true;
		}
		((Behaviour)_text).enabled = true;
		_gameObject.SetActive(true);
		IsActive = true;
	}

	public void Tick(Camera camera, float now)
	{
		//IL_0029: 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_0034: Unknown result type (might be due to invalid IL or missing references)
		//IL_0039: 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_004b: 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_006f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0074: 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_00e5: 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)
		//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
		//IL_0101: Unknown result type (might be due to invalid IL or missing references)
		//IL_0106: Unknown result type (might be due to invalid IL or missing references)
		//IL_008e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0095: Unknown result type (might be due to invalid IL or missing references)
		//IL_009a: Unknown result type (might be due to invalid IL or missing references)
		//IL_011e: Unknown result type (might be due to invalid IL or missing references)
		if (!IsActive)
		{
			return;
		}
		float num = now - StartTime;
		if (num >= _lifetime)
		{
			Stop();
			return;
		}
		_transform.position = _basePosition + _jitter + Vector3.up * (num * _floatSpeed);
		if ((Object)(object)camera != (Object)null)
		{
			Vector3 val = _transform.position - ((Component)camera).transform.position;
			if (((Vector3)(ref val)).sqrMagnitude > 0.0001f)
			{
				_transform.rotation = Quaternion.LookRotation(val, ((Component)camera).transform.up);
			}
		}
		int num2 = Mathf.Clamp(Mathf.CeilToInt(Mathf.Clamp01(1f - num / _lifetime) * 10f), 0, 10);
		if (num2 != _lastFadeStep)
		{
			_lastFadeStep = num2;
			float a = (float)num2 / 10f;
			Color baseColor = _baseColor;
			baseColor.a = a;
			((Graphic)_text).color = baseColor;
			Color black = Color.black;
			black.a = a;
			for (int i = 0; i < _outlineTexts.Length; i++)
			{
				((Graphic)_outlineTexts[i]).color = black;
			}
		}
	}

	public void Stop()
	{
		IsActive = false;
		if ((Object)(object)_text != (Object)null)
		{
			((Behaviour)_text).enabled = false;
		}
		if (_outlineTexts != null)
		{
			for (int i = 0; i < _outlineTexts.Length; i++)
			{
				if ((Object)(object)_outlineTexts[i] != (Object)null)
				{
					((Behaviour)_outlineTexts[i]).enabled = false;
				}
			}
		}
		if ((Object)(object)_gameObject != (Object)null)
		{
			_gameObject.SetActive(false);
		}
	}
}
internal static class DamageReceivePatch
{
	public static void Apply(Harmony harmony)
	{
		DamageLogPatch.Apply(harmony);
	}
}
[BepInPlugin("ryuka.sulfur.damagenumbers", "SULFUR Damage Numbers", "1.1.0")]
public sealed class Plugin : BaseUnityPlugin
{
	public const string PluginGuid = "ryuka.sulfur.damagenumbers";

	public const string PluginName = "SULFUR Damage Numbers";

	public const string PluginVersion = "1.1.0";

	internal static ConfigEntry<bool> Enabled;

	internal static ConfigEntry<DisplayMode> Mode;

	internal static ConfigEntry<RenderMode> Renderer;

	internal static ConfigEntry<MergedColorMode> AggregateColorMode;

	internal static ConfigEntry<bool> VanillaUseDamageTypeColors;

	internal static ConfigEntry<float> VanillaScale;

	internal static ConfigEntry<bool> UseWeakspotColors;

	internal static ConfigEntry<bool> TreatOneMultiplierAsNormal;

	internal static ConfigEntry<bool> RequireNpcTarget;

	internal static ConfigEntry<bool> RequireSourceUnitPlayer;

	internal static ConfigEntry<bool> ShowPlayerOwnedSecondaryEffects;

	internal static ConfigEntry<bool> ShowStatusEffectDamage;

	internal static ConfigEntry<float> MinDamageToShow;

	internal static ConfigEntry<bool> ShowDecimals;

	internal static ConfigEntry<float> Lifetime;

	internal static ConfigEntry<float> FloatSpeed;

	internal static ConfigEntry<float> WorldScale;

	internal static ConfigEntry<float> RandomJitter;

	internal static ConfigEntry<float> FontSize;

	internal static ConfigEntry<int> ScreenFontSize;

	internal static ConfigEntry<float> ScreenFloatSpeed;

	internal static ConfigEntry<float> ScreenJitter;

	internal static ConfigEntry<float> PerHitStackScreenSpread;

	internal static ConfigEntry<float> PerHitStackWorldSpread;

	internal static ConfigEntry<int> MaxActiveNumbers;

	internal static ConfigEntry<int> MaxNumbersPerFrame;

	internal static ConfigEntry<bool> EnableCrowdingProtection;

	internal static ConfigEntry<float> CrowdingRadius;

	internal static ConfigEntry<int> MaxNearbyNumbers;

	internal static ConfigEntry<bool> DebugLog;

	internal static ConfigEntry<bool> DebugSpawnTestOnF8;

	internal static ManualLogSource Log;

	private Harmony _harmony;

	private void Awake()
	{
		//IL_042c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0436: Expected O, but got Unknown
		Log = ((BaseUnityPlugin)this).Logger;
		Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enable damage number display.");
		Mode = ((BaseUnityPlugin)this).Config.Bind<DisplayMode>("General", "DamageDisplayMode", DisplayMode.PerTargetTotal, "PerTargetTotal = same frame, same player attack source, same target damage is merged. PerHit = each real damage log is shown separately. Crowding and frame-budget settings are independent visual performance limits applied after either mode.");
		Renderer = ((BaseUnityPlugin)this).Config.Bind<RenderMode>("Visual", "Renderer", RenderMode.ScreenSpace, "ScreenSpace uses pooled TextMeshProUGUI objects. WorldTextMeshPro uses pooled 3D TextMeshPro objects. Both renders both at the same time. Vanilla reuses the game's own damage text prefab, the one the target dummies use, with its original animation, font and damage-type colors; it shows whole numbers only and falls back to ScreenSpace if the game does not provide that prefab.");
		VanillaUseDamageTypeColors = ((BaseUnityPlugin)this).Config.Bind<bool>("Visual", "VanillaUseDamageTypeColors", true, "Renderer=Vanilla only. True uses the game's damage-type colors exactly like the target dummies. False keeps this mod's weakspot multiplier colors on the vanilla animation.");
		VanillaScale = ((BaseUnityPlugin)this).Config.Bind<float>("Visual", "VanillaScale", 1f, "Renderer=Vanilla only. Scale applied to the game's damage text. 1.0 is the size the target dummies use.");
		UseWeakspotColors = ((BaseUnityPlugin)this).Config.Bind<bool>("Visual", "UseWeakspotColors", true, "Use weakspot/body-part multiplier colors. Red >= 1.5, orange >= 1.0, yellow >= 0.75, white when no multiplier is available.");
		TreatOneMultiplierAsNormal = ((BaseUnityPlugin)this).Config.Bind<bool>("Visual", "TreatOneMultiplierAsNormal", false, "If true, multiplier 1.0 is shown as white instead of orange.");
		AggregateColorMode = ((BaseUnityPlugin)this).Config.Bind<MergedColorMode>("Visual", "AggregateColorMode", MergedColorMode.HighestMultiplier, "Color rule for PerTargetTotal. HighestMultiplier = strongest hit color. DamageWeightedAverage = damage-weighted multiplier. LastHit = last hit color.");
		RequireNpcTarget = ((BaseUnityPlugin)this).Config.Bind<bool>("Filter", "RequireNpcTarget", true, "Only show damage numbers on Npc targets. Keep true to avoid barrels/objects if they also use Unit damage code.");
		RequireSourceUnitPlayer = ((BaseUnityPlugin)this).Config.Bind<bool>("Filter", "RequireSourceUnitPlayer", false, "If true, sourceData.sourceUnit must exist and be the player. Default false because some projectiles/explosions keep only the game's isPlayer flag.");
		ShowPlayerOwnedSecondaryEffects = ((BaseUnityPlugin)this).Config.Bind<bool>("Filter", "ShowPlayerOwnedSecondaryEffects", true, "Show player-owned secondary damage such as projectile explosions if the game reports them as created by the player.");
		ShowStatusEffectDamage = ((BaseUnityPlugin)this).Config.Bind<bool>("Filter", "ShowStatusEffectDamage", true, "Show damage over time from status effects the player applied, such as burning, poison and electrocution. The game builds this damage without its player flag and only records the unit that applied the status, so it was silently dropped before 1.1.0. These are the colored numbers the target dummies show.");
		MinDamageToShow = ((BaseUnityPlugin)this).Config.Bind<float>("Filter", "MinDamageToShow", 0.01f, "Final damage below this value will not be shown.");
		ShowDecimals = ((BaseUnityPlugin)this).Config.Bind<bool>("Visual", "ShowDecimals", false, "Show one decimal place for non-integer damage. Integer values such as 5.0 are still shown as 5.");
		Lifetime = ((BaseUnityPlugin)this).Config.Bind<float>("Visual", "Lifetime", 0.85f, "Damage number lifetime in seconds.");
		FloatSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("Visual", "FloatSpeed", 1.25f, "World-space upward speed for WorldTextMeshPro renderer.");
		WorldScale = ((BaseUnityPlugin)this).Config.Bind<float>("Visual", "WorldScale", 0.045f, "World-space scale of each TextMeshPro damage number.");
		RandomJitter = ((BaseUnityPlugin)this).Config.Bind<float>("Visual", "RandomJitter", 0.18f, "Random horizontal world-space offset. Useful for PerHit shotgun pellets.");
		FontSize = ((BaseUnityPlugin)this).Config.Bind<float>("Visual", "FontSize", 8f, "TextMeshPro font size for WorldTextMeshPro renderer.");
		ScreenFontSize = ((BaseUnityPlugin)this).Config.Bind<int>("Visual", "ScreenFontSize", 30, "Screen-space TextMeshPro font size.");
		ScreenFloatSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("Visual", "ScreenFloatSpeed", 70f, "Screen-space upward speed in pixels per second.");
		ScreenJitter = ((BaseUnityPlugin)this).Config.Bind<float>("Visual", "ScreenJitter", 26f, "Random screen-space offset in pixels. Useful for PerHit shotgun pellets.");
		PerHitStackScreenSpread = ((BaseUnityPlugin)this).Config.Bind<float>("Visual", "PerHitStackScreenSpread", 12.8f, "Extra deterministic screen-space spread in pixels for multiple PerHit numbers created on the same target in the same frame.");
		PerHitStackWorldSpread = ((BaseUnityPlugin)this).Config.Bind<float>("Visual", "PerHitStackWorldSpread", 0.06f, "Extra deterministic world-space spread for multiple PerHit numbers created on the same target in the same frame.");
		MaxActiveNumbers = ((BaseUnityPlugin)this).Config.Bind<int>("Performance", "MaxActiveNumbers", 160, "Maximum active damage numbers in each enabled renderer. Values are hard-clamped to 1-256 and the oldest active number is reused when full.");
		MaxNumbersPerFrame = ((BaseUnityPlugin)this).Config.Bind<int>("Performance", "MaxNumbersPerFrame", 32, "Maximum new logical damage numbers spawned in one frame. Values are hard-clamped to 1-256. Extra events are dropped to protect Unity's GC during extreme hit spam.");
		EnableCrowdingProtection = ((BaseUnityPlugin)this).Config.Bind<bool>("Performance", "EnableCrowdingProtection", true, "Skip a new number when several active numbers already occupy the same small screen area. This is a visual limiter applied after the selected display mode; it does not merge PerHit damage or change PerTargetTotal aggregation.");
		CrowdingRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Performance", "CrowdingRadius", 36f, "Screen-space radius in pixels used by crowding protection. Values are hard-clamped to 8-120.");
		MaxNearbyNumbers = ((BaseUnityPlugin)this).Config.Bind<int>("Performance", "MaxNearbyNumbers", 5, "Maximum existing numbers allowed inside the crowding radius before a new visually covered number is skipped. Values are hard-clamped to 1-32.");
		DebugLog = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "DebugLog", false, "Print accepted/rejected damage events and rate-limit warnings to LogOutput.log.");
		DebugSpawnTestOnF8 = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "DebugSpawnTestOnF8", false, "Press F8 in-game to spawn a test number. Disabled by default in release builds.");
		DamageNumberManager.EnsureExists();
		_harmony = new Harmony("ryuka.sulfur.damagenumbers");
		DamageLogPatch.Apply(_harmony);
		((BaseUnityPlugin)this).Logger.LogInfo((object)("SULFUR Damage Numbers 1.1.0 loaded. Renderer=" + Renderer.Value.ToString() + ", Mode=" + Mode.Value.ToString() + "."));
	}

	private void OnDestroy()
	{
		if (_harmony != null)
		{
			_harmony.UnpatchSelf();
			_harmony = null;
		}
		DamageLogPatch.Reset();
		DamageNumberManager.Shutdown();
		try
		{
			VanillaDamageText.Shutdown();
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)("Releasing the game's damage text assets failed: " + ex.Message));
		}
	}
}
public enum DisplayMode
{
	PerTargetTotal = 1,
	PerHit
}
public enum RenderMode
{
	ScreenSpace = 1,
	WorldTextMeshPro,
	Both,
	Vanilla
}
public enum MergedColorMode
{
	HighestMultiplier = 1,
	DamageWeightedAverage,
	LastHit
}
internal sealed class VanillaDamageNumberView : IDamageNumberView
{
	private const float RecycleAfterSeconds = 2.5f;

	private readonly GameObject _root;

	private readonly Transform _rootTransform;

	private readonly DamageTextInstance _instance;

	public bool IsActive { get; private set; }

	public float StartTime { get; private set; }

	public Vector3 CurrentWorldPosition => _rootTransform.position;

	private VanillaDamageNumberView(GameObject root, DamageTextInstance instance)
	{
		_root = root;
		_rootTransform = root.transform;
		_instance = instance;
	}

	public static VanillaDamageNumberView TryCreate(Transform parent, GameObject textPrefab)
	{
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		//IL_001f: Expected O, but got Unknown
		//IL_0057: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)parent == (Object)null || (Object)(object)textPrefab == (Object)null)
		{
			return null;
		}
		GameObject val = new GameObject("SULFUR Vanilla Damage Number");
		val.transform.SetParent(parent, false);
		GameObject val2 = Object.Instantiate<GameObject>(textPrefab, val.transform);
		DamageTextInstance component = val2.GetComponent<DamageTextInstance>();
		if ((Object)(object)component == (Object)null)
		{
			Object.Destroy((Object)(object)val);
			return null;
		}
		val2.transform.localPosition = Vector3.zero;
		val.SetActive(false);
		return new VanillaDamageNumberView(val, component);
	}

	public void Play(int amount, Color color, Vector3 worldPosition, float scale, bool flyRight, bool critical)
	{
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_0012: Unknown result type (might be due to invalid IL or missing references)
		//IL_0023: Unknown result type (might be due to invalid IL or missing references)
		//IL_0040: Unknown result type (might be due to invalid IL or missing references)
		_rootTransform.position = worldPosition;
		_rootTransform.localScale = Vector3.one * Mathf.Max(0.01f, scale);
		_root.SetActive(true);
		_instance.Show(amount, color, (Vector3?)null, flyRight, critical);
		StartTime = Time.time;
		IsActive = true;
	}

	public void Tick(Camera camera, float now)
	{
		//IL_001e: Unknown result type (might be due to invalid IL or missing references)
		if (IsActive)
		{
			if ((Object)(object)camera != (Object)null)
			{
				_rootTransform.LookAt(((Component)camera).transform.position);
			}
			if (now - StartTime >= 2.5f)
			{
				IsActive = false;
			}
		}
	}

	public void Stop()
	{
		IsActive = false;
		if ((Object)(object)_root != (Object)null)
		{
			_root.SetActive(false);
		}
	}
}
internal static class VanillaDamageText
{
	private enum LoadState
	{
		Idle,
		Loading,
		Ready,
		Unavailable
	}

	private static readonly UnitId[] DummyUnitCandidates = (UnitId[])(object)new UnitId[2]
	{
		UnitIds.TargetDummy,
		UnitIds.TestDummy
	};

	private const float RetryInterval = 2f;

	private static LoadState _state;

	private static int _candidateIndex;

	private static float _nextAttemptTime;

	private static bool _unavailableLogged;

	private static AsyncOperationHandle<GameObject> _handle;

	private static bool _handleAcquired;

	private static GameObject _textPrefab;

	private static Color _colorElectric = Color.white;

	private static Color _colorExplosive = Color.white;

	private static Color _colorFire = Color.white;

	private static Color _colorFrost = Color.white;

	private static Color _colorHoly = Color.white;

	private static Color _colorPoison = Color.white;

	private static Color _colorPunish = Color.white;

	private static Color _colorShadow = Color.white;

	private static Color _colorWater = Color.white;

	public static bool IsReady
	{
		get
		{
			if (_state == LoadState.Ready)
			{
				return (Object)(object)_textPrefab != (Object)null;
			}
			return false;
		}
	}

	public static GameObject TextPrefab => _textPrefab;

	public static void Poll()
	{
		if (_state == LoadState.Unavailable)
		{
			return;
		}
		if (_state == LoadState.Ready)
		{
			if ((Object)(object)_textPrefab != (Object)null)
			{
				return;
			}
			Plugin.Log.LogWarning((object)"[DamageNumbers] The game's damage text prefab was unloaded. Reloading it.");
			ResetLookup();
		}
		try
		{
			PollInternal();
		}
		catch (Exception ex)
		{
			Plugin.Log.LogWarning((object)("[DamageNumbers] Vanilla damage text lookup failed: " + ex.Message));
			ReleaseHandle();
			_candidateIndex++;
			_state = LoadState.Idle;
			_nextAttemptTime = Time.unscaledTime + 2f;
			MarkUnavailableIfExhausted();
		}
	}

	private static void PollInternal()
	{
		//IL_0057: Unknown result type (might be due to invalid IL or missing references)
		//IL_005d: Invalid comparison between Unknown and I4
		if (_state == LoadState.Idle)
		{
			if (Time.unscaledTime < _nextAttemptTime)
			{
				return;
			}
			if (!TryStartCurrentCandidate())
			{
				_nextAttemptTime = Time.unscaledTime + 2f;
				return;
			}
			_state = LoadState.Loading;
		}
		if (!_handle.IsValid())
		{
			_state = LoadState.Idle;
		}
		else
		{
			if (!_handle.IsDone)
			{
				return;
			}
			if ((int)_handle.Status != 1 || (Object)(object)_handle.Result == (Object)null)
			{
				FailCurrentCandidate("unit prefab could not be loaded");
				return;
			}
			DamageTracker componentInChildren = _handle.Result.GetComponentInChildren<DamageTracker>(true);
			if ((Object)(object)componentInChildren == (Object)null)
			{
				FailCurrentCandidate("unit prefab has no DamageTracker");
				return;
			}
			GameObject val = ReadPrefabField(componentInChildren);
			if ((Object)(object)val == (Object)null)
			{
				FailCurrentCandidate("DamageTracker has no damage text prefab");
				return;
			}
			if ((Object)(object)val.GetComponent<DamageTextInstance>() == (Object)null)
			{
				FailCurrentCandidate("damage text prefab has no DamageTextInstance");
				return;
			}
			ReadColors(componentInChildren);
			_textPrefab = val;
			_state = LoadState.Ready;
			Plugin.Log.LogInfo((object)("[DamageNumbers] Using the game's damage text prefab '" + ((Object)val).name + "' from unit prefab '" + ((Object)_handle.Result).name + "'."));
			if (Plugin.DebugLog.Value)
			{
				Plugin.Log.LogInfo((object)("[DamageNumbers] Damage type colors read from DamageTracker: fire=" + ((object)Unsafe.As<Color, Color>(ref _colorFire)/*cast due to .constrained prefix*/).ToString() + ", poison=" + ((object)Unsafe.As<Color, Color>(ref _colorPoison)/*cast due to .constrained prefix*/).ToString() + ", frost=" + ((object)Unsafe.As<Color, Color>(ref _colorFrost)/*cast due to .constrained prefix*/).ToString() + ", electric=" + ((object)Unsafe.As<Color, Color>(ref _colorElectric)/*cast due to .constrained prefix*/).ToString() + ", explosive=" + ((object)Unsafe.As<Color, Color>(ref _colorExplosive)/*cast due to .constrained prefix*/).ToString() + ", holy=" + ((object)Unsafe.As<Color, Color>(ref _colorHoly)/*cast due to .constrained prefix*/).ToString() + ", shadow=" + ((object)Unsafe.As<Color, Color>(ref _colorShadow)/*cast due to .constrained prefix*/).ToString() + ", water=" + ((object)Unsafe.As<Color, Color>(ref _colorWater)/*cast due to .constrained prefix*/).ToString() + "."));
			}
		}
	}

	private static bool TryStartCurrentCandidate()
	{
		//IL_003e: Unknown result type (might be due to invalid IL or missing references)
		//IL_005f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0064: 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)
		//IL_008b: Unknown result type (might be due to invalid IL or missing references)
		if (_candidateIndex >= DummyUnitCandidates.Length)
		{
			MarkUnavailableIfExhausted();
			return false;
		}
		AsyncAssetLoading instance = StaticInstance<AsyncAssetLoading>.Instance;
		if ((Object)(object)instance == (Object)null || (Object)(object)instance.unitDatabase == (Object)null)
		{
			return false;
		}
		UnitSO asset = AssetAccess.GetAsset(DummyUnitCandidates[_candidateIndex]);
		if ((Object)(object)asset == (Object)null)
		{
			FailCurrentCandidate("unit asset is missing");
			return false;
		}
		_handle = asset.FetchAndLoadUnitLoader();
		if (!_handle.IsValid())
		{
			FailCurrentCandidate("unit loader handle is invalid");
			return false;
		}
		Addressables.ResourceManager.Acquire<GameObject>(_handle);
		_handleAcquired = true;
		return true;
	}

	private static void FailCurrentCandidate(string reason)
	{
		if (Plugin.DebugLog.Value && _candidateIndex < DummyUnitCandidates.Length)
		{
			Plugin.Log.LogInfo((object)("[DamageNumbers] Dummy candidate " + _candidateIndex + " rejected: " + reason + "."));
		}
		ReleaseHandle();
		_candidateIndex++;
		_state = LoadState.Idle;
		_nextAttemptTime = Time.unscaledTime + 2f;
		MarkUnavailableIfExhausted();
	}

	private static void MarkUnavailableIfExhausted()
	{
		if (_candidateIndex >= DummyUnitCandidates.Length)
		{
			_state = LoadState.Unavailable;
			if (!_unavailableLogged)
			{
				_unavailableLogged = true;
				Plugin.Log.LogWarning((object)"[DamageNumbers] The game's damage text prefab could not be found on any dummy unit. Renderer=Vanilla falls back to ScreenSpace.");
			}
		}
	}

	private static GameObject ReadPrefabField(DamageTracker tracker)
	{
		FieldInfo fieldInfo = AccessTools.Field(typeof(DamageTracker), "damageTextInstancePrefab");
		if (fieldInfo == null)
		{
			return null;
		}
		object? value = fieldInfo.GetValue(tracker);
		return (GameObject)((value is GameObject) ? value : null);
	}

	private static void ReadColors(DamageTracker tracker)
	{
		//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_0016: Unknown result type (might be due to invalid IL or missing references)
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		//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_0046: Unknown result type (might be due to invalid IL or missing references)
		//IL_004b: Unknown result type (might be due to invalid IL or missing references)
		//IL_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_0066: 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_0076: Unknown result type (might be due to invalid IL or missing references)
		//IL_007b: 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)
		//IL_008b: Unknown result type (might be due to invalid IL or missing references)
		_colorElectric = ReadColor(tracker, "colorElectric");
		_colorExplosive = ReadColor(tracker, "colorExplosive");
		_colorFire = ReadColor(tracker, "colorFire");
		_colorFrost = ReadColor(tracker, "colorFrost");
		_colorHoly = ReadColor(tracker, "colorHoly");
		_colorPoison = ReadColor(tracker, "colorPoison");
		_colorPunish = ReadColor(tracker, "colorPunish");
		_colorShadow = ReadColor(tracker, "colorShadow");
		_colorWater = ReadColor(tracker, "colorWater");
	}

	private static Color ReadColor(DamageTracker tracker, string fieldName)
	{
		//IL_0031: Unknown result type (might be due to invalid IL or missing references)
		//IL_003e: 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_0050: Unknown result type (might be due to invalid IL or missing references)
		FieldInfo fieldInfo = AccessTools.Field(typeof(DamageTracker), fieldName);
		if (fieldInfo == null || fieldInfo.FieldType != typeof(Color))
		{
			return Color.white;
		}
		Color result = (Color)fieldInfo.GetValue(tracker);
		result.a = 1f;
		return result;
	}

	public static Color GetDamageTypeColor(DamageTypes damageType)
	{
		//IL_0000: 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_003c: Expected I4, but got Unknown
		//IL_0062: 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)
		//IL_0056: 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_005c: Unknown result type (might be due to invalid IL or missing references)
		//IL_004a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0074: Unknown result type (might be due to invalid IL or missing references)
		//IL_003e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0068: 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)
		return (Color)((damageType - 1) switch
		{
			8 => _colorPoison, 
			3 => _colorFire, 
			5 => _colorHoly, 
			1 => _colorElectric, 
			2 => _colorExplosive, 
			4 => _colorFrost, 
			0 => Color.white, 
			10 => _colorShadow, 
			12 => _colorWater, 
			_ => Color.white, 
		});
	}

	public static void Shutdown()
	{
		ResetLookup();
		_candidateIndex = 0;
		_state = LoadState.Idle;
		_nextAttemptTime = 0f;
		_unavailableLogged = false;
	}

	private static void ResetLookup()
	{
		ReleaseHandle();
		_textPrefab = null;
		_state = LoadState.Idle;
		_candidateIndex = 0;
		_nextAttemptTime = 0f;
	}

	private static void ReleaseHandle()
	{
		//IL_000c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0053: Unknown result type (might be due to invalid IL or missing references)
		//IL_0025: Unknown result type (might be due to invalid IL or missing references)
		if (!_handleAcquired)
		{
			_handle = default(AsyncOperationHandle<GameObject>);
			return;
		}
		_handleAcquired = false;
		try
		{
			if (_handle.IsValid())
			{
				Addressables.Release<GameObject>(_handle);
			}
		}
		catch (Exception ex)
		{
			Plugin.Log.LogWarning((object)("[DamageNumbers] Releasing the dummy unit handle failed: " + ex.Message));
		}
		_handle = default(AsyncOperationHandle<GameObject>);
	}
}