Decompiled source of HUDdleUP v1.1.1

plugins/HUDdleUP/HUDdleUP.dll

Decompiled 2 hours ago
using System;
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.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using EntityStates;
using EntityStates.Railgunner.Reload;
using EntityStates.Railgunner.Weapon;
using HUDdleUP.Bandit;
using HUDdleUP.Behaviours;
using HUDdleUP.Compatibility;
using HUDdleUP.Loot;
using HUDdleUP.Multiplayer;
using HUDdleUP.Railgunner;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Mono.Cecil.Cil;
using MonoMod.Cil;
using MonoMod.RuntimeDetour;
using Rewired;
using RoR2;
using RoR2.Networking;
using RoR2.Skills;
using RoR2.UI;
using RoR2.UI.SkinControllers;
using TMPro;
using UnityEngine;
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("HUDdleUP")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.1.1.0")]
[assembly: AssemblyInformationalVersion("1.1.1+d7bc65e833a176a49056e7f05dead1dfa4362bde")]
[assembly: AssemblyProduct("HUDdleUP")]
[assembly: AssemblyTitle("HUDdleUP")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.1.1.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.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[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 HUDdleUP
{
	public sealed class Config
	{
		private readonly ConfigFile file;

		private readonly ConfigEntry<bool> fullerItemDescriptions;

		private readonly ConfigEntry<bool> fullerEquipmentDescriptions;

		private readonly ConfigEntry<bool> equipmentIconCooldownVisual;

		private readonly ConfigEntry<bool> commandMenuItemTooltips;

		private readonly ConfigEntry<bool> renameEquipmentDrones;

		private readonly ConfigEntry<bool> runDifficultyTooltip;

		private readonly ConfigEntry<bool> scoreboardShowChat;

		private readonly ConfigEntry<bool> lootPanel;

		private readonly ConfigEntry<bool> multiplayerConnectionPanel;

		private readonly ConfigEntry<bool> railgunnerAccuracyPanel;

		private readonly ConfigEntry<bool> banditComboPanel;

		public bool FullerItemDescriptions => fullerItemDescriptions.Value;

		public bool FullerEquipmentDescriptions => fullerEquipmentDescriptions.Value;

		public bool EquipmentIconCooldownVisual => equipmentIconCooldownVisual.Value;

		public bool CommandMenuItemTooltips => commandMenuItemTooltips.Value;

		public bool RenameEquipmentDrones => renameEquipmentDrones.Value;

		public bool RunDifficultyTooltip => runDifficultyTooltip.Value;

		public bool ScoreboardShowChat => scoreboardShowChat.Value;

		public bool LootPanel => lootPanel.Value;

		public bool MultiplayerConnectionPanel => multiplayerConnectionPanel.Value;

		public bool RailgunnerAccuracyPanel => railgunnerAccuracyPanel.Value;

		public bool BanditComboPanel => banditComboPanel.Value;

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

		internal Config(ConfigFile config)
		{
			file = config;
			fullerItemDescriptions = config.Bind<bool>("", "fullerItemDescriptions", true, "Replace the default short (pickup) descriptions in item tooltips with a combination of the short and detailed descriptions.\n\nNote that this mod currently does not provide calculated item stack stats.");
			fullerEquipmentDescriptions = config.Bind<bool>("", "fullerEquipmentDescriptions", true, "Replace the default short (pickup) descriptions in equipment tooltips with a combination of the short and detailed descriptions, as well as the equipment cooldown.\n\nNote that this mod currently does not provide calculated item stack stats.");
			equipmentIconCooldownVisual = config.Bind<bool>("", "equipmentIconCooldownVisual", true, "Add the cooldown progress visual from skill icons to the equipment icon.");
			commandMenuItemTooltips = config.Bind<bool>("", "commandMenuItemTooltips", true, "Add tooltips to items and equipment in pickup picker menus (e.g. command cubes, void potentials) that show the (fuller) description of the item.");
			renameEquipmentDrones = config.Bind<bool>("", "renameEquipmentDrones", true, "Replace the names of equipment drones in ally cards with the name of its held equipment.");
			runDifficultyTooltip = config.Bind<bool>("", "runDifficultyTooltip", true, "Add a tooltip to the difficulty icon in the HUD that shows the description of the run's difficulty.");
			scoreboardShowChat = config.Bind<bool>("", "scoreboardShowChat", true, "Show the chat history when the scoreboard is open.");
			lootPanel = config.Bind<bool>("HUD Panels", "lootPanel", true, "Add a Loot panel to the HUD to track how much loot is left on a stage.\n\nOnly visible when the scoreboard is open.");
			multiplayerConnectionPanel = config.Bind<bool>("HUD Panels", "multiplayerConnectionPanel", true, "Add a Connection panel to the HUD to check multiplayer latency (ping).\n\nOnly visible when the scoreboard is open.");
			railgunnerAccuracyPanel = config.Bind<bool>("HUD Panels", "railgunnerAccuracyPanel", true, "Add an Accuracy panel to the HUD to track your accuracy with landing perfect reloads and hitting weak points.");
			banditComboPanel = config.Bind<bool>("HUD Panels", "banditComboPanel", true, "Add a Combo panel to the HUD to track your consecutive cooldown resets when using the special skill \"Lights Out\".");
		}
	}
	public sealed class HUDPanel
	{
		public readonly GameObject gameObject;

		public readonly TextMeshProUGUI label;

		public readonly Transform stripContainer;

		private HUDPanel(GameObject panel, TextMeshProUGUI label, Transform stripContainer)
		{
			gameObject = panel;
			this.label = label;
			this.stripContainer = stripContainer;
		}

		public TextMeshProUGUI AddTextComponent(string name)
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			TextMeshProUGUI obj = Object.Instantiate<TextMeshProUGUI>(label, ((Component)stripContainer).transform);
			((Object)obj).name = name;
			LayoutElement val = default(LayoutElement);
			if (((Component)obj).TryGetComponent<LayoutElement>(ref val))
			{
				Object.Destroy((Object)(object)val);
			}
			LabelSkinController val2 = default(LabelSkinController);
			if (((Component)obj).TryGetComponent<LabelSkinController>(ref val2))
			{
				val2.labelType = (LabelType)0;
			}
			((TMP_Text)obj).fontSize = 12f;
			((TMP_Text)obj).fontSizeMax = 12f;
			((TMP_Text)obj).fontSizeMin = 6f;
			((TMP_Text)obj).alignment = (TextAlignmentOptions)257;
			((TMP_Text)obj).text = "hello world.";
			return obj;
		}

		public static HUDPanel ClonePanel(ObjectivePanelController objectivePanel, string name)
		{
			ObjectivePanelController obj = Object.Instantiate<ObjectivePanelController>(objectivePanel, ((Component)objectivePanel).transform.parent);
			GameObject val = ((Component)obj).gameObject;
			((Object)val).name = name;
			Object.DestroyImmediate((Object)(object)obj);
			Transform child = val.transform.GetChild(val.transform.childCount - 1);
			for (int num = ((Component)child).transform.childCount - 1; num >= 0; num--)
			{
				Object.Destroy((Object)(object)((Component)child.GetChild(num)).gameObject);
			}
			HudObjectiveTargetSetter val2 = default(HudObjectiveTargetSetter);
			if (val.TryGetComponent<HudObjectiveTargetSetter>(ref val2))
			{
				Object.Destroy((Object)(object)val2);
			}
			TextMeshProUGUI val3 = (TextMeshProUGUI)(((object)val.GetComponentInChildren<HGTextMeshProUGUI>()) ?? ((object)val.GetComponentInChildren<TextMeshProUGUI>()));
			LanguageTextMeshController val4 = default(LanguageTextMeshController);
			if ((Object)(object)val3 == (Object)null)
			{
				Plugin.Logger.LogWarning((object)("New HUD panel \"" + ((Object)val).name + "\" is missing a label!"));
			}
			else if (((Component)val3).TryGetComponent<LanguageTextMeshController>(ref val4))
			{
				Object.DestroyImmediate((Object)(object)val4);
			}
			return new HUDPanel(val, val3, child);
		}
	}
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInPlugin("itsschwer.HUDdleUP", "HUDdleUP", "1.1.1")]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string GUID = "itsschwer.HUDdleUP";

		public const string Author = "itsschwer";

		public const string Name = "HUDdleUP";

		public const string Version = "1.1.1";

		internal static ManualLogSource Logger { get; private set; }

		public static Config Config { get; private set; }

		private void Awake()
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			Logger.Sources.Remove((ILogSource)(object)((BaseUnityPlugin)this).Logger);
			Logger = Logger.CreateLogSource("itsschwer.HUDdleUP");
			Config = new Config(((BaseUnityPlugin)this).Config);
			new Harmony(((BaseUnityPlugin)this).Info.Metadata.GUID).PatchAll();
			MiniMapMod.TryPatch();
			Logger.LogMessage((object)"~awake.");
		}

		private void OnEnable()
		{
			Run.onRunStartGlobal += OnRunStart;
			Run.onRunDestroyGlobal += OnRunDestroy;
			Logger.LogMessage((object)"~enabled.");
		}

		private void OnDisable()
		{
			Run.onRunStartGlobal -= OnRunStart;
			Run.onRunDestroyGlobal -= OnRunDestroy;
			Logger.LogMessage((object)"~disabled.");
		}

		private void OnRunStart(Run _)
		{
			LootPanel.Hook();
			ConnectionPanel.Hook();
			RailgunnerAccuracyPanel.Hook();
			BanditComboPanel.Hook();
		}

		private void OnRunDestroy(Run _)
		{
			LootPanel.Unhook();
			ConnectionPanel.Unhook();
			RailgunnerAccuracyPanel.Unhook();
			BanditComboPanel.Unhook();
		}
	}
	public static class TooltipHelper
	{
		public static TooltipProvider AddTooltipProvider(Graphic target, bool suppressLogs = false)
		{
			if ((Object)(object)target == (Object)null)
			{
				return null;
			}
			((Component)(object)target).AddGraphicRaycasterToParentCanvas(!suppressLogs);
			target.raycastTarget = true;
			return ((Component)target).gameObject.AddComponentIfMissing<TooltipProvider>(!suppressLogs);
		}

		private static bool AddGraphicRaycasterToParentCanvas(this Component child, bool emitLog)
		{
			GameObject gameObject = ((Component)child.GetComponentInParent<Canvas>()).gameObject;
			if (emitLog)
			{
				Plugin.Logger.LogDebug((object)("Found parent canvas " + ((Object)gameObject).name + " for " + ((Object)child).name));
			}
			return Object.op_Implicit((Object)(object)gameObject.AddComponentIfMissing<GraphicRaycaster>(emitLog));
		}

		private static T AddComponentIfMissing<T>(this GameObject target, bool emitLog) where T : Component
		{
			T val = target.GetComponent<T>();
			if ((Object)(object)val == (Object)null)
			{
				val = target.AddComponent<T>();
				if (emitLog)
				{
					Plugin.Logger.LogDebug((object)("Added " + typeof(T).FullName + " to " + ((Object)target).name));
				}
			}
			return val;
		}
	}
}
namespace HUDdleUP.Patches
{
	[HarmonyPatch]
	internal static class EquipmentCooldownProgressVisual
	{
		[HarmonyPostfix]
		[HarmonyPatch(typeof(HUD), "Awake")]
		private static void HUD_Awake(HUD __instance)
		{
			if (!Plugin.Config.EquipmentIconCooldownVisual || __instance.skillIcons.Length == 0 || !Object.op_Implicit((Object)(object)__instance.skillIcons[0]))
			{
				return;
			}
			if (!Object.op_Implicit((Object)(object)__instance.skillIcons[0].cooldownRemapPanel) || !Object.op_Implicit((Object)(object)((Component)__instance.skillIcons[0].cooldownRemapPanel).gameObject))
			{
				Plugin.Logger.LogWarning((object)"EquipmentCooldownProgressVisual> Could not initialize — missing cooldownRemapPanel. This warning can safely be ignored if RiskUI is installed.");
				return;
			}
			GameObject gameObject = ((Component)__instance.skillIcons[0].cooldownRemapPanel).gameObject;
			EquipmentIcon[] equipmentIcons = __instance.equipmentIcons;
			for (int i = 0; i < equipmentIcons.Length; i++)
			{
				EquipmentCooldownPanel.Init(equipmentIcons[i], gameObject);
			}
		}
	}
	[HarmonyPatch]
	internal static class EquipmentDroneUseHeldEquipmentNameInAllyCard
	{
		[HarmonyPostfix]
		[HarmonyPatch(typeof(AllyCardController), "LateUpdate")]
		private static void AllyCardController_LateUpdate(AllyCardController __instance)
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.Config.RenameEquipmentDrones || !Object.op_Implicit((Object)(object)__instance.sourceMaster) || !Object.op_Implicit((Object)(object)__instance.sourceMaster.inventory))
			{
				return;
			}
			EquipmentDef equipmentDef = EquipmentCatalog.GetEquipmentDef(__instance.sourceMaster.inventory.currentEquipmentIndex);
			if ((Object)(object)equipmentDef == (Object)null)
			{
				return;
			}
			string @string = Language.GetString(equipmentDef.nameToken);
			if (!(((TMP_Text)__instance.nameLabel).text == @string))
			{
				CharacterBody body = __instance.sourceMaster.GetBody();
				if (!((Object)(object)body == (Object)null) && !(body.baseNameToken != "EQUIPMENTDRONE_BODY_NAME"))
				{
					((TMP_Text)__instance.nameLabel).text = Language.GetString(equipmentDef.nameToken);
				}
			}
		}
	}
	[HarmonyPatch]
	internal static class FullerDescriptions
	{
		[HarmonyPostfix]
		[HarmonyPatch(typeof(ItemIcon), "SetItemIndex")]
		private static void ItemIcon_SetItemIndex(ItemIcon __instance)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			if (Plugin.Config.FullerItemDescriptions)
			{
				ItemDef itemDef = ItemCatalog.GetItemDef(__instance.itemIndex);
				if (!((Object)(object)itemDef == (Object)null) && !((Object)(object)__instance.tooltipProvider == (Object)null))
				{
					__instance.tooltipProvider.overrideBodyText = GetCombinedDescription(itemDef.descriptionToken, itemDef.pickupToken);
				}
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(EquipmentIcon), "SetDisplayData")]
		private static void EquipmentIcon_SetDisplayData(EquipmentIcon __instance)
		{
			if (Plugin.Config.FullerEquipmentDescriptions)
			{
				EquipmentDef equipmentDef = __instance.currentDisplayData.equipmentDef;
				if (!((Object)(object)equipmentDef == (Object)null) && !((Object)(object)__instance.tooltipProvider == (Object)null))
				{
					StringBuilder stringBuilder = new StringBuilder(GetCombinedDescription(equipmentDef.descriptionToken, equipmentDef.pickupToken));
					stringBuilder.AppendLine().AppendLine().Append(GetEquipmentCooldown(equipmentDef, __instance.targetInventory));
					__instance.tooltipProvider.overrideBodyText = stringBuilder.ToString();
				}
			}
		}

		internal static string GetCombinedDescription(string descriptionToken, string pickupToken)
		{
			StringBuilder stringBuilder = new StringBuilder();
			string @string = Language.GetString(descriptionToken);
			string string2 = Language.GetString(pickupToken);
			if (@string != descriptionToken && @string != string2)
			{
				stringBuilder.AppendLine("<style=cStack>" + string2 + "</style>");
				stringBuilder.AppendLine();
				stringBuilder.Append(@string);
			}
			else
			{
				stringBuilder.Append(string2);
			}
			return stringBuilder.ToString();
		}

		internal static string GetEquipmentCooldown(EquipmentDef equipment, Inventory inventory)
		{
			if ((Object)(object)inventory == (Object)null)
			{
				return $"Cooldown: <style=cIsDamage>{equipment.cooldown:0.###}s</style>";
			}
			StringBuilder stringBuilder = new StringBuilder();
			float num = inventory.CalculateEquipmentCooldownScale();
			stringBuilder.Append($"Cooldown: <style=cIsDamage>{equipment.cooldown * num:0.###}s</style>");
			if (num < 1f)
			{
				stringBuilder.Append($" <style=cStack>({equipment.cooldown}×<style=cIsUtility>{num:0.###%}</style>)</style>");
			}
			return stringBuilder.ToString();
		}
	}
	[HarmonyPatch]
	internal static class PickupPickerTooltips
	{
		[HarmonyPostfix]
		[HarmonyPatch(typeof(PickupPickerPanel), "SetPickupOptions")]
		private static void PickupPickerPanel_SetPickupOptions(PickupPickerPanel __instance, Option[] options)
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: 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_006c: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.Config.CommandMenuItemTooltips)
			{
				return;
			}
			for (int i = 0; i < options.Length; i++)
			{
				TooltipProvider val = TooltipHelper.AddTooltipProvider(((Component)__instance.buttonAllocator.elements[i]).GetComponent<Graphic>(), suppressLogs: true);
				PickupDef pickupDef = PickupCatalog.GetPickupDef(options[i].pickupIndex);
				ItemDef itemDef = ItemCatalog.GetItemDef(pickupDef.itemIndex);
				EquipmentDef equipmentDef = EquipmentCatalog.GetEquipmentDef(pickupDef.equipmentIndex);
				bool flag = (Object)(object)itemDef != (Object)null;
				val.titleColor = pickupDef.darkColor;
				val.titleToken = (flag ? itemDef.nameToken : equipmentDef.nameToken);
				val.bodyToken = (flag ? itemDef.descriptionToken : equipmentDef.descriptionToken);
				if (flag)
				{
					val.overrideBodyText = FullerDescriptions.GetCombinedDescription(val.bodyToken, itemDef.pickupToken);
				}
				else
				{
					val.overrideBodyText = FullerDescriptions.GetCombinedDescription(val.bodyToken, equipmentDef.pickupToken) + "\n\n" + FullerDescriptions.GetEquipmentCooldown(equipmentDef, null);
				}
			}
		}
	}
	[HarmonyPatch]
	internal static class RunDifficultyTooltip
	{
		[HarmonyPostfix]
		[HarmonyPatch(typeof(CurrentDifficultyIconController), "Start")]
		private static void CurrentDifficultyIconController_Start(CurrentDifficultyIconController __instance)
		{
			//IL_002b: 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_003d: Unknown result type (might be due to invalid IL or missing references)
			if (Plugin.Config.RunDifficultyTooltip && (Object)(object)Run.instance != (Object)null)
			{
				TooltipProvider obj = TooltipHelper.AddTooltipProvider(((Component)__instance).GetComponent<Graphic>());
				DifficultyDef difficultyDef = DifficultyCatalog.GetDifficultyDef(Run.instance.selectedDifficulty);
				obj.titleColor = difficultyDef.color;
				obj.titleToken = difficultyDef.nameToken;
				obj.bodyToken = difficultyDef.descriptionToken;
			}
		}
	}
	[HarmonyPatch]
	internal static class ScoreboardShowChat
	{
		[HarmonyPostfix]
		[HarmonyPatch(typeof(ChatBox), "UpdateFade")]
		private static void ChatBox_UpdateFade(ChatBox __instance)
		{
			if (Plugin.Config.ScoreboardShowChat && (Object)(object)__instance.fadeGroup != (Object)null)
			{
				LocalUser firstLocalUser = LocalUserManager.GetFirstLocalUser();
				Player val = ((firstLocalUser != null) ? firstLocalUser.inputPlayer : null);
				if (val != null && val.GetButton("info"))
				{
					__instance.fadeGroup.alpha = 1f;
				}
			}
		}
	}
}
namespace HUDdleUP.Railgunner
{
	internal sealed class RailgunnerAccuracyPanel : MonoBehaviour
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static ShouldHudDisplayDelegate <0>__Init;
		}

		private static HUD hud;

		private static ReloadAccuracy reloadAccuracy;

		private static WeakPointAccuracy weakPointAccuracy;

		private HUDPanel panel;

		private TextMeshProUGUI display;

		public static void Hook()
		{
			//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>__Init;
			if (obj == null)
			{
				ShouldHudDisplayDelegate val = Init;
				<>O.<0>__Init = val;
				obj = (object)val;
			}
			HUD.shouldHudDisplay += (ShouldHudDisplayDelegate)obj;
		}

		public static void Unhook()
		{
			//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>__Init;
			if (obj == null)
			{
				ShouldHudDisplayDelegate val = Init;
				<>O.<0>__Init = val;
				obj = (object)val;
			}
			HUD.shouldHudDisplay -= (ShouldHudDisplayDelegate)obj;
			if (reloadAccuracy != null)
			{
				reloadAccuracy.Unhook();
				reloadAccuracy = null;
			}
			if (weakPointAccuracy != null)
			{
				weakPointAccuracy.Unhook();
				weakPointAccuracy = null;
			}
		}

		private static void Init(HUD hud, ref bool _)
		{
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.Config.RailgunnerAccuracyPanel || (Object)(object)RailgunnerAccuracyPanel.hud != (Object)null)
			{
				return;
			}
			ObjectivePanelController componentInChildren = ((Component)hud).GetComponentInChildren<ObjectivePanelController>();
			if (!Object.op_Implicit((Object)(object)componentInChildren) || (Object)(object)hud.localUserViewer.cachedBody == (Object)null)
			{
				return;
			}
			RailgunnerAccuracyPanel.hud = hud;
			if (hud.localUserViewer.cachedBody.bodyIndex != BodyCatalog.FindBodyIndex("RailgunnerBody"))
			{
				Plugin.Logger.LogDebug((object)"Local user is not Railgunner, skipping RailgunnerAccuracyPanel initialization.");
				return;
			}
			if (reloadAccuracy == null)
			{
				reloadAccuracy = new ReloadAccuracy();
				reloadAccuracy.Hook();
			}
			if (weakPointAccuracy == null)
			{
				weakPointAccuracy = new WeakPointAccuracy();
				weakPointAccuracy.Hook();
			}
			HUDPanel hUDPanel = HUDPanel.ClonePanel(componentInChildren, "RailgunnerAccuracyPanel");
			((Component)hud).gameObject.AddComponent<RailgunnerAccuracyPanel>().panel = hUDPanel;
			Plugin.Logger.LogDebug((object)"Initialized RailgunnerAccuracyPanel.");
		}

		private void Start()
		{
			((TMP_Text)panel.label).text = "Accuracy:";
			display = panel.AddTextComponent("Accuracy Tracker");
		}

		private void Update()
		{
			if (reloadAccuracy != null)
			{
				StringBuilder stringBuilder = new StringBuilder();
				stringBuilder.AppendLine(reloadAccuracy.ToString());
				stringBuilder.AppendLine();
				stringBuilder.AppendLine(weakPointAccuracy.ToString());
				((TMP_Text)display).text = stringBuilder.ToString();
			}
		}
	}
	internal sealed class ReloadAccuracy
	{
		private static readonly MethodInfo AttemptBoost = typeof(Reloading).GetMethod("AttemptBoost", BindingFlags.Instance | BindingFlags.Public);

		private readonly string labelColor = "#" + ColorUtility.ToHtmlStringRGB(DamageColor.FindColor((DamageColorIndex)12));

		private int totalReloads;

		private int perfectReloads;

		private int totalReloadsStage;

		private int perfectReloadsStage;

		private int consecutive;

		private int consecutiveBest;

		private Hook OnReloadAttemptBoost;

		public void Hook()
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Expected O, but got Unknown
			MethodInfo method = typeof(ReloadAccuracy).GetMethod("RecordReload", BindingFlags.Instance | BindingFlags.NonPublic);
			OnReloadAttemptBoost = new Hook((MethodBase)AttemptBoost, method, (object)this);
			Stage.onStageStartGlobal += OnStageStart;
		}

		public void Unhook()
		{
			OnReloadAttemptBoost.Dispose();
			Stage.onStageStartGlobal -= OnStageStart;
		}

		private bool RecordReload(Func<Reloading, bool> orig, Reloading self)
		{
			bool num = orig(self);
			if (num)
			{
				perfectReloads++;
				perfectReloadsStage++;
				consecutive++;
			}
			else
			{
				if (consecutive > consecutiveBest)
				{
					consecutiveBest = consecutive;
				}
				consecutive = 0;
			}
			totalReloads++;
			totalReloadsStage++;
			return num;
		}

		private void OnStageStart(Stage _)
		{
			totalReloadsStage = 0;
			perfectReloadsStage = 0;
		}

		public override string ToString()
		{
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.Append("<style=cStack>> </style><color=" + labelColor + ">Perfect Reloads</color><style=cStack>: </style>");
			if (totalReloads == 0)
			{
				stringBuilder.Append("<style=cStack>-.--%</style>");
			}
			else
			{
				stringBuilder.Append($"{(float)perfectReloads / (float)totalReloads:0.00%}");
			}
			stringBuilder.AppendLine();
			stringBuilder.Append("<style=cStack>   > this stage: </style>");
			if (totalReloadsStage == 0)
			{
				stringBuilder.Append("<style=cStack>-.--%</style>");
			}
			else
			{
				stringBuilder.Append($"{(float)perfectReloadsStage / (float)totalReloadsStage:0.00%}");
			}
			stringBuilder.AppendLine($"<style=cStack> ({perfectReloadsStage}/{totalReloadsStage})</style>");
			stringBuilder.Append($"<style=cStack>   > consecutive: </style>{consecutive}<style=cStack> ({consecutiveBest})</style>");
			return stringBuilder.ToString();
		}
	}
	internal sealed class WeakPointAccuracy
	{
		private readonly string labelColor = "#" + ColorUtility.ToHtmlStringRGB(DamageColor.FindColor((DamageColorIndex)5));

		private int shots;

		private int weakPointHits;

		private int consecutive;

		private int consecutiveBest;

		public void Hook()
		{
			BaseFireSnipe.onFireSnipe += Snipe_onFireSnipe;
			BaseFireSnipe.onWeakPointHit += Snipe_onWeakPointHit;
			BaseFireSnipe.onWeakPointMissed += Snipe_onWeakPointMissed;
			Stage.onStageStartGlobal += OnStageStart;
		}

		public void Unhook()
		{
			BaseFireSnipe.onFireSnipe -= Snipe_onFireSnipe;
			BaseFireSnipe.onWeakPointHit -= Snipe_onWeakPointHit;
			BaseFireSnipe.onWeakPointMissed -= Snipe_onWeakPointMissed;
			Stage.onStageStartGlobal -= OnStageStart;
		}

		private void Snipe_onFireSnipe(BaseFireSnipe snipe)
		{
			if (((EntityState)snipe).isAuthority)
			{
				shots++;
			}
		}

		private void Snipe_onWeakPointHit(DamageInfo _)
		{
			weakPointHits++;
			consecutive++;
		}

		private void Snipe_onWeakPointMissed()
		{
			if (consecutive > consecutiveBest)
			{
				consecutiveBest = consecutive;
			}
			consecutive = 0;
		}

		private void OnStageStart(Stage _)
		{
			shots = 0;
			weakPointHits = 0;
		}

		public override string ToString()
		{
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.Append("<style=cStack>> </style><color=" + labelColor + ">Weak Points Hit</color><style=cStack>: </style>");
			stringBuilder.AppendLine($"{weakPointHits}<style=cStack> : {shots}</style>");
			stringBuilder.Append($"<style=cStack>   > consecutive: </style>{consecutive}<style=cStack> ({consecutiveBest})</style>");
			return stringBuilder.ToString();
		}
	}
}
namespace HUDdleUP.Multiplayer
{
	internal sealed class ConnectionPanel : MonoBehaviour
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static ShouldHudDisplayDelegate <0>__Init;
		}

		private const float updateFrequency = 0f;

		private float lastUpdateTimestamp;

		private static HUD hud;

		private HUDPanel panel;

		private TextMeshProUGUI display;

		public static void Hook()
		{
			//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>__Init;
			if (obj == null)
			{
				ShouldHudDisplayDelegate val = Init;
				<>O.<0>__Init = val;
				obj = (object)val;
			}
			HUD.shouldHudDisplay += (ShouldHudDisplayDelegate)obj;
		}

		public static void Unhook()
		{
			//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>__Init;
			if (obj == null)
			{
				ShouldHudDisplayDelegate val = Init;
				<>O.<0>__Init = val;
				obj = (object)val;
			}
			HUD.shouldHudDisplay -= (ShouldHudDisplayDelegate)obj;
		}

		public static void Init(HUD hud, ref bool _)
		{
			if (Plugin.Config.MultiplayerConnectionPanel && NetworkUser.readOnlyInstancesList.Count > 1 && !((Object)(object)ConnectionPanel.hud != (Object)null))
			{
				ObjectivePanelController componentInChildren = ((Component)hud).GetComponentInChildren<ObjectivePanelController>();
				if (Object.op_Implicit((Object)(object)componentInChildren))
				{
					ConnectionPanel.hud = hud;
					HUDPanel hUDPanel = HUDPanel.ClonePanel(componentInChildren, "ConnectionPanel");
					((Component)hud).gameObject.AddComponent<ConnectionPanel>().panel = hUDPanel;
					Plugin.Logger.LogDebug((object)"Initialized ConnectionPanel");
				}
			}
		}

		private void Start()
		{
			((TMP_Text)panel.label).text = "Connection:";
			display = panel.AddTextComponent("Multiplayer Connection");
		}

		private void Update()
		{
			LocalUser localUserViewer = hud.localUserViewer;
			bool flag = ((localUserViewer != null) ? localUserViewer.inputPlayer : null) != null && hud.localUserViewer.inputPlayer.GetButton("info");
			panel.gameObject.SetActive(flag);
			if (flag && !(Time.unscaledTime - lastUpdateTimestamp < 0f))
			{
				lastUpdateTimestamp = Time.unscaledTime;
				((TMP_Text)display).text = "<style=cStack>> <style=cIsUtility>Ping (round-trip time)</style>:</style>\n" + (NetworkServer.active ? GetPingHost() : GetPingClient());
			}
		}

		private string GetPingClient()
		{
			int num = -1;
			if (NetworkClient.active && Object.op_Implicit((Object)(object)NetworkManagerSystem.singleton))
			{
				NetworkConnection connection = ((NetworkManager)NetworkManagerSystem.singleton).client.connection;
				if (connection != null)
				{
					num = (int)RttManager.GetConnectionRTTInMilliseconds(connection);
				}
			}
			return $"<style=cStack>   > You are client</style>\n<style=cStack>      > <style=cSub>{num}</style> ms</style>";
		}

		private string GetPingHost()
		{
			StringBuilder stringBuilder = new StringBuilder("<style=cStack>   > You are host</style>");
			foreach (NetworkUser readOnlyInstances in NetworkUser.readOnlyInstancesList)
			{
				if (Object.op_Implicit((Object)(object)readOnlyInstances) && !((NetworkBehaviour)readOnlyInstances).hasAuthority)
				{
					int num = ((((NetworkBehaviour)readOnlyInstances).connectionToClient != null) ? ((int)RttManager.GetConnectionRTTInMilliseconds(((NetworkBehaviour)readOnlyInstances).connectionToClient)) : (-1));
					stringBuilder.AppendLine().Append($"<style=cStack>   > <style=cUserSetting>{readOnlyInstances.userName}</style>: <style=cSub>{num}</style> ms</style>");
				}
			}
			return stringBuilder.ToString();
		}
	}
}
namespace HUDdleUP.Loot
{
	public sealed record Interactables
	{
		public readonly int chests;

		public readonly int chestsAvailable;

		public readonly int terminals;

		public readonly int terminalsAvailable;

		public readonly int chanceShrines;

		public readonly int chanceShrinesAvailable;

		public readonly int shrineChances;

		public readonly int shrineChancesAvailable;

		public readonly int lockboxes;

		public readonly int lockboxesAvailable;

		public readonly int adaptiveChests;

		public readonly int adaptiveChestsAvailable;

		public readonly int voids;

		public readonly int voidsAvailable;

		public readonly int cloakedChests;

		public readonly int cloakedChestsAvailable;

		public readonly int equipment;

		public readonly int equipmentAvailable;

		public readonly int lunarPods;

		public readonly int lunarPodsAvailable;

		public readonly bool cleansingPoolPresent;

		public readonly bool scrapperPresent;

		public readonly int whiteTakers;

		public readonly int greenTakers;

		public readonly int redTakers;

		public readonly int yellowTakers;

		public Interactables(List<PurchaseInteraction> interactions, bool scrapperPresent)
		{
			//IL_0579: Unknown result type (might be due to invalid IL or missing references)
			//IL_057e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0580: Unknown result type (might be due to invalid IL or missing references)
			//IL_0583: Unknown result type (might be due to invalid IL or missing references)
			//IL_05a5: Expected I4, but got Unknown
			this.scrapperPresent = scrapperPresent;
			for (int i = 0; i < interactions.Count; i++)
			{
				switch (interactions[i].displayNameToken)
				{
				case "CHEST1_NAME":
				case "CHEST2_NAME":
				case "CATEGORYCHEST_HEALING_NAME":
				case "CATEGORYCHEST_UTILITY_NAME":
				case "CATEGORYCHEST2_DAMAGE_NAME":
				case "CATEGORYCHEST2_HEALING_NAME":
				case "CATEGORYCHEST2_UTILITY_NAME":
				case "GOLDCHEST_NAME":
				case "CATEGORYCHEST_DAMAGE_NAME":
					chests++;
					if (interactions[i].available)
					{
						chestsAvailable++;
					}
					break;
				case "EQUIPMENTBARREL_NAME":
					equipment++;
					if (interactions[i].available)
					{
						equipmentAvailable++;
					}
					break;
				case "MULTISHOP_TERMINAL_NAME":
					if (((Object)interactions[i]).name.Contains("Equipment"))
					{
						equipment++;
						if (interactions[i].available)
						{
							equipmentAvailable++;
						}
					}
					else
					{
						terminals++;
						if (interactions[i].available)
						{
							terminalsAvailable++;
						}
					}
					break;
				case "SHRINE_CHANCE_NAME":
					chanceShrines++;
					if (interactions[i].available)
					{
						chanceShrinesAvailable++;
					}
					if (NetworkServer.active)
					{
						ShrineChanceBehavior component = ((Component)interactions[i]).GetComponent<ShrineChanceBehavior>();
						shrineChances += component.maxPurchaseCount;
						shrineChancesAvailable += component.maxPurchaseCount - component.successfulPurchaseCount;
					}
					break;
				case "VOIDLOCKBOX_NAME":
				case "LOCKBOX_NAME":
					lockboxes++;
					if (interactions[i].available)
					{
						lockboxesAvailable++;
					}
					break;
				case "CASINOCHEST_NAME":
					adaptiveChests++;
					if (interactions[i].available)
					{
						adaptiveChestsAvailable++;
					}
					break;
				case "VOID_TRIPLE_NAME":
				case "VOID_CHEST_NAME":
					voids++;
					if (interactions[i].available)
					{
						voidsAvailable++;
					}
					break;
				case "CHEST1_STEALTHED_NAME":
					cloakedChests++;
					if (interactions[i].available)
					{
						cloakedChestsAvailable++;
					}
					break;
				case "DUPLICATOR_WILD_NAME":
				case "BAZAAR_CAULDRON_NAME":
				case "DUPLICATOR_NAME":
				case "DUPLICATOR_MILITARY_NAME":
				{
					CostTypeIndex costType = interactions[i].costType;
					switch (costType - 4)
					{
					case 0:
						whiteTakers++;
						break;
					case 1:
						greenTakers++;
						break;
					case 2:
						redTakers++;
						break;
					case 6:
						yellowTakers++;
						break;
					}
					break;
				}
				case "SHRINE_CLEANSE_NAME":
					cleansingPoolPresent = true;
					break;
				case "LUNAR_CHEST_NAME":
					lunarPods++;
					if (interactions[i].available)
					{
						lunarPodsAvailable++;
					}
					break;
				}
			}
		}
	}
	internal sealed class LootPanel : MonoBehaviour
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static ShouldHudDisplayDelegate <0>__Init;
		}

		private static HUD hud;

		private HUDPanel panel;

		private TextMeshProUGUI display;

		private Interactables interactables;

		public static void Hook()
		{
			//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>__Init;
			if (obj == null)
			{
				ShouldHudDisplayDelegate val = Init;
				<>O.<0>__Init = val;
				obj = (object)val;
			}
			HUD.shouldHudDisplay += (ShouldHudDisplayDelegate)obj;
		}

		public static void Unhook()
		{
			//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>__Init;
			if (obj == null)
			{
				ShouldHudDisplayDelegate val = Init;
				<>O.<0>__Init = val;
				obj = (object)val;
			}
			HUD.shouldHudDisplay -= (ShouldHudDisplayDelegate)obj;
		}

		private static void Init(HUD hud, ref bool _)
		{
			if (Plugin.Config.LootPanel && !((Object)(object)LootPanel.hud != (Object)null))
			{
				ObjectivePanelController componentInChildren = ((Component)hud).GetComponentInChildren<ObjectivePanelController>();
				if (Object.op_Implicit((Object)(object)componentInChildren))
				{
					LootPanel.hud = hud;
					HUDPanel hUDPanel = HUDPanel.ClonePanel(componentInChildren, "LootPanel");
					((Component)hud).gameObject.AddComponent<LootPanel>().panel = hUDPanel;
					Plugin.Logger.LogDebug((object)"Initialized LootPanel.");
				}
			}
		}

		private void Start()
		{
			((TMP_Text)panel.label).text = "Loot:";
			display = panel.AddTextComponent("Loot Tracker");
		}

		private void Update()
		{
			LocalUser localUserViewer = hud.localUserViewer;
			bool flag = ((localUserViewer != null) ? localUserViewer.inputPlayer : null) != null && hud.localUserViewer.inputPlayer.GetButton("info");
			panel.gameObject.SetActive(flag);
			if (flag)
			{
				interactables = new Interactables(InstanceTracker.GetInstancesList<PurchaseInteraction>(), (Object)(object)Object.FindObjectOfType<ScrapperController>() != (Object)null);
				((TMP_Text)display).text = GenerateText();
			}
		}

		public string GenerateText()
		{
			string tagValue = "#" + ColorCatalog.GetColorHexString((ColorIndex)5);
			StringBuilder stringBuilder = new StringBuilder();
			if (interactables.terminals > 0)
			{
				stringBuilder.AppendLine(FormatLine("style", "cIsUtility", "MULTISHOP_TERMINAL_NAME", interactables.terminalsAvailable, interactables.terminals));
			}
			if (interactables.chests > 0)
			{
				stringBuilder.AppendLine(FormatLine("style", "cIsDamage", "CHEST1_NAME", interactables.chestsAvailable, interactables.chests));
			}
			if (interactables.adaptiveChests > 0)
			{
				stringBuilder.AppendLine(FormatLine("style", "cArtifact", "CASINOCHEST_NAME", interactables.adaptiveChestsAvailable, interactables.adaptiveChests));
			}
			if (interactables.chanceShrines > 0)
			{
				stringBuilder.AppendLine(NetworkServer.active ? FormatLine("style", "cShrine", "SHRINE_CHANCE_NAME", interactables.shrineChancesAvailable, interactables.shrineChances, interactables.chanceShrinesAvailable) : FormatLine("style", "cShrine", "SHRINE_CHANCE_NAME", interactables.chanceShrinesAvailable, interactables.chanceShrines));
			}
			if (interactables.equipment > 0)
			{
				stringBuilder.AppendLine(FormatLine("color", tagValue, "EQUIPMENTBARREL_NAME", interactables.equipmentAvailable, interactables.equipment));
			}
			if (interactables.lockboxes > 0)
			{
				stringBuilder.AppendLine(FormatLine("style", "cHumanObjective", "LOCKBOX_NAME", interactables.lockboxesAvailable, interactables.lockboxes));
			}
			if ((Object)(object)TeleporterInteraction.instance != (Object)null)
			{
				if (TeleporterInteraction.instance.monstersCleared)
				{
					string text = (interactables.cleansingPoolPresent ? " · <style=cLunarObjective>@</style>" : "");
					stringBuilder.AppendLine().AppendLine(FormatLabel("<style=cSub>" + Language.GetString("SCRAPPER_NAME") + "</style>") + (interactables.scrapperPresent ? "@" : "×") + text);
					AppendFabricators(interactables, stringBuilder);
					if (interactables.voids > 0)
					{
						stringBuilder.AppendLine(FormatLine("style", "cIsVoid", "VOID_CHEST_NAME", interactables.voidsAvailable, interactables.voids));
					}
					if (interactables.lunarPods > 0)
					{
						stringBuilder.AppendLine(FormatLine("style", "cLunarObjective", "LUNAR_CHEST_NAME", interactables.lunarPodsAvailable, interactables.lunarPods));
					}
				}
				if (TeleporterInteraction.instance.isCharged && interactables.cloakedChests > 0)
				{
					stringBuilder.AppendLine().AppendLine(FormatLine("style", "cLunarObjective", "CHEST1_STEALTHED_NAME", interactables.cloakedChestsAvailable, interactables.cloakedChests));
				}
			}
			stringBuilder.AppendLine().AppendLine(FormatEnemies());
			if ((Object)(object)TeleporterInteraction.instance != (Object)null && TeleporterInteraction.instance.shrineBonusStacks > 0)
			{
				stringBuilder.AppendLine($"<style=cStack>Invitations: <style=cIsUtility>{TeleporterInteraction.instance.shrineBonusStacks}</style></style>");
			}
			return stringBuilder.ToString();
		}

		private static StringBuilder AppendFabricators(Interactables interactables, StringBuilder sb)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: 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)
			List<string> list = new List<string>();
			if (interactables.whiteTakers > 0)
			{
				int whiteTakers = interactables.whiteTakers;
				list.Add(Util.GenerateColoredString(whiteTakers.ToString(), ColorCatalog.GetColor((ColorIndex)1)));
			}
			if (interactables.greenTakers > 0)
			{
				int whiteTakers = interactables.greenTakers;
				list.Add(Util.GenerateColoredString(whiteTakers.ToString(), ColorCatalog.GetColor((ColorIndex)2)));
			}
			if (interactables.redTakers > 0)
			{
				int whiteTakers = interactables.redTakers;
				list.Add(Util.GenerateColoredString(whiteTakers.ToString(), ColorCatalog.GetColor((ColorIndex)3)));
			}
			if (interactables.yellowTakers > 0)
			{
				int whiteTakers = interactables.yellowTakers;
				list.Add(Util.GenerateColoredString(whiteTakers.ToString(), ColorCatalog.GetColor((ColorIndex)13)));
			}
			string text = string.Join(" · ", list);
			if (!string.IsNullOrEmpty(text))
			{
				sb.AppendLine(FormatToken("DUPLICATOR_NAME", "style", "cStack") + "<style=cStack>" + text + "</style>");
			}
			return sb;
		}

		private static string FormatEnemies()
		{
			int count = TeamComponent.GetTeamMembers((TeamIndex)2).Count;
			int count2 = TeamComponent.GetTeamMembers((TeamIndex)3).Count;
			int count3 = TeamComponent.GetTeamMembers((TeamIndex)4).Count;
			List<string> list = new List<string>();
			if (count > 0)
			{
				list.Add($"<style=cSub>{count}</style>");
			}
			if (count2 > 0)
			{
				list.Add($"<style=cLunarObjective>{count2}</style>");
			}
			if (count3 > 0)
			{
				list.Add($"<style=cIsVoid>{count3}</style>");
			}
			string text = string.Join(" · ", list);
			return "<style=cStack>Enemies: " + (string.IsNullOrEmpty(text) ? "0" : text) + "</style>";
		}

		private static string FormatLine(string tagKey, string tagValue, string token, int available, int total, int meta)
		{
			return FormatToken(token, tagKey, tagValue) + FormatCounter(available, total, meta);
		}

		private static string FormatLine(string tagKey, string tagValue, string token, int available, int total)
		{
			return FormatToken(token, tagKey, tagValue) + FormatCounter(available, total);
		}

		private static string FormatToken(string token, string tagKey, string tagValue)
		{
			return FormatLabel("<" + tagKey + "=" + tagValue + ">" + Language.GetString(token) + "</" + tagKey + ">");
		}

		private static string FormatLabel(string label)
		{
			return "<style=cStack>> </style>" + label + "<style=cStack>:</style> ";
		}

		private static string FormatCounter(int available, int total, int meta)
		{
			return $"{FormatCounter(available, total)}<style=cStack><size=90%> ({meta})</size></style>";
		}

		private static string FormatCounter(int available, int total)
		{
			if (available != 0)
			{
				return $"{available}<style=cStack>/{total}</style>";
			}
			return $"<style=cSub>{available}</style><style=cStack>/{total}</style>";
		}
	}
}
namespace HUDdleUP.Bandit
{
	internal sealed class BanditComboPanel : MonoBehaviour
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static ShouldHudDisplayDelegate <0>__Init;
		}

		private static HUD hud;

		private static ConsecutiveReset tracker;

		private HUDPanel panel;

		private TextMeshProUGUI display;

		public static void Hook()
		{
			//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>__Init;
			if (obj == null)
			{
				ShouldHudDisplayDelegate val = Init;
				<>O.<0>__Init = val;
				obj = (object)val;
			}
			HUD.shouldHudDisplay += (ShouldHudDisplayDelegate)obj;
		}

		public static void Unhook()
		{
			//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>__Init;
			if (obj == null)
			{
				ShouldHudDisplayDelegate val = Init;
				<>O.<0>__Init = val;
				obj = (object)val;
			}
			HUD.shouldHudDisplay -= (ShouldHudDisplayDelegate)obj;
			if (tracker != null)
			{
				tracker.Unhook();
				tracker = null;
			}
		}

		private static void Init(HUD hud, ref bool _)
		{
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.Config.BanditComboPanel || (Object)(object)BanditComboPanel.hud != (Object)null)
			{
				return;
			}
			ObjectivePanelController componentInChildren = ((Component)hud).GetComponentInChildren<ObjectivePanelController>();
			if (!Object.op_Implicit((Object)(object)componentInChildren) || (Object)(object)hud.localUserViewer.cachedBody == (Object)null)
			{
				return;
			}
			BanditComboPanel.hud = hud;
			if (hud.localUserViewer.cachedBody.bodyIndex != BodyCatalog.FindBodyIndex("Bandit2Body"))
			{
				Plugin.Logger.LogDebug((object)"Local user is not Bandit, skipping BanditComboPanel initialization.");
				return;
			}
			if (!ConsecutiveReset.HasRequiredSkill(hud.localUserViewer.cachedBody))
			{
				Plugin.Logger.LogDebug((object)"Local user is Bandit but does not have \"Lights Out\" selected, skipping BanditComboPanel initialization.");
				return;
			}
			if (tracker == null)
			{
				tracker = new ConsecutiveReset(hud.localUserViewer);
				tracker.Hook();
			}
			HUDPanel hUDPanel = HUDPanel.ClonePanel(componentInChildren, "BanditComboPanel");
			((Component)hud).gameObject.AddComponent<BanditComboPanel>().panel = hUDPanel;
			Plugin.Logger.LogDebug((object)"Initialized BanditComboPanel.");
		}

		private void Start()
		{
			((TMP_Text)panel.label).text = "Combo:";
			display = panel.AddTextComponent("Combo Tracker");
		}

		private void Update()
		{
			if (tracker != null)
			{
				((TMP_Text)display).text = tracker.ToString();
			}
		}

		private void FixedUpdate()
		{
			if (tracker != null)
			{
				tracker.FixedUpdate();
			}
		}
	}
	internal sealed class ConsecutiveReset
	{
		private const string banditSkullColour = "#40C5E4";

		private static readonly SkillDef requiredSkillDef = SkillCatalog.GetSkillDef(SkillCatalog.FindSkillIndexByName("Bandit2.ResetRevolver"));

		private readonly LocalUser user;

		private CharacterBody _trackedBody;

		private bool waitingForKill;

		private int _resets;

		private int consecutive;

		private int consecutiveBest;

		private int totalShots;

		private int resetShots;

		private int totalShotsStage;

		private int resetShotsStage;

		private CharacterBody trackedBody
		{
			get
			{
				return _trackedBody;
			}
			set
			{
				if ((Object)(object)value != (Object)(object)_trackedBody)
				{
					if ((Object)(object)_trackedBody != (Object)null)
					{
						_trackedBody.onSkillActivatedAuthority -= Tracker_Start;
					}
					_trackedBody = value;
					if ((Object)(object)_trackedBody != (Object)null)
					{
						_trackedBody.onSkillActivatedAuthority += Tracker_Start;
						resets = 0;
						waitingForKill = false;
					}
				}
			}
		}

		private int resets
		{
			get
			{
				return _resets;
			}
			set
			{
				_resets = value;
				if (resets < consecutive && consecutive > consecutiveBest)
				{
					consecutiveBest = consecutive;
				}
				consecutive = resets;
			}
		}

		public ConsecutiveReset(LocalUser user)
		{
			this.user = user;
		}

		public void Hook()
		{
			GlobalEventManager.onCharacterDeathGlobal += Tracker_End;
			Stage.onStageStartGlobal += OnStageStart;
		}

		public void Unhook()
		{
			GlobalEventManager.onCharacterDeathGlobal -= Tracker_End;
			trackedBody = null;
			Stage.onStageStartGlobal -= OnStageStart;
		}

		private void OnStageStart(Stage _)
		{
			totalShotsStage = 0;
			resetShotsStage = 0;
		}

		private void Tracker_Start(GenericSkill skillSlot)
		{
			if ((Object)(object)skillSlot.skillDef == (Object)(object)requiredSkillDef && (Object)(object)requiredSkillDef != (Object)null)
			{
				if (waitingForKill)
				{
					resets = 0;
				}
				waitingForKill = true;
				totalShots++;
				totalShotsStage++;
			}
		}

		private void Tracker_End(DamageReport damageReport)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Invalid comparison between Unknown and I4
			if (!((Object)(object)damageReport.attackerBody == (Object)null) && !((Object)(object)damageReport.attackerBody != (Object)(object)trackedBody) && (HUDdleUP.Compatibility.Compatibility.ExtractDamageType(damageReport.damageInfo) & 4) == 4)
			{
				waitingForKill = false;
				resets++;
				resetShots++;
				resetShotsStage++;
			}
		}

		internal static bool HasRequiredSkill(CharacterBody body)
		{
			return Object.op_Implicit((Object)(object)body.skillLocator.FindSkillByDef(requiredSkillDef));
		}

		private bool HasRequiredSkill()
		{
			return HasRequiredSkill(trackedBody);
		}

		internal void FixedUpdate()
		{
			trackedBody = user.currentNetworkUser.GetCurrentBody();
		}

		public override string ToString()
		{
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.Append("<style=cStack>> </style><color=#40C5E4>Consecutive Resets</color><style=cStack>: </style>");
			if (totalShots == 0)
			{
				stringBuilder.Append("<style=cStack>-.--%</style>");
			}
			else
			{
				stringBuilder.Append($"{(float)resetShots / (float)totalShots:0.00%}");
			}
			stringBuilder.AppendLine();
			stringBuilder.Append("<style=cStack>   > this stage: </style>");
			if (totalShotsStage == 0)
			{
				stringBuilder.Append("<style=cStack>-.--%</style>");
			}
			else
			{
				stringBuilder.Append($"{(float)resetShotsStage / (float)totalShotsStage:0.00%}");
			}
			stringBuilder.AppendLine($"<style=cStack> ({resetShotsStage}/{totalShotsStage})</style>");
			stringBuilder.Append($"<style=cStack>   > consecutive: </style>{consecutive}<style=cStack> ({consecutiveBest})</style>");
			bool flag = !HasRequiredSkill();
			bool flag2 = !NetworkServer.active;
			if (flag || flag2)
			{
				stringBuilder.AppendLine().AppendLine();
				if (flag)
				{
					stringBuilder.AppendLine("<size=80%><style=cDeath>WARN: nothing to track</style></size>");
					stringBuilder.Append("<size=80%><style=cStack>    × <style=cDeath><color=#40C5E4>" + Language.GetString(requiredSkillDef.skillNameToken) + "</color> not selected.</style></style></size>");
				}
				if (flag && flag2)
				{
					stringBuilder.AppendLine();
				}
				if (flag2)
				{
					stringBuilder.AppendLine("<size=80%><style=cDeath>WARN: sorry, this feature only works").Append("  on host.</style></size>");
					stringBuilder.AppendLine().Append("<size=80%><style=cStack>    × <style=cDeath>report on <style=cStack>GitHub</style> if you know a fix!</style></style></size>");
				}
			}
			return stringBuilder.ToString();
		}
	}
}
namespace HUDdleUP.Compatibility
{
	internal static class Compatibility
	{
		private static FieldInfo _DamageType_Field;

		private static FieldInfo _DamageTypeCombo_Field;

		internal static FieldInfo DamageType_Field
		{
			get
			{
				if (_DamageType_Field == null)
				{
					Plugin.Logger.LogWarning((object)"MissingFieldException: Using Seekers of the Storm version of DamageInfo.damageType");
					_DamageType_Field = DamageTypeCombo_Field.FieldType.GetField("damageType");
				}
				return _DamageType_Field;
			}
		}

		internal static FieldInfo DamageTypeCombo_Field
		{
			get
			{
				if (_DamageTypeCombo_Field == null)
				{
					_DamageTypeCombo_Field = typeof(DamageInfo).GetField("damageType");
				}
				return _DamageTypeCombo_Field;
			}
		}

		internal static DamageType ExtractDamageType(DamageInfo damageInfo)
		{
			//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_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				return ExtractDamageType_Old(damageInfo);
			}
			catch (MissingFieldException)
			{
				object value = DamageTypeCombo_Field.GetValue(damageInfo);
				return (DamageType)DamageType_Field.GetValue(value);
			}
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		private static DamageType ExtractDamageType_Old(DamageInfo damageInfo)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			return damageInfo.damageType;
		}
	}
	internal static class MiniMapMod
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static Manipulator <0>__TryCreateMinimap_InSeparatePanel;
		}

		internal const string PLUGIN_GUID = "MiniMap";

		private const string TARGET_ASSEMBLY = "MiniMapMod";

		private const string TARGET_TYPE = "MiniMapMod.MiniMapPlugin";

		private const string TARGET_METHOD = "TryCreateMinimap";

		internal static void TryPatch()
		{
			//IL_0080: 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_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Expected O, but got Unknown
			if (!Chainloader.PluginInfos.ContainsKey("MiniMap"))
			{
				return;
			}
			try
			{
				MethodInfo? obj = (AppDomain.CurrentDomain.GetAssemblies().SingleOrDefault((Assembly a) => a.GetName().Name == "MiniMapMod")?.GetType("MiniMapMod.MiniMapPlugin"))?.GetMethod("TryCreateMinimap", BindingFlags.Instance | BindingFlags.NonPublic);
				object obj2 = <>O.<0>__TryCreateMinimap_InSeparatePanel;
				if (obj2 == null)
				{
					Manipulator val = TryCreateMinimap_InSeparatePanel;
					<>O.<0>__TryCreateMinimap_InSeparatePanel = val;
					obj2 = (object)val;
				}
				new ILHook((MethodBase)obj, (Manipulator)obj2);
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogError((object)ex);
			}
		}

		private static void TryCreateMinimap_InSeparatePanel(ILContext il)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Expected O, but got Unknown
			ILCursor val = new ILCursor(il);
			Func<Instruction, bool>[] array = new Func<Instruction, bool>[3]
			{
				(Instruction x) => ILPatternMatchingExt.MatchLdstr(x, "ObjectivePanel"),
				(Instruction x) => ILPatternMatchingExt.MatchCallOrCallvirt<GameObject>(x, "Find"),
				(Instruction x) => ILPatternMatchingExt.MatchStloc(x, 0)
			};
			if (val.TryGotoNext((MoveType)2, array))
			{
				int index = val.Index;
				val.Index = index - 1;
				val.EmitDelegate<Func<GameObject, GameObject>>((Func<GameObject, GameObject>)delegate(GameObject objectivePanelGameObject)
				{
					if ((Object)(object)objectivePanelGameObject == (Object)null)
					{
						return null;
					}
					Plugin.Logger.LogDebug((object)("Compatibility: MiniMapMod> Attempting to redirect minimap creation from " + ((Object)objectivePanelGameObject).name + " to separate panel."));
					try
					{
						HUDPanel hUDPanel = HUDPanel.ClonePanel(objectivePanelGameObject.GetComponent<ObjectivePanelController>(), "MinimapPanel");
						if (Object.op_Implicit((Object)(object)hUDPanel.label))
						{
							Object.Destroy((Object)(object)((Component)hUDPanel.label).gameObject);
						}
						hUDPanel.gameObject.transform.SetAsFirstSibling();
						return hUDPanel.gameObject;
					}
					catch (Exception ex)
					{
						Plugin.Logger.LogError((object)ex);
						Plugin.Logger.LogWarning((object)"Compatibility: MiniMapMod> Attempt to redirect minimap creation failed! Using original target instead. Other HUD panels may have non-functional copies of the minimap.");
						return objectivePanelGameObject;
					}
				});
			}
			else
			{
				Plugin.Logger.LogError((object)"Compatibility: MiniMapMod> Cannot hook TryCreateMinimap: failed to match IL instructions.");
			}
		}
	}
}
namespace HUDdleUP.Behaviours
{
	internal class EquipmentCooldownPanel : MonoBehaviour
	{
		private static float LastLogTime;

		private EquipmentIcon parent;

		private RawImage cooldownRemapPanel;

		private float cooldownEndTime;

		private float cooldownTimerMax;

		internal static void Init(EquipmentIcon parent, GameObject target)
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = Object.Instantiate<GameObject>(target, ((Component)parent).transform);
			EquipmentCooldownPanel equipmentCooldownPanel = val.AddComponent<EquipmentCooldownPanel>();
			equipmentCooldownPanel.parent = parent;
			equipmentCooldownPanel.cooldownRemapPanel = val.GetComponent<RawImage>();
			((RectTransform)((Component)equipmentCooldownPanel.cooldownRemapPanel).transform).sizeDelta = ((RectTransform)((Component)parent).transform).sizeDelta;
		}

		private void Update()
		{
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: 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_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: 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)
			if ((Object)(object)parent == (Object)null)
			{
				float time = Time.time;
				if (!Mathf.Approximately(LastLogTime, time))
				{
					Plugin.Logger.LogWarning((object)"EquipmentCooldownPanel> Component instantiated but parent became null, removing self. This warning can safely be ignored if Starstorm 2 is installed.");
					LastLogTime = time;
				}
				Object.Destroy((Object)(object)((Component)this).gameObject);
				return;
			}
			float num = 1f;
			if (Object.op_Implicit((Object)(object)parent.targetInventory))
			{
				EquipmentState val = (parent.displayAlternateEquipment ? parent.targetInventory.alternateEquipmentState : parent.targetInventory.currentEquipmentState);
				float timeUntilClamped = ((FixedTimeStamp)(ref val.chargeFinishTime)).timeUntilClamped;
				if (cooldownEndTime != val.chargeFinishTime.t)
				{
					cooldownTimerMax = timeUntilClamped;
					cooldownEndTime = val.chargeFinishTime.t;
				}
				if (cooldownTimerMax > 0f)
				{
					num = 1f - timeUntilClamped / cooldownTimerMax;
				}
			}
			((Behaviour)cooldownRemapPanel).enabled = num < 1f;
			((Graphic)cooldownRemapPanel).color = new Color(1f, 1f, 1f, num);
		}
	}
}