Decompiled source of KillFeed v1.1.4

BepInEx/plugins/GTFOKillFeed/GTFOKillFeed.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.Encodings.Web;
using System.Text.Json;
using AK;
using Agents;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using CharacterDestruction;
using Enemies;
using FX_EffectSystem;
using GameData;
using HarmonyLib;
using Il2CppInterop.Runtime.Injection;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSystem.Collections.Generic;
using Player;
using SNetwork;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyFileVersion("1.1.4.0")]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = "")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.1.4.0")]
[module: UnverifiableCode]
namespace HawChow.GTFOKillFeed;

public sealed class CorpseVisualLease : MonoBehaviour
{
	private Renderer[] _renderers;

	private bool[] _enabled;

	private Rigidbody[] _bodies;

	private bool[] _kinematic;

	private bool[] _gravity;

	private float[] _drag;

	internal Vector3[] Origins;

	internal int Generation;

	internal int BodyCount
	{
		get
		{
			Rigidbody[] bodies = _bodies;
			if (bodies == null)
			{
				return 0;
			}
			return bodies.Length;
		}
	}

	internal Vector3 Center
	{
		get
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			if (_bodies != null && _bodies.Length != 0 && (Object)(object)_bodies[0] != (Object)null)
			{
				return _bodies[0].position;
			}
			return ((Component)this).transform.position;
		}
	}

	public CorpseVisualLease(IntPtr pointer)
		: base(pointer)
	{
	}

	internal void Capture()
	{
		//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
		RestoreState();
		_renderers = Il2CppArrayBase<Renderer>.op_Implicit(((Component)this).GetComponentsInChildren<Renderer>(true));
		_enabled = new bool[_renderers.Length];
		for (int i = 0; i < _renderers.Length; i++)
		{
			_enabled[i] = _renderers[i].enabled;
		}
		_bodies = Il2CppArrayBase<Rigidbody>.op_Implicit(((Component)this).GetComponentsInChildren<Rigidbody>(true));
		Origins = (Vector3[])(object)new Vector3[_bodies.Length];
		_kinematic = new bool[_bodies.Length];
		_gravity = new bool[_bodies.Length];
		_drag = new float[_bodies.Length];
		for (int j = 0; j < _bodies.Length; j++)
		{
			Rigidbody val = _bodies[j];
			Origins[j] = val.position;
			_kinematic[j] = val.isKinematic;
			_gravity[j] = val.useGravity;
			_drag[j] = val.drag;
		}
	}

	internal void Launch(Vector3 direction, float strength)
	{
		//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_004f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0054: 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_005a: 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_0086: 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_0095: Unknown result type (might be due to invalid IL or missing references)
		//IL_009b: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a5: 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_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_00b0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c8: 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_00d8: 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_00de: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
		if (_bodies == null || _bodies.Length == 0)
		{
			return;
		}
		Vector3 center = Center;
		for (int i = 0; i < _bodies.Length; i++)
		{
			Rigidbody val = _bodies[i];
			if (!((Object)(object)val == (Object)null))
			{
				val.isKinematic = false;
				val.useGravity = true;
				val.drag = 0.8f;
				Vector3 val2 = val.position - center;
				if (((Vector3)(ref val2)).sqrMagnitude < 0.01f)
				{
					val2 = direction;
				}
				else
				{
					val2.y = Mathf.Max(val2.y, 0.15f);
					Vector3 val3 = ((Vector3)(ref val2)).normalized * 0.8f + direction * 0.2f;
					val2 = ((Vector3)(ref val3)).normalized;
				}
				val.velocity = val2 * FeedbackPolicy.LaunchSpeed(strength) + Vector3.up * (1.6f + strength);
				val.angularVelocity = Vector3.Cross(val2, Vector3.up) * (1f + strength * 2f);
			}
		}
	}

	internal void Limit(float maxDistance)
	{
		//IL_0026: Unknown result type (might be due to invalid IL or missing references)
		//IL_0032: Unknown result type (might be due to invalid IL or missing references)
		//IL_0037: Unknown result type (might be due to invalid IL or missing references)
		//IL_003c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0084: Unknown result type (might be due to invalid IL or missing references)
		//IL_0089: 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_0058: 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_0063: Unknown result type (might be due to invalid IL or missing references)
		//IL_006e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0079: 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_009f: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
		if (_bodies == null)
		{
			return;
		}
		for (int i = 0; i < _bodies.Length; i++)
		{
			Rigidbody val = _bodies[i];
			if (!((Object)(object)val == (Object)null))
			{
				Vector3 val2 = val.position - Origins[i];
				if (((Vector3)(ref val2)).sqrMagnitude > maxDistance * maxDistance)
				{
					val.position = Origins[i] + ((Vector3)(ref val2)).normalized * maxDistance;
					val.velocity = Vector3.zero;
					val.angularVelocity = Vector3.zero;
				}
				Vector3 velocity = val.velocity;
				if (((Vector3)(ref velocity)).sqrMagnitude > 81f)
				{
					velocity = val.velocity;
					val.velocity = ((Vector3)(ref velocity)).normalized * 9f;
				}
			}
		}
	}

	internal void Hide()
	{
		if (_renderers == null)
		{
			return;
		}
		Renderer[] renderers = _renderers;
		foreach (Renderer val in renderers)
		{
			if ((Object)(object)val != (Object)null)
			{
				val.enabled = false;
			}
		}
	}

	internal void RestoreState()
	{
		//IL_0068: Unknown result type (might be due to invalid IL or missing references)
		//IL_0073: Unknown result type (might be due to invalid IL or missing references)
		if (_renderers != null)
		{
			for (int i = 0; i < _renderers.Length; i++)
			{
				try
				{
					if ((Object)(object)_renderers[i] != (Object)null)
					{
						_renderers[i].enabled = _enabled[i];
					}
				}
				catch
				{
				}
			}
		}
		if (_bodies != null)
		{
			for (int j = 0; j < _bodies.Length; j++)
			{
				try
				{
					Rigidbody val = _bodies[j];
					if (!((Object)(object)val == (Object)null))
					{
						val.velocity = Vector3.zero;
						val.angularVelocity = Vector3.zero;
						val.isKinematic = _kinematic[j];
						val.useGravity = _gravity[j];
						val.drag = _drag[j];
					}
				}
				catch
				{
				}
			}
		}
		_renderers = null;
		_enabled = null;
		_bodies = null;
		Origins = null;
		Generation = ((Generation == int.MaxValue) ? 1 : (Generation + 1));
	}

	private void OnDisable()
	{
		RestoreState();
	}
}
internal static class CorpseFeedback
{
	private sealed class Corpse
	{
		internal EnemyAgent Enemy;

		internal IntPtr Identity;

		internal int ModelGeneration;

		internal int RagdollGeneration;

		internal float At;

		internal float Strength;

		internal float BurstAt;

		internal float EndAt;

		internal float BodySize = 1f;

		internal Vector3 Direction;

		internal Vector3 Origin;

		internal bool Launched;

		internal bool Broken;

		internal bool Exploded;

		internal int GibDataCalls;

		internal int GibDataSetupMisses;

		internal CorpseVisualLease Model;

		internal CorpseVisualLease Ragdoll;

		internal readonly List<CD_Gib> Gibs = new List<CD_Gib>();
	}

	private static readonly List<Corpse> Active = new List<Corpse>(16);

	private static readonly Dictionary<IntPtr, Corpse> Hidden = new Dictionary<IntPtr, Corpse>();

	private static readonly Dictionary<IntPtr, Corpse> GibOwners = new Dictionary<IntPtr, Corpse>();

	private static readonly Dictionary<IntPtr, Vector3> GibOrigins = new Dictionary<IntPtr, Vector3>();

	private static readonly Dictionary<IntPtr, Vector3> GibScales = new Dictionary<IntPtr, Vector3>();

	private static FX_Pool _deathPool;

	private static Corpse _fragmentOwner;

	private static int _warnings;

	private static float _pruneAt;

	private static readonly CorpseSoundThrottle ExplosionSound = new CorpseSoundThrottle();

	private static Vector3 _pendingSoundPosition;

	private static AudioClip _customExplosionClip;

	private static bool _customExplosionLoadAttempted;

	private static void Log(string message)
	{
		Plugin instance = Plugin.Instance;
		if (instance != null)
		{
			((BasePlugin)instance).Log.LogInfo((object)("[CORPSE] " + message));
		}
	}

	internal static void Schedule(EnemyAgent enemy, Vector3 direction, float strength)
	{
		//IL_026e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0273: Unknown result type (might be due to invalid IL or missing references)
		//IL_027f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0284: Unknown result type (might be due to invalid IL or missing references)
		//IL_0201: Unknown result type (might be due to invalid IL or missing references)
		//IL_0206: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e0: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d2: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e5: Unknown result type (might be due to invalid IL or missing references)
		if (!Plugin.Enabled.Value || !Plugin.CorpseEffects.Value)
		{
			return;
		}
		if ((Object)(object)enemy == (Object)null)
		{
			Log("schedule=skipped;reason=enemy-null");
			return;
		}
		foreach (Corpse item in Active)
		{
			if (item.Identity == ((Il2CppObjectBase)enemy).Pointer)
			{
				Log($"schedule=skipped;enemyId={enemy.EnemyDataID};reason=already-active");
				return;
			}
		}
		if (Hidden.ContainsKey(((Il2CppObjectBase)enemy).Pointer))
		{
			Log($"schedule=skipped;enemyId={enemy.EnemyDataID};reason=already-hidden");
			return;
		}
		if (Active.Count >= 16)
		{
			Log($"schedule=skipped;enemyId={enemy.EnemyDataID};reason=active-cap;active={Active.Count}");
			return;
		}
		if (Hidden.Count >= 256)
		{
			Log($"schedule=skipped;enemyId={enemy.EnemyDataID};reason=hidden-cap;hidden={Hidden.Count}");
			return;
		}
		if (((Vector3)(ref direction)).sqrMagnitude < 0.01f)
		{
			Camera currentCamera = CameraManager.GetCurrentCamera();
			direction = (((Object)(object)currentCamera != (Object)null) ? ((Component)currentCamera).transform.forward : Vector3.forward);
		}
		direction.y = 0f;
		if (((Vector3)(ref direction)).sqrMagnitude < 0.01f)
		{
			direction = Vector3.forward;
		}
		float num = FeedbackPolicy.Clamp(Plugin.CorpseExplosionDelay.Value, 0.65f, 1.6f, 1.15f);
		float volume;
		float num2 = MeasureSize(enemy, out volume);
		Active.Add(new Corpse
		{
			Identity = ((Il2CppObjectBase)enemy).Pointer,
			Enemy = enemy,
			At = Time.unscaledTime,
			Strength = FeedbackPolicy.Unit(strength),
			BodySize = num2,
			Direction = ((Vector3)(ref direction)).normalized,
			Origin = ((Component)enemy).transform.position,
			BurstAt = num,
			EndAt = num + 0.75f
		});
		Log($"schedule=accepted;enemyId={enemy.EnemyDataID};strength={FeedbackPolicy.Unit(strength):0.##};bodyVolume={volume:0.###}m3;sizeFactor={num2:0.##};active={Active.Count}");
	}

	internal static void Tick(float now)
	{
		//IL_079b: Unknown result type (might be due to invalid IL or missing references)
		//IL_07a0: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
		//IL_04ba: Unknown result type (might be due to invalid IL or missing references)
		//IL_04ad: Unknown result type (might be due to invalid IL or missing references)
		//IL_04bf: Unknown result type (might be due to invalid IL or missing references)
		//IL_04ef: Unknown result type (might be due to invalid IL or missing references)
		//IL_04f1: Unknown result type (might be due to invalid IL or missing references)
		//IL_054f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0534: Unknown result type (might be due to invalid IL or missing references)
		//IL_0503: Unknown result type (might be due to invalid IL or missing references)
		//IL_0528: Unknown result type (might be due to invalid IL or missing references)
		//IL_052d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0532: Unknown result type (might be due to invalid IL or missing references)
		if (now >= _pruneAt)
		{
			_pruneAt = now + 2f;
			foreach (Corpse item in new List<Corpse>(Hidden.Values))
			{
				try
				{
					if ((Object)(object)item.Enemy == (Object)null || ((Agent)item.Enemy).Alive || ((Object)(object)item.Ragdoll != (Object)null && !FeedbackPolicy.IsLeaseCurrent(item.RagdollGeneration, item.Ragdoll.Generation)))
					{
						Release(item, removeHidden: true);
					}
				}
				catch (Exception error)
				{
					Warn(error);
					Release(item, removeHidden: true);
				}
			}
		}
		for (int num = Active.Count - 1; num >= 0; num--)
		{
			Corpse corpse = Active[num];
			try
			{
				if ((Object)(object)corpse.Enemy == (Object)null || ((Agent)corpse.Enemy).Alive || ((Object)(object)corpse.Ragdoll != (Object)null && !FeedbackPolicy.IsLeaseCurrent(corpse.RagdollGeneration, corpse.Ragdoll.Generation)))
				{
					Release(corpse, removeHidden: true);
					Active.RemoveAt(num);
				}
				else
				{
					float num2 = now - corpse.At;
					if (!Plugin.Enabled.Value || !Plugin.CorpseEffects.Value)
					{
						Release(corpse, removeHidden: true);
						Active.RemoveAt(num);
					}
					else
					{
						if (!corpse.Launched && num2 >= 0.04f)
						{
							GameObject ragdollInstance = corpse.Enemy.RagdollInstance;
							if ((Object)(object)ragdollInstance != (Object)null)
							{
								CorpseVisualLease corpseVisualLease = Lease(ragdollInstance);
								if (corpseVisualLease.BodyCount > 0)
								{
									corpse.Ragdoll = corpseVisualLease;
									corpse.Ragdoll.Launch(corpse.Direction, corpse.Strength);
									corpse.RagdollGeneration = corpse.Ragdoll.Generation;
									corpse.Launched = true;
									Log($"launch=applied;enemyId={corpse.Enemy.EnemyDataID};ragdollBodies={corpseVisualLease.BodyCount};age={num2:0.00}s;mode=radial");
								}
								else
								{
									corpseVisualLease.RestoreState();
									if (!FeedbackPolicy.ShouldWaitForRagdoll(num2, corpse.BurstAt))
									{
										corpse.Launched = true;
										Log($"launch=skipped;enemyId={corpse.Enemy.EnemyDataID};reason=ragdoll-has-no-rigidbody;age={num2:0.00}s");
									}
								}
							}
							else if (!FeedbackPolicy.ShouldWaitForRagdoll(num2, corpse.BurstAt))
							{
								corpse.Launched = true;
								Log($"launch=skipped;enemyId={corpse.Enemy.EnemyDataID};reason=ragdoll-instance-unavailable;age={num2:0.00}s");
							}
						}
						float travel = FeedbackPolicy.Travel(corpse.Strength, Plugin.MinLaunchDistance.Value, Plugin.MaxLaunchDistance.Value, corpse.BodySize) * FeedbackPolicy.Clamp(Plugin.CorpseTravelScale.Value, 0.5f, 1.5f, 1f);
						corpse.Ragdoll?.Limit(FeedbackPolicy.AppliedTravel(travel));
						LimitGibs(corpse);
						if (!corpse.Broken && num2 >= 0.12f)
						{
							corpse.Broken = true;
							int value = BreakLimbs(corpse);
							Log($"dismemberment=complete;enemyId={corpse.Enemy.EnemyDataID};limbsBroken={value};gibDataCalls={corpse.GibDataCalls};setupIdMisses={corpse.GibDataSetupMisses};gibsCaptured={corpse.Gibs.Count};attemptBudget={FeedbackPolicy.Fragments(corpse.Strength)}");
						}
						if (!corpse.Exploded && num2 >= corpse.BurstAt)
						{
							corpse.Exploded = true;
							Vector3 val = (((Object)(object)corpse.Ragdoll != (Object)null) ? corpse.Ragdoll.Center : Chest(corpse.Enemy));
							int num3 = FeedbackPolicy.BurstCount(corpse.BodySize, corpse.Strength);
							int num4 = 0;
							float num5 = FeedbackPolicy.BurstSpread(corpse.Strength, corpse.BodySize);
							for (int i = 0; i < num3; i++)
							{
								Vector3 val2 = val;
								if (i > 0)
								{
									float num6 = (float)i * 2.39996f;
									val2 += new Vector3(Mathf.Cos(num6) * num5, 0.3f + 0.25f * (float)i, Mathf.Sin(num6) * num5);
								}
								if (Explode(val2))
								{
									num4++;
								}
							}
							string value2 = RequestExplosionSound(val);
							Log($"burst=complete;enemyId={corpse.Enemy.EnemyDataID};fx={num4}/{num3};sound={value2};ragdollBodies={corpse.Ragdoll?.BodyCount ?? 0};dismembermentStage={(corpse.Broken ? "attempted" : "not-run")};gibDataCalls={corpse.GibDataCalls};setupIdMisses={corpse.GibDataSetupMisses};gibsCaptured={corpse.Gibs.Count};sizeFactor={corpse.BodySize:0.##}");
							if ((Object)(object)corpse.Enemy.MainModelGO != (Object)null)
							{
								CorpseVisualLease component = corpse.Enemy.MainModelGO.GetComponent<CorpseVisualLease>();
								corpse.Model = (((Object)(object)component != (Object)null && (Object)(object)corpse.Ragdoll != (Object)null && ((Il2CppObjectBase)component).Pointer == ((Il2CppObjectBase)corpse.Ragdoll).Pointer) ? corpse.Ragdoll : Lease(corpse.Enemy.MainModelGO));
								corpse.ModelGeneration = corpse.Model.Generation;
								corpse.Model.Hide();
							}
							corpse.Ragdoll?.Hide();
							Hidden[corpse.Identity] = corpse;
						}
						if (num2 >= corpse.EndAt)
						{
							ReleaseGibs(corpse);
							Active.RemoveAt(num);
						}
					}
				}
			}
			catch (Exception error2)
			{
				Warn(error2);
				Release(corpse, removeHidden: true);
				Active.RemoveAt(num);
			}
		}
		if (!Plugin.Enabled.Value || !Plugin.CorpseEffects.Value)
		{
			ExplosionSound.Reset();
			_pendingSoundPosition = Vector3.zero;
		}
		else
		{
			FlushExplosionSound(now);
		}
	}

	private static string RequestExplosionSound(Vector3 position)
	{
		//IL_001d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0011: Unknown result type (might be due to invalid IL or missing references)
		//IL_0012: Unknown result type (might be due to invalid IL or missing references)
		if (!ExplosionSound.Request(Time.unscaledTime))
		{
			_pendingSoundPosition = position;
			return "coalesced";
		}
		return PostExplosionSound(position);
	}

	private static void FlushExplosionSound(float now)
	{
		//IL_0012: Unknown result type (might be due to invalid IL or missing references)
		if (ExplosionSound.TryFlush(now))
		{
			Log("sound=" + PostExplosionSound(_pendingSoundPosition) + ";coalesced=true");
		}
	}

	private static string PostExplosionSound(Vector3 position)
	{
		//IL_0010: 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)
		AudioClip val = LoadExplosionSound();
		if ((Object)(object)val != (Object)null)
		{
			try
			{
				AudioSource.PlayClipAtPoint(val, position, 0.82f);
				return "custom";
			}
			catch (Exception error)
			{
				Warn(error);
			}
		}
		try
		{
			CellSound.Post(EVENTS.ENEMYEXPLODE, position);
			return "game-fallback";
		}
		catch (Exception error2)
		{
			Warn(error2);
			return "failed";
		}
	}

	private static AudioClip LoadExplosionSound()
	{
		if (_customExplosionLoadAttempted)
		{
			return _customExplosionClip;
		}
		_customExplosionLoadAttempted = true;
		try
		{
			using Stream stream = typeof(Plugin).Assembly.GetManifestResourceStream("KillFeed.Audio.corpse-burst.wav");
			if (stream == null)
			{
				throw new InvalidOperationException("Embedded corpse burst WAV is missing.");
			}
			using MemoryStream memoryStream = new MemoryStream();
			stream.CopyTo(memoryStream);
			byte[] array = memoryStream.ToArray();
			if (array.Length < 12 || Encoding.ASCII.GetString(array, 0, 4) != "RIFF" || Encoding.ASCII.GetString(array, 8, 4) != "WAVE")
			{
				throw new InvalidOperationException("Embedded corpse burst WAV has an invalid RIFF header.");
			}
			int num = 0;
			int num2 = 0;
			int num3 = 0;
			int num4 = 0;
			int num5 = -1;
			int num6 = 0;
			int num7 = 12;
			while (num7 <= array.Length - 8)
			{
				string text = Encoding.ASCII.GetString(array, num7, 4);
				int num8 = BitConverter.ToInt32(array, num7 + 4);
				int num9 = num7 + 8;
				if (num8 < 0 || num9 > array.Length - num8)
				{
					throw new InvalidOperationException("Embedded corpse burst WAV has a malformed chunk.");
				}
				if (text == "fmt ")
				{
					if (num8 < 16)
					{
						throw new InvalidOperationException("Embedded corpse burst WAV format chunk is incomplete.");
					}
					num = BitConverter.ToUInt16(array, num9);
					num2 = BitConverter.ToUInt16(array, num9 + 2);
					num3 = BitConverter.ToInt32(array, num9 + 4);
					num4 = BitConverter.ToUInt16(array, num9 + 14);
				}
				else if (text == "data")
				{
					num5 = num9;
					num6 = num8;
				}
				long num10 = (long)num9 + (long)num8 + (num8 & 1);
				if (num10 > array.Length)
				{
					throw new InvalidOperationException("Embedded corpse burst WAV chunk exceeds the file length.");
				}
				num7 = (int)num10;
			}
			if (num != 1 || num2 != 1 || num3 < 8000 || num3 > 192000 || num4 != 16 || num5 < 0 || num6 <= 0 || num6 % (num2 * (num4 / 8)) != 0)
			{
				throw new InvalidOperationException("Embedded corpse burst WAV must be mono PCM16 with a valid sample rate.");
			}
			int num11 = num6 / 2;
			float[] array2 = new float[num11];
			for (int i = 0; i < num11; i++)
			{
				int num12 = num5 + i * 2;
				short num13 = (short)(array[num12] | (array[num12 + 1] << 8));
				array2[i] = (float)num13 / 32768f;
			}
			AudioClip val = AudioClip.Create("KillFeed_CorpseBurst", num11, num2, num3, false);
			if ((Object)(object)val == (Object)null || !val.SetData(new Il2CppStructArray<float>(array2), 0))
			{
				throw new InvalidOperationException("Unity could not load the embedded corpse burst samples.");
			}
			_customExplosionClip = val;
		}
		catch (Exception error)
		{
			Warn(error);
		}
		return _customExplosionClip;
	}

	private static CorpseVisualLease Lease(GameObject obj)
	{
		CorpseVisualLease corpseVisualLease = obj.GetComponent<CorpseVisualLease>();
		if ((Object)(object)corpseVisualLease == (Object)null)
		{
			corpseVisualLease = obj.AddComponent<CorpseVisualLease>();
		}
		corpseVisualLease.Capture();
		return corpseVisualLease;
	}

	private static Vector3 Chest(EnemyAgent enemy)
	{
		//IL_0033: 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_0027: 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)
		EnemyModelRefs modelRef = enemy.ModelRef;
		Transform val = ((modelRef != null) ? modelRef.m_chestBone : null);
		if (!((Object)(object)val != (Object)null))
		{
			return ((Component)enemy).transform.position + Vector3.up;
		}
		return val.position;
	}

	private static float MeasureSize(EnemyAgent enemy, out float volume)
	{
		//IL_002c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0031: Unknown result type (might be due to invalid IL or missing references)
		//IL_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_003b: 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_0048: Unknown result type (might be due to invalid IL or missing references)
		volume = 0f;
		try
		{
			BurnableSkinnedMesh componentInChildren = ((Component)enemy).GetComponentInChildren<BurnableSkinnedMesh>(true);
			SkinnedMeshRenderer val = (((Object)(object)componentInChildren != (Object)null) ? componentInChildren.m_skinnedMesh : null);
			if ((Object)(object)val != (Object)null)
			{
				Bounds bounds = ((Renderer)val).bounds;
				Vector3 size = ((Bounds)(ref bounds)).size;
				volume = Math.Abs(size.x * size.y * size.z);
			}
		}
		catch (Exception error)
		{
			Warn(error);
		}
		return FeedbackPolicy.SizeFactor(volume);
	}

	private static int ActivateGibData(CD_CharacterDestructionCollider destruction, byte destructionId, Vector3 position, Vector3 force, int maxCalls, out bool setupMatched, out int setupMatches, out int dataEntries)
	{
		//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
		setupMatched = false;
		setupMatches = 0;
		dataEntries = 0;
		if ((Object)(object)destruction == (Object)null || maxCalls <= 0)
		{
			return 0;
		}
		List<CD_DestructionSetup> allowedDestructions = destruction.m_allowedDestructions;
		if (allowedDestructions == null)
		{
			return 0;
		}
		int num = 0;
		for (int i = 0; i < allowedDestructions.Count; i++)
		{
			if (num >= maxCalls)
			{
				break;
			}
			CD_DestructionSetup val = allowedDestructions[i];
			if ((Object)(object)val == (Object)null || val.m_id != destructionId)
			{
				continue;
			}
			setupMatched = true;
			setupMatches++;
			Il2CppReferenceArray<CD_GibData> gibDatas = val.m_gibDatas;
			if (gibDatas == null || ((Il2CppArrayBase<CD_GibData>)(object)gibDatas).Length == 0)
			{
				continue;
			}
			dataEntries += ((Il2CppArrayBase<CD_GibData>)(object)gibDatas).Length;
			for (int j = 0; j < ((Il2CppArrayBase<CD_GibData>)(object)gibDatas).Length; j++)
			{
				if (num >= maxCalls)
				{
					break;
				}
				CD_GibData val2 = ((Il2CppArrayBase<CD_GibData>)(object)gibDatas)[j];
				if (!((Object)(object)val2 == (Object)null) && !((Object)(object)val2.m_gibPrefab == (Object)null))
				{
					try
					{
						val2.Activate(position, force);
						num++;
					}
					catch (Exception error)
					{
						Warn(error);
					}
				}
			}
		}
		return num;
	}

	private static int BreakLimbs(Corpse item)
	{
		//IL_014f: Unknown result type (might be due to invalid IL or missing references)
		//IL_026c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0275: Unknown result type (might be due to invalid IL or missing references)
		//IL_0277: Unknown result type (might be due to invalid IL or missing references)
		//IL_02cd: Unknown result type (might be due to invalid IL or missing references)
		//IL_0171: Unknown result type (might be due to invalid IL or missing references)
		//IL_0178: Unknown result type (might be due to invalid IL or missing references)
		//IL_017c: Unknown result type (might be due to invalid IL or missing references)
		//IL_018c: Unknown result type (might be due to invalid IL or missing references)
		//IL_01fe: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d4: 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_00de: Unknown result type (might be due to invalid IL or missing references)
		//IL_0105: 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)
		Dam_EnemyDamageBase damage = item.Enemy.Damage;
		Il2CppReferenceArray<Dam_EnemyDamageLimb> val = ((damage != null) ? damage.DamageLimbs : null);
		if (val == null)
		{
			return 0;
		}
		int num = FeedbackPolicy.Fragments(item.Strength);
		int num2 = 0;
		_fragmentOwner = item;
		try
		{
			int num3 = ((Il2CppArrayBase<Dam_EnemyDamageLimb>)(object)val).Length - 1;
			Vector3 val4 = default(Vector3);
			sDestructionEventData val6 = default(sDestructionEventData);
			while (num3 >= 0 && num2 < num)
			{
				Dam_EnemyDamageLimb val2 = ((Il2CppArrayBase<Dam_EnemyDamageLimb>)(object)val)[num3];
				CD_CharacterDestructionCollider val3 = ((val2 != null) ? val2.m_destruction : null);
				if (!((Object)(object)val2 == (Object)null) && !val2.IsDestroyed && !((Object)(object)val3 == (Object)null) && val3.HasDestruction())
				{
					float num4 = (float)(num2 + 1) * 2.39996f;
					((Vector3)(ref val4))..ctor(Mathf.Cos(num4), 0.65f, Mathf.Sin(num4));
					Vector3 val5 = ((Vector3)(ref val4)).normalized * (1.8f + 3f * item.Strength);
					if (val3.TryDoDestruction((ImpactDirection)1, item.Direction, Vector3.zero, val5, (CD_DestructionSeverity)((item.Strength > 0.45f) ? 3 : 2), false, ref val6))
					{
						Vector3 position = ((Component)val2).transform.position;
						int value = 0;
						try
						{
							value = val3.m_allowedDestructions?.Count ?? 0;
						}
						catch (Exception error)
						{
							Warn(error);
						}
						CD_CharacterDestruction characterDestruction = val3.m_characterDestruction;
						bool value2 = false;
						if ((Object)(object)characterDestruction != (Object)null)
						{
							try
							{
								characterDestruction.ApplyDestruction((Agent)(object)item.Enemy, val6);
								value2 = true;
							}
							catch (Exception error2)
							{
								Warn(error2);
							}
						}
						if (item.GibDataCalls < 24)
						{
							bool setupMatched;
							int setupMatches;
							int dataEntries;
							int num5 = ActivateGibData(val3, val6.m_destructionID, position, ((Vector3)(ref val4)).normalized * FeedbackPolicy.GibLaunchSpeed(item.Strength), 24 - item.GibDataCalls, out setupMatched, out setupMatches, out dataEntries);
							item.GibDataCalls += num5;
							if (!setupMatched)
							{
								item.GibDataSetupMisses++;
							}
							Log($"gibdata=resolved;enemyId={item.Enemy.EnemyDataID};destructionId={val6.m_destructionID};setupMatched={setupMatched};setupMatches={setupMatches};entries={dataEntries};activateCalls={num5}");
						}
						val2.DestroyLimb(val6);
						FX_Manager.PlayEffect(true, (FX_GroupName)4, position, Quaternion.identity, false);
						Log($"destruction=local;enemyId={item.Enemy.EnemyDataID};limb={num3};destructionId={val6.m_destructionID};meshDestroyed={value2};setups={value};gibs={item.Gibs.Count}");
						num2++;
					}
				}
				num3--;
			}
		}
		finally
		{
			_fragmentOwner = null;
		}
		return num2;
	}

	internal static void GibReused(CD_Gib gib)
	{
		//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)gib == (Object)null)
		{
			return;
		}
		if (GibOwners.TryGetValue(((Il2CppObjectBase)gib).Pointer, out var value))
		{
			for (int num = value.Gibs.Count - 1; num >= 0; num--)
			{
				if (((Il2CppObjectBase)value.Gibs[num]).Pointer == ((Il2CppObjectBase)gib).Pointer)
				{
					value.Gibs.RemoveAt(num);
				}
			}
		}
		GibOwners.Remove(((Il2CppObjectBase)gib).Pointer);
		GibOrigins.Remove(((Il2CppObjectBase)gib).Pointer);
		if (GibScales.TryGetValue(((Il2CppObjectBase)gib).Pointer, out var value2))
		{
			Rigidbody rigidbody = gib.m_rigidbody;
			if ((Object)(object)rigidbody != (Object)null && (Object)(object)((Component)rigidbody).transform != (Object)null)
			{
				((Component)rigidbody).transform.localScale = value2;
			}
			GibScales.Remove(((Il2CppObjectBase)gib).Pointer);
		}
	}

	internal static void CaptureGib(CD_Gib gib)
	{
		//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
		//IL_013a: Unknown result type (might be due to invalid IL or missing references)
		//IL_013f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0143: Unknown result type (might be due to invalid IL or missing references)
		//IL_0148: Unknown result type (might be due to invalid IL or missing references)
		//IL_014a: 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_0159: Unknown result type (might be due to invalid IL or missing references)
		//IL_015e: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c2: Unknown result type (might be due to invalid IL or missing references)
		//IL_0170: Unknown result type (might be due to invalid IL or missing references)
		//IL_0188: Unknown result type (might be due to invalid IL or missing references)
		//IL_0192: Unknown result type (might be due to invalid IL or missing references)
		//IL_0197: Unknown result type (might be due to invalid IL or missing references)
		//IL_019d: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e8: 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_0108: Unknown result type (might be due to invalid IL or missing references)
		if (_fragmentOwner == null || (Object)(object)gib == (Object)null || _fragmentOwner.Gibs.Count >= 24)
		{
			return;
		}
		foreach (CD_Gib gib2 in _fragmentOwner.Gibs)
		{
			if (((Il2CppObjectBase)gib2).Pointer == ((Il2CppObjectBase)gib).Pointer)
			{
				return;
			}
		}
		_fragmentOwner.Gibs.Add(gib);
		GibOwners[((Il2CppObjectBase)gib).Pointer] = _fragmentOwner;
		Rigidbody rigidbody = gib.m_rigidbody;
		if (!((Object)(object)rigidbody == (Object)null))
		{
			GibOrigins[((Il2CppObjectBase)gib).Pointer] = rigidbody.position;
			Transform transform = ((Component)rigidbody).transform;
			if ((Object)(object)transform != (Object)null && !GibScales.ContainsKey(((Il2CppObjectBase)gib).Pointer))
			{
				GibScales[((Il2CppObjectBase)gib).Pointer] = transform.localScale;
				transform.localScale *= FeedbackPolicy.GibScale(_fragmentOwner.BodySize);
			}
			float num = (float)_fragmentOwner.Gibs.Count * 2.39996f;
			Vector3 val = new Vector3(Mathf.Cos(num), 0.7f, Mathf.Sin(num));
			Vector3 normalized = ((Vector3)(ref val)).normalized;
			Vector3 val2 = rigidbody.position - _fragmentOwner.Origin;
			if (((Vector3)(ref val2)).sqrMagnitude > 0.01f)
			{
				val2.y = Mathf.Max(val2.y, 0.25f);
				val = ((Vector3)(ref val2)).normalized * 0.7f + normalized * 0.3f;
				normalized = ((Vector3)(ref val)).normalized;
			}
			rigidbody.velocity = normalized * FeedbackPolicy.GibLaunchSpeed(_fragmentOwner.Strength);
		}
	}

	private static void LimitGibs(Corpse owner)
	{
		//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_007e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0083: Unknown result type (might be due to invalid IL or missing references)
		//IL_0093: 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_009d: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a2: 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)
		float num = FeedbackPolicy.FragmentRadius(owner.Strength, owner.BodySize);
		foreach (CD_Gib gib in owner.Gibs)
		{
			if ((Object)(object)gib == (Object)null || !GibOwners.TryGetValue(((Il2CppObjectBase)gib).Pointer, out var value) || value != owner)
			{
				continue;
			}
			Rigidbody rigidbody = gib.m_rigidbody;
			if (!((Object)(object)rigidbody == (Object)null) && GibOrigins.TryGetValue(((Il2CppObjectBase)gib).Pointer, out var value2))
			{
				Vector3 val = rigidbody.position - value2;
				if (((Vector3)(ref val)).sqrMagnitude > num * num)
				{
					rigidbody.position = value2 + ((Vector3)(ref val)).normalized * num;
					rigidbody.velocity = Vector3.zero;
				}
			}
		}
	}

	private static bool Explode(Vector3 position)
	{
		//IL_0082: Unknown result type (might be due to invalid IL or missing references)
		//IL_0083: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)_deathPool == (Object)null)
		{
			GameObject val = Resources.Load<GameObject>("FXC_FlyerDeath");
			if ((Object)(object)val == (Object)null)
			{
				Warn(new InvalidOperationException("FXC_FlyerDeath resource unavailable"));
				return false;
			}
			_deathPool = FX_Manager.CreatePool(val);
		}
		if ((Object)(object)_deathPool == (Object)null)
		{
			Warn(new InvalidOperationException("FXC_FlyerDeath pool unavailable"));
			return false;
		}
		FX_EffectBase_Poolable val2 = _deathPool.AquireEffect();
		if ((Object)(object)val2 == (Object)null)
		{
			Warn(new InvalidOperationException("FXC_FlyerDeath pool returned no effect"));
			return false;
		}
		((FX_EffectBase)val2).Play((FX_Trigger)null, position, Quaternion.identity);
		return true;
	}

	private static void ReleaseGibs(Corpse item)
	{
		CD_Gib[] array = item.Gibs.ToArray();
		foreach (CD_Gib val in array)
		{
			try
			{
				if ((Object)(object)val != (Object)null && GibOwners.TryGetValue(((Il2CppObjectBase)val).Pointer, out var value) && value == item)
				{
					GibReused(val);
					val.Deactivate();
				}
			}
			catch (Exception error)
			{
				Warn(error);
			}
		}
		item.Gibs.Clear();
	}

	private static void Release(Corpse item, bool removeHidden)
	{
		try
		{
			ReleaseGibs(item);
		}
		catch (Exception error)
		{
			Warn(error);
		}
		try
		{
			if ((Object)(object)item.Model != (Object)null && FeedbackPolicy.IsLeaseCurrent(item.ModelGeneration, item.Model.Generation))
			{
				item.Model.RestoreState();
			}
		}
		catch (Exception error2)
		{
			Warn(error2);
		}
		try
		{
			if ((Object)(object)item.Ragdoll != (Object)null && FeedbackPolicy.IsLeaseCurrent(item.RagdollGeneration, item.Ragdoll.Generation))
			{
				item.Ragdoll.RestoreState();
			}
		}
		catch (Exception error3)
		{
			Warn(error3);
		}
		if (removeHidden)
		{
			Hidden.Remove(item.Identity);
		}
	}

	internal static void Restore(EnemyAgent enemy)
	{
		if ((Object)(object)enemy == (Object)null)
		{
			return;
		}
		if (Hidden.TryGetValue(((Il2CppObjectBase)enemy).Pointer, out var value))
		{
			Release(value, removeHidden: true);
		}
		for (int num = Active.Count - 1; num >= 0; num--)
		{
			if (Active[num].Identity == ((Il2CppObjectBase)enemy).Pointer)
			{
				Release(Active[num], removeHidden: true);
				Active.RemoveAt(num);
			}
		}
	}

	internal static void Reset()
	{
		//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)
		foreach (Corpse item in Active)
		{
			Release(item, removeHidden: false);
		}
		foreach (Corpse value in Hidden.Values)
		{
			Release(value, removeHidden: false);
		}
		Active.Clear();
		Hidden.Clear();
		GibOwners.Clear();
		GibOrigins.Clear();
		GibScales.Clear();
		_deathPool = null;
		_fragmentOwner = null;
		ExplosionSound.Reset();
		_pendingSoundPosition = Vector3.zero;
	}

	private static void Warn(Exception error)
	{
		if (_warnings++ < 6)
		{
			Plugin instance = Plugin.Instance;
			if (instance != null)
			{
				((BasePlugin)instance).Log.LogWarning((object)("[CORPSE] " + error.Message));
			}
		}
	}
}
[HarmonyPatch(typeof(CD_Gib), "Activate", new Type[]
{
	typeof(Vector3),
	typeof(Vector3)
})]
internal static class GibActivatePatch
{
	[HarmonyPrefix]
	private static void Prefix(CD_Gib __instance)
	{
		KillTracker.GuardAction(delegate
		{
			CorpseFeedback.GibReused(__instance);
		});
	}

	[HarmonyPostfix]
	private static void Postfix(CD_Gib __instance)
	{
		KillTracker.GuardAction(delegate
		{
			CorpseFeedback.CaptureGib(__instance);
		});
	}
}
[HarmonyPatch(typeof(CD_Gib), "Activate", new Type[] { typeof(Vector3) })]
internal static class GibActivateSimplePatch
{
	[HarmonyPrefix]
	private static void Prefix(CD_Gib __instance)
	{
		KillTracker.GuardAction(delegate
		{
			CorpseFeedback.GibReused(__instance);
		});
	}

	[HarmonyPostfix]
	private static void Postfix(CD_Gib __instance)
	{
		KillTracker.GuardAction(delegate
		{
			CorpseFeedback.CaptureGib(__instance);
		});
	}
}
[HarmonyPatch(typeof(CD_Gib), "Deactivate")]
internal static class GibDeactivatePatch
{
	[HarmonyPrefix]
	private static void Prefix(CD_Gib __instance)
	{
		KillTracker.GuardAction(delegate
		{
			CorpseFeedback.GibReused(__instance);
		});
	}
}
internal static class DamageNumbers
{
	private sealed class Number
	{
		internal Vector3 World;

		internal float At;

		internal float Side;

		internal HitKind Kind;

		internal string Text;

		internal bool Preview;
	}

	private static readonly List<Number> Active = new List<Number>(64);

	private static int _sequence;

	private static GUIStyle _style;

	internal static void Add(Vector3 world, float damage, HitKind kind, bool preview = false)
	{
		//IL_0030: Unknown result type (might be due to invalid IL or missing references)
		//IL_003d: Unknown result type (might be due to invalid IL or missing references)
		//IL_004a: Unknown result type (might be due to invalid IL or missing references)
		//IL_008a: Unknown result type (might be due to invalid IL or missing references)
		//IL_008b: Unknown result type (might be due to invalid IL or missing references)
		if (Plugin.ShowDamageNumbers == null || !Plugin.ShowDamageNumbers.Value || !Plugin.Enabled.Value)
		{
			return;
		}
		string text = FeedbackPolicy.DamageText(damage, kind);
		if (text.Length != 0 && KillPolicy.IsFinite(world.x) && KillPolicy.IsFinite(world.y) && KillPolicy.IsFinite(world.z))
		{
			while (Active.Count >= 64)
			{
				Active.RemoveAt(0);
			}
			int num = _sequence++;
			Active.Add(new Number
			{
				World = world,
				At = Time.unscaledTime,
				Side = (float)(num % 7 - 3) * 11f,
				Kind = kind,
				Text = text,
				Preview = preview
			});
		}
	}

	internal static void Tick(float now)
	{
		float num = ((Plugin.DamageNumberLifetime != null) ? FeedbackPolicy.Clamp(Plugin.DamageNumberLifetime.Value, 0.35f, 1.2f, 0.72f) : 0.72f);
		for (int num2 = Active.Count - 1; num2 >= 0; num2--)
		{
			if (now - Active[num2].At >= num)
			{
				Active.RemoveAt(num2);
			}
		}
	}

	internal static void Draw()
	{
		//IL_0360: Unknown result type (might be due to invalid IL or missing references)
		//IL_0091: 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_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_003c: 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_004a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0056: Expected O, but got Unknown
		//IL_0121: 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_012d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0153: 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_0164: Unknown result type (might be due to invalid IL or missing references)
		//IL_0176: Unknown result type (might be due to invalid IL or missing references)
		//IL_0187: Unknown result type (might be due to invalid IL or missing references)
		//IL_01db: Unknown result type (might be due to invalid IL or missing references)
		//IL_01fd: Unknown result type (might be due to invalid IL or missing references)
		//IL_025d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0309: Unknown result type (might be due to invalid IL or missing references)
		//IL_030e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0310: Unknown result type (might be due to invalid IL or missing references)
		//IL_0317: Unknown result type (might be due to invalid IL or missing references)
		//IL_031e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0327: Unknown result type (might be due to invalid IL or missing references)
		//IL_0331: Unknown result type (might be due to invalid IL or missing references)
		//IL_0302: Unknown result type (might be due to invalid IL or missing references)
		//IL_02ec: Unknown result type (might be due to invalid IL or missing references)
		//IL_02ac: Unknown result type (might be due to invalid IL or missing references)
		if (!Plugin.ShowDamageNumbers.Value || Active.Count == 0)
		{
			return;
		}
		Camera currentCamera = CameraManager.GetCurrentCamera();
		if (_style == null)
		{
			_style = new GUIStyle(GUI.skin.label)
			{
				alignment = (TextAnchor)4,
				fontStyle = (FontStyle)1,
				clipping = (TextClipping)0,
				richText = false
			};
		}
		float num = Mathf.Clamp((float)Screen.height / 1080f, 0.75f, 1.6f);
		float num2 = FeedbackPolicy.Clamp(Plugin.DamageNumberLifetime.Value, 0.35f, 1.2f, 0.72f);
		Color color = GUI.color;
		try
		{
			Vector3 val = default(Vector3);
			Rect val2 = default(Rect);
			foreach (Number item in Active)
			{
				float num3 = Time.unscaledTime - item.At;
				if (num3 < 0f || num3 >= num2)
				{
					continue;
				}
				if (item.Preview)
				{
					((Vector3)(ref val))..ctor((float)Screen.width * 0.5f + item.World.x * num, (float)Screen.height * 0.5f, 1f);
				}
				else
				{
					if ((Object)(object)currentCamera == (Object)null)
					{
						continue;
					}
					val = currentCamera.WorldToScreenPoint(item.World);
					if (val.z <= 0.05f)
					{
						continue;
					}
					val.y = (float)Screen.height - val.y;
				}
				if (val.x < 0f || val.x > (float)Screen.width || val.y < 0f || val.y > (float)Screen.height)
				{
					continue;
				}
				float num4 = FeedbackPolicy.Clamp(Plugin.DamageNumberSize.Value, 16f, 42f, 27f) * FeedbackPolicy.NumberScale(num3, item.Kind) * num;
				_style.fontSize = Mathf.RoundToInt(num4);
				float num5 = val.x + item.Side * (0.35f + num3 * 1.7f) * num;
				float num6 = val.y + (-95f * num3 + 105f * num3 * num3) * num;
				float num7 = FeedbackPolicy.Alpha(num3, num2);
				((Rect)(ref val2))..ctor(num5 - 100f * num, num6 - num4, 200f * num, num4 * 2f);
				GUI.color = new Color(0.035f, 0.04f, 0.045f, num7);
				float num8 = 1.6f * num;
				for (int i = -1; i <= 1; i++)
				{
					for (int j = -1; j <= 1; j++)
					{
						if (i != 0 || j != 0)
						{
							GUI.Label(new Rect(((Rect)(ref val2)).x + (float)i * num8, ((Rect)(ref val2)).y + (float)j * num8, ((Rect)(ref val2)).width, ((Rect)(ref val2)).height), item.Text, _style);
						}
					}
				}
				Color val3 = (Color)((item.Kind == HitKind.Weakspot) ? KillHud.Accent : ((item.Kind == HitKind.Armor) ? new Color(0.65f, 0.72f, 0.77f) : KillHud.Ink));
				GUI.color = new Color(val3.r, val3.g, val3.b, num7);
				GUI.Label(val2, item.Text, _style);
			}
		}
		finally
		{
			GUI.color = color;
		}
	}

	internal static void Preview()
	{
		//IL_000f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0020: 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)
		Add(new Vector3(-90f, 0f, 0f), 6.75f, HitKind.Armor, preview: true);
		Add(Vector3.zero, 24.35f, HitKind.Normal, preview: true);
		Add(new Vector3(90f, 0f, 0f), 81.2f, HitKind.Weakspot, preview: true);
	}

	internal static void Clear()
	{
		Active.Clear();
	}
}
internal static class EnemyNames
{
	private sealed class NameFile
	{
		public string Source { get; set; }

		public bool UseHikariaDefaults { get; set; } = true;

		public List<NameGroup> Names { get; set; }

		public List<EnemyNameRule> Rules { get; set; } = new List<EnemyNameRule>();
	}

	private sealed class NameGroup
	{
		public List<uint> IDs { get; set; }

		public string Name { get; set; }
	}

	private static List<EnemyNameRule> _rules = new List<EnemyNameRule>();

	private static Dictionary<uint, string> _defaults = new Dictionary<uint, string>();

	private static NameFile _bundled;

	private static DateTime _stamp;

	private static float _checkAt;

	private static bool _useDefaults = true;

	private static readonly JsonSerializerOptions JsonOptions = new JsonSerializerOptions
	{
		PropertyNameCaseInsensitive = true,
		ReadCommentHandling = JsonCommentHandling.Skip,
		AllowTrailingCommas = true,
		WriteIndented = true,
		Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
	};

	internal static string FilePath => Path.Combine(Paths.ConfigPath, "HawChow.KillFeed.EnemyNames.json");

	internal static void Initialize()
	{
		try
		{
			using Stream stream = typeof(Plugin).Assembly.GetManifestResourceStream("KillFeed.EnemyNames.defaults.json");
			if (stream == null)
			{
				throw new InvalidOperationException("Bundled Hikaria name table missing.");
			}
			_bundled = JsonSerializer.Deserialize<NameFile>(stream, JsonOptions);
			_defaults = BuildDefaults(_bundled.Names);
			if (!File.Exists(FilePath))
			{
				File.WriteAllText(FilePath, JsonSerializer.Serialize(_bundled, JsonOptions));
			}
			Reload();
		}
		catch (Exception ex)
		{
			((BasePlugin)Plugin.Instance).Log.LogWarning((object)("[NAMES] initialization failed: " + ex.Message));
		}
	}

	internal static void Tick(float now)
	{
		if (now < _checkAt)
		{
			return;
		}
		_checkAt = now + 2f;
		try
		{
			if (File.GetLastWriteTimeUtc(FilePath) != _stamp)
			{
				Reload();
			}
		}
		catch (Exception ex)
		{
			((BasePlugin)Plugin.Instance).Log.LogWarning((object)("[NAMES] file check failed: " + ex.Message));
		}
	}

	internal static string Resolve(uint id, string raw)
	{
		return EnemyNamePolicy.Resolve(id, raw, _rules, _useDefaults ? _defaults : null);
	}

	private static void Reload()
	{
		//IL_010e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0114: Expected O, but got Unknown
		try
		{
			_stamp = File.GetLastWriteTimeUtc(FilePath);
			FileInfo fileInfo = new FileInfo(FilePath);
			if (!fileInfo.Exists || fileInfo.Length > 262144)
			{
				throw new FormatException("Name file missing or exceeds 256 KiB.");
			}
			NameFile nameFile = JsonSerializer.Deserialize<NameFile>(File.ReadAllText(FilePath), JsonOptions);
			if (nameFile?.Rules == null || nameFile.Rules.Count > 1024)
			{
				throw new FormatException("Rules must be an array with at most 1024 entries.");
			}
			foreach (EnemyNameRule rule in nameFile.Rules)
			{
				if (!EnemyNamePolicy.Valid(rule))
				{
					throw new FormatException("Rules need RawName and a single-line DisplayName up to 96 characters.");
				}
			}
			Dictionary<uint, string> defaults = BuildDefaults(nameFile.Names ?? _bundled?.Names ?? new List<NameGroup>());
			_rules = nameFile.Rules;
			_defaults = defaults;
			_useDefaults = nameFile.UseHikariaDefaults;
			ManualLogSource log = ((BasePlugin)Plugin.Instance).Log;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(103, 4, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[NAMES] defaults=");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(_defaults.Count);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(";enabled=");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<bool>(_useDefaults);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(";overrides=");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(_rules.Count);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(";file=");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(FilePath);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(";custom-rundown IDs may override defaults by exact raw name.");
			}
			log.LogInfo(val);
		}
		catch (Exception ex)
		{
			((BasePlugin)Plugin.Instance).Log.LogWarning((object)("[NAMES] keeping previous valid mappings: " + ex.Message));
		}
	}

	private static Dictionary<uint, string> BuildDefaults(List<NameGroup> groups)
	{
		if (groups == null || groups.Count > 1024)
		{
			throw new FormatException("Invalid default name groups.");
		}
		Dictionary<uint, string> dictionary = new Dictionary<uint, string>();
		foreach (NameGroup group in groups)
		{
			if (group.IDs == null || group.IDs.Count > 1024 || string.IsNullOrWhiteSpace(group.Name) || group.Name.Length > 96 || group.Name.Contains('\n') || group.Name.Contains('\r'))
			{
				throw new FormatException("Invalid name group.");
			}
			foreach (uint iD in group.IDs)
			{
				if (iD != 0)
				{
					dictionary[iD] = group.Name;
				}
			}
		}
		if (dictionary.Count > 4096)
		{
			throw new FormatException("Default map exceeds 4096 IDs.");
		}
		return dictionary;
	}
}
internal enum HitKind
{
	Normal,
	Armor,
	Weakspot
}
internal static class FeedbackPolicy
{
	internal const float BurstWindow = 0.65f;

	internal const float NumberLifetime = 0.72f;

	internal const float CorpseBurstDelay = 1.15f;

	internal const float CorpseSoundInterval = 0.12f;

	internal const float CorpseCleanupDelay = 1.9f;

	internal const int MaxNumbers = 64;

	internal const int MaxCorpses = 16;

	internal const float SizeBaselineVolume = 1.4f;

	internal const float SizeFactorMin = 0.7f;

	internal const float SizeFactorMax = 2.4f;

	internal const float DefaultPanelOpacity = 0f;

	internal const float DefaultMinDistance = 3.8f;

	internal const float DefaultMaxDistance = 8.5f;

	internal const float AbsoluteDistanceCeiling = 40f;

	internal static float Clamp(float value, float min, float max, float fallback)
	{
		if (KillPolicy.IsFinite(value))
		{
			return Math.Max(min, Math.Min(max, value));
		}
		return fallback;
	}

	internal static bool IsLeaseCurrent(int captured, int current)
	{
		if (captured > 0)
		{
			return captured == current;
		}
		return false;
	}

	internal static float Unit(float value)
	{
		return Clamp(value, 0f, 1f, 0f);
	}

	internal static float Strength(float burstDamage, float window = 0.65f)
	{
		window = Clamp(window, 0.2f, 1.5f, 0.65f);
		float num = Math.Max(0f, Clamp(burstDamage, 0f, 100000f, 0f)) / window;
		return Unit((float)(Math.Log(1f + num / 35f) / Math.Log(23.85714340209961)));
	}

	internal static float SizeFactor(float volume)
	{
		if (KillPolicy.IsFinite(volume) && !(volume <= 0f))
		{
			return Clamp((float)Math.Pow(volume / 1.4f, 0.3333333432674408), 0.7f, 2.4f, 1f);
		}
		return 1f;
	}

	private static float BodySize(float sizeFactor)
	{
		return Clamp(sizeFactor, 0.7f, 2.4f, 1f);
	}

	internal static float PanelAlpha(float opacity)
	{
		return Clamp(opacity, 0f, 0.9f, 0f);
	}

	internal static float RuleAlpha(float panelAlpha)
	{
		return Clamp(panelAlpha * 0.55f, 0.05f, 0.35f, 0.22f);
	}

	internal static float TravelBias(float sizeFactor)
	{
		return 0.75f + 0.25f * BodySize(sizeFactor);
	}

	internal static float LaunchBudget(float strength, float minDistance, float maxDistance)
	{
		float num = Clamp(minDistance, 0.5f, 20f, 3.8f);
		float num2 = Clamp(maxDistance, num, 30f, Math.Max(num, 8.5f));
		return num + (num2 - num) * Unit(strength);
	}

	internal static float AppliedTravel(float travel)
	{
		return Clamp(travel, 0.5f, 40f, 3.8f);
	}

	internal static float GibScale(float sizeFactor)
	{
		return BodySize(sizeFactor);
	}

	internal static float GibScatter(float sizeFactor)
	{
		return 0.6f + 0.4f * BodySize(sizeFactor);
	}

	internal static int BurstCount(float sizeFactor, float strength = 0f)
	{
		float num = Unit((BodySize(sizeFactor) - 0.7f) / 1.7f);
		return 3 + (int)Math.Round(num * 2f, MidpointRounding.AwayFromZero) + (int)Math.Round(Unit(strength) * 2f, MidpointRounding.AwayFromZero);
	}

	internal static float BurstSpread(float strength, float sizeFactor)
	{
		return 0.8f * GibScatter(sizeFactor) * (0.8f + 0.4f * Unit(strength));
	}

	internal static float GibLaunchSpeed(float strength)
	{
		return 5.5f + 6.5f * Unit(strength);
	}

	internal static bool ShouldWaitForRagdoll(float age, float burstAt)
	{
		if (KillPolicy.IsFinite(age) && KillPolicy.IsFinite(burstAt))
		{
			return age < Math.Max(0f, burstAt);
		}
		return false;
	}

	internal static float Travel(float strength)
	{
		return LaunchBudget(strength, 3.8f, 8.5f);
	}

	internal static float Travel(float strength, float sizeFactor)
	{
		return Travel(strength) * TravelBias(sizeFactor);
	}

	internal static float Travel(float strength, float minDistance, float maxDistance, float sizeFactor)
	{
		return LaunchBudget(strength, minDistance, maxDistance) * TravelBias(sizeFactor);
	}

	internal static float LaunchSpeed(float strength)
	{
		return 4.2f + 4.4f * Unit(strength);
	}

	internal static int Fragments(float strength)
	{
		return 2 + (int)Math.Floor(4f * Unit(strength));
	}

	internal static float FragmentRadius(float strength)
	{
		return 0.65f + 1.35f * Unit(strength);
	}

	internal static float FragmentRadius(float strength, float sizeFactor)
	{
		return FragmentRadius(strength) * GibScatter(sizeFactor);
	}

	internal static string DamageText(float value, HitKind kind)
	{
		if (!KillPolicy.IsFinite(value) || value < 0f)
		{
			return string.Empty;
		}
		string text = ((value > 0f && value < 0.01f) ? value.ToString("0.####", CultureInfo.InvariantCulture) : value.ToString("0.##", CultureInfo.InvariantCulture));
		return kind switch
		{
			HitKind.Armor => "[" + text + "]", 
			HitKind.Weakspot => text + "!", 
			_ => text, 
		};
	}

	internal static float NumberScale(float age, HitKind kind)
	{
		float num = Unit(age / 0.14f);
		float num2 = (float)Math.Sin((double)num * Math.PI) * (1f - num);
		return kind switch
		{
			HitKind.Armor => 0.82f, 
			HitKind.Weakspot => 1.18f, 
			_ => 1f, 
		} * (1f + 0.28f * num2);
	}

	internal static float Alpha(float age, float lifetime)
	{
		return Unit((lifetime - age) / 0.22f);
	}

	internal static float CardWidth(float iconWidth, float textWidth, float scale, float maximumWidth)
	{
		float val = Clamp(maximumWidth, 0f, 10000f, 0f);
		float val2 = Math.Max(0f, iconWidth) + 30f * Clamp(scale, 0.5f, 2f, 1f) + Math.Max(0f, Clamp(textWidth, 0f, 10000f, 0f));
		return Math.Max(0f, Math.Min(val, val2));
	}

	internal static float CenteredCardX(float screenWidth, float cardWidth, float offset, float margin = 12f)
	{
		float num = Clamp(screenWidth, 1f, 100000f, 1f);
		float num2 = Clamp(margin, 0f, num * 0.5f, 0f);
		float num3 = Clamp(cardWidth, 0f, Math.Max(0f, num - 2f * num2), Math.Max(0f, num - 2f * num2));
		float num4 = (num - num3) * 0.5f;
		return Clamp(num4 + offset, num2, Math.Max(num2, num - num3 - num2), num4);
	}

	internal static string CardDetail(KillCard card, bool distance, bool health)
	{
		string text = (distance ? (card.DistanceText + "   /   ") : string.Empty);
		if (health)
		{
			text = text + card.HealthText + "   /   ";
		}
		return text + card.EnemyName;
	}
}
internal sealed class CorpseSoundThrottle
{
	private float _nextAllowedAt;

	private bool _pending;

	internal bool HasPending => _pending;

	internal bool Request(float now)
	{
		if (!KillPolicy.IsFinite(now))
		{
			return false;
		}
		if (_pending || now < _nextAllowedAt)
		{
			_pending = true;
			return false;
		}
		_pending = false;
		_nextAllowedAt = now + 0.12f;
		return true;
	}

	internal bool TryFlush(float now)
	{
		if (!_pending || !KillPolicy.IsFinite(now) || now < _nextAllowedAt)
		{
			return false;
		}
		_pending = false;
		_nextAllowedAt = now + 0.12f;
		return true;
	}

	internal void Reset()
	{
		_nextAllowedAt = 0f;
		_pending = false;
	}
}
internal sealed class BurstHistory
{
	private readonly Dictionary<long, Queue<(float Time, float Damage)>> _entries = new Dictionary<long, Queue<(float, float)>>();

	internal void Add(long id, float now, float damage)
	{
		if (id == 0L || !KillPolicy.IsFinite(now) || !KillPolicy.IsFinite(damage) || damage <= 0f)
		{
			return;
		}
		if (!_entries.TryGetValue(id, out Queue<(float, float)> value))
		{
			if (_entries.Count >= 256)
			{
				Prune(now);
			}
			if (_entries.Count >= 256)
			{
				return;
			}
			value = (_entries[id] = new Queue<(float, float)>());
		}
		while (value.Count > 0 && now - value.Peek().Item1 > 0.65f)
		{
			value.Dequeue();
		}
		if (value.Count >= 96)
		{
			value.Dequeue();
		}
		value.Enqueue((now, damage));
	}

	internal float Sum(long id, float now)
	{
		if (!_entries.TryGetValue(id, out Queue<(float, float)> value))
		{
			return 0f;
		}
		while (value.Count > 0 && now - value.Peek().Item1 > 0.65f)
		{
			value.Dequeue();
		}
		float num = 0f;
		foreach (var item in value)
		{
			num += item.Item2;
		}
		return num;
	}

	internal void Prune(float now)
	{
		List<long> list = new List<long>();
		foreach (KeyValuePair<long, Queue<(float, float)>> entry in _entries)
		{
			Queue<(float, float)> value = entry.Value;
			while (value.Count > 0 && now - value.Peek().Item1 > 0.65f)
			{
				value.Dequeue();
			}
			if (value.Count == 0)
			{
				list.Add(entry.Key);
			}
		}
		foreach (long item in list)
		{
			_entries.Remove(item);
		}
	}

	internal void Remove(long id)
	{
		_entries.Remove(id);
	}

	internal void Clear()
	{
		_entries.Clear();
	}
}
public sealed class EnemyNameRule
{
	public uint DataBlockId { get; set; }

	public string RawName { get; set; } = string.Empty;

	public string DisplayName { get; set; } = string.Empty;
}
internal static class EnemyNamePolicy
{
	internal static string Resolve(uint id, string rawName, IReadOnlyList<EnemyNameRule> rules, IReadOnlyDictionary<uint, string> defaults = null)
	{
		rawName = (string.IsNullOrWhiteSpace(rawName) ? "Unknown" : rawName);
		if (rules == null)
		{
			rules = Array.Empty<EnemyNameRule>();
		}
		foreach (EnemyNameRule rule in rules)
		{
			if (Valid(rule) && rule.DataBlockId == id && rule.DataBlockId != 0 && string.Equals(rule.RawName, rawName, StringComparison.Ordinal))
			{
				return rule.DisplayName;
			}
		}
		foreach (EnemyNameRule rule2 in rules)
		{
			if (Valid(rule2) && rule2.DataBlockId == 0 && string.Equals(rule2.RawName, rawName, StringComparison.Ordinal))
			{
				return rule2.DisplayName;
			}
		}
		if (defaults == null || !defaults.TryGetValue(id, out var value) || string.IsNullOrWhiteSpace(value))
		{
			return rawName;
		}
		return value;
	}

	internal static bool Valid(EnemyNameRule rule)
	{
		if (rule != null && !string.IsNullOrWhiteSpace(rule.RawName) && !string.IsNullOrWhiteSpace(rule.DisplayName) && rule.RawName.Length <= 256 && rule.DisplayName.Length <= 96 && !rule.DisplayName.Contains('\n'))
		{
			return !rule.DisplayName.Contains('\r');
		}
		return false;
	}
}
public sealed class KillHud : MonoBehaviour
{
	internal static readonly Color Ink = new Color(0.91f, 0.925f, 0.92f);

	internal static readonly Color Accent = new Color(0.9f, 0.67f, 0.34f);

	private Texture2D _normalIcon;

	private Texture2D _weakIcon;

	private GUIStyle _titleStyle;

	private GUIStyle _detailStyle;

	private bool _visible = true;

	private bool _triedIcons;

	private int _warnings;

	private int _layoutLogs;

	internal static KillHud Instance;

	public KillHud(IntPtr pointer)
		: base(pointer)
	{
	}

	private void Update()
	{
		//IL_0029: 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_0035: Unknown result type (might be due to invalid IL or missing references)
		//IL_0061: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			float unscaledTime = Time.unscaledTime;
			EnemyNames.Tick(unscaledTime);
			DamageNumbers.Tick(unscaledTime);
			CorpseFeedback.Tick(unscaledTime);
			if (Plugin.Enabled.Value)
			{
				if ((int)Plugin.ToggleKey.Value != 0 && Input.GetKeyDown(Plugin.ToggleKey.Value))
				{
					_visible = !_visible;
				}
				if ((int)Plugin.PreviewKey.Value != 0 && Input.GetKeyDown(Plugin.PreviewKey.Value))
				{
					KillTracker.AddPreview(weakspot: false);
					KillTracker.AddPreview(weakspot: true);
					DamageNumbers.Preview();
				}
			}
		}
		catch (Exception ex)
		{
			Warn("update", ex.Message);
		}
	}

	private void OnGUI()
	{
		//IL_02f6: Unknown result type (might be due to invalid IL or missing references)
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		//IL_0026: Invalid comparison between Unknown and I4
		//IL_0029: Unknown result type (might be due to invalid IL or missing references)
		//IL_002e: Unknown result type (might be due to invalid IL or missing references)
		//IL_02c2: Unknown result type (might be due to invalid IL or missing references)
		//IL_01cc: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d3: Expected O, but got Unknown
		if (!_visible || Plugin.Enabled == null || !Plugin.Enabled.Value || (int)Event.current.type != 7)
		{
			return;
		}
		Color color = GUI.color;
		try
		{
			EnsureStyles();
			EnsureIcons();
			DamageNumbers.Draw();
			VisibleKillCard[] array = KillTracker.Snapshot(Time.unscaledTime);
			float num = Mathf.Clamp((float)Screen.height / 1080f, 0.75f, 1.6f);
			float num2 = FeedbackPolicy.Clamp(Plugin.IconSize.Value, 26f, 76f, 46f) * num;
			float num3 = Mathf.Max(50f * num, num2 + 10f * num);
			float maxWidth = Mathf.Max(0f, Mathf.Min((float)Screen.width - 32f, 430f * num));
			float num4 = Mathf.Clamp((float)Screen.height * 0.78f + Plugin.VerticalOffset.Value, num3 * (float)array.Length, (float)Screen.height - num3 - 12f);
			bool flag = default(bool);
			for (int i = 0; i < array.Length; i++)
			{
				float num5 = Mathf.Max(0f, Time.unscaledTime - array[i].Card.CreatedAt);
				float num6 = Mathf.Pow(1f - Mathf.Clamp01(num5 / 0.16f), 3f);
				float num7 = num4 - (float)(array.Length - 1 - i) * (num3 + 5f * num) + num6 * 7f * num;
				float num8 = MeasureCardWidth(array[i], num2, num, maxWidth);
				float num9 = FeedbackPolicy.CenteredCardX(Screen.width, num8, Plugin.HorizontalOffset.Value);
				if (_layoutLogs++ < 8)
				{
					Plugin instance = Plugin.Instance;
					if (instance != null)
					{
						ManualLogSource log = ((BasePlugin)instance).Log;
						BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(65, 7, ref flag);
						if (flag)
						{
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[HUD] card layout enemy=");
							((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(array[i].Card.EnemyName);
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral(";x=");
							((BepInExLogInterpolatedStringHandler)val).AppendFormatted<float>(num9, "0.0");
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral(";width=");
							((BepInExLogInterpolatedStringHandler)val).AppendFormatted<float>(num8, "0.0");
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral(";center=");
							((BepInExLogInterpolatedStringHandler)val).AppendFormatted<float>(num9 + num8 * 0.5f, "0.0");
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral(";screenCenter=");
							((BepInExLogInterpolatedStringHandler)val).AppendFormatted<float>((float)Screen.width * 0.5f, "0.0");
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral(";screen=");
							((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(Screen.width);
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral("x");
							((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(Screen.height);
						}
						log.LogInfo(val);
					}
				}
				DrawCard(array[i], new Rect(num9, num7, num8, num3), num2, num);
			}
		}
		catch (Exception ex)
		{
			Warn("draw", ex.Message);
		}
		finally
		{
			GUI.color = color;
		}
	}

	private float MeasureCardWidth(VisibleKillCard visible, float iconSize, float scale, float maxWidth)
	{
		//IL_0091: Unknown result type (might be due to invalid IL or missing references)
		//IL_009b: Expected O, but got Unknown
		//IL_0096: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b1: Expected O, but got Unknown
		//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
		KillCard card = visible.Card;
		bool flag = card.Kind == KillKind.Weakspot;
		string text = ((!KillPolicy.IsChinese(Plugin.Language.Value)) ? (flag ? "WEAKPOINT KILL" : "KILL CONFIRMED") : (flag ? "弱点击杀" : "击杀确认"));
		string text2 = FeedbackPolicy.CardDetail(card, Plugin.ShowDistance.Value, Plugin.ShowEnemyHealth.Value);
		_titleStyle.fontSize = Mathf.RoundToInt(13f * scale);
		_detailStyle.fontSize = Mathf.RoundToInt(12f * scale);
		float textWidth = Mathf.Max(_titleStyle.CalcSize(new GUIContent(text)).x, _detailStyle.CalcSize(new GUIContent(text2)).x);
		return FeedbackPolicy.CardWidth(iconSize, textWidth, scale, maxWidth);
	}

	private void DrawCard(VisibleKillCard visible, Rect rect, float iconSize, float scale)
	{
		//IL_0048: Unknown result type (might be due to invalid IL or missing references)
		//IL_0052: 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_0095: 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_00a7: 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_00f5: Unknown result type (might be due to invalid IL or missing references)
		//IL_011c: Unknown result type (might be due to invalid IL or missing references)
		//IL_019f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0229: Unknown result type (might be due to invalid IL or missing references)
		//IL_0255: Unknown result type (might be due to invalid IL or missing references)
		//IL_0267: Unknown result type (might be due to invalid IL or missing references)
		//IL_026e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0275: Unknown result type (might be due to invalid IL or missing references)
		//IL_027d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0287: Unknown result type (might be due to invalid IL or missing references)
		//IL_02cc: Unknown result type (might be due to invalid IL or missing references)
		//IL_02d3: Expected O, but got Unknown
		//IL_0200: Unknown result type (might be due to invalid IL or missing references)
		//IL_020a: Expected O, but got Unknown
		//IL_0205: Unknown result type (might be due to invalid IL or missing references)
		//IL_0326: Unknown result type (might be due to invalid IL or missing references)
		//IL_035e: Unknown result type (might be due to invalid IL or missing references)
		//IL_038a: Unknown result type (might be due to invalid IL or missing references)
		//IL_03c1: Unknown result type (might be due to invalid IL or missing references)
		//IL_03cb: Unknown result type (might be due to invalid IL or missing references)
		//IL_0312: Unknown result type (might be due to invalid IL or missing references)
		KillCard card = visible.Card;
		bool flag = card.Kind == KillKind.Weakspot;
		float alpha = visible.Alpha;
		float num = FeedbackPolicy.PanelAlpha((Plugin.BackgroundOpacity != null) ? Plugin.BackgroundOpacity.Value : 0f);
		GUI.color = new Color(0.055f, 0.064f, 0.068f, num * alpha);
		GUI.DrawTexture(rect, (Texture)(object)Texture2D.whiteTexture);
		GUI.color = new Color(0.28f, 0.31f, 0.32f, FeedbackPolicy.RuleAlpha(num) * alpha);
		GUI.DrawTexture(new Rect(((Rect)(ref rect)).x, ((Rect)(ref rect)).y, ((Rect)(ref rect)).width, scale), (Texture)(object)Texture2D.whiteTexture);
		Color val = (flag ? Accent : Ink);
		Rect val2 = default(Rect);
		((Rect)(ref val2))..ctor(((Rect)(ref rect)).x + 8f * scale, ((Rect)(ref rect)).y + (((Rect)(ref rect)).height - iconSize) * 0.5f, iconSize, iconSize);
		GUI.color = new Color(1f, 1f, 1f, alpha);
		Texture2D val3 = (flag ? _weakIcon : _normalIcon);
		if ((Object)(object)val3 != (Object)null)
		{
			GUI.DrawTexture(val2, (Texture)(object)val3, (ScaleMode)2, true);
		}
		float num2 = ((Rect)(ref val2)).xMax + 10f * scale;
		float num3 = ((Rect)(ref rect)).xMax - num2 - 12f * scale;
		string text = ((!KillPolicy.IsChinese(Plugin.Language.Value)) ? (flag ? "WEAKPOINT KILL" : "KILL CONFIRMED") : (flag ? "弱点击杀" : "击杀确认"));
		_titleStyle.fontSize = Mathf.RoundToInt(13f * scale);
		Rect val4 = default(Rect);
		((Rect)(ref val4))..ctor(num2, ((Rect)(ref rect)).center.y - 20f * scale, num3, 22f * scale);
		int num4 = Mathf.RoundToInt(8f * scale);
		while (_titleStyle.fontSize > num4 && _titleStyle.CalcSize(new GUIContent(text)).x > num3)
		{
			GUIStyle titleStyle = _titleStyle;
			int fontSize = titleStyle.fontSize;
			titleStyle.fontSize = fontSize - 1;
		}
		GUI.color = new Color(0f, 0f, 0f, 0.65f * alpha);
		GUI.Label(new Rect(((Rect)(ref val4)).x + scale, ((Rect)(ref val4)).y + scale, ((Rect)(ref val4)).width, ((Rect)(ref val4)).height), text, _titleStyle);
		GUI.color = new Color(val.r, val.g, val.b, alpha);
		GUI.Label(val4, text, _titleStyle);
		string text2 = FeedbackPolicy.CardDetail(card, Plugin.ShowDistance.Value, Plugin.ShowEnemyHealth.Value);
		_detailStyle.fontSize = Mathf.RoundToInt(12f * scale);
		GUIContent val5 = new GUIContent(text2);
		int num5 = Mathf.RoundToInt(8f * scale);
		while (_detailStyle.fontSize > num5 && _detailStyle.CalcSize(val5).x > num3)
		{
			GUIStyle detailStyle = _detailStyle;
			int fontSize = detailStyle.fontSize;
			detailStyle.fontSize = fontSize - 1;
		}
		Rect val6 = default(Rect);
		((Rect)(ref val6))..ctor(num2, ((Rect)(ref rect)).center.y + 1f * scale, num3, 19f * scale);
		GUI.color = new Color(0f, 0f, 0f, 0.65f * alpha);
		GUI.Label(new Rect(((Rect)(ref val6)).x + scale, ((Rect)(ref val6)).y + scale, ((Rect)(ref val6)).width, ((Rect)(ref val6)).height), text2, _detailStyle);
		GUI.color = new Color(Ink.r, Ink.g, Ink.b, 0.96f * alpha);
		GUI.Label(val6, text2, _detailStyle);
	}

	private void EnsureStyles()
	{
		//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)
		//IL_0021: 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_002f: 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_0042: Expected O, but got Unknown
		//IL_004d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0052: Unknown result type (might be due to invalid IL or missing references)
		//IL_005a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0061: 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_0074: Expected O, but got Unknown
		if (_titleStyle == null)
		{
			_titleStyle = new GUIStyle(GUI.skin.label)
			{
				fontSize = 15,
				fontStyle = (FontStyle)1,
				alignment = (TextAnchor)3,
				clipping = (TextClipping)1,
				richText = false
			};
			_detailStyle = new GUIStyle(GUI.skin.label)
			{
				fontSize = 13,
				alignment = (TextAnchor)3,
				clipping = (TextClipping)1,
				richText = false
			};
		}
	}

	private void EnsureIcons()
	{
		//IL_007d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0083: Expected O, but got Unknown
		if (!_triedIcons)
		{
			_triedIcons = true;
			string path = Path.Combine(Path.GetDirectoryName(typeof(Plugin).Assembly.Location) ?? string.Empty, "Assets", "icons");
			_normalIcon = LoadIcon(Path.Combine(path, "kill-normal.png"));
			_weakIcon = LoadIcon(Path.Combine(path, "kill-weakspot.png"));
			ManualLogSource log = ((BasePlugin)Plugin.Instance).Log;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(72, 2, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[HUD] icons ready normal=");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<bool>((Object)(object)_normalIcon != (Object)null);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(";weakspot=");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<bool>((Object)(object)_weakIcon != (Object)null);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(";layout=two-line;health-tiers=removed");
			}
			log.LogInfo(val);
		}
	}

	private static Texture2D LoadIcon(string path)
	{
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0014: Expected O, but got Unknown
		if (!File.Exists(path))
		{
			return null;
		}
		Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false);
		if (!ImageConversion.LoadImage(val, Il2CppStructArray<byte>.op_Implicit(File.ReadAllBytes(path))))
		{
			Object.Destroy((Object)(object)val);
			return null;
		}
		((Object)val).hideFlags = (HideFlags)61;
		return val;
	}

	private void Warn(string stage, string detail)
	{
		if (_warnings++ < 5)
		{
			Plugin instance = Plugin.Instance;
			if (instance != null)
			{
				((BasePlugin)instance).Log.LogWarning((object)("[HUD] " + stage + ": " + detail));
			}
		}
	}
}
internal enum KillKind
{
	Normal,
	Weakspot
}
internal enum KillTier
{
	Minor,
	Elite,
	Boss
}
internal readonly struct KillDecision
{
	internal readonly bool Credited;

	internal readonly KillKind Kind;

	internal KillDecision(bool credited, KillKind kind)
	{
		Credited = credited;
		Kind = kind;
	}
}
internal static class KillDefaults
{
	internal const bool Enabled = true;

	internal const float IconSize = 46f;

	internal const float CardLifetime = 2.6f;

	internal const float FadeSeconds = 0.45f;

	internal const float MaxDistance = 999f;

	internal const float MinorHealthThreshold = 120f;

	internal const float EliteHealthThreshold = 1000f;

	internal const int MaxCards = 3;
}
internal static class KillPolicy
{
	internal static KillDecision ClassifyLethalHit(bool localPlayerSource, float healthBefore, float healthAfter, bool limbObserved, bool limbIsWeakspot)
	{
		bool flag = IsFinite(healthBefore) && IsFinite(healthAfter) && healthBefore > 0f && healthAfter <= 0f;
		if (!localPlayerSource || !flag)
		{
			return new KillDecision(credited: false, KillKind.Normal);
		}
		return new KillDecision(credited: true, (limbObserved && limbIsWeakspot) ? KillKind.Weakspot : KillKind.Normal);
	}

	internal static KillTier ClassifyTier(float healthMax, float minorThreshold = 120f, float eliteThreshold = 1000f)
	{
		if (!IsFinite(minorThreshold) || minorThreshold <= 0f)
		{
			minorThreshold = 120f;
		}
		if (!IsFinite(eliteThreshold) || eliteThreshold <= minorThreshold)
		{
			eliteThreshold = Math.Max(1000f, minorThreshold + 1f);
		}
		if (!IsFinite(healthMax) || healthMax < 0f)
		{
			return KillTier.Minor;
		}
		if (healthMax < minorThreshold)
		{
			return KillTier.Minor;
		}
		if (healthMax < eliteThreshold)
		{
			return KillTier.Elite;
		}
		return KillTier.Boss;
	}

	internal static string FormatDistance(float meters, float maximum = 999f)
	{
		if (!IsFinite(meters) || meters < 0f)
		{
			return "—";
		}
		if (!IsFinite(maximum) || maximum < 1f)
		{
			maximum = 999f;
		}
		if (meters > maximum)
		{
			return ((int)Math.Floor(maximum + 0.5f)).ToString(CultureInfo.InvariantCulture) + "m+";
		}
		return ((int)Math.Floor(meters + 0.5f)).ToString(CultureInfo.InvariantCulture) + "m";
	}

	internal static string FormatHealth(float healthMax)
	{
		if (!IsFinite(healthMax) || healthMax < 0f)
		{
			return "— HP";
		}
		return healthMax.ToString("0.#", CultureInfo.InvariantCulture) + " HP";
	}

	internal static string IconKey(KillKind kind)
	{
		if (kind != KillKind.Weakspot)
		{
			return "kill-normal.png";
		}
		return "kill-weakspot.png";
	}

	internal static bool IsChinese(string language)
	{
		if (!string.Equals(language, "zh", StringComparison.OrdinalIgnoreCase) && !string.Equals(language, "zh-CN", StringComparison.OrdinalIgnoreCase))
		{
			return string.Equals(language, "cn", StringComparison.OrdinalIgnoreCase);
		}
		return true;
	}

	internal static string TierLabel(KillTier tier, string language)
	{
		if (!IsChinese(language))
		{
			return tier switch
			{
				KillTier.Elite => "ELITE", 
				KillTier.Minor => "MINOR", 
				_ => "BOSS", 
			};
		}
		return tier switch
		{
			KillTier.Elite => "精英", 
			KillTier.Minor => "普通", 
			_ => "BOSS", 
		};
	}

	internal static bool IsFinite(float value)
	{
		if (!float.IsNaN(value))
		{
			return !float.IsInfinity(value);
		}
		return false;
	}
}
internal sealed class KillLedger
{
	private readonly HashSet<long> _credited = new HashSet<long>();

	internal int Count => _credited.Count;

	internal bool TryCredit(long enemyIdentity)
	{
		if (enemyIdentity != 0L)
		{
			return _credited.Add(enemyIdentity);
		}
		return false;
	}

	internal void Reset()
	{
		_credited.Clear();
	}

	internal void Forget(long enemyIdentity)
	{
		_credited.Remove(enemyIdentity);
	}
}
internal sealed class KillCard
{
	internal readonly KillKind Kind;

	internal readonly KillTier Tier;

	internal readonly string EnemyName;

	internal readonly string DistanceText;

	internal readonly string HealthText;

	internal readonly float CreatedAt;

	internal KillCard(KillKind kind, KillTier tier, string enemyName, float distanceMeters, float healthMax, float createdAt, float maxDistance = 999f)
	{
		Kind = kind;
		Tier = tier;
		EnemyName = (string.IsNullOrWhiteSpace(enemyName) ? "Unknown" : enemyName.Trim());
		DistanceText = KillPolicy.FormatDistance(distanceMeters, maxDistance);
		HealthText = KillPolicy.FormatHealth(healthMax);
		CreatedAt = createdAt;
	}
}
internal readonly struct VisibleKillCard
{
	internal readonly KillCard Card;

	internal readonly float Alpha;

	internal VisibleKillCard(KillCard card, float alpha)
	{
		Card = card;
		Alpha = alpha;
	}
}
internal sealed class KillCardQueue
{
	private readonly List<KillCard> _cards = new List<KillCard>();

	internal int Count => _cards.Count;

	internal bool Enqueue(KillCard card, float now, float lifetime, float fadeSeconds, int capacity)
	{
		if (card == null || capacity <= 0 || !KillPolicy.IsFinite(now))
		{
			return false;
		}
		lifetime = (KillPolicy.IsFinite(lifetime) ? Math.Max(0.1f, lifetime) : 2.6f);
		fadeSeconds = (KillPolicy.IsFinite(fadeSeconds) ? Math.Max(0f, Math.Min(fadeSeconds, lifetime)) : 0.45f);
		Trim(now, lifetime);
		while (_cards.Count >= capacity)
		{
			_cards.RemoveAt(0);
		}
		_cards.Add(card);
		return true;
	}

	internal VisibleKillCard[] Snapshot(float now, float lifetime, float fadeSeconds, int capacity)
	{
		if (!KillPolicy.IsFinite(now))
		{
			return Array.Empty<VisibleKillCard>();
		}
		lifetime = (KillPolicy.IsFinite(lifetime) ? Math.Max(0.1f, lifetime) : 2.6f);
		fadeSeconds = (KillPolicy.IsFinite(fadeSeconds) ? Math.Max(0f, Math.Min(fadeSeconds, lifetime)) : 0.45f);
		Trim(now, lifetime);
		int num = Math.Max(0, _cards.Count - Math.Max(0, capacity));
		VisibleKillCard[] array = new VisibleKillCard[_cards.Count - num];
		for (int i = num; i < _cards.Count; i++)
		{
			KillCard killCard = _cards[i];
			float num2 = Math.Max(0f, now - killCard.CreatedAt);
			float alpha = ((fadeSeconds <= 0f || num2 <= lifetime - fadeSeconds) ? 1f : Math.Max(0f, Math.Min(1f, (lifetime - num2) / fadeSeconds)));
			array[i - num] = new VisibleKillCard(killCard, alpha);
		}
		return array;
	}

	internal void Clear()
	{
		_cards.Clear();
	}

	private void Trim(float now, float lifetime)
	{
		for (int num = _cards.Count - 1; num >= 0; num--)
		{
			if (now - _cards[num].CreatedAt >= lifetime)
			{
				_cards.RemoveAt(num);
			}
		}
	}
}
internal sealed class DamageRoot
{
	internal IntPtr EnemyPointer;

	internal float HealthBefore;

	internal bool LocalSource;

	internal bool LimbObserved;

	internal bool Weakspot;

	internal bool Credited;

	internal bool HitRecorded;

	internal bool HasValue;

	internal bool Processed;

	internal ulong PlayerLookup;

	internal HitKind Kind;

	internal float Damage;

	internal Vector3 Position;

	internal Vector3 Direction;
}
internal sealed class DamageScope
{
	internal DamageScope Previous;

	internal DamageRoot Root;
}
internal static class KillTracker
{
	private static readonly KillLedger Ledger = new KillLedger();

	private static readonly KillCardQueue Cards = new KillCardQueue();

	private static readonly BurstHistory Bursts = new BurstHistory();

	[ThreadStatic]
	private static DamageScope _active;

	private static int _diagnosticBudget = 12;

	internal static void Reset()
	{
		Ledger.Reset();
		Cards.Clear();
		Bursts.Clear();
		_active = null;
		DamageNumbers.Clear();
		CorpseFeedback.Reset();
	}

	internal static void Spawned(Dam_EnemyDamageBase enemy)
	{
		if (!((Object)(object)enemy == (Object)null))
		{
			Ledger.Forget(((Il2CppObjectBase)enemy).Pointer.ToInt64());
			Bursts.Remove(((Il2CppObjectBase)enemy).Pointer.ToInt64());
		}
	}

	private static DamageScope Begin(Dam_EnemyDamageBase enemy, Agent sourceAgent, int limbId, Vector3 position, Vector3 direction)
	{
		//IL_00ad: 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_00b4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
		//IL_0104: Invalid comparison between Unknown and I4
		//IL_0115: Unknown result type (might be due to invalid IL or missing references)
		//IL_011b: Invalid comparison between Unknown and I4
		(bool, ulong) tuple = ResolveSource(sourceAgent);
		IntPtr intPtr = (((Object)(object)enemy != (Object)null) ? ((Il2CppObjectBase)enemy).Pointer : IntPtr.Zero);
		DamageRoot damageRoot = _active?.Root;
		if (damageRoot == null || damageRoot.HitRecorded || damageRoot.EnemyPointer != intPtr || damageRoot.PlayerLookup != tuple.Item2 || damageRoot.LocalSource != tuple.Item1)
		{
			damageRoot = new DamageRoot
			{
				Kind = HitKind.Normal,
				EnemyPointer = intPtr,
				HealthBefore = (((Object)(object)enemy != (Object)null) ? ((Dam_SyncedDamageBase)enemy).Health : 0f),
				LocalSource = tuple.Item1,
				PlayerLookup = tuple.Item2,
				Position = position,
				Direction = direction
			};
		}
		if ((Object)(object)enemy != (Object)null && limbId >= 0 && enemy.DamageLimbs != null && limbId < ((Il2CppArrayBase<Dam_EnemyDamageLimb>)(object)enemy.DamageLimbs).Length)
		{
			Dam_EnemyDamageLimb val = ((Il2CppArrayBase<Dam_EnemyDamageLimb>)(object)enemy.DamageLimbs)[limbId];
			if ((Object)(object)val != (Object)null)
			{
				damageRoot.LimbObserved = true;
				damageRoot.Weakspot = (int)val.m_type == 1;
				damageRoot.Kind = (damageRoot.Weakspot ? HitKind.Weakspot : (((int)val.m_type == 2) ? HitKind.Armor : HitKind.Normal));
			}
		}
		return _active = new DamageScope
		{
			Previous = _active,
			Root = damageRoot
		};
	}

	internal static DamageScope BeginLimb(Dam_EnemyDamageLimb limb, float damage, Agent source, Vector3 position, Vector3 direction, float precision, bool behind, bool melee, float backstabber = 1f, float sleeper = 1f)
	{
		//IL_0027: 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_0085: Unknown result type (might be due to invalid IL or missing references)
		//IL_008c: Invalid comparison between Unknown and I4
		//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
		Dam_EnemyDamageBase val = (((Object)(object)limb != (Object)null) ? limb.m_base : null);
		DamageScope damageScope = Begin(val, source, ((Object)(object)limb != (Object)null) ? limb.m_limbID : (-1), position, direction);
		DamageRoot root = damageScope.Root;
		if (!root.LocalSource || root.HealthBefore <= 0f || (Object)(object)val == (Object)null || (Object)(object)limb == (Object)null)
		{
			return damageScope;
		}
		try
		{
			float num = AgentModifierManager.ApplyModifier((Agent)(object)val.Owner, (AgentModifier)(melee ? 6 : 7), damage);
			if (melee && (int)val.Owner.Locomotion.CurrentStateEnum == 14)
			{
				num *= sleeper;
			}
			num = limb.ApplyWeakspotAndArmorModifiers(num, precision);
			if (behind)
			{
				num = limb.ApplyDamageFromBehindBonus(num, position, direction, backstabber);
			}
			root.Damage = Dam_EnemyDamageBase.RoundDamage(num);
			root.HasValue = KillPolicy.IsFinite(root.Damage) && root.Damage >= 0f;
		}
		catch (Exception ex)
		{
			Note("modifier capture unavailable: " + ex.GetType().Name);
		}
		return damageScope;
	}

	internal static DamageScope BeginBullet(Dam_EnemyDamageBase enemy, pBulletDamageData data)
	{
		//IL_0018: 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_003e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0027: 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)
		Agent sourceAgent = null;
		try
		{
			((pAgent)(ref data.source)).TryGet(ref sourceAgent);
		}
		catch
		{
		}
		return Begin(enemy, sourceAgent, data.limbID, ((Object)(object)enemy != (Object)null) ? (((Component)enemy).transform.position + Vector3.up) : Vector3.zero, Vector3.zero);
	}

	internal static DamageScope BeginProcessedDamage(Dam_EnemyDamageBase enemy, Agent source, float damage, Vector3 position, Vector3 direction, int limbId)
	{
		//IL_0004: Unknown result type (might be due to invalid IL or missing references)
		//IL_0005: 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_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_0059: Unknown result type (might be due to invalid IL or missing references)
		DamageScope damageScope = Begin(enemy, source, limbId, position, direction);
		damageScope.Root.Processed = true;
		damageScope.Root.Damage = damage;
		damageScope.Root.HasValue = KillPolicy.IsFinite(damage) && damage >= 0f;
		damageScope.Root.Position = position;
		damageScope.Root.Direction = direction;
		return damageScope;
	}

	private static void RecordHit(Dam_EnemyDamageBase enemy, DamageRoot root)
	{
		//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
		if (root.HitRecorded || !root.LocalSource || root.HealthBefore <= 0f)
		{
			return;
		}
		root.HitRecorded = true;
		float num = (root.HasValue ? root.Damage : Math.Max(0f, root.HealthBefore - ((Dam_SyncedDamageBase)enemy).Health));
		if (KillPolicy.IsFinite(num) && !(num < 0f))
		{
			if (root.Processed && ((Dam_SyncedDamageBase)enemy).Health >= root.HealthBefore)
			{
				num = 0f;
			}
			if (num > 0f)
			{
				Bursts.Add(root.EnemyPointer.ToInt64(), Time.unscaledTime, num);
			}
			if (num > 0f || root.Kind == HitKind.Armor)
			{
				DamageNumbers.Add(root.Position, num, root.Kind);
				Note($"number={num:0.####};kind={root.Kind};source={(root.Processed ? "final-settlement" : (root.HasValue ? "native-modifiers" : "health-delta"))}");
			}
		}
	}

	internal static void Complete(Dam_EnemyDamageBase enemy, DamageScope scope)
	{
		//IL_015e: Unknown result type (might be due to invalid IL or missing references)
		//IL_019b: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a2: Expected O, but got Unknown
		//IL_00c4: 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)
		if ((Object)(object)enemy == (Object)null || scope?.Root == null)
		{
			return;
		}
		DamageRoot root = scope.Root;
		if (root.EnemyPointer != ((Il2CppObjectBase)enemy).Pointer || !root.LocalSource)
		{
			return;
		}
		RecordHit(enemy, root);
		KillDecision killDecision = KillPolicy.ClassifyLethalHit(root.LocalSource, root.HealthBefore, ((Dam_SyncedDamageBase)enemy).Health, root.LimbObserved, root.Weakspot);
		if (!killDecision.Credited || root.Credited || !Ledger.TryCredit(root.EnemyPointer.ToInt64()))
		{
			return;
		}
		root.Credited = true;
		EnemyAgent owner = enemy.Owner;
		if ((Object)(object)owner == (Object)null)
		{
			return;
		}
		float distanceMeters = float.NaN;
		try
		{
			PlayerAgent localPlayerAgent = PlayerManager.GetLocalPlayerAgent();
			if ((Object)(object)localPlayerAgent != (Object)null)
			{
				distanceMeters = Vector3.Distance(((Component)localPlayerAgent).transform.position, ((Component)owner).transform.position);
			}
		}
		catch
		{
		}
		string text = ResolveEnemyName(owner);
		string text2 = EnemyNames.Resolve(owner.EnemyDataID, text);
		KillCard killCard = new KillCard(killDecision.Kind, KillTier.Minor, text2, distanceMeters, ((Dam_SyncedDamageBase)enemy).HealthMax, Time.unscaledTime, Plugin.MaxDistance?.Value ?? 999f);
		Cards.Enqueue(killCard, Time.unscaledTime, Plugin.CardLifetime.Value, Plugin.FadeSeconds.Value, ClampCards(Plugin.MaxCards.Value));
		CorpseFeedback.Schedule(owner, root.Direction, FeedbackPolicy.Strength(Bursts.Sum(root.EnemyPointer.ToInt64(), Time.unscaledTime)));
		ManualLogSource log = ((BasePlugin)Plugin.Instance).Log;
		bool flag = default(bool);
		BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(82, 6, ref flag);
		if (flag)
		{
			((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[KILLFEED] classification=");
			((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>((killDecision.Kind == KillKind.Weakspot) ? "WEAKSPOT" : "NORMAL");
			((BepInExLogInterpolatedStringHandler)val).AppendLiteral(";enemyId=");
			((BepInExLogInterpolatedStringHandler)val).AppendFormatted<uint>(owner.EnemyDataID);
			((BepInExLogInterpolatedStringHandler)val).AppendLiteral(";rawName=");
			((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(text);
			((BepInExLogInterpolatedStringHandler)val).AppendLiteral(";displayName=");
			((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(text2);
			((BepInExLogInterpolatedStringHandler)val).AppendLiteral(";distance=");
			((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(killCard.DistanceText);
			((BepInExLogInterpolatedStringHandler)val).AppendLiteral(";limbObserved=");
			((BepInExLogInterpolatedStringHandler)val).AppendFormatted<bool>(root.LimbObserved);
			((BepInExLogInterpolatedStringHandler)val).AppendLiteral(".");
		}
		log.LogInfo(val);
	}

	internal static void CompleteFromAgent(EnemyAgent agent)
	{
		if ((Object)(object)((agent != null) ? agent.Damage : null) != (Object)null && _active?.Root?.EnemyPointer == ((Il2CppObjectBase)agent.Damage).Pointer)
		{
			Complete(agent.Damage, _active);
		}
	}

	internal static void CompleteFromActive(Dam_EnemyDamageBase enemy)
	{
		if ((Object)(object)enemy != (Object)null && _active?.Root?.EnemyPointer == ((Il2CppObjectBase)enemy).Pointer)
		{
			Complete(enemy, _active);
		}
	}

	internal static Exception End(Dam_EnemyDamageBase enemy, DamageScope scope, Exception error)
	{
		try
		{
			if (error == null)
			{
				Complete(enemy, scope);
			}
		}
		catch (Exception ex)
		{
			Note("capture skipped: " + ex.Message);
		}
		finally
		{
			if (_active == scope)
			{
				_active = scope?.Previous;
			}
		}
		return error;
	}

	internal static VisibleKillCard[] Snapshot(float now)
	{
		return Cards.Snapshot(now, Plugin.CardLifetime.Value, Plugin.FadeSeconds.Value, ClampCards(Plugin.MaxCards.Value));
	}

	internal static void AddPreview(bool weakspot)
	{
		Cards.Enqueue(new KillCard(weakspot ? KillKind.Weakspot : KillKind.Normal, KillTier.Minor, weakspot ? "大壮" : "小白", weakspot ? 13f : 27f, weakspot ? 120f : 80f, Time.unscaledTime), Time.unscaledTime, Plugin.CardLifetime.Value, Plugin.FadeSeconds.Value, ClampCards(Plugin.MaxCards.Value));
	}

	internal static void ObserveState(eGameStateName state)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0003: Invalid comparison between Unknown and I4
		if ((int)state != 10)
		{
			Reset();
		}
	}

	internal static void LogPatchReceipts(Harmony harmony, ManualLogSource log)
	{
		//IL_0025: Unknown result type (might be due to invalid IL or missing references)
		//IL_002b: Expected O, but got Unknown
		bool flag = default(bool);
		foreach (MethodBase patchedMethod in harmony.GetPatchedMethods())
		{
			Patches patchInfo = Harmony.GetPatchInfo(patchedMethod);
			BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(33, 5, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[DIAG] patch ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(patchedMethod.DeclaringType.Name);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(".");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(patchedMethod.Name);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(": pre=");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(patchInfo.Prefixes.Count);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(",post=");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(patchInfo.Postfixes.Count);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(",final=");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(patchInfo.Finalizers.Count);
			}
			log.LogInfo(val);
		}
	}

	private static int ClampCards(int value)
	{
		return Math.Max(1, Math.Min(6, value));
	}

	private static (bool Local, ulong Lookup) ResolveSource(Agent source)
	{
		try
		{
			object obj;
			if (source == null)
			{
				obj = null;
			}
			else
			{
				PlayerAgent obj2 = ((Il2CppObjectBase)source).TryCast<PlayerAgent>();
				obj = ((obj2 != null) ? obj2.Owner : null);
			}
			SNet_Player val = (SNet_Player)obj;
			return ((Object)(object)val != (Object)null && val.IsLocal) ? (Local: true, Lookup: val.Lookup) : (Local: false, Lookup: 0uL);
		}
		catch
		{
			return (Local: false, Lookup: 0uL);
		}
	}

	private static string ResolveEnemyName(EnemyAgent agent)
	{
		try
		{
			EnemyDataBlock block = GameDataBlockBase<EnemyDataBlock>.GetBlock(agent.EnemyDataID);
			if (block != null && !string.IsNul