Decompiled source of DamageLog v1.1.2

plugins/DamageLog/DamageLog.dll

Decompiled a month ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using RoR2;
using RoR2.UI;
using TMPro;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.Networking;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")]
[assembly: AssemblyCompany("DamageLog")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+dbff6a40faa85d22ce963c8b86a6ab65bd48c222")]
[assembly: AssemblyProduct("DamageLog")]
[assembly: AssemblyTitle("DamageLog")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace DamageLog
{
	internal static class ConfigUtility
	{
		public static ConfigEntry<string> BindInputKey(this ConfigFile config, string section, string key, string defaultInputKey, string description)
		{
			ConfigEntry<string> val = config.Bind<string>(section, key, defaultInputKey, description + "\nKey names follow the naming conventions outlined at: https://docs.unity3d.com/2019.4/Documentation/Manual/class-InputManager.html#:~:text=Key%20family");
			try
			{
				Input.GetKeyDown(val.Value);
			}
			catch (ArgumentException)
			{
				Log.Warning("Config> " + section + "." + key + " | '" + val.Value + "' is not a valid input key string, using '" + defaultInputKey + "' instead.");
				val.Value = defaultInputKey;
			}
			return val;
		}
	}
	internal sealed class Config
	{
		private readonly ConfigEntry<bool> trackBosses;

		private readonly ConfigEntry<float> entryMaxRetainTime;

		private readonly ConfigEntry<int> entryMaxCount;

		private readonly ConfigEntry<bool> onlyShowWithScoreboard;

		private readonly ConfigEntry<bool> showDamageIdentifier;

		private readonly ConfigEntry<bool> useSimpleTextMode;

		private readonly ConfigEntry<string> cycleUserKey;

		private readonly ConfigEntry<string> cycleBossKey;

		private readonly ConfigEntry<float> textSize;

		private readonly ConfigEntry<float> portraitSpacing;

		private readonly ConfigEntry<float> portraitSize;

		private readonly ConfigEntry<float> eliteIconSize;

		private readonly ConfigEntry<float> portraitTextSize;

		private readonly ConfigEntry<float> damageTextSize;

		public bool TrackBosses => trackBosses.Value;

		public float EntryMaxRetainTime
		{
			get
			{
				if (!(entryMaxRetainTime.Value < 1f))
				{
					return entryMaxRetainTime.Value;
				}
				return 1f;
			}
		}

		public int EntryMaxCount
		{
			get
			{
				if (entryMaxCount.Value <= 0)
				{
					return 1;
				}
				return entryMaxCount.Value;
			}
		}

		public bool OnlyShowWithScoreboard => onlyShowWithScoreboard.Value;

		public bool ShowIdentifier => showDamageIdentifier.Value;

		public bool SimpleTextMode => useSimpleTextMode.Value;

		public string CycleUserKey => cycleUserKey.Value;

		public string CycleBossKey => cycleBossKey.Value;

		public float TextSize => textSize.Value;

		public float Spacing => portraitSpacing.Value;

		public float PortraitSize => portraitSize.Value;

		public float EliteIconSize => eliteIconSize.Value;

		public float PortraitTextSize => portraitTextSize.Value;

		public float DamageTextSize => damageTextSize.Value;

		public Config(ConfigFile config)
		{
			trackBosses = config.Bind<bool>("Bosses", "trackBosses", false, "Generate Damage Logs for bosses. Use cycleBossKey to display these in the UI.");
			entryMaxRetainTime = config.Bind<float>("Constraints", "entryMaxRetainTime", 10f, "The maximum length of time (seconds) a Damage Log entry will be retained for.\nMinimum is 1.");
			entryMaxCount = config.Bind<int>("Constraints", "entryMaxCount", 16, "The maximum number of Damage Log entries to retain at a time.\nMinimum is 1.");
			onlyShowWithScoreboard = config.Bind<bool>("Display", "onlyShowWithScoreboard", false, "Only show the Damage Log when the scoreboard is open.");
			showDamageIdentifier = config.Bind<bool>("Display", "showDamageIdentifier", false, "Show damage identifier in tooltip.");
			useSimpleTextMode = config.Bind<bool>("Display", "useSimpleTextMode", false, "Display Damage Log entries as text instead of portraits with tooltips.");
			cycleUserKey = config.BindInputKey("Controls", "cycleUserKey", "left alt", "The key to use to cycle which user's Damage Log should be shown.");
			cycleBossKey = config.BindInputKey("Controls", "cycleBossKey", "`", "The key to use to cycle which boss's Damage Log should be shown.");
			textSize = config.Bind<float>("m_Debug", "textSize", 12f, (ConfigDescription)null);
			portraitSpacing = config.Bind<float>("m_Debug", "portraitSpacing", 6f, (ConfigDescription)null);
			portraitSize = config.Bind<float>("m_Debug", "portraitSize", 78f, (ConfigDescription)null);
			eliteIconSize = config.Bind<float>("m_Debug", "eliteIconSize", 24f, (ConfigDescription)null);
			portraitTextSize = config.Bind<float>("m_Debug", "portraitTextSize", 18f, (ConfigDescription)null);
			damageTextSize = config.Bind<float>("m_Debug", "damageTextSize", 20f, (ConfigDescription)null);
		}
	}
	public sealed class DamageLog
	{
		public readonly string targetDisplayName;

		public readonly int targetDiscriminator;

		public readonly bool isBoss;

		private readonly Dictionary<string, DamageSource> entries = new Dictionary<string, DamageSource>();

		private readonly CharacterBody targetBody;

		private float timeOfDeath = -1f;

		private string targetName
		{
			get
			{
				if (targetDiscriminator != 0)
				{
					return $"{targetDisplayName} {targetDiscriminator}";
				}
				return targetDisplayName;
			}
		}

		public float time
		{
			get
			{
				if (!(timeOfDeath > 0f))
				{
					return Time.time;
				}
				return timeOfDeath;
			}
		}

		public DamageLog(NetworkUser user, CharacterBody body)
		{
			if (!((Object)(object)user == (Object)null) && !((Object)(object)body == (Object)null))
			{
				targetBody = body;
				targetDisplayName = user.userName;
				Plugin.Data.AddUserLog(user, Track(body));
			}
		}

		public DamageLog(CharacterBody body)
		{
			if (!((Object)(object)body == (Object)null) && !IsIgnoredBossSubtitle(body.subtitleNameToken))
			{
				targetBody = body;
				targetDisplayName = Util.GetBestBodyName(((Component)body).gameObject);
				targetDiscriminator = Plugin.Data.EncounterBody(body.baseNameToken);
				isBoss = true;
				int instanceID = ((Object)body).GetInstanceID();
				Plugin.Data.AddBossLog(instanceID, Track(body));
			}
		}

		private DamageLog Track(CharacterBody body)
		{
			GlobalEventManager.onClientDamageNotified += Record;
			body.master.onBodyDestroyed += Cease;
			Log.Debug("Tracking " + targetName + ".");
			return this;
		}

		internal void Cease(CharacterBody _ = null)
		{
			if (timeOfDeath <= 0f)
			{
				timeOfDeath = Time.time;
			}
			GlobalEventManager.onClientDamageNotified -= Record;
			CharacterBody obj = targetBody;
			if ((Object)(object)((obj != null) ? obj.master : null) != (Object)null)
			{
				targetBody.master.onBodyDestroyed -= Cease;
			}
			else
			{
				Log.Warning("Could not unsubscribe RoR2.CharacterMaster::onBodyDestroyed for " + targetName + ".");
			}
			MethodBase method = new StackTrace().GetFrame(1).GetMethod();
			Log.Debug($"Untracking {targetName}. | {method.DeclaringType}::{method.Name}");
		}

		private void Record(DamageDealtMessage e)
		{
			if (!((Object)(object)targetBody == (Object)null) && !((Object)(object)e.victim != (Object)(object)((Component)targetBody).gameObject))
			{
				string key = DamageSource.GenerateIdentifier(e.attacker, DamageSource.IsFallDamage(e), DamageSource.IsVoidFogDamage(e));
				if (entries.TryGetValue(key, out var value) && !IsExpired(time - value.time))
				{
					value.Add(e);
				}
				else
				{
					entries.Remove(key);
					value = new DamageSource(e);
					entries.Add(key, value);
				}
				if (value.remainingHpPercent <= 0f)
				{
					timeOfDeath = Time.time;
				}
				if (entries.Count > Plugin.Config.EntryMaxCount && !isBoss)
				{
					Prune();
				}
			}
		}

		private void Prune()
		{
			Decay();
			Displace();
		}

		private void Decay()
		{
			float num = time;
			foreach (DamageSource entry in GetEntries())
			{
				if (IsExpired(num - entry.time))
				{
					entries.Remove(entry.identifier);
				}
			}
		}

		private void Displace()
		{
			List<DamageSource> list = GetEntries();
			for (int i = Plugin.Config.EntryMaxCount; i < list.Count; i++)
			{
				entries.Remove(list[i].identifier);
			}
		}

		public bool IsExpired(float elapsedTime)
		{
			if (!isBoss)
			{
				return elapsedTime > Plugin.Config.EntryMaxRetainTime;
			}
			return false;
		}

		public List<DamageSource> GetEntries()
		{
			List<DamageSource> list = entries.Values.ToList();
			if (list.Count > 1)
			{
				list.Sort((DamageSource a, DamageSource b) => Math.Sign(b.time - a.time));
			}
			return list;
		}

		public static bool IsIgnoredBossSubtitle(string subtitleNameToken)
		{
			if (string.IsNullOrEmpty(subtitleNameToken))
			{
				return true;
			}
			switch (subtitleNameToken)
			{
			default:
				return false;
			case "NULL_SUBTITLE":
			case "LUNARWISP_BODY_SUBTITLE":
			case "LUNARGOLEM_BODY_SUBTITLE":
			case "LUNAREXPLODER_BODY_SUBTITLE":
				return true;
			}
		}
	}
	internal sealed class DamageLogUI : MonoBehaviour
	{
		private static HUD hud;

		private int bossIndex;

		private bool showingBoss;

		private GameObject gameObject;

		private Canvas canvas;

		private HGTextMeshProUGUI text;

		private readonly List<DamageSourceUI> uiEntries = new List<DamageSourceUI>();

		public NetworkUser user { get; private set; }

		public static void Init(HUD hud, ref bool shouldDisplay)
		{
			if (!((Object)(object)DamageLogUI.hud != (Object)null))
			{
				Log.Debug("Adding to HUD.");
				((Component)hud).gameObject.AddComponent<DamageLogUI>();
				DamageLogUI.hud = hud;
			}
		}

		internal static void MoveToGameEndReportPanel(GameEndReportPanelController panel)
		{
			if ((Object)(object)hud == (Object)null)
			{
				Log.Warning("Failed to move canvas (no HUD). This can safely be ignored if triggered by viewing Game End Report from Run History.");
				return;
			}
			DamageLogUI component = ((Component)hud).gameObject.GetComponent<DamageLogUI>();
			if ((Object)(object)component == (Object)null)
			{
				Log.Warning("Failed to move canvas (missing).");
				return;
			}
			component.gameObject.transform.SetParent(((Component)panel).transform);
			((Behaviour)component).enabled = false;
			((Behaviour)component.canvas).enabled = true;
			Log.Debug("Moved canvas.");
		}

		internal static void DisplayPlayerDamageLog(NetworkUser user)
		{
			if ((Object)(object)hud == (Object)null)
			{
				Log.Warning("Failed to update canvas (no HUD). This can safely be ignored if triggered by viewing Game End Report from Run History.");
				return;
			}
			DamageLogUI component = ((Component)hud).gameObject.GetComponent<DamageLogUI>();
			if ((Object)(object)component == (Object)null)
			{
				Log.Warning("Failed to update canvas (missing).");
				return;
			}
			if (!Plugin.Data.TryGetUserLog(user, out var log))
			{
				Log.Warning("Failed to find damage log for " + user.userName + ".");
				return;
			}
			component.UpdateText(log);
			component.UpdatePortraits(log);
		}

		private void Start()
		{
			CreateUI(hud.mainContainer);
		}

		private void CreateUI(GameObject parent)
		{
			Plugin.RequestConfigReload();
			HUD obj = hud;
			object obj2;
			if (obj == null)
			{
				obj2 = null;
			}
			else
			{
				LocalUser localUserViewer = obj.localUserViewer;
				obj2 = ((localUserViewer != null) ? localUserViewer.currentNetworkUser : null);
			}
			user = (NetworkUser)obj2;
			if ((Object)(object)user == (Object)null)
			{
				Log.Warning("Failed to get HUD user (null).");
			}
			CreateCanvas(parent);
			CreateText();
			if (!Plugin.Config.SimpleTextMode)
			{
				CreateLayout();
			}
			Log.Debug("Created canvas.");
		}

		private void CreateCanvas(GameObject parent)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Expected O, but got Unknown
			//IL_0056: 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)
			//IL_0078: 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_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: 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_0098: Unknown result type (might be due to invalid IL or missing references)
			gameObject = new GameObject("DamageLogUI", new Type[2]
			{
				typeof(Canvas),
				typeof(GraphicRaycaster)
			});
			RectTransform component = gameObject.GetComponent<RectTransform>();
			((Transform)component).SetParent(parent.transform);
			ResetRectTransform(component);
			AnchorStretchRight(component);
			component.pivot = Vector2.one;
			Vector2 val = default(Vector2);
			((Vector2)(ref val))..ctor(4f, 12f);
			((Transform)component).localPosition = ((Transform)component).localPosition - Vector2.op_Implicit(val);
			component.sizeDelta = new Vector2(92f, 0f) - val;
			canvas = gameObject.GetComponent<Canvas>();
		}

		private void CreateLayout()
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Expected O, but got Unknown
			VerticalLayoutGroup obj = gameObject.AddComponent<VerticalLayoutGroup>();
			((HorizontalOrVerticalLayoutGroup)obj).childForceExpandHeight = false;
			((HorizontalOrVerticalLayoutGroup)obj).childControlHeight = false;
			((HorizontalOrVerticalLayoutGroup)obj).childForceExpandWidth = false;
			((HorizontalOrVerticalLayoutGroup)obj).childControlWidth = false;
			((HorizontalOrVerticalLayoutGroup)obj).spacing = Plugin.Config.Spacing;
			for (int i = 0; i < Plugin.Config.EntryMaxCount; i++)
			{
				uiEntries.Add(DamageSourceUI.Create((RectTransform)gameObject.transform).Hide());
			}
		}

		private void CreateText()
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Expected O, but got Unknown
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: 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_0079: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("DamageLogText", new Type[1] { typeof(RectTransform) });
			RectTransform component = val.GetComponent<RectTransform>();
			((Transform)component).SetParent(gameObject.transform);
			ResetRectTransform(component);
			AnchorTopStretch(component);
			component.pivot = Vector2.one;
			component.sizeDelta = (Vector2)(Plugin.Config.SimpleTextMode ? Vector2.zero : new Vector2(((RectTransform)gameObject.transform).sizeDelta.x, 0f));
			text = val.AddComponent<HGTextMeshProUGUI>();
			((TMP_Text)text).fontSize = Plugin.Config.TextSize;
			((TMP_Text)text).SetText("<style=cDeath>Damage Log <null></style>", true);
		}

		private void Update()
		{
			int num;
			if (Plugin.Config.OnlyShowWithScoreboard)
			{
				LocalUser localUserViewer = hud.localUserViewer;
				num = ((((localUserViewer != null) ? localUserViewer.inputPlayer : null) != null && hud.localUserViewer.inputPlayer.GetButton("info")) ? 1 : 0);
			}
			else
			{
				num = 1;
			}
			bool flag = (byte)num != 0;
			((Behaviour)canvas).enabled = flag;
			if (!flag)
			{
				return;
			}
			bool reverse = Input.GetKey("left shift") || Input.GetKey("right shift");
			bool keyDown = Input.GetKeyDown(Plugin.Config.CycleUserKey);
			bool flag2 = Plugin.Config.TrackBosses && Input.GetKeyDown(Plugin.Config.CycleBossKey);
			if (keyDown)
			{
				if (!showingBoss)
				{
					user = Plugin.Data.CycleUser(user, reverse);
				}
				showingBoss = false;
			}
			else if (flag2 && Plugin.Data.HasBossLogs)
			{
				if (showingBoss)
				{
					bossIndex = Plugin.Data.CycleBossIndex(bossIndex, reverse);
				}
				showingBoss = true;
			}
			if ((!showingBoss && (Object)(object)user != (Object)null && Plugin.Data.TryGetUserLog(user, out var log)) || (showingBoss && Plugin.Data.TryGetBossLog(bossIndex, out log)))
			{
				UpdateText(log);
				UpdatePortraits(log);
			}
		}

		private void UpdateText(DamageLog log)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: 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)
			((TMP_Text)text).SetText(GenerateTextLog(log), true);
			Vector2 sizeDelta = ((TMP_Text)text).rectTransform.sizeDelta;
			if (sizeDelta.y != ((TMP_Text)text).preferredHeight)
			{
				((TMP_Text)text).rectTransform.sizeDelta = new Vector2(sizeDelta.x, ((TMP_Text)text).preferredHeight);
			}
		}

		private void UpdatePortraits(DamageLog log)
		{
			if (Plugin.Config.SimpleTextMode)
			{
				return;
			}
			float time = log.time;
			List<DamageSource> entries = log.GetEntries();
			for (int i = 0; i < uiEntries.Count; i++)
			{
				if (i >= entries.Count)
				{
					uiEntries[i].Hide();
					continue;
				}
				float elapsedTime = time - entries[i].time;
				if (log.IsExpired(elapsedTime))
				{
					uiEntries[i].Hide();
				}
				else
				{
					uiEntries[i].Display(entries[i], elapsedTime);
				}
			}
		}

		private static string GenerateTextLog(DamageLog log)
		{
			StringBuilder stringBuilder = new StringBuilder();
			string text = (log.isBoss ? ("<style=cIsHealth>" + log.targetDisplayName + "</style>") : log.targetDisplayName);
			string text2 = ((log.targetDiscriminator == 0) ? "" : $" <style=cStack>{log.targetDiscriminator}</style>");
			stringBuilder.AppendLine("<style=cWorldEvent>Damage Log <" + text + text2 + "></style>");
			if (!Plugin.Config.SimpleTextMode)
			{
				return stringBuilder.ToString();
			}
			float time = log.time;
			foreach (DamageSource entry in log.GetEntries())
			{
				float num = time - entry.time;
				if (!log.IsExpired(num))
				{
					string text3 = (entry.isPlayerDamage ? "cDeath" : (entry.isFallDamage ? "cHumanObjective" : (entry.isVoidFogDamage ? "cIsVoid" : "")));
					if (string.IsNullOrEmpty(text3))
					{
						stringBuilder.Append(entry.attackerName);
					}
					else
					{
						stringBuilder.Append("<style=" + text3 + ">" + entry.attackerName + "</style>");
					}
					bool num2 = entry.hits == 1;
					if (!num2)
					{
						stringBuilder.Append($"<style=cStack>×{entry.hits}</style>");
					}
					stringBuilder.Append($" · <style=cIsDamage>-{entry.totalDamagePercent:0.0%}</style>");
					if (num2)
					{
						stringBuilder.Append($" <style=cEvent>({entry.remainingHpPercent:0.0%})</style>");
					}
					stringBuilder.AppendLine($" · <style=cSub>{num:0.00s}</style>");
				}
			}
			return stringBuilder.ToString();
		}

		public static RectTransform ResetRectTransform(RectTransform rect)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			((Transform)rect).localPosition = Vector3.zero;
			((Transform)rect).localScale = Vector3.one;
			((Transform)rect).localRotation = Quaternion.identity;
			((Component)rect).gameObject.layer = LayerMask.NameToLayer("UI");
			return rect;
		}

		private static RectTransform AnchorStretchRight(RectTransform rect)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			rect.anchoredPosition = Vector2.zero;
			rect.anchorMin = Vector2.right;
			rect.anchorMax = Vector2.one;
			return rect;
		}

		private static RectTransform AnchorTopStretch(RectTransform rect)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			rect.anchoredPosition = Vector2.zero;
			rect.anchorMin = Vector2.up;
			rect.anchorMax = Vector2.one;
			return rect;
		}
	}
	public sealed class DamageSource
	{
		private static Texture _PlanetPortrait;

		private static Texture _SotVPortrait;

		public readonly string identifier;

		public readonly Texture attackerPortrait;

		public readonly Color attackerColor;

		public readonly string attackerName;

		public readonly Sprite eliteIcon;

		public readonly Color eliteColor;

		public readonly bool isPlayerDamage;

		public readonly bool isFallDamage;

		public readonly bool isVoidFogDamage;

		public readonly float timeStart;

		public static Texture PlanetPortrait
		{
			get
			{
				if ((Object)(object)_PlanetPortrait == (Object)null)
				{
					_PlanetPortrait = LegacyResourcesAPI.Load<Texture>("Textures/BodyIcons/texUnidentifiedKillerIcon");
				}
				return _PlanetPortrait;
			}
		}

		public static Texture SotVPortrait
		{
			get
			{
				//IL_0012: Unknown result type (might be due to invalid IL or missing references)
				//IL_0017: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)_SotVPortrait == (Object)null)
				{
					_SotVPortrait = Addressables.LoadAssetAsync<Texture>((object)"RoR2/DLC1/UI/texVoidExpansionIcon.png").WaitForCompletion();
				}
				return _SotVPortrait;
			}
		}

		public float time { get; private set; }

		public int hits { get; private set; }

		public float totalDamage { get; private set; }

		public float totalDamagePercent { get; private set; }

		public float remainingHpPercent { get; private set; }

		public DamageSource(DamageDealtMessage e)
		{
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			GameObject attacker = e.attacker;
			CharacterBody val = ((attacker != null) ? attacker.GetComponent<CharacterBody>() : null);
			isPlayerDamage = val != null && val.isPlayerControlled;
			isFallDamage = IsFallDamage(e);
			isVoidFogDamage = IsVoidFogDamage(e);
			identifier = GenerateIdentifier(e.attacker, isFallDamage, isVoidFogDamage);
			GetAttackerInfo(e.attacker, isFallDamage, isVoidFogDamage, out attackerName, out attackerPortrait, out attackerColor);
			GetEliteIcon(val, out eliteIcon, out eliteColor);
			if (identifier == "??")
			{
				identifier += $" | {e.damageType} | {e.damageColorIndex} | {e.damage}";
			}
			timeStart = Time.time;
			time = timeStart;
			hits = 1;
			totalDamage = e.damage;
			UpdateHpDamagePercent(e.victim, e.damage);
		}

		public DamageSource Add(DamageDealtMessage e)
		{
			time = Time.time;
			hits++;
			totalDamage += e.damage;
			UpdateHpDamagePercent(e.victim, e.damage);
			return this;
		}

		private void UpdateHpDamagePercent(GameObject victim, float latestHitDamage)
		{
			HealthComponent val = ((victim != null) ? victim.GetComponent<HealthComponent>() : null);
			if ((Object)(object)val != (Object)null)
			{
				remainingHpPercent = (NetworkServer.active ? val.combinedHealthFraction : ((val.combinedHealth - latestHitDamage) / val.fullCombinedHealth));
				totalDamagePercent = totalDamage / val.fullCombinedHealth;
			}
			else
			{
				Log.Warning("Could not UpdateHpDamagePercent");
			}
		}

		public static bool IsFallDamage(DamageDealtMessage e)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			return ((Enum)e.damageType).HasFlag((Enum)(object)(DamageType)2097152);
		}

		public static bool IsVoidFogDamage(DamageDealtMessage e)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Invalid comparison between Unknown and I4
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Invalid comparison between Unknown and I4
			if ((int)e.damageType == 66 && (int)e.damageColorIndex == 9)
			{
				return (Object)(object)e.attacker == (Object)null;
			}
			return false;
		}

		public static void GetAttackerInfo(GameObject attacker, bool isFallDamage, bool isVoidFogDamage, out string name, out Texture portrait, out Color color)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			name = Language.GetString("UNIDENTIFIED_KILLER_NAME");
			portrait = PlanetPortrait;
			color = Color.white;
			if ((Object)(object)attacker != (Object)null)
			{
				string bestBodyName = Util.GetBestBodyName(attacker);
				Texture val = attacker.GetComponent<CharacterBody>()?.portraitIcon;
				if (!string.IsNullOrEmpty(bestBodyName))
				{
					name = bestBodyName;
				}
				if ((Object)(object)val == (Object)null)
				{
					val = GetAlternativePortrait(bestBodyName, ref color, attacker);
				}
				if ((Object)(object)val != (Object)null)
				{
					portrait = val;
				}
			}
			else if (isFallDamage)
			{
				name = "The Ground";
				portrait = (Texture)(object)Artifacts.weakAssKneesArtifactDef.smallIconSelectedSprite.texture;
			}
			else if (isVoidFogDamage)
			{
				name = "Void Fog";
				portrait = (Texture)(object)Buffs.VoidFogMild.iconSprite.texture;
				color = DamageColor.FindColor((DamageColorIndex)9);
			}
		}

		public static Texture GetAlternativePortrait(string attackerName, ref Color color, GameObject attacker)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			if (attackerName == Language.GetString("SHRINE_BLOOD_NAME"))
			{
				color = Color32.op_Implicit(ColorCatalog.GetColor((ColorIndex)9));
				if (attacker == null)
				{
					return null;
				}
				ShrineBloodBehavior component = attacker.GetComponent<ShrineBloodBehavior>();
				if (component == null)
				{
					return null;
				}
				Transform symbolTransform = component.symbolTransform;
				if (symbolTransform == null)
				{
					return null;
				}
				MeshRenderer component2 = ((Component)symbolTransform).GetComponent<MeshRenderer>();
				if (component2 == null)
				{
					return null;
				}
				Material material = ((Renderer)component2).material;
				if (material == null)
				{
					return null;
				}
				return material.mainTexture;
			}
			if (attackerName == Language.GetString("VOID_CHEST_NAME") || attackerName == Language.GetString("VOID_TRIPLE_NAME"))
			{
				return SotVPortrait;
			}
			if (attackerName == Language.GetString("ARTIFACTSHELL_BODY_NAME"))
			{
				return (Texture)(object)Items.ArtifactKey.pickupIconSprite.texture;
			}
			return null;
		}

		public static void GetEliteIcon(CharacterBody body, out Sprite icon, out Color color)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			BuffDef eliteBuffDef = GetEliteBuffDef(body);
			icon = eliteBuffDef?.iconSprite;
			color = eliteBuffDef?.buffColor ?? Color.white;
		}

		public static BuffDef GetEliteBuffDef(CharacterBody body)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			BuffDef result = null;
			if ((Object)(object)body == (Object)null || !body.isElite)
			{
				return result;
			}
			BuffIndex[] eliteBuffIndices = BuffCatalog.eliteBuffIndices;
			foreach (BuffIndex val in eliteBuffIndices)
			{
				if (body.HasBuff(val))
				{
					result = BuffCatalog.GetBuffDef(val);
				}
			}
			return result;
		}

		public static string GenerateIdentifier(GameObject attacker, bool isFallDamage, bool isVoidFogDamage)
		{
			string text = "??";
			if ((Object)(object)attacker != (Object)null)
			{
				text = ((Object)attacker).GetInstanceID().ToString();
			}
			if (isFallDamage)
			{
				text = "fall_damage";
			}
			if (isVoidFogDamage)
			{
				text = "void_fog_damage";
			}
			if ((Object)(object)attacker != (Object)null)
			{
				GetAttackerInfo(attacker, isFallDamage, isVoidFogDamage, out var name, out var _, out var _);
				text = text + "·" + name;
			}
			return text;
		}
	}
	internal sealed class DamageSourceUI : MonoBehaviour
	{
		private RawImage portrait;

		private Image elite;

		private HGTextMeshProUGUI damage;

		private HGTextMeshProUGUI hits;

		private HGTextMeshProUGUI time;

		private TooltipProvider tooltip;

		public static DamageSourceUI Create(RectTransform parent)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Expected O, but got Unknown
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("DamageEntry", new Type[2]
			{
				typeof(DamageSourceUI),
				typeof(RawImage)
			});
			val.transform.SetParent((Transform)(object)parent, false);
			((RectTransform)val.transform).sizeDelta = Vector2.one * ((Plugin.Config.PortraitSize > 0f) ? Plugin.Config.PortraitSize : parent.sizeDelta.x);
			return val.GetComponent<DamageSourceUI>().Create(val);
		}

		private DamageSourceUI Create(GameObject root)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: 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)
			//IL_0163: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ee: Unknown result type (might be due to invalid IL or missing references)
			RectTransform val = (RectTransform)root.transform;
			float x = ((RectTransform)((Transform)val).parent).sizeDelta.x;
			tooltip = root.AddComponent<TooltipProvider>();
			portrait = root.GetComponent<RawImage>();
			elite = AddChild<Image>(val, "elite");
			AnchorTopLeft(((Graphic)elite).rectTransform);
			((Graphic)elite).raycastTarget = false;
			((Graphic)elite).rectTransform.sizeDelta = Vector2.one * Plugin.Config.EliteIconSize;
			damage = AddChild<HGTextMeshProUGUI>(val, "damage");
			AnchorTopRight(((TMP_Text)damage).rectTransform);
			((Graphic)damage).raycastTarget = false;
			((TMP_Text)damage).enableWordWrapping = false;
			((TMP_Text)damage).alignment = (TextAlignmentOptions)260;
			((TMP_Text)damage).rectTransform.sizeDelta = Vector2.one * (x - Plugin.Config.EliteIconSize);
			((TMP_Text)damage).fontSize = Plugin.Config.DamageTextSize;
			hits = AddChild<HGTextMeshProUGUI>(val, "hits");
			AnchorBottomLeft(((TMP_Text)hits).rectTransform);
			((Graphic)hits).raycastTarget = false;
			((TMP_Text)hits).enableWordWrapping = false;
			((TMP_Text)hits).alignment = (TextAlignmentOptions)1025;
			((TMP_Text)hits).rectTransform.sizeDelta = Vector2.one * (x / 2f);
			((TMP_Text)hits).fontSize = Plugin.Config.PortraitTextSize;
			time = AddChild<HGTextMeshProUGUI>(val, "time");
			AnchorBottomRight(((TMP_Text)time).rectTransform);
			((Graphic)time).raycastTarget = false;
			((TMP_Text)time).enableWordWrapping = false;
			((TMP_Text)time).alignment = (TextAlignmentOptions)1028;
			((TMP_Text)time).rectTransform.sizeDelta = Vector2.one * (x / 2f);
			((TMP_Text)time).fontSize = Plugin.Config.PortraitTextSize;
			return this;
		}

		private static T AddChild<T>(RectTransform parent, string name) where T : Component
		{
			//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_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Expected O, but got Unknown
			GameObject val = new GameObject(name, new Type[1] { typeof(T) });
			val.transform.SetParent((Transform)(object)parent);
			DamageLogUI.ResetRectTransform((RectTransform)val.transform);
			return val.GetComponent<T>();
		}

		public void Display(DamageSource src, float elapsedTime)
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_0149: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: 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_0124: Unknown result type (might be due to invalid IL or missing references)
			if (src == null)
			{
				Hide();
				return;
			}
			((Component)portrait).gameObject.SetActive(true);
			portrait.texture = src.attackerPortrait;
			((Graphic)portrait).color = src.attackerColor;
			if ((Object)(object)src.eliteIcon != (Object)null)
			{
				elite.sprite = src.eliteIcon;
				((Graphic)elite).color = src.eliteColor;
				((Behaviour)elite).enabled = true;
			}
			else
			{
				((Behaviour)elite).enabled = false;
			}
			((TMP_Text)damage).SetText($"<style=cIsDamage>-{src.totalDamagePercent:0.0%}</style>", true);
			if (src.hits == 1)
			{
				((TMP_Text)hits).SetText("", true);
			}
			else
			{
				((TMP_Text)hits).SetText($"<style=cStack>×{src.hits}</style>", true);
			}
			((TMP_Text)time).SetText($"<style=cSub>{elapsedTime:0.00s}</style>", true);
			tooltip.titleColor = Color32.op_Implicit(src.isPlayerDamage ? ColorCatalog.GetColor((ColorIndex)17) : (src.isFallDamage ? ColorCatalog.GetColor((ColorIndex)16) : (src.isVoidFogDamage ? ColorCatalog.GetColor((ColorIndex)25) : ColorCatalog.GetColor((ColorIndex)20))));
			tooltip.titleToken = src.attackerName;
			tooltip.bodyToken = GenerateTooltipString(src);
		}

		public DamageSourceUI Hide()
		{
			((Component)portrait).gameObject.SetActive(false);
			return this;
		}

		private static string GenerateTooltipString(DamageSource src)
		{
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.Append($"Dealt <style=cIsHealth>{src.totalDamage:0.0}</style> damage");
			if (src.hits == 1)
			{
				stringBuilder.Append($" <style=cEvent>({src.remainingHpPercent:0.0%} health remaining)</style>");
			}
			else
			{
				stringBuilder.Append($" in <style=cStack>{src.hits} hits</style> over <style=cSub>{src.time - src.timeStart:0.00s}</style>");
			}
			stringBuilder.AppendLine(".");
			if (Plugin.Config.ShowIdentifier)
			{
				stringBuilder.AppendLine();
				stringBuilder.AppendLine("<style=cIsDamage>" + src.identifier + "</style>");
			}
			return stringBuilder.ToString();
		}

		private static void AnchorTopLeft(RectTransform rect)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			Anchor(rect, Vector2.up);
		}

		private static void AnchorTopRight(RectTransform rect)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			Anchor(rect, Vector2.one);
		}

		private static void AnchorBottomLeft(RectTransform rect)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			Anchor(rect, Vector2.zero);
		}

		private static void AnchorBottomRight(RectTransform rect)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			Anchor(rect, Vector2.right);
		}

		private static void Anchor(RectTransform rect, Vector2 anchor)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//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_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			Vector2 val2 = (rect.anchorMax = anchor);
			Vector2 pivot = (rect.anchorMin = val2);
			rect.pivot = pivot;
		}
	}
	internal sealed class Data
	{
		private readonly Dictionary<NetworkUser, DamageLog> userLogs = new Dictionary<NetworkUser, DamageLog>();

		private readonly Dictionary<int, DamageLog> bossLogs = new Dictionary<int, DamageLog>();

		private readonly Dictionary<string, int> encounters = new Dictionary<string, int>();

		public bool HasBossLogs => bossLogs.Count > 0;

		public int EncounterBody(string nameToken)
		{
			if (!encounters.ContainsKey(nameToken))
			{
				return encounters[nameToken] = 1;
			}
			return ++encounters[nameToken];
		}

		internal void AddUserLog(NetworkUser user, DamageLog log)
		{
			Add(userLogs, user, log);
		}

		internal void AddBossLog(int instanceID, DamageLog log)
		{
			Add(bossLogs, instanceID, log);
		}

		internal bool TryGetUserLog(NetworkUser user, out DamageLog log)
		{
			return userLogs.TryGetValue(user, out log);
		}

		internal bool TryGetBossLog(int index, out DamageLog log)
		{
			return TryGetDamageLog(index, bossLogs, out log);
		}

		internal void ClearUserLogs()
		{
			Log.Debug("Clearing user damage logs.");
			Clear(userLogs);
		}

		internal void ClearBossLogs()
		{
			Log.Debug("Clearing boss damage logs.");
			Clear(bossLogs);
			encounters.Clear();
		}

		internal void ClearAll()
		{
			ClearUserLogs();
			ClearBossLogs();
		}

		internal NetworkUser CycleUser(NetworkUser current, bool reverse)
		{
			if (userLogs.Count <= 0)
			{
				return null;
			}
			int index = ((!((Object)(object)current == (Object)null)) ? NetworkUser.readOnlyInstancesList.IndexOf(current) : 0);
			index = CycleCollectionIndex(index, NetworkUser.readOnlyInstancesList, reverse);
			NetworkUser val = NetworkUser.readOnlyInstancesList[index];
			if (userLogs.ContainsKey(val))
			{
				return val;
			}
			return CycleUser(val, reverse);
		}

		internal int CycleBossIndex(int current, bool reverse)
		{
			return CycleCollectionIndex(current, bossLogs, reverse);
		}

		internal static int CycleCollectionIndex(int index, ICollection collection, bool reverse)
		{
			index = ((!reverse) ? (index + 1) : (index - 1));
			if (index < 0)
			{
				index = collection.Count - 1;
			}
			else if (index >= collection.Count)
			{
				index = 0;
			}
			return index;
		}

		public static void Add<TKey>(Dictionary<TKey, DamageLog> logs, TKey key, DamageLog newLog)
		{
			if (logs.TryGetValue(key, out var value))
			{
				value.Cease();
				Log.Debug("Replacing existing damage log.");
			}
			logs[key] = newLog;
		}

		public static void Clear<TKey>(Dictionary<TKey, DamageLog> logs)
		{
			foreach (DamageLog value in logs.Values)
			{
				value.Cease();
			}
			logs.Clear();
		}

		public static bool TryGetDamageLog<TKey>(int index, Dictionary<TKey, DamageLog> dictionary, out DamageLog log)
		{
			log = null;
			if (index < 0)
			{
				return false;
			}
			if (index >= dictionary.Count)
			{
				return false;
			}
			log = dictionary.ElementAt(index).Value;
			return true;
		}
	}
	[HarmonyPatch]
	internal static class HarmonyPatches
	{
		[HarmonyPostfix]
		[HarmonyPatch(typeof(GameEndReportPanelController), "Awake")]
		private static void GameEndReportPanelController_Awake(GameEndReportPanelController __instance)
		{
			DamageLogUI.MoveToGameEndReportPanel(__instance);
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(GameEndReportPanelController), "SetPlayerInfo")]
		private static void GameEndReportPanelController_SetPlayerInfo(PlayerInfo playerInfo)
		{
			DamageLogUI.DisplayPlayerDamageLog(playerInfo?.networkUser);
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(BossGroup), "OnMemberDiscovered")]
		private static void BossGroup_OnMemberDiscovered(BossGroup __instance, CharacterMaster memberMaster)
		{
			Plugin.TrackBoss(__instance, memberMaster);
		}
	}
	internal static class Log
	{
		private static ManualLogSource _logSource;

		internal static void Init(ManualLogSource baseLogger)
		{
			Logger.Sources.Remove((ILogSource)(object)baseLogger);
			_logSource = Logger.CreateLogSource("itsschwer.DamageLog");
		}

		internal static void Debug(object data)
		{
			_logSource.LogDebug(data);
		}

		internal static void Error(object data)
		{
			_logSource.LogError(data);
		}

		internal static void Fatal(object data)
		{
			_logSource.LogFatal(data);
		}

		internal static void Info(object data)
		{
			_logSource.LogInfo(data);
		}

		internal static void Message(object data)
		{
			_logSource.LogMessage(data);
		}

		internal static void Warning(object data)
		{
			_logSource.LogWarning(data);
		}
	}
	[BepInPlugin("itsschwer.DamageLog", "DamageLog", "1.1.2")]
	public sealed class Plugin : BaseUnityPlugin
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static Action<Run> <0>__OnRunStartOrDestroy;

			public static Action<CharacterBody> <1>__TrackUser;

			public static ShouldHudDisplayDelegate <2>__Init;

			public static Action<Stage> <3>__OnStageStart;

			public static Action<CharacterBody> <4>__TrackBoss;
		}

		public const string GUID = "itsschwer.DamageLog";

		public const string Author = "itsschwer";

		public const string Name = "DamageLog";

		public const string Version = "1.1.2";

		private static Action ReloadConfig;

		internal static Config Config { get; private set; }

		internal static Data Data { get; private set; }

		internal static void RequestConfigReload()
		{
			ReloadConfig?.Invoke();
		}

		private void Awake()
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			Log.Init(((BaseUnityPlugin)this).Logger);
			Config = new Config(((BaseUnityPlugin)this).Config);
			Data = new Data();
			new Harmony(((BaseUnityPlugin)this).Info.Metadata.GUID).PatchAll();
			ReloadConfig = ((BaseUnityPlugin)this).Config.Reload;
			Log.Message("~awake.");
		}

		private void OnEnable()
		{
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Expected O, but got Unknown
			Run.onRunStartGlobal += OnRunStartOrDestroy;
			Run.onRunDestroyGlobal += OnRunStartOrDestroy;
			CharacterBody.onBodyStartGlobal += TrackUser;
			object obj = <>O.<2>__Init;
			if (obj == null)
			{
				ShouldHudDisplayDelegate val = DamageLogUI.Init;
				<>O.<2>__Init = val;
				obj = (object)val;
			}
			HUD.shouldHudDisplay += (ShouldHudDisplayDelegate)obj;
			Stage.onStageStartGlobal += OnStageStart;
			Log.Message("~enabled.");
		}

		private void OnDisable()
		{
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Expected O, but got Unknown
			Run.onRunStartGlobal -= OnRunStartOrDestroy;
			Run.onRunDestroyGlobal -= OnRunStartOrDestroy;
			CharacterBody.onBodyStartGlobal -= TrackUser;
			object obj = <>O.<2>__Init;
			if (obj == null)
			{
				ShouldHudDisplayDelegate val = DamageLogUI.Init;
				<>O.<2>__Init = val;
				obj = (object)val;
			}
			HUD.shouldHudDisplay -= (ShouldHudDisplayDelegate)obj;
			Stage.onStageStartGlobal -= OnStageStart;
			Log.Message("~disabled.");
		}

		private static void OnRunStartOrDestroy(Run _)
		{
			Data.ClearAll();
		}

		private static void OnStageStart(Stage _)
		{
			Data.ClearBossLogs();
		}

		private static void TrackUser(CharacterBody body)
		{
			if (body.isPlayerControlled)
			{
				new DamageLog(Util.LookUpBodyNetworkUser(body), body);
			}
		}

		internal static void TrackBoss(BossGroup boss, CharacterMaster member)
		{
			if (Config.TrackBosses)
			{
				CharacterBody body = member.GetBody();
				if ((Object)(object)body != (Object)null)
				{
					Log.Debug("TrackBoss> Discovered and found " + ((Object)member).name + " | " + ((Object)body).name + " | " + ((Object)boss).name);
					new DamageLog(body);
				}
				else
				{
					Log.Debug("TrackBoss> Discovered " + ((Object)member).name + " | " + ((Object)boss).name);
					member.onBodyStart += TrackBoss;
				}
			}
		}

		private static void TrackBoss(CharacterBody body)
		{
			body.master.onBodyStart -= TrackBoss;
			Log.Debug("TrackBoss> Found " + ((Object)body.master).name + " | " + ((Object)body).name);
			new DamageLog(body);
		}
	}
}