Decompiled source of DamageLog v1.2.5

plugins/DamageLog/DamageLog.dll

Decompiled a month ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
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.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("DamageLog")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.2.5.0")]
[assembly: AssemblyInformationalVersion("1.2.5+0d472968ff35083749d9e161d7fe412da0901ee2")]
[assembly: AssemblyProduct("DamageLog")]
[assembly: AssemblyTitle("DamageLog")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.2.5.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 sealed class BossDamageLog : DamageLog
	{
		public readonly uint targetNetId;

		public override string displayName => $"<style=cStack>{targetNetId:x8}</style> <style=cIsHealth>{base.displayName}</style>";

		public override string loggingName => $"{base.loggingName} <{targetNetId:x8}>";

		public BossDamageLog(CharacterBody body)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			NetworkInstanceId netId = ((NetworkBehaviour)body).netId;
			targetNetId = ((NetworkInstanceId)(ref netId)).Value;
			base..ctor(body, Util.GetBestBodyName(((Component)body).gameObject));
		}

		public override bool IsExpired(float elapsedTime)
		{
			return false;
		}

		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 static class Compatibility
	{
		internal static string ApplicationVersion => "RoR2v" + Application.version + " (" + Application.buildGUID + ")";

		internal static string PluginVersion => Assembly.GetExecutingAssembly().GetCustomAttribute<AssemblyInformationalVersionAttribute>().InformationalVersion;

		internal static bool DamageInfoChanged()
		{
			try
			{
				DamageInfoChanged_Test();
				return false;
			}
			catch (MissingFieldException)
			{
				Plugin.Logger.LogError((object)("DamageLogv" + PluginVersion + " is not compatible with " + ApplicationVersion + "\nPlease refer to the README on the mod page for guidance."));
				return true;
			}
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		private static void DamageInfoChanged_Test()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			((object)(DamageTypeCombo)(ref new DamageInfo().damageType)).ToString();
		}
	}
	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)
			{
				Plugin.Logger.LogWarning((object)("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 ConfigFile file;

		private readonly ConfigEntry<bool> trackBosses;

		private readonly ConfigEntry<float> entryMaxRetainTime;

		private readonly ConfigEntry<bool> onlyShowWithScoreboard;

		private readonly ConfigEntry<bool> useSimpleTextMode;

		private readonly ConfigEntry<bool> hideDamageTimer;

		private readonly ConfigEntry<int> maximumPortraitCount;

		private readonly ConfigEntry<bool> showDamageIdentifier;

		private readonly ConfigEntry<bool> compactLines;

		private readonly ConfigEntry<bool> showRawDamageInsteadOfPercentage;

		private readonly ConfigEntry<string> cycleUserKey;

		private readonly ConfigEntry<string> cycleBossKey;

		private readonly ConfigEntry<float> canvasOffsetRight;

		private readonly ConfigEntry<float> canvasOffsetTop;

		private readonly ConfigEntry<float> canvasWidth;

		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 bool OnlyShowWithScoreboard => onlyShowWithScoreboard.Value;

		public bool SimpleTextMode => useSimpleTextMode.Value;

		public bool HideDamageTimer => hideDamageTimer.Value;

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

		public bool ShowIdentifier => showDamageIdentifier.Value;

		public bool CompactLines => compactLines.Value;

		public bool ShowRawDamageInsteadOfPercentage => showRawDamageInsteadOfPercentage.Value;

		public string CycleUserKey => cycleUserKey.Value;

		public string CycleBossKey => cycleBossKey.Value;

		public Vector2 CanvasOffsetTopRight => new Vector2(canvasOffsetRight.Value, canvasOffsetTop.Value);

		public float CanvasWidth => canvasWidth.Value;

		public float TextSize => textSize.Value;

		public float PortraitSpacing => portraitSpacing.Value;

		public float PortraitSize => portraitSize.Value;

		public float EliteIconSize => eliteIconSize.Value;

		public float PortraitTextSize => portraitTextSize.Value;

		public float DamageTextSize => damageTextSize.Value;

		internal void Reload()
		{
			Plugin.Logger.LogDebug((object)("Reloading " + file.ConfigFilePath.Substring(file.ConfigFilePath.LastIndexOf(Path.DirectorySeparatorChar) + 1)));
			file.Reload();
		}

		public Config(ConfigFile config)
		{
			file = 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.");
			onlyShowWithScoreboard = config.Bind<bool>("Display", "onlyShowWithScoreboard", false, "Only show the Damage Log when the scoreboard is open.");
			useSimpleTextMode = config.Bind<bool>("Display", "useSimpleTextMode", false, "Display Damage Log entries as text instead of portraits with tooltips.");
			hideDamageTimer = config.Bind<bool>("Display", "hideDamageTimer", false, "Hide the timer portion of each Damage Log entry showing how long it has been since the damage was inflicted.");
			maximumPortraitCount = config.Bind<int>("Display: Portraits Mode", "maximumPortraitCount", 12, "The maximum number of Damage Log entry portraits to show at a time.\nMinimum is 1.");
			showDamageIdentifier = config.Bind<bool>("Display: Portraits Mode", "showDamageIdentifier", false, "Show the damage identifier in the portrait tooltip. Can show additional information about damage attributed to The Planet.");
			compactLines = config.Bind<bool>("Display: Simple Text Mode", "compactLines", false, "Remove empty lines used as separators between Damage Log entries.");
			showRawDamageInsteadOfPercentage = config.Bind<bool>("Display: Simple Text Mode", "showRawDamageInsteadOfPercentage", false, "Show the raw damage value instead of the percentage of full combined health.");
			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.");
			canvasOffsetRight = config.Bind<float>("m_Debug", "canvasOffsetRight", 8f, (ConfigDescription)null);
			canvasOffsetTop = config.Bind<float>("m_Debug", "canvasOffsetTop", 12f, (ConfigDescription)null);
			canvasWidth = config.Bind<float>("m_Debug", "canvasWidth", 88f, (ConfigDescription)null);
			textSize = config.Bind<float>("m_Debug", "textSize", 14f, (ConfigDescription)null);
			portraitSpacing = config.Bind<float>("m_Debug", "portraitSpacing", 8f, (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 static class DamageDealtMessageExtension
	{
		public static bool IsFallDamage(this DamageDealtMessage e)
		{
			//IL_0001: 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_0010: Unknown result type (might be due to invalid IL or missing references)
			return DamageTypeCombo.op_Implicit(e.damageType & DamageTypeCombo.op_Implicit((DamageType)2097152)) != 0;
		}

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

		public static bool IsMeridianLightningDamage(this DamageDealtMessage e)
		{
			//IL_0001: 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_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_0024: 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)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			return DamageTypeCombo.op_Implicit(e.damageType) == DamageTypeCombo.op_Implicit(DamageTypeCombo.Generic | DamageTypeCombo.op_Implicit((DamageType)131072) | DamageTypeCombo.op_Implicit((DamageType)1073741824) | DamageTypeCombo.op_Implicit((DamageTypeExtended)268435456) | DamageTypeCombo.op_Implicit((DamageTypeExtended)536870912));
		}

		public static string GetAttackerName(this DamageDealtMessage e)
		{
			string result = Language.GetString("UNIDENTIFIED_KILLER_NAME");
			if ((Object)(object)e.attacker != (Object)null)
			{
				string bestBodyName = Util.GetBestBodyName(e.attacker);
				if (!string.IsNullOrEmpty(bestBodyName))
				{
					result = bestBodyName;
				}
			}
			else if (e.IsFallDamage())
			{
				result = "The Ground";
			}
			else if (e.IsVoidFogDamage())
			{
				result = "Void Fog";
			}
			return result;
		}

		public static string GenerateIdentifier(this DamageDealtMessage e)
		{
			//IL_0006: 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)
			string result = $"?? | {e.damageType} | {e.damageColorIndex} | {e.damage}";
			if (e.IsFallDamage())
			{
				result = "fall_damage";
			}
			if (e.IsVoidFogDamage())
			{
				result = "void_fog_damage";
			}
			if ((Object)(object)e.attacker != (Object)null)
			{
				result = $"{((Object)e.attacker).GetInstanceID()} | {e.GetAttackerName()}";
			}
			else if (e.IsMeridianLightningDamage())
			{
				result = "meridian_lightning";
			}
			return result;
		}
	}
	public class DamageLog
	{
		private readonly CharacterBody targetBody;

		private readonly string targetName;

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

		private float timeOfDeath = -1f;

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

		public virtual string displayName => targetName;

		public virtual string loggingName => targetName;

		public DamageLog(NetworkUser user, CharacterBody body)
			: this(body, user.userName)
		{
		}

		protected DamageLog(CharacterBody targetBody, string targetName)
		{
			this.targetBody = targetBody;
			this.targetName = targetName;
			Track(targetBody);
		}

		private DamageLog Track(CharacterBody body)
		{
			GlobalEventManager.onClientDamageNotified += Record;
			body.master.onBodyDestroyed += Cease;
			Plugin.Logger.LogDebug((object)("Tracking " + loggingName + "."));
			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
			{
				Plugin.Logger.LogWarning((object)("Could not unsubscribe RoR2.CharacterMaster::onBodyDestroyed for " + loggingName + "."));
			}
			MethodBase method = new StackTrace().GetFrame(1).GetMethod();
			Plugin.Logger.LogDebug((object)$"Untracking {loggingName}. | {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 = e.GenerateIdentifier();
				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;
				}
				Decay();
			}
		}

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

		public virtual bool IsExpired(float elapsedTime)
		{
			return elapsedTime > Plugin.Config.EntryMaxRetainTime;
		}

		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;
		}
	}
	internal sealed class DamageLogUI : MonoBehaviour
	{
		private static HUD hud;

		private int bossIndex;

		private bool showingBoss;

		private Canvas canvas;

		private HGTextMeshProUGUI text;

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

		public NetworkUser user { get; private set; }

		public static void Instantiate(HUD hud, ref bool _)
		{
			if (!((Object)(object)DamageLogUI.hud != (Object)null))
			{
				Plugin.Logger.LogDebug((object)"Adding to HUD.");
				((Component)hud).gameObject.AddComponent<DamageLogUI>();
				DamageLogUI.hud = hud;
			}
		}

		internal static void MoveToGameEndReportPanel(GameEndReportPanelController panel)
		{
			if ((Object)(object)hud == (Object)null)
			{
				Plugin.Logger.LogWarning((object)"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)
			{
				Plugin.Logger.LogWarning((object)"Failed to move canvas (missing).");
				return;
			}
			Transform val = ((Component)panel).transform;
			while ((Object)(object)val != (Object)null)
			{
				if (((Object)val).name.Contains("Logbook") || ((Object)val).name.Contains("Pause"))
				{
					Plugin.Logger.LogWarning((object)"Blocked attempt to move canvas. This can safely be ignored if triggered by viewing Game End Report from Run History mid-run.");
					return;
				}
				val = val.parent;
			}
			((Component)component.canvas).transform.SetParent(((Component)panel).transform);
			((Behaviour)component.canvas).enabled = true;
			((Behaviour)component).enabled = false;
			Plugin.Logger.LogDebug((object)"Moved canvas.");
		}

		internal static void DisplayPlayerDamageLog(NetworkUser user)
		{
			if ((Object)(object)hud == (Object)null)
			{
				Plugin.Logger.LogWarning((object)"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)
			{
				Plugin.Logger.LogWarning((object)"Failed to update canvas (missing).");
				return;
			}
			if ((Object)(object)user == (Object)null)
			{
				Plugin.Logger.LogWarning((object)"Failed to display player damage log (null).");
				return;
			}
			if (!Plugin.Data.TryGetUserLog(user, out var log))
			{
				Plugin.Logger.LogWarning((object)("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.Config.Reload();
			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)
			{
				Plugin.Logger.LogWarning((object)"Failed to get HUD user (null).");
			}
			CreateCanvas(parent);
			CreateText();
			if (!Plugin.Config.SimpleTextMode)
			{
				CreatePortraits();
			}
			Plugin.Logger.LogDebug((object)"Created canvas.");
		}

		private void CreateCanvas(GameObject parent)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			canvas = new GameObject("DamageLogUI", new Type[2]
			{
				typeof(Canvas),
				typeof(GraphicRaycaster)
			}).GetComponent<Canvas>();
			RectTransform component = ((Component)canvas).GetComponent<RectTransform>();
			((Transform)component).SetParent(parent.transform);
			ResetRectTransform(component);
			AnchorStretchRight(component);
			component.pivot = Vector2.one;
			((Transform)component).localPosition = ((Transform)component).localPosition - Vector2.op_Implicit(Plugin.Config.CanvasOffsetTopRight);
			component.sizeDelta = Vector2.right * Plugin.Config.CanvasWidth - Vector2.up * Plugin.Config.CanvasOffsetTopRight;
		}

		private void CreatePortraits()
		{
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Expected O, but got Unknown
			VerticalLayoutGroup obj = ((Component)canvas).gameObject.AddComponent<VerticalLayoutGroup>();
			((HorizontalOrVerticalLayoutGroup)obj).childForceExpandHeight = false;
			((HorizontalOrVerticalLayoutGroup)obj).childControlHeight = false;
			((HorizontalOrVerticalLayoutGroup)obj).childForceExpandWidth = false;
			((HorizontalOrVerticalLayoutGroup)obj).childControlWidth = false;
			((HorizontalOrVerticalLayoutGroup)obj).spacing = Plugin.Config.PortraitSpacing;
			for (int i = 0; i < Plugin.Config.MaximumPortraitCount; i++)
			{
				uiEntries.Add(DamageSourceUI.Instantiate((RectTransform)((Component)canvas).transform).Hide());
			}
		}

		private void CreateText()
		{
			//IL_0018: 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_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)
			RectTransform component = new GameObject("DamageLogText", new Type[1] { typeof(RectTransform) }).GetComponent<RectTransform>();
			((Transform)component).SetParent(((Component)canvas).transform);
			ResetRectTransform(component);
			AnchorTopStretch(component);
			component.pivot = Vector2.one;
			component.sizeDelta = (Vector2)(Plugin.Config.SimpleTextMode ? Vector2.zero : new Vector2(((RectTransform)((Component)canvas).transform).sizeDelta.x, 0f));
			text = ((Component)component).gameObject.AddComponent<HGTextMeshProUGUI>();
			((TMP_Text)text).fontSize = Plugin.Config.TextSize;
			((TMP_Text)text).SetText("<style=cDeath>Damage Log <null></style>", true);
		}

		private void ListenForRebuild()
		{
			if (Input.GetKey((KeyCode)278) && Input.GetKeyDown((KeyCode)279))
			{
				Plugin.Logger.LogWarning((object)"Rebuild input triggered, destroying DamageLogUI.");
				Object.Destroy((Object)(object)((Component)canvas).gameObject);
				Object.Destroy((Object)(object)this);
				hud = null;
			}
		}

		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;
			}
			ListenForRebuild();
			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();
			stringBuilder.AppendLine("<style=cWorldEvent>Damage Log");
			stringBuilder.AppendLine("<" + log.displayName + "></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))
				{
					if (!Plugin.Config.CompactLines)
					{
						stringBuilder.AppendLine();
					}
					string text = (entry.isPlayerDamage ? "cDeath" : (entry.isFallDamage ? "cHumanObjective" : (entry.isVoidFogDamage ? "cIsVoid" : "")));
					if (string.IsNullOrEmpty(text))
					{
						stringBuilder.Append(entry.attackerName);
					}
					else
					{
						stringBuilder.Append("<style=" + text + ">" + entry.attackerName + "</style>");
					}
					bool num2 = entry.hits == 1;
					if (!num2)
					{
						stringBuilder.Append($"<style=cStack><nobr>×{entry.hits}</nobr></style>");
					}
					if (Plugin.Config.ShowRawDamageInsteadOfPercentage)
					{
						stringBuilder.Append($" · <style=cIsHealth><nobr>{-1f * entry.totalDamage:0.0}</nobr></style>");
					}
					else
					{
						stringBuilder.Append($" · <style=cIsDamage><nobr>{-1f * entry.totalDamagePercent:0.0%}</nobr></style>");
					}
					if (num2)
					{
						stringBuilder.Append($" <style=cEvent><nobr>({entry.remainingHpPercent:0.0%})</nobr></style>");
					}
					if (!Plugin.Config.HideDamageTimer)
					{
						stringBuilder.AppendLine($" · <style=cSub>{num:0.00s}</style>");
					}
					else
					{
						stringBuilder.AppendLine();
					}
				}
			}
			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 string attackerName;

		public readonly Texture attackerPortrait;

		public readonly Color attackerPortraitColor;

		public readonly Sprite eliteIcon;

		public readonly Color eliteIconColor;

		public readonly bool isPlayerDamage;

		public readonly bool isFallDamage;

		public readonly bool isVoidFogDamage;

		public readonly float timeStart;

		private static Texture PlanetPortrait => _PlanetPortrait ?? (_PlanetPortrait = LegacyResourcesAPI.Load<Texture>("Textures/BodyIcons/texUnidentifiedKillerIcon"));

		private static Texture SotVPortrait => _SotVPortrait ?? (_SotVPortrait = Addressables.LoadAssetAsync<Texture>((object)"RoR2/DLC1/UI/texVoidExpansionIcon.png").WaitForCompletion());

		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)
		{
			GameObject attacker = e.attacker;
			CharacterBody val = ((attacker != null) ? attacker.GetComponent<CharacterBody>() : null);
			isPlayerDamage = val != null && val.isPlayerControlled;
			isFallDamage = e.IsFallDamage();
			isVoidFogDamage = e.IsVoidFogDamage();
			identifier = e.GenerateIdentifier();
			attackerName = e.GetAttackerName();
			GetAttackerPortrait(e, out attackerPortrait, out attackerPortraitColor);
			GetEliteIcon(val, out eliteIcon, out eliteIconColor);
			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
			{
				Plugin.Logger.LogWarning((object)"Could not UpdateHpDamagePercent");
			}
		}

		private static void GetAttackerPortrait(DamageDealtMessage e, out Texture portrait, out Color color)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: 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)
			portrait = PlanetPortrait;
			color = Color.white;
			if ((Object)(object)e.attacker != (Object)null)
			{
				Texture val = e.attacker.GetComponent<CharacterBody>()?.portraitIcon;
				if ((Object)(object)val == (Object)null || (Object)(object)val == (Object)(object)PlanetPortrait)
				{
					val = GetAlternativeAttackerPortrait(e.attacker, e.GetAttackerName(), ref color);
				}
				if ((Object)(object)val != (Object)null)
				{
					portrait = val;
				}
			}
			else if (e.IsFallDamage())
			{
				portrait = (Texture)(object)Artifacts.weakAssKneesArtifactDef.smallIconSelectedSprite.texture;
			}
			else if (e.IsVoidFogDamage())
			{
				portrait = (Texture)(object)Buffs.VoidFogMild.iconSprite.texture;
				color = DamageColor.FindColor((DamageColorIndex)9);
			}
			else if (e.IsMeridianLightningDamage())
			{
				portrait = (Texture)(object)Buffs.lunarruin.iconSprite.texture;
			}
		}

		private static Texture GetAlternativeAttackerPortrait(GameObject attacker, string attackerName, ref Color color)
		{
			//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;
		}

		private 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;
		}

		private 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;
		}
	}
	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 Instantiate(RectTransform parent)
		{
			//IL_0025: 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_0035: Expected O, but got Unknown
			//IL_003e: 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_006b: Unknown result type (might be due to invalid IL or missing references)
			RectTransform val = (RectTransform)new GameObject("DamageEntry", new Type[2]
			{
				typeof(DamageSourceUI),
				typeof(RawImage)
			}).transform;
			((Transform)val).SetParent((Transform)(object)parent, false);
			val.sizeDelta = Vector2.one * ((Plugin.Config.PortraitSize > 0f) ? Plugin.Config.PortraitSize : parent.sizeDelta.x);
			return ((Component)val).GetComponent<DamageSourceUI>().Build(val);
		}

		private DamageSourceUI Build(RectTransform root)
		{
			//IL_0001: 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_0064: 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_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: 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_01a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
			float x = root.sizeDelta.x;
			tooltip = ((Component)root).gameObject.AddComponent<TooltipProvider>();
			portrait = ((Component)root).GetComponent<RawImage>();
			elite = AddChild<Image>(root, "elite");
			AnchorTopLeft(((Graphic)elite).rectTransform);
			((Graphic)elite).rectTransform.sizeDelta = Vector2.one * Plugin.Config.EliteIconSize;
			damage = AddChild<HGTextMeshProUGUI>(root, "damage");
			AnchorTopRight(((TMP_Text)damage).rectTransform);
			((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>(root, "hits");
			AnchorBottomLeft(((TMP_Text)hits).rectTransform);
			((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>(root, "time");
			AnchorBottomRight(((TMP_Text)time).rectTransform);
			((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;
			if (Plugin.Config.HideDamageTimer)
			{
				((Component)time).gameObject.SetActive(false);
			}
			return this;
		}

		private static T AddChild<T>(RectTransform parent, string name) where T : Graphic
		{
			//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);
			T component = val.GetComponent<T>();
			((Graphic)component).raycastTarget = false;
			return component;
		}

		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_0145: 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_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: 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.attackerPortraitColor;
			if ((Object)(object)src.eliteIcon != (Object)null)
			{
				elite.sprite = src.eliteIcon;
				((Graphic)elite).color = src.eliteIconColor;
				((Behaviour)elite).enabled = true;
			}
			else
			{
				((Behaviour)elite).enabled = false;
			}
			((TMP_Text)damage).SetText($"<style=cIsDamage>{-1f * 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<uint, DamageLog> bossLogs = new Dictionary<uint, DamageLog>();

		public bool HasBossLogs => bossLogs.Count > 0;

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

		internal void AddBossLog(BossDamageLog log)
		{
			Add(bossLogs, log.targetNetId, 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()
		{
			Plugin.Logger.LogDebug((object)"Clearing user damage logs.");
			Clear(userLogs);
		}

		internal void ClearBossLogs()
		{
			Plugin.Logger.LogDebug((object)"Clearing boss damage logs.");
			Clear(bossLogs);
		}

		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();
				Plugin.Logger.LogDebug((object)"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);
		}
	}
	[BepInPlugin("itsschwer.DamageLog", "DamageLog", "1.2.5")]
	public sealed class Plugin : BaseUnityPlugin
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static ShouldHudDisplayDelegate <0>__Instantiate;

			public static Action<CharacterBody> <1>__TrackUser;

			public static Action<Run> <2>__OnRunStartOrDestroy;

			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.2.5";

		internal static ManualLogSource Logger { get; private set; }

		internal static Config Config { get; private set; }

		internal static Data Data { get; private set; }

		private void Awake()
		{
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			Logger.Sources.Remove((ILogSource)(object)((BaseUnityPlugin)this).Logger);
			Logger = Logger.CreateLogSource("itsschwer.DamageLog");
			Config = new Config(((BaseUnityPlugin)this).Config);
			Data = new Data();
			if (Compatibility.DamageInfoChanged())
			{
				Object.DestroyImmediate((Object)(object)this);
				return;
			}
			new Harmony(((BaseUnityPlugin)this).Info.Metadata.GUID).PatchAll();
			Logger.LogMessage((object)"~awake.");
		}

		private void OnEnable()
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			object obj = <>O.<0>__Instantiate;
			if (obj == null)
			{
				ShouldHudDisplayDelegate val = DamageLogUI.Instantiate;
				<>O.<0>__Instantiate = val;
				obj = (object)val;
			}
			HUD.shouldHudDisplay += (ShouldHudDisplayDelegate)obj;
			CharacterBody.onBodyStartGlobal += TrackUser;
			Run.onRunStartGlobal += OnRunStartOrDestroy;
			Run.onRunDestroyGlobal += OnRunStartOrDestroy;
			Stage.onStageStartGlobal += OnStageStart;
			Logger.LogMessage((object)"~enabled.");
		}

		private void OnDisable()
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			object obj = <>O.<0>__Instantiate;
			if (obj == null)
			{
				ShouldHudDisplayDelegate val = DamageLogUI.Instantiate;
				<>O.<0>__Instantiate = val;
				obj = (object)val;
			}
			HUD.shouldHudDisplay -= (ShouldHudDisplayDelegate)obj;
			CharacterBody.onBodyStartGlobal -= TrackUser;
			Run.onRunStartGlobal -= OnRunStartOrDestroy;
			Run.onRunDestroyGlobal -= OnRunStartOrDestroy;
			Stage.onStageStartGlobal -= OnStageStart;
			Logger.LogMessage((object)"~disabled.");
		}

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

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

		private static void TrackUser(CharacterBody body)
		{
			if (body.isPlayerControlled)
			{
				NetworkUser val = Util.LookUpBodyNetworkUser(body);
				if (!((Object)(object)val == (Object)null))
				{
					DamageLog log = new DamageLog(val, body);
					Data.AddUserLog(val, log);
				}
			}
		}

		internal static void TrackBoss(BossGroup boss, CharacterMaster member)
		{
			//IL_0031: 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)
			if (Config.TrackBosses)
			{
				ManualLogSource logger = Logger;
				object[] obj = new object[4]
				{
					"TrackBoss",
					((Object)member).name,
					null,
					null
				};
				NetworkInstanceId netId = ((NetworkBehaviour)member).netId;
				obj[2] = ((NetworkInstanceId)(ref netId)).Value;
				obj[3] = ((Object)boss).name;
				logger.LogDebug((object)string.Format("{0}> Discovered {1} <{2:x8}> | {3}", obj));
				member.onBodyStart += TrackBoss;
			}
		}

		private static void TrackBoss(CharacterBody body)
		{
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			body.master.onBodyStart -= TrackBoss;
			if (!BossDamageLog.IsIgnoredBossSubtitle(body.subtitleNameToken))
			{
				ManualLogSource logger = Logger;
				object[] obj = new object[5]
				{
					"TrackBoss",
					((Object)body.master).name,
					null,
					null,
					null
				};
				NetworkInstanceId netId = ((NetworkBehaviour)body.master).netId;
				obj[2] = ((NetworkInstanceId)(ref netId)).Value;
				obj[3] = ((Object)body).name;
				netId = ((NetworkBehaviour)body).netId;
				obj[4] = ((NetworkInstanceId)(ref netId)).Value;
				logger.LogDebug((object)string.Format("{0}> Found {1} <{2:x8}> | {3} <{4:x8}>", obj));
				Data.AddBossLog(new BossDamageLog(body));
			}
		}
	}
}