Decompiled source of QualityHUDdleUPCompat v1.0.2

QualitiesHUDdleUPCompat.dll

Decompiled 3 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using RoR2;
using UnityEngine;

[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("QualitiesHUDdleUPCompat")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("QualitiesHUDdleUPCompat")]
[assembly: AssemblyTitle("QualitiesHUDdleUPCompat")]
[assembly: AssemblyVersion("1.0.0.0")]
[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 QualitiesHUDdleUPCompat
{
	[BepInPlugin("com.dbossofdworld.qualitieshuddleupcompat", "Qualities HUDdleUP Compat", "1.0.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		private enum DisplayTiming
		{
			Always,
			AfterTeleporterBossDefeated,
			AfterTeleporterCharged,
			Never
		}

		private Harmony harmony;

		private static ConfigEntry<bool> enableQualityChestLabel;

		private static ConfigEntry<bool> enableQualityCloakedChestLabel;

		private static ConfigEntry<bool> enableQualityEquipmentBarrelLabel;

		private static ConfigEntry<bool> enableQualityPrinterLabel;

		private static ConfigEntry<DisplayTiming> qualityChestDisplayTiming;

		private static ConfigEntry<DisplayTiming> qualityCloakedChestDisplayTiming;

		private static ConfigEntry<DisplayTiming> qualityEquipmentBarrelDisplayTiming;

		private static ConfigEntry<DisplayTiming> qualityPrinterDisplayTiming;

		private static ConfigEntry<string> qualityChestLabel;

		private static ConfigEntry<string> qualityCloakedChestLabel;

		private static ConfigEntry<string> qualityEquipmentBarrelLabel;

		private static ConfigEntry<string> qualityPrinterLabel;

		private static ConfigEntry<string> qualityChestLabelColor;

		private static ConfigEntry<string> qualityCloakedChestLabelColor;

		private static ConfigEntry<string> qualityEquipmentBarrelLabelColor;

		private static ConfigEntry<string> qualityPrinterLabelColor;

		private static ConfigEntry<bool> combineQualityChestWithNormalChest;

		private static ConfigEntry<bool> combineQualityEquipmentBarrelWithNormalEquipmentBarrel;

		private static ConfigEntry<bool> enableDebugLogging;

		private static int qualityChests;

		private static int qualityChestsAvailable;

		private static int qualityCloakedChests;

		private static int qualityCloakedChestsAvailable;

		private static int qualityEquipmentBarrels;

		private static int qualityEquipmentBarrelsAvailable;

		private static int qualityPrinters;

		private static int qualityPrintersAvailable;

		private static MethodInfo hudFormatLabelMethod;

		private static MethodInfo hudFormatCounterMethod;

		public void Awake()
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Expected O, but got Unknown
			BindConfig();
			harmony = new Harmony("com.dbossofdworld.qualitieshuddleupcompat");
			try
			{
				Assembly assembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault((Assembly a) => a.GetName().Name.Equals("HUDdleUP", StringComparison.OrdinalIgnoreCase));
				if (assembly == null)
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)"HUDdleUP assembly not found. Compat patch skipped.");
					return;
				}
				PatchInteractablesConstructor(assembly);
				PatchLootPanelText(assembly);
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Qualities HUDdleUP Compat 1.0.0 loaded.");
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)ex);
			}
		}

		private void BindConfig()
		{
			enableQualityChestLabel = ((BaseUnityPlugin)this).Config.Bind<bool>("Labels - Enable", "Enable Quality Chest", true, "If true, shows the Quality Chest line on HUDdleUP's loot panel.");
			enableQualityCloakedChestLabel = ((BaseUnityPlugin)this).Config.Bind<bool>("Labels - Enable", "Enable Quality Cloaked Chest", true, "If true, shows the Quality Cloaked Chest line on HUDdleUP's loot panel.");
			enableQualityEquipmentBarrelLabel = ((BaseUnityPlugin)this).Config.Bind<bool>("Labels - Enable", "Enable Quality Equipment Barrel", true, "If true, shows the Quality Equipment Barrel line on HUDdleUP's loot panel.");
			enableQualityPrinterLabel = ((BaseUnityPlugin)this).Config.Bind<bool>("Labels - Enable", "Enable Quality 3D Printer", true, "If true, shows the Quality 3D Printer line on HUDdleUP's loot panel.");
			qualityChestDisplayTiming = ((BaseUnityPlugin)this).Config.Bind<DisplayTiming>("Labels - Timing", "Quality Chest Timing", DisplayTiming.Always, "When the Quality Chest line should appear. Options: Always, AfterTeleporterBossDefeated, AfterTeleporterCharged, Never.");
			qualityCloakedChestDisplayTiming = ((BaseUnityPlugin)this).Config.Bind<DisplayTiming>("Labels - Timing", "Quality Cloaked Chest Timing", DisplayTiming.AfterTeleporterBossDefeated, "When the Quality Cloaked Chest line should appear. Options: Always, AfterTeleporterBossDefeated, AfterTeleporterCharged, Never.");
			qualityEquipmentBarrelDisplayTiming = ((BaseUnityPlugin)this).Config.Bind<DisplayTiming>("Labels - Timing", "Quality Equipment Barrel Timing", DisplayTiming.Always, "When the Quality Equipment Barrel line should appear. Options: Always, AfterTeleporterBossDefeated, AfterTeleporterCharged, Never.");
			qualityPrinterDisplayTiming = ((BaseUnityPlugin)this).Config.Bind<DisplayTiming>("Labels - Timing", "Quality 3D Printer Timing", DisplayTiming.AfterTeleporterBossDefeated, "When the Quality 3D Printer line should appear. Options: Always, AfterTeleporterBossDefeated, AfterTeleporterCharged, Never.");
			qualityChestLabel = ((BaseUnityPlugin)this).Config.Bind<string>("Labels - Text", "Quality Chest Label", "Quality Chest", "Text used for the Quality Chest line.");
			qualityCloakedChestLabel = ((BaseUnityPlugin)this).Config.Bind<string>("Labels - Text", "Quality Cloaked Chest Label", "Quality Cloaked Chest", "Text used for the Quality Cloaked Chest line.");
			qualityEquipmentBarrelLabel = ((BaseUnityPlugin)this).Config.Bind<string>("Labels - Text", "Quality Equipment Barrel Label", "Quality Equipment Barrel", "Text used for the Quality Equipment Barrel line.");
			qualityPrinterLabel = ((BaseUnityPlugin)this).Config.Bind<string>("Labels - Text", "Quality 3D Printer Label", "Quality 3D Printer", "Text used for the Quality 3D Printer line.");
			qualityChestLabelColor = ((BaseUnityPlugin)this).Config.Bind<string>("Labels - Color", "Quality Chest Label Color", "#FFFFFFFF", "Hex color for the Quality Chest label. Example: #FFFFFFFF for white.");
			qualityCloakedChestLabelColor = ((BaseUnityPlugin)this).Config.Bind<string>("Labels - Color", "Quality Cloaked Chest Label Color", "#FFFFFFFF", "Hex color for the Quality Cloaked Chest label. Example: #FFFFFFFF for white.");
			qualityEquipmentBarrelLabelColor = ((BaseUnityPlugin)this).Config.Bind<string>("Labels - Color", "Quality Equipment Barrel Label Color", "#FFFFFFFF", "Hex color for the Quality Equipment Barrel label. Example: #FFFFFFFF for white.");
			qualityPrinterLabelColor = ((BaseUnityPlugin)this).Config.Bind<string>("Labels - Color", "Quality 3D Printer Label Color", "#FFFFFFFF", "Hex color for the Quality 3D Printer label. Example: #FFFFFFFF for white.");
			combineQualityChestWithNormalChest = ((BaseUnityPlugin)this).Config.Bind<bool>("Formatting", "Combine Quality Chest With Normal Chest", false, "If true, Quality Chest counts are added to HUDdleUP's normal Chest line instead of showing a separate Quality Chest line.");
			combineQualityEquipmentBarrelWithNormalEquipmentBarrel = ((BaseUnityPlugin)this).Config.Bind<bool>("Formatting", "Combine Quality Equipment Barrel With Normal Equipment Barrel", false, "If true, Quality Equipment Barrel counts are added to HUDdleUP's normal Equipment Barrel line instead of showing a separate Quality Equipment Barrel line.");
			enableDebugLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "Enable Debug Logging", false, "If true, logs possible Quality interactables seen by the compatibility mod.");
		}

		private void PatchInteractablesConstructor(Assembly hudAsm)
		{
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Expected O, but got Unknown
			Type type = hudAsm.GetType("HUDdleUP.Loot.Interactables");
			if (type == null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)"Could not find HUDdleUP.Loot.Interactables. HUDdleUP may have changed its loot internals.");
				return;
			}
			ConstructorInfo constructor = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public, null, new Type[1] { typeof(List<PurchaseInteraction>) }, null);
			if (constructor == null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)"Could not find Interactables(List<PurchaseInteraction>). HUDdleUP may have changed its loot internals.");
				return;
			}
			harmony.Patch((MethodBase)constructor, (HarmonyMethod)null, new HarmonyMethod(typeof(Plugin).GetMethod("InteractablesCtorPostfix", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Patched HUDdleUP.Loot.Interactables constructor for separate Quality loot counts.");
		}

		private void PatchLootPanelText(Assembly hudAsm)
		{
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Expected O, but got Unknown
			Type type = hudAsm.GetType("HUDdleUP.Loot.LootPanel");
			if (type == null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)"Could not find HUDdleUP.Loot.LootPanel. Separate Quality loot lines will not be displayed.");
				return;
			}
			MethodInfo methodInfo = type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault((MethodInfo m) => m.Name == "GenerateText" && m.ReturnType == typeof(string));
			if (methodInfo == null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)"Could not find LootPanel.GenerateText returning string. Separate Quality loot lines will not be displayed.");
				return;
			}
			hudFormatLabelMethod = type.GetMethod("FormatLabel", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(string) }, null);
			hudFormatCounterMethod = type.GetMethod("FormatCounter", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[2]
			{
				typeof(int),
				typeof(int)
			}, null);
			if (hudFormatLabelMethod == null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)"Could not find HUDdleUP FormatLabel method. Falling back to local Quality line formatting.");
			}
			if (hudFormatCounterMethod == null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)"Could not find HUDdleUP FormatCounter method. Falling back to local Quality counter formatting.");
			}
			harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(Plugin).GetMethod("GenerateTextPostfix", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Patched HUDdleUP.Loot.LootPanel.GenerateText for separate Quality loot lines.");
		}

		private static void InteractablesCtorPostfix(object __instance, List<PurchaseInteraction> interactions)
		{
			if (__instance == null || interactions == null)
			{
				return;
			}
			int num = 0;
			int num2 = 0;
			int num3 = 0;
			int num4 = 0;
			int num5 = 0;
			int num6 = 0;
			int num7 = 0;
			int num8 = 0;
			foreach (PurchaseInteraction interaction in interactions)
			{
				if ((Object)(object)interaction == (Object)null)
				{
					continue;
				}
				string text = interaction.displayNameToken ?? "";
				string text2 = (Object.op_Implicit((Object)(object)((Component)interaction).gameObject) ? (((Object)((Component)interaction).gameObject).name ?? "") : "");
				if (enableDebugLogging != null && enableDebugLogging.Value && LooksQualityRelated(text, text2))
				{
					Debug.Log((object)$"[QualitiesHUDdleUPCompat] Saw possible Quality interactable: token={text}, object={text2}, available={interaction.available}");
				}
				if (IsQualityPrinter(text, text2))
				{
					num7++;
					if (interaction.available)
					{
						num8++;
					}
				}
				else if (IsQualityEquipmentBarrel(text, text2))
				{
					num5++;
					if (interaction.available)
					{
						num6++;
					}
				}
				else
				{
					if (!IsQualityChest(text, text2))
					{
						continue;
					}
					if (IsCloaked(text, text2))
					{
						num3++;
						if (interaction.available)
						{
							num4++;
						}
					}
					else
					{
						num++;
						if (interaction.available)
						{
							num2++;
						}
					}
				}
			}
			qualityChests = num;
			qualityChestsAvailable = num2;
			qualityCloakedChests = num3;
			qualityCloakedChestsAvailable = num4;
			qualityEquipmentBarrels = num5;
			qualityEquipmentBarrelsAvailable = num6;
			qualityPrinters = num7;
			qualityPrintersAvailable = num8;
		}

		private static void GenerateTextPostfix(ref string __result)
		{
			if (string.IsNullOrEmpty(__result))
			{
				return;
			}
			List<string> list = __result.Replace("\r\n", "\n").Replace('\r', '\n').Split('\n')
				.ToList();
			bool flag = false;
			bool flag2 = false;
			if (ShouldCombineQualityChestWithNormalChest())
			{
				flag = TryMergeQualityCountIntoExistingLine(list, (string line) => ContainsIgnoreCase(line, "Chest") && !ContainsIgnoreCase(line, "Quality") && !ContainsIgnoreCase(line, "Cloaked") && !ContainsIgnoreCase(line, "Legendary") && !ContainsIgnoreCase(line, "Equipment"), "Chest", qualityChestsAvailable, qualityChests);
			}
			if (ShouldCombineQualityEquipmentBarrelWithNormalEquipmentBarrel())
			{
				flag2 = TryMergeQualityCountIntoExistingLine(list, (string line) => ContainsIgnoreCase(line, "Equipment Barrel") && !ContainsIgnoreCase(line, "Quality"), "Equipment Barrel", qualityEquipmentBarrelsAvailable, qualityEquipmentBarrels);
			}
			List<string> list2 = BuildQualityOpenableLootLines(flag, flag2);
			List<string> list3 = BuildQualityPrinterLootLines();
			if (list2.Count != 0 || list3.Count != 0 || flag || flag2)
			{
				if (list2.Count > 0)
				{
					InsertQualityOpenableLines(list, list2);
				}
				if (list3.Count > 0)
				{
					InsertQualityPrinterLines(list, list3);
				}
				__result = string.Join("\n", list);
			}
		}

		private static bool ShouldCombineQualityChestWithNormalChest()
		{
			if (combineQualityChestWithNormalChest != null && combineQualityChestWithNormalChest.Value && enableQualityChestLabel != null && enableQualityChestLabel.Value && qualityChests > 0)
			{
				return ShouldDisplay(qualityChestDisplayTiming.Value);
			}
			return false;
		}

		private static bool ShouldCombineQualityEquipmentBarrelWithNormalEquipmentBarrel()
		{
			if (combineQualityEquipmentBarrelWithNormalEquipmentBarrel != null && combineQualityEquipmentBarrelWithNormalEquipmentBarrel.Value && enableQualityEquipmentBarrelLabel != null && enableQualityEquipmentBarrelLabel.Value && qualityEquipmentBarrels > 0)
			{
				return ShouldDisplay(qualityEquipmentBarrelDisplayTiming.Value);
			}
			return false;
		}

		private static bool TryMergeQualityCountIntoExistingLine(List<string> lines, Func<string, bool> linePredicate, string normalLabel, int qualityAvailable, int qualityTotal)
		{
			if (lines == null || linePredicate == null || qualityTotal <= 0)
			{
				return false;
			}
			int num = FindLineIndex(lines, linePredicate);
			if (num < 0)
			{
				return false;
			}
			string text = lines[num];
			Match match = Regex.Match(StripRichTextTags(text), "(?<available>\\d+)\\s*/\\s*(?<total>\\d+)");
			if (!match.Success)
			{
				return false;
			}
			if (!int.TryParse(match.Groups["available"].Value, out var result))
			{
				return false;
			}
			if (!int.TryParse(match.Groups["total"].Value, out var result2))
			{
				return false;
			}
			string value = GetOriginalLinePrefixBeforeCounter(text);
			if (string.IsNullOrEmpty(value))
			{
				value = FormatHudLabel(normalLabel);
			}
			value = CloseUnclosedRichTextTags(value);
			lines[num] = value + FormatHudCounter(result + qualityAvailable, result2 + qualityTotal);
			return true;
		}

		private static string GetOriginalLinePrefixBeforeCounter(string line)
		{
			if (string.IsNullOrEmpty(line))
			{
				return string.Empty;
			}
			int num = line.LastIndexOf(':');
			if (num < 0)
			{
				return string.Empty;
			}
			int i;
			for (i = num + 1; i < line.Length && char.IsWhiteSpace(line[i]); i++)
			{
			}
			return line.Substring(0, i);
		}

		private static string CloseUnclosedRichTextTags(string value)
		{
			if (string.IsNullOrEmpty(value))
			{
				return string.Empty;
			}
			StringBuilder stringBuilder = new StringBuilder(value);
			int count = Regex.Matches(value, "<color(?:=|>)", RegexOptions.IgnoreCase).Count;
			for (int i = Regex.Matches(value, "</color>", RegexOptions.IgnoreCase).Count; i < count; i++)
			{
				stringBuilder.Append("</color>");
			}
			int count2 = Regex.Matches(value, "<style(?:=|>)", RegexOptions.IgnoreCase).Count;
			for (int j = Regex.Matches(value, "</style>", RegexOptions.IgnoreCase).Count; j < count2; j++)
			{
				stringBuilder.Append("</style>");
			}
			return stringBuilder.ToString();
		}

		private static string StripRichTextTags(string value)
		{
			if (string.IsNullOrEmpty(value))
			{
				return string.Empty;
			}
			return Regex.Replace(value, "<.*?>", string.Empty);
		}

		private static void InsertQualityOpenableLines(List<string> lines, List<string> qualityLines)
		{
			int num = FindFirstUtilityLineIndex(lines);
			if (num >= 0)
			{
				int index = num;
				if (num > 0 && string.IsNullOrWhiteSpace(lines[num - 1]))
				{
					index = num - 1;
				}
				lines.InsertRange(index, qualityLines);
				return;
			}
			int num2 = FindLineIndex(lines, (string line) => ContainsIgnoreCase(line, "Enemies"));
			int num3 = FindLineIndex(lines, IsStageHeaderLine);
			int num4 = ((num2 >= 0) ? num2 : num3);
			if (num4 >= 0)
			{
				if (num4 > 0 && string.IsNullOrWhiteSpace(lines[num4 - 1]))
				{
					num4--;
					lines.RemoveAt(num4);
				}
				lines.InsertRange(num4, qualityLines);
				int num5 = num4 + qualityLines.Count;
				if (num5 >= lines.Count || !string.IsNullOrWhiteSpace(lines[num5]))
				{
					lines.Insert(num5, string.Empty);
				}
			}
			else
			{
				lines.AddRange(qualityLines);
			}
		}

		private static void InsertQualityPrinterLines(List<string> lines, List<string> qualityLines)
		{
			int num = FindLineIndex(lines, (string line) => ContainsIgnoreCase(line, "Enemies"));
			int num2 = FindLineIndex(lines, IsStageHeaderLine);
			int num3 = ((num >= 0) ? num : num2);
			int num4 = FindLastUtilityLineIndex(lines, num3);
			if (num4 >= 0)
			{
				lines.InsertRange(num4 + 1, qualityLines);
			}
			else if (num3 >= 0)
			{
				if (num3 > 0 && string.IsNullOrWhiteSpace(lines[num3 - 1]))
				{
					num3--;
					lines.RemoveAt(num3);
				}
				lines.InsertRange(num3, qualityLines);
				int num5 = num3 + qualityLines.Count;
				if (num5 >= lines.Count || !string.IsNullOrWhiteSpace(lines[num5]))
				{
					lines.Insert(num5, string.Empty);
				}
			}
			else
			{
				lines.AddRange(qualityLines);
			}
		}

		private static int FindFirstUtilityLineIndex(List<string> lines)
		{
			return FindLineIndex(lines, (string line) => !ContainsIgnoreCase(line, "Quality") && (ContainsIgnoreCase(line, "Scrapper") || ContainsIgnoreCase(line, "Printer")));
		}

		private static int FindLastUtilityLineIndex(List<string> lines, int boundaryIndex)
		{
			int num = ((boundaryIndex >= 0) ? boundaryIndex : lines.Count);
			int result = -1;
			for (int i = 0; i < num; i++)
			{
				string value = lines[i];
				if (!ContainsIgnoreCase(value, "Quality") && (ContainsIgnoreCase(value, "Scrapper") || ContainsIgnoreCase(value, "Printer")))
				{
					result = i;
				}
			}
			return result;
		}

		private static int FindLineIndex(List<string> lines, Func<string, bool> predicate)
		{
			for (int i = 0; i < lines.Count; i++)
			{
				if (predicate(lines[i]))
				{
					return i;
				}
			}
			return -1;
		}

		private static bool IsStageHeaderLine(string line)
		{
			return line?.TrimStart().StartsWith("-- ", StringComparison.OrdinalIgnoreCase) ?? false;
		}

		private static bool ContainsIgnoreCase(string value, string search)
		{
			if (value != null)
			{
				return value.IndexOf(search, StringComparison.OrdinalIgnoreCase) >= 0;
			}
			return false;
		}

		private static List<string> BuildQualityOpenableLootLines(bool qualityChestWasCombined, bool qualityEquipmentWasCombined)
		{
			List<string> list = new List<string>();
			if (!qualityChestWasCombined && enableQualityChestLabel.Value && qualityChests > 0 && ShouldDisplay(qualityChestDisplayTiming.Value))
			{
				bool flag = ShouldCombineQualityChestWithNormalChest();
				list.Add(flag ? FormatNormalAvailableLine("Chest", qualityChestsAvailable, qualityChests) : FormatAvailableLine(qualityChestLabel.Value, qualityChestLabelColor.Value, qualityChestsAvailable, qualityChests));
			}
			if (enableQualityCloakedChestLabel.Value && qualityCloakedChests > 0 && ShouldDisplay(qualityCloakedChestDisplayTiming.Value))
			{
				list.Add(FormatAvailableLine(qualityCloakedChestLabel.Value, qualityCloakedChestLabelColor.Value, qualityCloakedChestsAvailable, qualityCloakedChests));
			}
			if (!qualityEquipmentWasCombined && enableQualityEquipmentBarrelLabel.Value && qualityEquipmentBarrels > 0 && ShouldDisplay(qualityEquipmentBarrelDisplayTiming.Value))
			{
				bool flag2 = ShouldCombineQualityEquipmentBarrelWithNormalEquipmentBarrel();
				list.Add(flag2 ? FormatNormalAvailableLine("Equipment Barrel", qualityEquipmentBarrelsAvailable, qualityEquipmentBarrels) : FormatAvailableLine(qualityEquipmentBarrelLabel.Value, qualityEquipmentBarrelLabelColor.Value, qualityEquipmentBarrelsAvailable, qualityEquipmentBarrels));
			}
			return list;
		}

		private static List<string> BuildQualityPrinterLootLines()
		{
			List<string> list = new List<string>();
			if (enableQualityPrinterLabel.Value && qualityPrinters > 0 && ShouldDisplay(qualityPrinterDisplayTiming.Value))
			{
				list.Add(FormatTotalOnlyLine(qualityPrinterLabel.Value, qualityPrinterLabelColor.Value, qualityPrinters));
			}
			return list;
		}

		private static bool ShouldDisplay(DisplayTiming timing)
		{
			switch (timing)
			{
			case DisplayTiming.Always:
				return true;
			case DisplayTiming.AfterTeleporterBossDefeated:
				return IsTeleporterBossDefeated();
			case DisplayTiming.AfterTeleporterCharged:
				if ((Object)(object)TeleporterInteraction.instance != (Object)null)
				{
					return TeleporterInteraction.instance.isCharged;
				}
				return false;
			default:
				return false;
			}
		}

		private static bool IsTeleporterBossDefeated()
		{
			TeleporterInteraction instance = TeleporterInteraction.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return false;
			}
			if (instance.isCharged)
			{
				return true;
			}
			try
			{
				object memberValue = GetMemberValue(instance, "bossGroup");
				if (memberValue == null)
				{
					memberValue = GetMemberValue(instance, "currentBossGroup");
				}
				if (memberValue == null)
				{
					return false;
				}
				if (GetMemberValue(memberValue, "isDefeated") is bool result)
				{
					return result;
				}
				if (GetMemberValue(memberValue, "livingMembers") is int num)
				{
					return num <= 0;
				}
				if (GetMemberValue(memberValue, "membersList") is ICollection collection)
				{
					return collection.Count == 0;
				}
			}
			catch
			{
			}
			return false;
		}

		private static object GetMemberValue(object instance, string memberName)
		{
			if (instance == null || string.IsNullOrEmpty(memberName))
			{
				return null;
			}
			Type type = instance.GetType();
			FieldInfo field = type.GetField(memberName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (field != null)
			{
				return field.GetValue(instance);
			}
			PropertyInfo property = type.GetProperty(memberName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (property != null && property.GetIndexParameters().Length == 0)
			{
				return property.GetValue(instance, null);
			}
			return null;
		}

		private static string FormatNormalAvailableLine(string label, int available, int total)
		{
			return FormatHudLabel(label) + FormatHudCounter(available, total);
		}

		private static string FormatAvailableLine(string label, string color, int available, int total)
		{
			return FormatHudLabel(WrapColor(label, color)) + FormatHudCounter(available, total);
		}

		private static string FormatTotalOnlyLine(string label, string color, int total)
		{
			return FormatHudLabel(WrapColor(label, color)) + total;
		}

		private static string FormatHudLabel(string formattedLabel)
		{
			try
			{
				if (hudFormatLabelMethod != null)
				{
					return (string)hudFormatLabelMethod.Invoke(null, new object[1] { formattedLabel });
				}
			}
			catch
			{
			}
			return "> " + formattedLabel + ": ";
		}

		private static string FormatHudCounter(int available, int total)
		{
			try
			{
				if (hudFormatCounterMethod != null)
				{
					return (string)hudFormatCounterMethod.Invoke(null, new object[2] { available, total });
				}
			}
			catch
			{
			}
			return $"{available}/{total}";
		}

		private static string WrapColor(string label, string color)
		{
			if (string.IsNullOrWhiteSpace(label))
			{
				label = "Quality";
			}
			string text = NormalizeColor(color);
			return "<color=" + text + ">" + label + "</color>";
		}

		private static string NormalizeColor(string color)
		{
			if (string.IsNullOrWhiteSpace(color))
			{
				return "#FFFFFFFF";
			}
			color = color.Trim();
			if (!color.StartsWith("#"))
			{
				color = "#" + color;
			}
			if (color.Length == 4 || color.Length == 7 || color.Length == 9)
			{
				return color;
			}
			return "#FFFFFFFF";
		}

		private static bool LooksQualityRelated(string token, string objectName)
		{
			if (token.IndexOf("QUALITY", StringComparison.OrdinalIgnoreCase) < 0 && objectName.IndexOf("Quality", StringComparison.OrdinalIgnoreCase) < 0)
			{
				return objectName.IndexOf("ItemQualities", StringComparison.OrdinalIgnoreCase) >= 0;
			}
			return true;
		}

		private static bool IsQualityChest(string token, string objectName)
		{
			if (LooksQualityRelated(token, objectName))
			{
				if (token.IndexOf("CHEST", StringComparison.OrdinalIgnoreCase) < 0)
				{
					return objectName.IndexOf("Chest", StringComparison.OrdinalIgnoreCase) >= 0;
				}
				return true;
			}
			return false;
		}

		private static bool IsQualityEquipmentBarrel(string token, string objectName)
		{
			if (LooksQualityRelated(token, objectName))
			{
				if (token.IndexOf("EQUIPMENT", StringComparison.OrdinalIgnoreCase) < 0 && objectName.IndexOf("Equipment", StringComparison.OrdinalIgnoreCase) < 0)
				{
					return objectName.IndexOf("Barrel", StringComparison.OrdinalIgnoreCase) >= 0;
				}
				return true;
			}
			return false;
		}

		private static bool IsQualityPrinter(string token, string objectName)
		{
			if (LooksQualityRelated(token, objectName))
			{
				if (token.IndexOf("DUPLICATOR", StringComparison.OrdinalIgnoreCase) < 0 && token.IndexOf("PRINTER", StringComparison.OrdinalIgnoreCase) < 0 && objectName.IndexOf("Duplicator", StringComparison.OrdinalIgnoreCase) < 0)
				{
					return objectName.IndexOf("Printer", StringComparison.OrdinalIgnoreCase) >= 0;
				}
				return true;
			}
			return false;
		}

		private static bool IsCloaked(string token, string objectName)
		{
			if (token.IndexOf("STEALTHED", StringComparison.OrdinalIgnoreCase) < 0 && objectName.IndexOf("Stealthed", StringComparison.OrdinalIgnoreCase) < 0)
			{
				return objectName.IndexOf("Cloaked", StringComparison.OrdinalIgnoreCase) >= 0;
			}
			return true;
		}
	}
}